ghostdogpr / caliban

Functional GraphQL library for Scala

Home Page:https://ghostdogpr.github.io/caliban/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Rendering. renderDescription produces SDL that can't be parsed

camarena opened this issue · comments

I'm having a problem with the parsing/rendering code in caliban. I have a couple of cases where the SDL generated by Rendering can't be parsed by RemoteSchema (or by a bunch of other graphQL tools for that matter).

The following snippet shows the problem.

import caliban.Rendering
import caliban.tools.{RemoteSchema, SchemaLoader}
import zio.Console._
import zio._

object ReproduceBug extends ZIOAppDefault {
  val tripleQuoteSchema =
      "\"\"\"This is a description \nwith a \"quote at the end\"\n\"\"\"" +
      """
        |type MyType {
        |   aField: String
        |}
        |
        |type Query{someQuery: MyType}
        |""".stripMargin

  def parseSchema(schema: String) = SchemaLoader.fromString(schema).load.flatMap(d => ZIO.fromOption(RemoteSchema.parseRemoteSchema(d)))

  override def run = {
    var topType = """schema{
                    |   query: Query
                    |}
                    |""".stripMargin
    for {
      schema <- parseSchema(topType + tripleQuoteSchema)
      _ <- printLine(s"Schema read ok")
      renderedSchema <- ZIO.attempt(Rendering.renderTypes(schema.types))
      _ <- printLine(s"Rendered schema contains four double quotes on description:\n$renderedSchema")
      parsedRenderedSchema <- parseSchema(topType + renderedSchema).catchAll(_ =>
        printLine("ERROR: Rendered schema can't be parsed")) *> ZIO.succeed()
    } yield ()
  }
}

This is how I'm working around the issue.

  private def renderDescription(description: Option[String], newline: Boolean = true): String = description match
    case None                   => ""
    case Some(value) if newline =>
      if value.contains("\n") then
        renderTripleQuotedString("\n" + value + (if value.endsWith("\n") then "" else "\n")) + "\n"
      else renderString(value) + "\n"
    case Some(value)            =>
      if value.contains("\n") then renderTripleQuotedString(value + (if value.endsWith("\"") then " " else "")) + " "
      else renderString(value) + " "

If you think this is the correct fix I can submit a PR.

Another concern I have as I read the October 2021 spec the grammar production for BlockString should not be greedy. So the parser should deal with BlockStrings that end in """, """" and """"".

All the tools/parsers I tried are greedy since it is a lot easier to implement without looking ahead the incoming tokens. This makes my code necessary to interact with other tools.

You're right! A PR with the related tests would be welcome!

I'll work on the tests and submit the PR. This week is pretty busy at work but I'll get to it as soon as I can