diff --git a/src/main/java/graphql/GraphQLError.java b/src/main/java/graphql/GraphQLError.java index b4fc6fa600..c18752b14a 100644 --- a/src/main/java/graphql/GraphQLError.java +++ b/src/main/java/graphql/GraphQLError.java @@ -39,8 +39,10 @@ public interface GraphQLError extends Serializable { ErrorClassification getErrorType(); /** - * The graphql spec says that the (optional) path field of any error should be a list - * of path entries https://spec.graphql.org/October2021/#sec-Handling-Field-Errors + * The graphql spec says that the (optional) path field of any error must be + * a list of path entries starting at the root of the response + * and ending with the field associated with the error + * https://spec.graphql.org/draft/#sec-Errors.Error-Result-Format * * @return the path in list format */ diff --git a/src/main/java/graphql/language/AstPrinter.java b/src/main/java/graphql/language/AstPrinter.java index 218dabd59e..5070a4f139 100644 --- a/src/main/java/graphql/language/AstPrinter.java +++ b/src/main/java/graphql/language/AstPrinter.java @@ -534,7 +534,7 @@ private String description(Node node) { if (description.isMultiLine()) { s = "\"\"\"" + (startNewLine ? "" : "\n") + description.getContent() + "\n\"\"\"\n"; } else { - s = "\"" + description.getContent() + "\"\n"; + s = "\"" + escapeJsonString(description.getContent()) + "\"\n"; } return s; } diff --git a/src/test/groovy/graphql/parser/ParserTest.groovy b/src/test/groovy/graphql/parser/ParserTest.groovy index 4484eb9e58..42e604e9a6 100644 --- a/src/test/groovy/graphql/parser/ParserTest.groovy +++ b/src/test/groovy/graphql/parser/ParserTest.groovy @@ -4,6 +4,7 @@ package graphql.parser import graphql.language.Argument import graphql.language.ArrayValue import graphql.language.AstComparator +import graphql.language.AstPrinter import graphql.language.BooleanValue import graphql.language.Description import graphql.language.Directive @@ -1151,5 +1152,40 @@ triple3 : """edge cases \\""" "" " \\"" \\" edge cases""" document.getDefinitions()[0].getSourceLocation() == SourceLocation.EMPTY } + def "escape characters correctly printed when printing AST"() { + given: + def env = newParserEnvironment() + .document(src) + .parserOptions( + ParserOptions.newParserOptions() + .captureIgnoredChars(true) + .build() + ) + .build() + + when: + // Parse the original Document + def doc = Parser.parse(env) + // Print the AST + def printed = AstPrinter.printAst(doc) + // Re-parse printed AST + def reparsed = Parser.parse(printed) + + then: + noExceptionThrown() // The printed AST was re-parsed without exception + + when: + def reparsedPrinted = AstPrinter.printAst(reparsed) + + then: + reparsedPrinted == printed // Re-parsing and re-printing produces the same result + + where: + src | _ + "\"\\\"\" scalar A" | _ + "\"\f\" scalar A" | _ + "\"\b\" scalar A" | _ + "\"\t\" scalar A" | _ + } }