From 8139577272ff2d47a865e6b7b4076b6cdebee7b4 Mon Sep 17 00:00:00 2001 From: Brad Baker Date: Tue, 16 Aug 2022 09:58:19 +1000 Subject: [PATCH 1/3] Adding Locale to Parser --- src/main/java/graphql/i18n/I18n.java | 1 + .../graphql/parser/ExtendedBailStrategy.java | 37 +++++-- .../parser/GraphqlAntlrToLanguage.java | 16 ++- .../parser/InvalidSyntaxException.java | 22 +--- .../parser/ParseCancelledException.java | 12 --- src/main/java/graphql/parser/Parser.java | 102 +++++++++++++----- .../graphql/parser/ParserEnvironment.java | 99 +++++++++++++++++ .../graphql/parser/StringValueParsing.java | 9 +- src/main/java/graphql/parser/UnicodeUtil.java | 24 +++-- .../InvalidUnicodeSyntaxException.java | 16 +++ .../exceptions/MoreTokensSyntaxException.java | 17 +++ .../exceptions/ParseCancelledException.java | 18 ++++ src/main/resources/i18n/Parsing.properties | 26 +++++ src/test/groovy/graphql/GraphQLTest.groovy | 2 +- .../graphql/ParseAndValidateTest.groovy | 2 +- .../groovy/graphql/parser/ParserTest.groovy | 41 +++++-- .../parser/StringValueParsingTest.groovy | 15 ++- .../StringValueParsingUnicodeTest.groovy | 76 ++++++------- 18 files changed, 390 insertions(+), 145 deletions(-) delete mode 100644 src/main/java/graphql/parser/ParseCancelledException.java create mode 100644 src/main/java/graphql/parser/ParserEnvironment.java create mode 100644 src/main/java/graphql/parser/exceptions/InvalidUnicodeSyntaxException.java create mode 100644 src/main/java/graphql/parser/exceptions/MoreTokensSyntaxException.java create mode 100644 src/main/java/graphql/parser/exceptions/ParseCancelledException.java create mode 100644 src/main/resources/i18n/Parsing.properties diff --git a/src/main/java/graphql/i18n/I18n.java b/src/main/java/graphql/i18n/I18n.java index dd9efae54..0875ce210 100644 --- a/src/main/java/graphql/i18n/I18n.java +++ b/src/main/java/graphql/i18n/I18n.java @@ -18,6 +18,7 @@ public class I18n { * This enum is a type safe way to control what resource bundle to load from */ public enum BundleType { + Parsing, Validation, Execution, General; diff --git a/src/main/java/graphql/parser/ExtendedBailStrategy.java b/src/main/java/graphql/parser/ExtendedBailStrategy.java index e6d33d5ea..a0861ed0c 100644 --- a/src/main/java/graphql/parser/ExtendedBailStrategy.java +++ b/src/main/java/graphql/parser/ExtendedBailStrategy.java @@ -1,19 +1,25 @@ package graphql.parser; +import com.google.common.collect.ImmutableList; import graphql.Internal; import graphql.language.SourceLocation; +import graphql.parser.exceptions.MoreTokensSyntaxException; import org.antlr.v4.runtime.BailErrorStrategy; import org.antlr.v4.runtime.Parser; import org.antlr.v4.runtime.RecognitionException; import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.misc.ParseCancellationException; +import java.util.List; + @Internal public class ExtendedBailStrategy extends BailErrorStrategy { private final MultiSourceReader multiSourceReader; + private final ParserEnvironment environment; - public ExtendedBailStrategy(MultiSourceReader multiSourceReader) { + public ExtendedBailStrategy(MultiSourceReader multiSourceReader, ParserEnvironment environment) { this.multiSourceReader = multiSourceReader; + this.environment = environment; } @Override @@ -37,23 +43,38 @@ public Token recoverInline(Parser recognizer) throws RecognitionException { InvalidSyntaxException mkMoreTokensException(Token token) { SourceLocation sourceLocation = AntlrHelper.createSourceLocation(multiSourceReader, token); String sourcePreview = AntlrHelper.createPreview(multiSourceReader, token.getLine()); - return new InvalidSyntaxException(sourceLocation, - "There are more tokens in the query that have not been consumed", - sourcePreview, token.getText(), null); + return new MoreTokensSyntaxException(environment.getI18N(), sourceLocation, + token.getText(), sourcePreview); } private InvalidSyntaxException mkException(Parser recognizer, RecognitionException cause) { - String sourcePreview = null; - String offendingToken = null; - SourceLocation sourceLocation = null; + String sourcePreview; + String offendingToken; + final SourceLocation sourceLocation; Token currentToken = recognizer.getCurrentToken(); if (currentToken != null) { sourceLocation = AntlrHelper.createSourceLocation(multiSourceReader, currentToken); offendingToken = currentToken.getText(); sourcePreview = AntlrHelper.createPreview(multiSourceReader, currentToken.getLine()); + } else { + sourcePreview = null; + offendingToken = null; + sourceLocation = null; + } + + String msgKey; + List args; + SourceLocation location = sourceLocation == null ? SourceLocation.EMPTY : sourceLocation; + if (offendingToken == null) { + msgKey = "InvalidSyntaxBail.noToken"; + args = ImmutableList.of(location.getLine(), location.getColumn()); + } else { + msgKey = "InvalidSyntaxBail.full"; + args = ImmutableList.of(offendingToken, sourceLocation.getLine(), sourceLocation.getColumn()); } - return new InvalidSyntaxException(sourceLocation, null, sourcePreview, offendingToken, cause); + String msg = environment.getI18N().msg(msgKey, args); + return new InvalidSyntaxException(msg, sourceLocation, offendingToken, sourcePreview, cause); } } diff --git a/src/main/java/graphql/parser/GraphqlAntlrToLanguage.java b/src/main/java/graphql/parser/GraphqlAntlrToLanguage.java index da0209c1f..b5ef55d21 100644 --- a/src/main/java/graphql/parser/GraphqlAntlrToLanguage.java +++ b/src/main/java/graphql/parser/GraphqlAntlrToLanguage.java @@ -5,6 +5,7 @@ import graphql.Assert; import graphql.Internal; import graphql.collect.ImmutableKit; +import graphql.i18n.I18n; import graphql.language.Argument; import graphql.language.ArrayValue; import graphql.language.BooleanValue; @@ -88,16 +89,13 @@ public class GraphqlAntlrToLanguage { private final CommonTokenStream tokens; private final MultiSourceReader multiSourceReader; private final ParserOptions parserOptions; + private final I18n i18N; - - public GraphqlAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader) { - this(tokens, multiSourceReader, null); - } - - public GraphqlAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader, ParserOptions parserOptions) { + public GraphqlAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader, ParserOptions parserOptions, I18n i18N) { this.tokens = tokens; this.multiSourceReader = multiSourceReader; this.parserOptions = ofNullable(parserOptions).orElse(ParserOptions.getDefaultParserOptions()); + this.i18N = i18N; } public ParserOptions getParserOptions() { @@ -213,7 +211,7 @@ protected SelectionSet createSelectionSet(GraphqlParser.SelectionSetContext ctx) if (selectionContext.inlineFragment() != null) { return createInlineFragment(selectionContext.inlineFragment()); } - return (Selection) Assert.assertShouldNeverHappen(); + return Assert.assertShouldNeverHappen(); }); builder.selections(selections); @@ -772,7 +770,7 @@ protected String quotedString(TerminalNode terminalNode) { if (multiLine) { return parseTripleQuotedString(strText); } else { - return parseSingleQuotedString(strText, sourceLocation); + return parseSingleQuotedString(i18N, strText, sourceLocation); } } @@ -849,7 +847,7 @@ protected Description newDescription(GraphqlParser.DescriptionContext descriptio if (multiLine) { content = parseTripleQuotedString(content); } else { - content = parseSingleQuotedString(content, sourceLocation); + content = parseSingleQuotedString(i18N, content, sourceLocation); } return new Description(content, sourceLocation, multiLine); } diff --git a/src/main/java/graphql/parser/InvalidSyntaxException.java b/src/main/java/graphql/parser/InvalidSyntaxException.java index 9136512c6..939dfd2e2 100644 --- a/src/main/java/graphql/parser/InvalidSyntaxException.java +++ b/src/main/java/graphql/parser/InvalidSyntaxException.java @@ -2,6 +2,7 @@ import graphql.GraphQLException; +import graphql.Internal; import graphql.InvalidSyntaxError; import graphql.PublicApi; import graphql.language.SourceLocation; @@ -20,35 +21,20 @@ public class InvalidSyntaxException extends GraphQLException { private final String offendingToken; private final SourceLocation location; - InvalidSyntaxException(SourceLocation location, String msg, String sourcePreview, String offendingToken, Exception cause) { + @Internal + protected InvalidSyntaxException(String msg, SourceLocation location, String offendingToken, String sourcePreview, Exception cause) { super(cause); - this.message = mkMessage(msg, offendingToken, location); + this.message = msg; this.sourcePreview = sourcePreview; this.offendingToken = offendingToken; this.location = location; } - private String mkMessage(String msg, String offendingToken, SourceLocation location) { - StringBuilder sb = new StringBuilder(); - sb.append("Invalid Syntax :"); - if (msg != null) { - sb.append(" ").append(msg); - } - if (offendingToken != null) { - sb.append(String.format(" offending token '%s'", offendingToken)); - } - if (location != null) { - sb.append(String.format(" at line %d column %d", location.getLine(), location.getColumn())); - } - return sb.toString(); - } - public InvalidSyntaxError toInvalidSyntaxError() { List sourceLocations = location == null ? null : Collections.singletonList(location); return new InvalidSyntaxError(sourceLocations, message, sourcePreview, offendingToken); } - @Override public String getMessage() { return message; diff --git a/src/main/java/graphql/parser/ParseCancelledException.java b/src/main/java/graphql/parser/ParseCancelledException.java deleted file mode 100644 index c416c1250..000000000 --- a/src/main/java/graphql/parser/ParseCancelledException.java +++ /dev/null @@ -1,12 +0,0 @@ -package graphql.parser; - -import graphql.PublicApi; -import graphql.language.SourceLocation; - -@PublicApi -public class ParseCancelledException extends InvalidSyntaxException { - - public ParseCancelledException(String msg, SourceLocation sourceLocation, String offendingToken) { - super(sourceLocation, msg, null, offendingToken, null); - } -} diff --git a/src/main/java/graphql/parser/Parser.java b/src/main/java/graphql/parser/Parser.java index d2726dda6..f5260bb71 100644 --- a/src/main/java/graphql/parser/Parser.java +++ b/src/main/java/graphql/parser/Parser.java @@ -1,5 +1,6 @@ package graphql.parser; +import com.google.common.collect.ImmutableList; import graphql.Internal; import graphql.PublicApi; import graphql.language.Document; @@ -10,6 +11,7 @@ import graphql.parser.antlr.GraphqlBaseListener; import graphql.parser.antlr.GraphqlLexer; import graphql.parser.antlr.GraphqlParser; +import graphql.parser.exceptions.ParseCancelledException; import org.antlr.v4.runtime.BaseErrorListener; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CodePointCharStream; @@ -36,10 +38,10 @@ *

* You should not generally need to call this class as the {@link graphql.GraphQL} code sets this up for you * but if you are doing specific graphql utilities this class is essential. - * + *

* Graphql syntax has a series of characters, such as spaces, new lines and commas that are not considered relevant * to the syntax. However they can be captured and associated with the AST elements they belong to. - * + *

* This costs more memory but for certain use cases (like editors) this maybe be useful. We have chosen to no capture * ignored characters by default but you can turn this on, either per parse or statically for the whole JVM * via {@link ParserOptions#setDefaultParserOptions(ParserOptions)} ()}} @@ -54,6 +56,19 @@ public class Parser { @Internal public static final int CHANNEL_WHITESPACE = 3; + /** + * Parses a string input into a graphql AST {@link Document} + * + * @param environment the parser environment to use + * + * @return an AST {@link Document} + * + * @throws InvalidSyntaxException if the document is not valid graphql syntax + */ + public static Document parse(ParserEnvironment environment) throws InvalidSyntaxException { + return new Parser().parseDocument(environment); + } + /** * Parses a string input into a graphql AST {@link Document} * @@ -93,6 +108,19 @@ public static Type parseType(String input) throws InvalidSyntaxException { return new Parser().parseTypeImpl(input); } + /** + * Parses document text into a graphql AST {@link Document} + * + * @param environment the parser environment to sue + * + * @return an AST {@link Document} + * + * @throws InvalidSyntaxException if the input is not valid graphql syntax + */ + public Document parseDocument(ParserEnvironment environment) throws InvalidSyntaxException { + return parseDocumentImpl(environment); + } + /** * Parses a string input into a graphql AST {@link Document} * @@ -152,7 +180,10 @@ public Document parseDocument(String input, ParserOptions parserOptions) throws * @throws InvalidSyntaxException if the input is not valid graphql syntax */ public Document parseDocument(Reader reader) throws InvalidSyntaxException { - return parseDocumentImpl(reader, null); + ParserEnvironment parserEnvironment = ParserEnvironment.newParserEnvironment() + .document(reader) + .build(); + return parseDocumentImpl(parserEnvironment); } /** @@ -166,16 +197,20 @@ public Document parseDocument(Reader reader) throws InvalidSyntaxException { * @throws InvalidSyntaxException if the input is not valid graphql syntax */ public Document parseDocument(Reader reader, ParserOptions parserOptions) throws InvalidSyntaxException { - return parseDocumentImpl(reader, parserOptions); + ParserEnvironment parserEnvironment = ParserEnvironment.newParserEnvironment() + .document(reader) + .parserOptions(parserOptions) + .build(); + return parseDocumentImpl(parserEnvironment); } - private Document parseDocumentImpl(Reader reader, ParserOptions parserOptions) throws InvalidSyntaxException { + private Document parseDocumentImpl(ParserEnvironment environment) throws InvalidSyntaxException { BiFunction nodeFunction = (parser, toLanguage) -> { GraphqlParser.DocumentContext documentContext = parser.document(); Document doc = toLanguage.createDocument(documentContext); return new Object[]{documentContext, doc}; }; - return (Document) parseImpl(reader, nodeFunction, parserOptions); + return (Document) parseImpl(environment, nodeFunction); } private Value parseValueImpl(String input) throws InvalidSyntaxException { @@ -188,7 +223,8 @@ private Value parseValueImpl(String input) throws InvalidSyntaxException { .string(input, null) .trackData(true) .build(); - return (Value) parseImpl(multiSourceReader, nodeFunction, null); + ParserEnvironment parserEnvironment = ParserEnvironment.newParserEnvironment().document(multiSourceReader).build(); + return (Value) parseImpl(parserEnvironment, nodeFunction); } private Type parseTypeImpl(String input) throws InvalidSyntaxException { @@ -201,11 +237,14 @@ private Type parseTypeImpl(String input) throws InvalidSyntaxException { .string(input, null) .trackData(true) .build(); - return (Type) parseImpl(multiSourceReader, nodeFunction, null); + + ParserEnvironment parserEnvironment = ParserEnvironment.newParserEnvironment().document(multiSourceReader).build(); + return (Type) parseImpl(parserEnvironment, nodeFunction); } - private Node parseImpl(Reader reader, BiFunction nodeFunction, ParserOptions parserOptions) throws InvalidSyntaxException { + private Node parseImpl(ParserEnvironment environment, BiFunction nodeFunction) throws InvalidSyntaxException { MultiSourceReader multiSourceReader; + Reader reader = environment.getDocument(); if (reader instanceof MultiSourceReader) { multiSourceReader = (MultiSourceReader) reader; } else { @@ -223,20 +262,31 @@ private Node parseImpl(Reader reader, BiFunction recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { + public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, String antlerMsg, RecognitionException e) { SourceLocation sourceLocation = AntlrHelper.createSourceLocation(multiSourceReader, line, charPositionInLine); String preview = AntlrHelper.createPreview(multiSourceReader, line); - throw new InvalidSyntaxException(sourceLocation, msg, preview, null, null); + String msgKey; + List args; + if (antlerMsg == null) { + msgKey = "InvalidSyntax.noMessage"; + args = ImmutableList.of(sourceLocation.getLine(), sourceLocation.getColumn()); + } else { + msgKey = "InvalidSyntax.full"; + args = ImmutableList.of(antlerMsg, sourceLocation.getLine(), sourceLocation.getColumn()); + } + String msg = environment.getI18N().msg(msgKey, args); + throw new InvalidSyntaxException(msg, sourceLocation, null, preview, null); } }); // default in the parser options if they are not set + ParserOptions parserOptions = environment.getParserOptions(); parserOptions = Optional.ofNullable(parserOptions).orElse(ParserOptions.getDefaultParserOptions()); // this lexer wrapper allows us to stop lexing when too many tokens are in place. This prevents DOS attacks. int maxTokens = parserOptions.getMaxTokens(); int maxWhitespaceTokens = parserOptions.getMaxWhitespaceTokens(); - BiConsumer onTooManyTokens = (maxTokenCount, token) -> throwCancelParseIfTooManyTokens(token, maxTokenCount, multiSourceReader); + BiConsumer onTooManyTokens = (maxTokenCount, token) -> throwCancelParseIfTooManyTokens(environment, token, maxTokenCount, multiSourceReader); SafeTokenSource safeTokenSource = new SafeTokenSource(lexer, maxTokens, maxWhitespaceTokens, onTooManyTokens); CommonTokenStream tokens = new CommonTokenStream(safeTokenSource); @@ -245,16 +295,13 @@ public void syntaxError(Recognizer recognizer, Object offendingSymbol, int parser.removeErrorListeners(); parser.getInterpreter().setPredictionMode(PredictionMode.SLL); - ExtendedBailStrategy bailStrategy = new ExtendedBailStrategy(multiSourceReader); + ExtendedBailStrategy bailStrategy = new ExtendedBailStrategy(multiSourceReader, environment); parser.setErrorHandler(bailStrategy); // preserve old protected call semantics - remove at some point - GraphqlAntlrToLanguage toLanguage = getAntlrToLanguage(tokens, multiSourceReader); - if (toLanguage == null) { - toLanguage = getAntlrToLanguage(tokens, multiSourceReader, parserOptions); - } + GraphqlAntlrToLanguage toLanguage = getAntlrToLanguage(tokens, multiSourceReader, environment); - setupParserListener(multiSourceReader, parser, toLanguage); + setupParserListener(environment, multiSourceReader, parser, toLanguage); // @@ -281,7 +328,7 @@ public void syntaxError(Recognizer recognizer, Object offendingSymbol, int return node; } - private void setupParserListener(MultiSourceReader multiSourceReader, GraphqlParser parser, GraphqlAntlrToLanguage toLanguage) { + private void setupParserListener(ParserEnvironment environment, MultiSourceReader multiSourceReader, GraphqlParser parser, GraphqlAntlrToLanguage toLanguage) { ParserOptions parserOptions = toLanguage.getParserOptions(); ParsingListener parsingListener = parserOptions.getParsingListener(); int maxTokens = parserOptions.getMaxTokens(); @@ -312,15 +359,15 @@ public int getCharPositionInLine() { count++; if (count > maxTokens) { - throwCancelParseIfTooManyTokens(token, maxTokens, multiSourceReader); + throwCancelParseIfTooManyTokens(environment, token, maxTokens, multiSourceReader); } } }; parser.addParseListener(listener); } - private void throwCancelParseIfTooManyTokens(Token token, int maxTokens, MultiSourceReader multiSourceReader) throws ParseCancelledException { - String tokenType = "grammar"; + private void throwCancelParseIfTooManyTokens(ParserEnvironment environment, Token token, int maxTokens, MultiSourceReader multiSourceReader) throws ParseCancelledException { + String tokenType = "grammar"; SourceLocation sourceLocation = null; String offendingToken = null; if (token != null) { @@ -330,8 +377,7 @@ private void throwCancelParseIfTooManyTokens(Token token, int maxTokens, MultiSo offendingToken = token.getText(); sourceLocation = AntlrHelper.createSourceLocation(multiSourceReader, token.getLine(), token.getCharPositionInLine()); } - String msg = String.format("More than %d %s tokens have been presented. To prevent Denial Of Service attacks, parsing has been cancelled.", maxTokens, tokenType); - throw new ParseCancelledException(msg, sourceLocation, offendingToken); + throw new ParseCancelledException(environment.getI18N(), sourceLocation, offendingToken, maxTokens, tokenType); } /** @@ -342,7 +388,7 @@ private void throwCancelParseIfTooManyTokens(Token token, int maxTokens, MultiSo * * @return a new GraphqlAntlrToLanguage instance * - * @deprecated - really should use {@link #getAntlrToLanguage(CommonTokenStream, MultiSourceReader, ParserOptions)} + * @deprecated - really should use {@link #getAntlrToLanguage(CommonTokenStream, MultiSourceReader, ParserEnvironment)} */ @Deprecated protected GraphqlAntlrToLanguage getAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader) { @@ -354,11 +400,11 @@ protected GraphqlAntlrToLanguage getAntlrToLanguage(CommonTokenStream tokens, Mu * * @param tokens the token stream * @param multiSourceReader the source of the query document - * @param parserOptions - the parser options + * @param environment the parser environment * * @return a new GraphqlAntlrToLanguage instance */ - protected GraphqlAntlrToLanguage getAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader, ParserOptions parserOptions) { - return new GraphqlAntlrToLanguage(tokens, multiSourceReader, parserOptions); + protected GraphqlAntlrToLanguage getAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader, ParserEnvironment environment) { + return new GraphqlAntlrToLanguage(tokens, multiSourceReader, environment.getParserOptions(), environment.getI18N()); } } diff --git a/src/main/java/graphql/parser/ParserEnvironment.java b/src/main/java/graphql/parser/ParserEnvironment.java new file mode 100644 index 000000000..9850688ac --- /dev/null +++ b/src/main/java/graphql/parser/ParserEnvironment.java @@ -0,0 +1,99 @@ +package graphql.parser; + +import graphql.PublicApi; +import graphql.i18n.I18n; + +import java.io.Reader; +import java.io.StringReader; +import java.util.Locale; + +import static graphql.Assert.assertNotNull; + +/** + * This is the arguments that can be passed to a {@link Parser} + */ +@PublicApi +public interface ParserEnvironment { + + /** + * @return the document to be parsed + */ + Reader getDocument(); + + /** + * @return the parsing options + */ + ParserOptions getParserOptions(); + + /** + * @return the locale to produce parsing error messages in + */ + Locale getLocale(); + + /** + * @return the {@link I18n} to produce parsing error messages with + */ + I18n getI18N(); + + /** + * @return a builder of new parsing options + */ + static Builder newParserEnvironment() { + return new Builder(); + } + + class Builder { + Reader reader; + ParserOptions parserOptions = ParserOptions.getDefaultParserOptions(); + + Locale locale = Locale.getDefault(); + + + public Builder() { + } + + public Builder document(Reader documentText) { + this.reader = assertNotNull(documentText); + return this; + } + + public Builder document(String documentText) { + return document(new StringReader(documentText)); + } + + public Builder parserOptions(ParserOptions parserOptions) { + this.parserOptions = parserOptions; + return this; + } + + public Builder locale(Locale locale) { + this.locale = assertNotNull(locale); + return this; + } + + public ParserEnvironment build() { + I18n i18n = I18n.i18n(I18n.BundleType.Parsing, locale); + return new ParserEnvironment() { + @Override + public Reader getDocument() { + return reader; + } + + @Override + public ParserOptions getParserOptions() { + return parserOptions; + } + + @Override + public Locale getLocale() { + return locale; + } + + @Override + public I18n getI18N() { + return i18n; + } + }; + } + } +} diff --git a/src/main/java/graphql/parser/StringValueParsing.java b/src/main/java/graphql/parser/StringValueParsing.java index d9da00dc8..56b1f1ec8 100644 --- a/src/main/java/graphql/parser/StringValueParsing.java +++ b/src/main/java/graphql/parser/StringValueParsing.java @@ -2,6 +2,7 @@ import graphql.Assert; import graphql.Internal; +import graphql.i18n.I18n; import graphql.language.SourceLocation; import java.io.StringWriter; @@ -103,7 +104,7 @@ private static boolean containsOnlyWhiteSpace(String str) { return leadingWhitespace(str) == str.length(); } - public static String parseSingleQuotedString(String string, SourceLocation sourceLocation) { + public static String parseSingleQuotedString(I18n i18n, String string, SourceLocation sourceLocation) { StringWriter writer = new StringWriter(string.length() - 2); int end = string.length() - 1; for (int i = 1; i < end; i++) { @@ -140,7 +141,7 @@ public static String parseSingleQuotedString(String string, SourceLocation sourc writer.write('\t'); continue; case 'u': - i = UnicodeUtil.parseAndWriteUnicode(writer, string, i, sourceLocation); + i = UnicodeUtil.parseAndWriteUnicode(i18n, writer, string, i, sourceLocation); continue; default: Assert.assertShouldNeverHappen(); @@ -148,8 +149,4 @@ public static String parseSingleQuotedString(String string, SourceLocation sourc } return writer.toString(); } - - public static String parseSingleQuotedString(String string) { - return parseSingleQuotedString(string, null); - } } diff --git a/src/main/java/graphql/parser/UnicodeUtil.java b/src/main/java/graphql/parser/UnicodeUtil.java index cdf55ace4..b32cbfea6 100644 --- a/src/main/java/graphql/parser/UnicodeUtil.java +++ b/src/main/java/graphql/parser/UnicodeUtil.java @@ -1,7 +1,9 @@ package graphql.parser; import graphql.Internal; +import graphql.i18n.I18n; import graphql.language.SourceLocation; +import graphql.parser.exceptions.InvalidUnicodeSyntaxException; import java.io.IOException; import java.io.StringWriter; @@ -19,14 +21,14 @@ public class UnicodeUtil { public static final int TRAILING_SURROGATE_LOWER_BOUND = 0xDC00; public static final int TRAILING_SURROGATE_UPPER_BOUND = 0xDFFF; - public static int parseAndWriteUnicode(StringWriter writer, String string, int i, SourceLocation sourceLocation) { + public static int parseAndWriteUnicode(I18n i18n, StringWriter writer, String string, int i, SourceLocation sourceLocation) { // Unicode code points can either be: // 1. Unbraced: four hex characters in the form \\u597D, or // 2. Braced: any number of hex characters surrounded by braces in the form \\u{1F37A} // Extract the code point hex digits. Index i points to 'u' int startIndex = isBracedEscape(string, i) ? i + 2 : i + 1; - int endIndexExclusive = getEndIndexExclusive(string, i, sourceLocation); + int endIndexExclusive = getEndIndexExclusive(i18n, string, i, sourceLocation); // Index for parser to continue at, the last character of the escaped unicode character. Either } or hex digit int continueIndex = isBracedEscape(string, i) ? endIndexExclusive : endIndexExclusive - 1; @@ -34,16 +36,16 @@ public static int parseAndWriteUnicode(StringWriter writer, String string, int i int codePoint = Integer.parseInt(hexStr, 16); if (isTrailingSurrogateValue(codePoint)) { - throw new InvalidSyntaxException(sourceLocation, "Invalid unicode - trailing surrogate must be preceded with a leading surrogate -", null, string.substring(i - 1, continueIndex + 1), null); + throw new InvalidUnicodeSyntaxException(i18n, "InvalidUnicode.trailingLeadingSurrogate", sourceLocation, offendingToken(string, i, continueIndex)); } else if (isLeadingSurrogateValue(codePoint)) { if (!isEscapedUnicode(string, continueIndex + 1)) { - throw new InvalidSyntaxException(sourceLocation, "Invalid unicode - leading surrogate must be followed by a trailing surrogate -", null, string.substring(i - 1, continueIndex + 1), null); + throw new InvalidUnicodeSyntaxException(i18n, "InvalidUnicode.leadingTrailingSurrogate", sourceLocation, offendingToken(string, i, continueIndex)); } // Shift parser ahead to 'u' in second escaped Unicode character i = continueIndex + 2; int trailingStartIndex = isBracedEscape(string, i) ? i + 2 : i + 1; - int trailingEndIndexExclusive = getEndIndexExclusive(string, i, sourceLocation); + int trailingEndIndexExclusive = getEndIndexExclusive(i18n, string, i, sourceLocation); String trailingHexStr = string.substring(trailingStartIndex, trailingEndIndexExclusive); int trailingCodePoint = Integer.parseInt(trailingHexStr, 16); continueIndex = isBracedEscape(string, i) ? trailingEndIndexExclusive : trailingEndIndexExclusive - 1; @@ -54,16 +56,20 @@ public static int parseAndWriteUnicode(StringWriter writer, String string, int i return continueIndex; } - throw new InvalidSyntaxException(sourceLocation, "Invalid unicode - leading surrogate must be followed by a trailing surrogate -", null, string.substring(i - 1, continueIndex + 1), null); + throw new InvalidUnicodeSyntaxException(i18n, "InvalidUnicode.leadingTrailingSurrogate", sourceLocation, offendingToken(string, i, continueIndex)); } else if (isValidUnicodeCodePoint(codePoint)) { writeCodePoint(writer, codePoint); return continueIndex; } - throw new InvalidSyntaxException(sourceLocation, "Invalid unicode - not a valid code point -", null, string.substring(i - 1, continueIndex + 1), null); + throw new InvalidUnicodeSyntaxException(i18n, "InvalidUnicode.invalidCodePoint", sourceLocation, offendingToken(string, i, continueIndex)); } - private static int getEndIndexExclusive(String string, int i, SourceLocation sourceLocation) { + private static String offendingToken(String string, int i, int continueIndex) { + return string.substring(i - 1, continueIndex + 1); + } + + private static int getEndIndexExclusive(I18n i18n, String string, int i, SourceLocation sourceLocation) { // Unbraced case, with exactly 4 hex digits if (string.length() > i + 5 && !isBracedEscape(string, i)) { return i + 5; @@ -73,7 +79,7 @@ private static int getEndIndexExclusive(String string, int i, SourceLocation sou int endIndexExclusive = i + 2; do { if (endIndexExclusive + 1 >= string.length()) { - throw new InvalidSyntaxException(sourceLocation, "Invalid unicode - incorrectly formatted escape -", null, string.substring(i - 1, endIndexExclusive), null); + throw new InvalidUnicodeSyntaxException(i18n, "InvalidUnicode.incorrectEscape", sourceLocation, string.substring(i - 1, endIndexExclusive)); } } while (string.charAt(++endIndexExclusive) != '}'); diff --git a/src/main/java/graphql/parser/exceptions/InvalidUnicodeSyntaxException.java b/src/main/java/graphql/parser/exceptions/InvalidUnicodeSyntaxException.java new file mode 100644 index 000000000..be7512704 --- /dev/null +++ b/src/main/java/graphql/parser/exceptions/InvalidUnicodeSyntaxException.java @@ -0,0 +1,16 @@ +package graphql.parser.exceptions; + +import graphql.Internal; +import graphql.i18n.I18n; +import graphql.language.SourceLocation; +import graphql.parser.InvalidSyntaxException; +import org.jetbrains.annotations.NotNull; + +@Internal +public class InvalidUnicodeSyntaxException extends InvalidSyntaxException { + + public InvalidUnicodeSyntaxException(@NotNull I18n i18N, @NotNull String msgKey, @NotNull SourceLocation sourceLocation, @NotNull String offendingToken) { + super(i18N.msg(msgKey, offendingToken, sourceLocation.getLine(), sourceLocation.getColumn()), + sourceLocation, offendingToken, null, null); + } +} diff --git a/src/main/java/graphql/parser/exceptions/MoreTokensSyntaxException.java b/src/main/java/graphql/parser/exceptions/MoreTokensSyntaxException.java new file mode 100644 index 000000000..6f73b38e4 --- /dev/null +++ b/src/main/java/graphql/parser/exceptions/MoreTokensSyntaxException.java @@ -0,0 +1,17 @@ +package graphql.parser.exceptions; + +import graphql.Internal; +import graphql.i18n.I18n; +import graphql.language.SourceLocation; +import graphql.parser.InvalidSyntaxException; +import org.jetbrains.annotations.NotNull; + +@Internal +public class MoreTokensSyntaxException extends InvalidSyntaxException { + + @Internal + public MoreTokensSyntaxException(@NotNull I18n i18N, @NotNull SourceLocation sourceLocation, @NotNull String offendingToken, @NotNull String sourcePreview) { + super(i18N.msg("InvalidSyntaxMoreTokens.full", offendingToken, sourceLocation.getLine(), sourceLocation.getColumn()), + sourceLocation, offendingToken, sourcePreview, null); + } +} diff --git a/src/main/java/graphql/parser/exceptions/ParseCancelledException.java b/src/main/java/graphql/parser/exceptions/ParseCancelledException.java new file mode 100644 index 000000000..ab183367f --- /dev/null +++ b/src/main/java/graphql/parser/exceptions/ParseCancelledException.java @@ -0,0 +1,18 @@ +package graphql.parser.exceptions; + +import graphql.Internal; +import graphql.i18n.I18n; +import graphql.language.SourceLocation; +import graphql.parser.InvalidSyntaxException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +@Internal +public class ParseCancelledException extends InvalidSyntaxException { + + @Internal + public ParseCancelledException(@NotNull I18n i18N, @Nullable SourceLocation sourceLocation, @Nullable String offendingToken, int maxTokens, @NotNull String tokenType) { + super(i18N.msg("ParseCancelled.full", maxTokens, tokenType), + sourceLocation, offendingToken, null, null); + } +} diff --git a/src/main/resources/i18n/Parsing.properties b/src/main/resources/i18n/Parsing.properties new file mode 100644 index 000000000..1152e601e --- /dev/null +++ b/src/main/resources/i18n/Parsing.properties @@ -0,0 +1,26 @@ +# +# This resource bundle is used for the query parsing code to produce i18n messages +# +# The keys have the format of rule class name and then message type within that. Most rules +# will only have 1 or 2 message keys +# +# Please try and keep this sorted within rule class and use # between sections so the IDEA Ctrl-Alt-L reformat does not bunch +# them too tightly. +# +# REMEMBER - a single quote ' in MessageFormat means things that are never replaced within them +# so use 2 '' characters to make it one ' on output. This will take for the form ''{0}'' +# +InvalidSyntax.noMessage=Invalid syntax at line {0} column {1} +InvalidSyntax.full=Invalid syntax with ANTLR error ''{0}'' at line {1} column {2} + +InvalidSyntaxBail.noToken=Invalid syntax at line {0} column {1} +InvalidSyntaxBail.full=Invalid syntax with offending token ''{0}'' at line {1} column {2} +# +InvalidSyntaxMoreTokens.full=Invalid syntax encountered. There are extra tokens in the text that have not been consumed. Offending token ''{0}'' at line {1} column {2} +# +ParseCancelled.full=More than {0} ''{1}'' tokens have been presented. To prevent Denial Of Service attacks, parsing has been cancelled. +# +InvalidUnicode.trailingLeadingSurrogate=Invalid unicode encountered. Trailing surrogate must be preceded with a leading surrogate. Offending token ''{0}'' at line {1} column {2} +InvalidUnicode.leadingTrailingSurrogate=Invalid unicode encountered. Leading surrogate must be followed by a trailing surrogate. Offending token ''{0}'' at line {1} column {2} +InvalidUnicode.invalidCodePoint=Invalid unicode encountered. Not a valid code point. Offending token ''{0}'' at line {1} column {2} +InvalidUnicode.incorrectEscape=Invalid unicode encountered. Incorrectly formatted escape sequence. Offending token ''{0}'' at line {1} column {2} diff --git a/src/test/groovy/graphql/GraphQLTest.groovy b/src/test/groovy/graphql/GraphQLTest.groovy index 0ae487f56..c75d68c61 100644 --- a/src/test/groovy/graphql/GraphQLTest.groovy +++ b/src/test/groovy/graphql/GraphQLTest.groovy @@ -205,7 +205,7 @@ class GraphQLTest extends Specification { then: errors.size() == 1 errors[0].errorType == ErrorType.InvalidSyntax - errors[0].message == "Invalid Syntax : Invalid unicode - leading surrogate must be followed by a trailing surrogate - offending token '\\ud83c' at line 1 column 13" + errors[0].message == "Invalid unicode encountered. Leading surrogate must be followed by a trailing surrogate. Offending token '\\ud83c' at line 1 column 13" errors[0].locations == [new SourceLocation(1, 13)] } diff --git a/src/test/groovy/graphql/ParseAndValidateTest.groovy b/src/test/groovy/graphql/ParseAndValidateTest.groovy index 3b676bd8d..949b4aeb5 100644 --- a/src/test/groovy/graphql/ParseAndValidateTest.groovy +++ b/src/test/groovy/graphql/ParseAndValidateTest.groovy @@ -110,7 +110,7 @@ class ParseAndValidateTest extends Specification { result.variables == [var1: 1] result.syntaxException != null - (result.errors[0] as InvalidSyntaxError).message.contains("Invalid Syntax") + (result.errors[0] as InvalidSyntaxError).message.contains("Invalid syntax") } def "can use the graphql context to stop certain validation rules"() { diff --git a/src/test/groovy/graphql/parser/ParserTest.groovy b/src/test/groovy/graphql/parser/ParserTest.groovy index 6a76ace1b..a5271eae5 100644 --- a/src/test/groovy/graphql/parser/ParserTest.groovy +++ b/src/test/groovy/graphql/parser/ParserTest.groovy @@ -40,6 +40,7 @@ import graphql.language.TypeName import graphql.language.UnionTypeDefinition import graphql.language.VariableDefinition import graphql.language.VariableReference +import graphql.parser.exceptions.ParseCancelledException import org.antlr.v4.runtime.CommonTokenStream import org.antlr.v4.runtime.ParserRuleContext import spock.lang.Issue @@ -605,7 +606,7 @@ class ParserTest extends Specification { then: def e = thrown(InvalidSyntaxException) - e.message.contains("Invalid Syntax") + e.message.contains("Invalid syntax") } def "three quotation marks is an illegal string"() { @@ -617,7 +618,7 @@ class ParserTest extends Specification { then: def e = thrown(InvalidSyntaxException) - e.message.contains("Invalid Syntax") + e.message.contains("Invalid syntax") } def "escaped triple quote inside block string"() { @@ -836,7 +837,7 @@ triple3 : """edge cases \\""" "" " \\"" \\" edge cases""" println document then: def e = thrown(InvalidSyntaxException) - e.message.contains("Invalid Syntax") + e.message.contains("Invalid syntax") e.sourcePreview == input + "\n" e.location.line == 3 e.location.column == 20 @@ -858,6 +859,24 @@ triple3 : """edge cases \\""" "" " \\"" \\" edge cases""" operationDefinition.getComments()[0].content == " Represents the 😕 emoji." } + + def "the parser can be invoked via parser environment"() { + def input = ''' + # Represents the 😕 emoji. + { + foo + } + ''' + when: + def parserEnvironment = ParserEnvironment.newParserEnvironment().document(input).build() + + Document document = Parser.parse(parserEnvironment) + OperationDefinition operationDefinition = (document.definitions[0] as OperationDefinition) + + then: + operationDefinition.getComments()[0].content == " Represents the 😕 emoji." + } + def "can override antlr to ast"() { def query = ''' @@ -868,9 +887,9 @@ triple3 : """edge cases \\""" "" " \\"" \\" edge cases""" when: Parser parser = new Parser() { @Override - protected GraphqlAntlrToLanguage getAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader) { + protected GraphqlAntlrToLanguage getAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader, ParserEnvironment environment) { // this pattern is used in Nadel - its backdoor but needed - return new GraphqlAntlrToLanguage(tokens, multiSourceReader) { + return new GraphqlAntlrToLanguage(tokens, multiSourceReader, environment.parserOptions, environment.i18N) { @Override protected void addCommonData(NodeBuilder nodeBuilder, ParserRuleContext parserRuleContext) { super.addCommonData(nodeBuilder, parserRuleContext) @@ -890,8 +909,8 @@ triple3 : """edge cases \\""" "" " \\"" \\" edge cases""" parser = new Parser() { @Override - protected GraphqlAntlrToLanguage getAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader, ParserOptions parserOptions) { - return new GraphqlAntlrToLanguage(tokens, multiSourceReader, parserOptions) { + protected GraphqlAntlrToLanguage getAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader, ParserEnvironment environment) { + return new GraphqlAntlrToLanguage(tokens, multiSourceReader, environment.parserOptions, environment.i18N) { @Override protected void addCommonData(NodeBuilder nodeBuilder, ParserRuleContext parserRuleContext) { super.addCommonData(nodeBuilder, parserRuleContext) @@ -933,7 +952,7 @@ triple3 : """edge cases \\""" "" " \\"" \\" edge cases""" then: def e = thrown(InvalidSyntaxException) - e.message.contains("Invalid Syntax") + e.message.contains("Invalid syntax") where: value | _ '00' | _ @@ -953,7 +972,7 @@ triple3 : """edge cases \\""" "" " \\"" \\" edge cases""" then: def e = thrown(InvalidSyntaxException) - e.message.contains("Invalid Syntax") + e.message.contains("Invalid syntax") where: value | _ '01.23' | _ @@ -1108,7 +1127,7 @@ triple3 : """edge cases \\""" "" " \\"" \\" edge cases""" then: InvalidSyntaxException e = thrown(InvalidSyntaxException) - e.message == "Invalid Syntax : Invalid unicode - leading surrogate must be followed by a trailing surrogate - offending token '\\ud83c' at line 3 column 24" + e.message == "Invalid unicode encountered. Leading surrogate must be followed by a trailing surrogate. Offending token '\\ud83c' at line 3 column 24" } def "invalid surrogate pair - no leading value"() { @@ -1124,7 +1143,7 @@ triple3 : """edge cases \\""" "" " \\"" \\" edge cases""" then: InvalidSyntaxException e = thrown(InvalidSyntaxException) - e.message == "Invalid Syntax : Invalid unicode - trailing surrogate must be preceded with a leading surrogate - offending token '\\uDC00' at line 3 column 24" + e.message == "Invalid unicode encountered. Trailing surrogate must be preceded with a leading surrogate. Offending token '\\uDC00' at line 3 column 24" } def "source locations are on by default but can be turned off"() { diff --git a/src/test/groovy/graphql/parser/StringValueParsingTest.groovy b/src/test/groovy/graphql/parser/StringValueParsingTest.groovy index 5543dbc33..2142c8417 100644 --- a/src/test/groovy/graphql/parser/StringValueParsingTest.groovy +++ b/src/test/groovy/graphql/parser/StringValueParsingTest.groovy @@ -1,5 +1,7 @@ package graphql.parser +import graphql.i18n.I18n +import graphql.language.SourceLocation import spock.lang.Specification import static java.util.Arrays.asList @@ -7,12 +9,15 @@ import static java.util.stream.Collectors.joining class StringValueParsingTest extends Specification { + def i18n = I18n.i18n(I18n.BundleType.Parsing, Locale.ENGLISH) + def sourceLocation = SourceLocation.EMPTY + def "parsing quoted string should work"() { given: def input = '''"simple quoted"''' when: - String parsed = StringValueParsing.parseSingleQuotedString(input) + String parsed = StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: parsed == "simple quoted" @@ -23,7 +28,7 @@ class StringValueParsingTest extends Specification { def input = '''"{\"name\": \"graphql\", \"year\": 2015}"''' when: - String parsed = StringValueParsing.parseSingleQuotedString(input) + String parsed = StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: parsed == '''{\"name\": \"graphql\", \"year\": 2015}''' @@ -34,7 +39,7 @@ class StringValueParsingTest extends Specification { def input = '''"""''' when: - String parsed = StringValueParsing.parseSingleQuotedString(input) + String parsed = StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: parsed == '''"''' @@ -45,7 +50,7 @@ class StringValueParsingTest extends Specification { def input = '''"\\ud83c\\udf7a"''' when: - String parsed = StringValueParsing.parseSingleQuotedString(input) + String parsed = StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: parsed == '''🍺''' // contains the beer icon U+1F37A : http://www.charbase.com/1f37a-unicode-beer-mug @@ -56,7 +61,7 @@ class StringValueParsingTest extends Specification { def input = '''"\\u5564\\u9152"''' when: - String parsed = StringValueParsing.parseSingleQuotedString(input) + String parsed = StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: parsed == '''啤酒''' diff --git a/src/test/groovy/graphql/parser/StringValueParsingUnicodeTest.groovy b/src/test/groovy/graphql/parser/StringValueParsingUnicodeTest.groovy index 63c59d801..192f3b009 100644 --- a/src/test/groovy/graphql/parser/StringValueParsingUnicodeTest.groovy +++ b/src/test/groovy/graphql/parser/StringValueParsingUnicodeTest.groovy @@ -1,12 +1,14 @@ package graphql.parser -import graphql.language.Document -import graphql.language.Field -import graphql.language.OperationDefinition -import graphql.language.StringValue +import graphql.i18n.I18n +import graphql.language.SourceLocation import spock.lang.Specification class StringValueParsingUnicodeTest extends Specification { + + def i18n = I18n.i18n(I18n.BundleType.Parsing, Locale.ENGLISH) + def sourceLocation = SourceLocation.EMPTY + /** * Implements RFC to support full Unicode https://github.com/graphql/graphql-spec/pull/849 * @@ -25,7 +27,7 @@ class StringValueParsingUnicodeTest extends Specification { def input = '''"\\u{1F37A} hello"''' when: - String parsed = StringValueParsing.parseSingleQuotedString(input) + String parsed = StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: parsed == '''🍺 hello''' // contains the beer icon U+1F37A : http://www.charbase.com/1f37a-unicode-beer-mug @@ -36,7 +38,7 @@ class StringValueParsingUnicodeTest extends Specification { def input = '''"🍺 hello"''' when: - String parsed = StringValueParsing.parseSingleQuotedString(input) + String parsed = StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: parsed == '''🍺 hello''' // contains the beer icon U+1F37A : http://www.charbase.com/1f37a-unicode-beer-mug @@ -60,11 +62,11 @@ class StringValueParsingUnicodeTest extends Specification { def input = '''"\\uD83D hello"''' when: - StringValueParsing.parseSingleQuotedString(input) + StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: InvalidSyntaxException e = thrown(InvalidSyntaxException) - e.message == "Invalid Syntax : Invalid unicode - leading surrogate must be followed by a trailing surrogate - offending token '\\uD83D'" + e.message == "Invalid unicode encountered. Leading surrogate must be followed by a trailing surrogate. Offending token '\\uD83D' at line -1 column -1" } def "invalid surrogate pair - end of string"() { @@ -72,11 +74,11 @@ class StringValueParsingUnicodeTest extends Specification { def input = '''"\\uD83D"''' when: - StringValueParsing.parseSingleQuotedString(input) + StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: InvalidSyntaxException e = thrown(InvalidSyntaxException) - e.message == "Invalid Syntax : Invalid unicode - leading surrogate must be followed by a trailing surrogate - offending token '\\uD83D'" + e.message == "Invalid unicode encountered. Leading surrogate must be followed by a trailing surrogate. Offending token '\\uD83D' at line -1 column -1" } def "invalid surrogate pair - invalid trailing value"() { @@ -84,11 +86,11 @@ class StringValueParsingUnicodeTest extends Specification { def input = '''"\\uD83D\\uDBFF"''' when: - StringValueParsing.parseSingleQuotedString(input) + StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: InvalidSyntaxException e = thrown(InvalidSyntaxException) - e.message == "Invalid Syntax : Invalid unicode - leading surrogate must be followed by a trailing surrogate - offending token '\\uDBFF'" + e.message == "Invalid unicode encountered. Leading surrogate must be followed by a trailing surrogate. Offending token '\\uDBFF' at line -1 column -1" } def "invalid surrogate pair - no leading value"() { @@ -96,11 +98,11 @@ class StringValueParsingUnicodeTest extends Specification { def input = '''"\\uDC00"''' when: - StringValueParsing.parseSingleQuotedString(input) + StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: InvalidSyntaxException e = thrown(InvalidSyntaxException) - e.message == "Invalid Syntax : Invalid unicode - trailing surrogate must be preceded with a leading surrogate - offending token '\\uDC00'" + e.message == "Invalid unicode encountered. Trailing surrogate must be preceded with a leading surrogate. Offending token '\\uDC00' at line -1 column -1" } def "invalid surrogate pair - invalid leading value"() { @@ -108,11 +110,11 @@ class StringValueParsingUnicodeTest extends Specification { def input = '''"\\uD700\\uDC00"''' when: - StringValueParsing.parseSingleQuotedString(input) + StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: InvalidSyntaxException e = thrown(InvalidSyntaxException) - e.message == "Invalid Syntax : Invalid unicode - trailing surrogate must be preceded with a leading surrogate - offending token '\\uDC00'" + e.message == "Invalid unicode encountered. Trailing surrogate must be preceded with a leading surrogate. Offending token '\\uDC00' at line -1 column -1" } def "valid surrogate pair - leading code with braces"() { @@ -120,7 +122,7 @@ class StringValueParsingUnicodeTest extends Specification { def input = '''"hello \\u{d83c}\\udf7a"''' when: - String parsed = StringValueParsing.parseSingleQuotedString(input) + String parsed = StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: parsed == '''hello 🍺''' // contains the beer icon U+1F37 A : http://www.charbase.com/1f37a-unicode-beer-mug @@ -131,7 +133,7 @@ class StringValueParsingUnicodeTest extends Specification { def input = '''"hello \\ud83c\\u{df7a}"''' when: - String parsed = StringValueParsing.parseSingleQuotedString(input) + String parsed = StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: parsed == '''hello 🍺''' // contains the beer icon U+1F37A : http://www.charbase.com/1f37a-unicode-beer-mug @@ -142,7 +144,7 @@ class StringValueParsingUnicodeTest extends Specification { def input = '''"hello \\u{d83c}\\u{df7a}"''' when: - String parsed = StringValueParsing.parseSingleQuotedString(input) + String parsed = StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: parsed == '''hello 🍺''' // contains the beer icon U+1F37A : http://www.charbase.com/1f37a-unicode-beer-mug @@ -153,11 +155,11 @@ class StringValueParsingUnicodeTest extends Specification { def input = '''"hello \\u{d83c}\\"''' when: - StringValueParsing.parseSingleQuotedString(input) + StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: InvalidSyntaxException e = thrown(InvalidSyntaxException) - e.message == "Invalid Syntax : Invalid unicode - leading surrogate must be followed by a trailing surrogate - offending token '\\u{d83c}'" + e.message == "Invalid unicode encountered. Leading surrogate must be followed by a trailing surrogate. Offending token '\\u{d83c}' at line -1 column -1" } def "invalid surrogate pair - leading code with only \\u at end of string"() { @@ -165,11 +167,11 @@ class StringValueParsingUnicodeTest extends Specification { def input = '''"hello \\u{d83c}\\u"''' when: - StringValueParsing.parseSingleQuotedString(input) + StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: InvalidSyntaxException e = thrown(InvalidSyntaxException) - e.message == "Invalid Syntax : Invalid unicode - incorrectly formatted escape - offending token '\\u\"'" + e.message == "Invalid unicode encountered. Incorrectly formatted escape sequence. Offending token '\\u\"' at line -1 column -1" } def "invalid surrogate pair - trailing code without closing brace"() { @@ -177,11 +179,11 @@ class StringValueParsingUnicodeTest extends Specification { def input = '''"hello \\u{d83c}\\u{df7a"''' when: - StringValueParsing.parseSingleQuotedString(input) + StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: InvalidSyntaxException e = thrown(InvalidSyntaxException) - e.message == "Invalid Syntax : Invalid unicode - incorrectly formatted escape - offending token '\\u{df7a'" + e.message == "Invalid unicode encountered. Incorrectly formatted escape sequence. Offending token '\\u{df7a' at line -1 column -1" } def "invalid surrogate pair - invalid trailing code without unicode escape 1"() { @@ -189,11 +191,11 @@ class StringValueParsingUnicodeTest extends Specification { def input = '''"hello \\u{d83c}{df7a}"''' when: - StringValueParsing.parseSingleQuotedString(input) + StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: InvalidSyntaxException e = thrown(InvalidSyntaxException) - e.message == "Invalid Syntax : Invalid unicode - leading surrogate must be followed by a trailing surrogate - offending token '\\u{d83c}'" + e.message == "Invalid unicode encountered. Leading surrogate must be followed by a trailing surrogate. Offending token '\\u{d83c}' at line -1 column -1" } def "invalid surrogate pair - invalid trailing code without unicode escape 2"() { @@ -201,11 +203,11 @@ class StringValueParsingUnicodeTest extends Specification { def input = '''"hello \\u{d83c}df7a"''' when: - StringValueParsing.parseSingleQuotedString(input) + StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: InvalidSyntaxException e = thrown(InvalidSyntaxException) - e.message == "Invalid Syntax : Invalid unicode - leading surrogate must be followed by a trailing surrogate - offending token '\\u{d83c}'" + e.message == "Invalid unicode encountered. Leading surrogate must be followed by a trailing surrogate. Offending token '\\u{d83c}' at line -1 column -1" } def "invalid surrogate pair - invalid leading code"() { @@ -213,11 +215,11 @@ class StringValueParsingUnicodeTest extends Specification { def input = '''"hello d83c\\u{df7a}"''' when: - StringValueParsing.parseSingleQuotedString(input) + StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: InvalidSyntaxException e = thrown(InvalidSyntaxException) - e.message == "Invalid Syntax : Invalid unicode - trailing surrogate must be preceded with a leading surrogate - offending token '\\u{df7a}'" + e.message == "Invalid unicode encountered. Trailing surrogate must be preceded with a leading surrogate. Offending token '\\u{df7a}' at line -1 column -1" } def "invalid surrogate pair - invalid leading value with braces"() { @@ -225,11 +227,11 @@ class StringValueParsingUnicodeTest extends Specification { def input = '''"\\u{5B57}\\uDC00"''' when: - StringValueParsing.parseSingleQuotedString(input) + StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: InvalidSyntaxException e = thrown(InvalidSyntaxException) - e.message == "Invalid Syntax : Invalid unicode - trailing surrogate must be preceded with a leading surrogate - offending token '\\uDC00'" + e.message == "Invalid unicode encountered. Trailing surrogate must be preceded with a leading surrogate. Offending token '\\uDC00' at line -1 column -1" } def "invalid surrogate pair - invalid trailing value with braces"() { @@ -237,11 +239,11 @@ class StringValueParsingUnicodeTest extends Specification { def input = '''"\\uD83D\\u{DBFF}"''' when: - StringValueParsing.parseSingleQuotedString(input) + StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: InvalidSyntaxException e = thrown(InvalidSyntaxException) - e.message == "Invalid Syntax : Invalid unicode - leading surrogate must be followed by a trailing surrogate - offending token '\\u{DBFF}'" + e.message == "Invalid unicode encountered. Leading surrogate must be followed by a trailing surrogate. Offending token '\\u{DBFF}' at line -1 column -1" } def "invalid unicode code point - value is too high"() { @@ -249,10 +251,10 @@ class StringValueParsingUnicodeTest extends Specification { def input = '''"\\u{fffffff}"''' when: - StringValueParsing.parseSingleQuotedString(input) + StringValueParsing.parseSingleQuotedString(i18n, input,sourceLocation) then: InvalidSyntaxException e = thrown(InvalidSyntaxException) - e.message == "Invalid Syntax : Invalid unicode - not a valid code point - offending token '\\u{fffffff}'" + e.message == "Invalid unicode encountered. Not a valid code point. Offending token '\\u{fffffff}' at line -1 column -1" } } From 38d89c1ee95800990deb1e12fb2eea37945f1cf3 Mon Sep 17 00:00:00 2001 From: Brad Baker Date: Tue, 16 Aug 2022 12:50:36 +1000 Subject: [PATCH 2/3] Adding Locale to Parser - merged in master --- .../graphql/parser/GraphqlAntlrToLanguage.java | 2 +- .../parser/NodeToRuleCapturingParser.java | 4 ++-- src/main/java/graphql/parser/Parser.java | 17 +---------------- .../groovy/graphql/parser/ParserTest.groovy | 4 ++-- 4 files changed, 6 insertions(+), 21 deletions(-) diff --git a/src/main/java/graphql/parser/GraphqlAntlrToLanguage.java b/src/main/java/graphql/parser/GraphqlAntlrToLanguage.java index 108b28b8b..eb5070bc6 100644 --- a/src/main/java/graphql/parser/GraphqlAntlrToLanguage.java +++ b/src/main/java/graphql/parser/GraphqlAntlrToLanguage.java @@ -95,7 +95,7 @@ public class GraphqlAntlrToLanguage { private final Map, ParserRuleContext> nodeToRuleMap; private final I18n i18N; - public GraphqlAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader, ParserOptions parserOptions, @Nullable Map, ParserRuleContext> nodeToRuleMap, I18n i18N) { + public GraphqlAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader, ParserOptions parserOptions, I18n i18N, @Nullable Map, ParserRuleContext> nodeToRuleMap) { this.tokens = tokens; this.multiSourceReader = multiSourceReader; this.parserOptions = ofNullable(parserOptions).orElse(ParserOptions.getDefaultParserOptions()); diff --git a/src/main/java/graphql/parser/NodeToRuleCapturingParser.java b/src/main/java/graphql/parser/NodeToRuleCapturingParser.java index 88ffc94be..f63fe5816 100644 --- a/src/main/java/graphql/parser/NodeToRuleCapturingParser.java +++ b/src/main/java/graphql/parser/NodeToRuleCapturingParser.java @@ -21,9 +21,9 @@ public NodeToRuleCapturingParser() { } @Override - protected GraphqlAntlrToLanguage getAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader, ParserOptions parserOptions) { + protected GraphqlAntlrToLanguage getAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader, ParserEnvironment environment) { parserContext.tokens = tokens; - return new GraphqlAntlrToLanguage(tokens, multiSourceReader, parserOptions, parserContext.nodeToRuleMap); + return new GraphqlAntlrToLanguage(tokens, multiSourceReader, environment.getParserOptions(), environment.getI18N(), parserContext.nodeToRuleMap); } public ParserContext getParserContext() { diff --git a/src/main/java/graphql/parser/Parser.java b/src/main/java/graphql/parser/Parser.java index f5260bb71..87ca0ba69 100644 --- a/src/main/java/graphql/parser/Parser.java +++ b/src/main/java/graphql/parser/Parser.java @@ -380,21 +380,6 @@ private void throwCancelParseIfTooManyTokens(ParserEnvironment environment, Toke throw new ParseCancelledException(environment.getI18N(), sourceLocation, offendingToken, maxTokens, tokenType); } - /** - * Allows you to override the ANTLR to AST code. - * - * @param tokens the token stream - * @param multiSourceReader the source of the query document - * - * @return a new GraphqlAntlrToLanguage instance - * - * @deprecated - really should use {@link #getAntlrToLanguage(CommonTokenStream, MultiSourceReader, ParserEnvironment)} - */ - @Deprecated - protected GraphqlAntlrToLanguage getAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader) { - return null; - } - /** * Allows you to override the ANTLR to AST code. * @@ -405,6 +390,6 @@ protected GraphqlAntlrToLanguage getAntlrToLanguage(CommonTokenStream tokens, Mu * @return a new GraphqlAntlrToLanguage instance */ protected GraphqlAntlrToLanguage getAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader, ParserEnvironment environment) { - return new GraphqlAntlrToLanguage(tokens, multiSourceReader, environment.getParserOptions(), environment.getI18N()); + return new GraphqlAntlrToLanguage(tokens, multiSourceReader, environment.getParserOptions(), environment.getI18N(), null); } } diff --git a/src/test/groovy/graphql/parser/ParserTest.groovy b/src/test/groovy/graphql/parser/ParserTest.groovy index a5271eae5..6dcf33674 100644 --- a/src/test/groovy/graphql/parser/ParserTest.groovy +++ b/src/test/groovy/graphql/parser/ParserTest.groovy @@ -889,7 +889,7 @@ triple3 : """edge cases \\""" "" " \\"" \\" edge cases""" @Override protected GraphqlAntlrToLanguage getAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader, ParserEnvironment environment) { // this pattern is used in Nadel - its backdoor but needed - return new GraphqlAntlrToLanguage(tokens, multiSourceReader, environment.parserOptions, environment.i18N) { + return new GraphqlAntlrToLanguage(tokens, multiSourceReader, environment.parserOptions, environment.i18N, null) { @Override protected void addCommonData(NodeBuilder nodeBuilder, ParserRuleContext parserRuleContext) { super.addCommonData(nodeBuilder, parserRuleContext) @@ -910,7 +910,7 @@ triple3 : """edge cases \\""" "" " \\"" \\" edge cases""" @Override protected GraphqlAntlrToLanguage getAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader, ParserEnvironment environment) { - return new GraphqlAntlrToLanguage(tokens, multiSourceReader, environment.parserOptions, environment.i18N) { + return new GraphqlAntlrToLanguage(tokens, multiSourceReader, environment.parserOptions, environment.i18N, null) { @Override protected void addCommonData(NodeBuilder nodeBuilder, ParserRuleContext parserRuleContext) { super.addCommonData(nodeBuilder, parserRuleContext) From da388344042a0503e1ce6e825cd0006eae3e6f4e Mon Sep 17 00:00:00 2001 From: Brad Baker Date: Wed, 31 Aug 2022 10:54:36 +1000 Subject: [PATCH 3/3] Merged master in parser branch --- src/main/java/graphql/ParseAndValidate.java | 8 ++- .../graphql/language/PrettyAstPrinter.java | 5 +- src/main/java/graphql/parser/Parser.java | 62 ++++++++----------- .../graphql/parser/ParserEnvironment.java | 2 - .../java/graphql/schema/idl/SchemaParser.java | 6 +- src/main/java/graphql/util/Anonymizer.java | 5 +- 6 files changed, 45 insertions(+), 43 deletions(-) diff --git a/src/main/java/graphql/ParseAndValidate.java b/src/main/java/graphql/ParseAndValidate.java index 63c29edad..9410a5ec1 100644 --- a/src/main/java/graphql/ParseAndValidate.java +++ b/src/main/java/graphql/ParseAndValidate.java @@ -3,6 +3,7 @@ import graphql.language.Document; import graphql.parser.InvalidSyntaxException; import graphql.parser.Parser; +import graphql.parser.ParserEnvironment; import graphql.parser.ParserOptions; import graphql.schema.GraphQLSchema; import graphql.validation.ValidationError; @@ -65,7 +66,12 @@ public static ParseAndValidateResult parse(@NotNull ExecutionInput executionInpu // we use the query parser options by default if they are not specified parserOptions = ofNullable(parserOptions).orElse(ParserOptions.getDefaultOperationParserOptions()); Parser parser = new Parser(); - Document document = parser.parseDocument(executionInput.getQuery(), parserOptions); + Locale locale = executionInput.getLocale() == null ? Locale.getDefault() : executionInput.getLocale(); + ParserEnvironment parserEnvironment = ParserEnvironment.newParserEnvironment() + .document(executionInput.getQuery()).parserOptions(parserOptions) + .locale(locale) + .build(); + Document document = parser.parseDocument(parserEnvironment); return ParseAndValidateResult.newResult().document(document).variables(executionInput.getVariables()).build(); } catch (InvalidSyntaxException e) { return ParseAndValidateResult.newResult().syntaxException(e).variables(executionInput.getVariables()).build(); diff --git a/src/main/java/graphql/language/PrettyAstPrinter.java b/src/main/java/graphql/language/PrettyAstPrinter.java index 2ff364ec7..eb02039f2 100644 --- a/src/main/java/graphql/language/PrettyAstPrinter.java +++ b/src/main/java/graphql/language/PrettyAstPrinter.java @@ -5,6 +5,7 @@ import graphql.collect.ImmutableKit; import graphql.parser.CommentParser; import graphql.parser.NodeToRuleCapturingParser; +import graphql.parser.ParserEnvironment; import java.util.Collections; import java.util.List; @@ -14,6 +15,7 @@ import java.util.stream.Collectors; import static graphql.Assert.assertTrue; +import static graphql.parser.ParserEnvironment.newParserEnvironment; /** * A printer that acts as a code formatter. @@ -67,7 +69,8 @@ public String print(Node node) { public static String print(String schemaDefinition, PrettyPrinterOptions options) { NodeToRuleCapturingParser parser = new NodeToRuleCapturingParser(); - Document document = parser.parseDocument(schemaDefinition); + ParserEnvironment parserEnvironment = newParserEnvironment().document(schemaDefinition).build(); + Document document = parser.parseDocument(parserEnvironment); return new PrettyAstPrinter(parser.getParserContext(), options).print(document); } diff --git a/src/main/java/graphql/parser/Parser.java b/src/main/java/graphql/parser/Parser.java index da91cb3ee..c1aac322f 100644 --- a/src/main/java/graphql/parser/Parser.java +++ b/src/main/java/graphql/parser/Parser.java @@ -1,7 +1,7 @@ package graphql.parser; -import graphql.DeprecatedAt; import com.google.common.collect.ImmutableList; +import graphql.DeprecatedAt; import graphql.Internal; import graphql.PublicApi; import graphql.language.Document; @@ -83,9 +83,6 @@ public static Document parse(String input) throws InvalidSyntaxException { return new Parser().parseDocument(input); } - public static Document parse(ParserEnvironment environment) throws InvalidSyntaxException { - return new Parser().parseDocument(environment); - } /** * Parses a string input into a graphql AST {@link Value} @@ -139,6 +136,22 @@ public Document parseDocument(String input) throws InvalidSyntaxException { return parseDocument(input, (ParserOptions) null); } + /** + * Parses reader input into a graphql AST {@link Document} + * + * @param reader the reader input to parse + * + * @return an AST {@link Document} + * + * @throws InvalidSyntaxException if the input is not valid graphql syntax + */ + public Document parseDocument(Reader reader) throws InvalidSyntaxException { + ParserEnvironment parserEnvironment = ParserEnvironment.newParserEnvironment() + .document(reader) + .build(); + return parseDocumentImpl(parserEnvironment); + } + /** * Parses a string input into a graphql AST {@link Document} * @@ -148,7 +161,10 @@ public Document parseDocument(String input) throws InvalidSyntaxException { * @return an AST {@link Document} * * @throws InvalidSyntaxException if the input is not valid graphql syntax + * @deprecated use {#{@link #parse(ParserEnvironment)}} instead */ + @DeprecatedAt("2022-08-31") + @Deprecated public Document parseDocument(String input, String sourceName) throws InvalidSyntaxException { MultiSourceReader multiSourceReader = MultiSourceReader.newMultiSourceReader() .string(input, sourceName) @@ -166,7 +182,10 @@ public Document parseDocument(String input, String sourceName) throws InvalidSyn * @return an AST {@link Document} * * @throws InvalidSyntaxException if the input is not valid graphql syntax + * @deprecated use {#{@link #parse(ParserEnvironment)}} instead */ + @DeprecatedAt("2022-08-31") + @Deprecated public Document parseDocument(String input, ParserOptions parserOptions) throws InvalidSyntaxException { MultiSourceReader multiSourceReader = MultiSourceReader.newMultiSourceReader() .string(input, null) @@ -175,22 +194,6 @@ public Document parseDocument(String input, ParserOptions parserOptions) throws return parseDocument(multiSourceReader, parserOptions); } - /** - * Parses reader input into a graphql AST {@link Document} - * - * @param reader the reader input to parse - * - * @return an AST {@link Document} - * - * @throws InvalidSyntaxException if the input is not valid graphql syntax - */ - public Document parseDocument(Reader reader) throws InvalidSyntaxException { - ParserEnvironment parserEnvironment = ParserEnvironment.newParserEnvironment() - .document(reader) - .build(); - return parseDocumentImpl(parserEnvironment); - } - /** * Parses reader input into a graphql AST {@link Document} * @@ -200,7 +203,10 @@ public Document parseDocument(Reader reader) throws InvalidSyntaxException { * @return an AST {@link Document} * * @throws InvalidSyntaxException if the input is not valid graphql syntax + * @deprecated use {#{@link #parse(ParserEnvironment)}} instead */ + @DeprecatedAt("2022-08-31") + @Deprecated public Document parseDocument(Reader reader, ParserOptions parserOptions) throws InvalidSyntaxException { ParserEnvironment parserEnvironment = ParserEnvironment.newParserEnvironment() .document(reader) @@ -397,20 +403,4 @@ private void throwCancelParseIfTooManyTokens(ParserEnvironment environment, Toke protected GraphqlAntlrToLanguage getAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader, ParserEnvironment environment) { return new GraphqlAntlrToLanguage(tokens, multiSourceReader, environment.getParserOptions(), environment.getI18N(), null); } - - /** - * Allows you to override the ANTLR to AST code. - * - * @param tokens the token stream - * @param multiSourceReader the source of the query document - * - * @return a new GraphqlAntlrToLanguage instance - * - * @deprecated - really should use {@link #getAntlrToLanguage(CommonTokenStream, MultiSourceReader, ParserOptions)} - */ - @Deprecated - @DeprecatedAt("2021-06-23") - protected GraphqlAntlrToLanguage getAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader) { - return null; - } } diff --git a/src/main/java/graphql/parser/ParserEnvironment.java b/src/main/java/graphql/parser/ParserEnvironment.java index 9850688ac..7f0ac696b 100644 --- a/src/main/java/graphql/parser/ParserEnvironment.java +++ b/src/main/java/graphql/parser/ParserEnvironment.java @@ -45,10 +45,8 @@ static Builder newParserEnvironment() { class Builder { Reader reader; ParserOptions parserOptions = ParserOptions.getDefaultParserOptions(); - Locale locale = Locale.getDefault(); - public Builder() { } diff --git a/src/main/java/graphql/schema/idl/SchemaParser.java b/src/main/java/graphql/schema/idl/SchemaParser.java index 097e5649f..8fc093236 100644 --- a/src/main/java/graphql/schema/idl/SchemaParser.java +++ b/src/main/java/graphql/schema/idl/SchemaParser.java @@ -8,6 +8,7 @@ import graphql.language.SDLDefinition; import graphql.parser.InvalidSyntaxException; import graphql.parser.Parser; +import graphql.parser.ParserEnvironment; import graphql.parser.ParserOptions; import graphql.schema.idl.errors.NonSDLDefinitionError; import graphql.schema.idl.errors.SchemaProblem; @@ -23,6 +24,7 @@ import java.util.Collections; import java.util.List; +import static graphql.parser.ParserEnvironment.newParserEnvironment; import static java.nio.charset.Charset.defaultCharset; /** @@ -116,8 +118,8 @@ private TypeDefinitionRegistry parseImpl(Reader schemaInput, ParserOptions parse if (parseOptions == null) { parseOptions = ParserOptions.getDefaultSdlParserOptions(); } - Parser parser = new Parser(); - Document document = parser.parseDocument(schemaInput, parseOptions); + ParserEnvironment parserEnvironment = newParserEnvironment().document(schemaInput).parserOptions(parseOptions).build(); + Document document = Parser.parse(parserEnvironment); return buildRegistry(document); } catch (InvalidSyntaxException e) { diff --git a/src/main/java/graphql/util/Anonymizer.java b/src/main/java/graphql/util/Anonymizer.java index a797535f0..f2614ef02 100644 --- a/src/main/java/graphql/util/Anonymizer.java +++ b/src/main/java/graphql/util/Anonymizer.java @@ -43,6 +43,7 @@ import graphql.language.VariableDefinition; import graphql.language.VariableReference; import graphql.parser.Parser; +import graphql.parser.ParserEnvironment; import graphql.schema.GraphQLAppliedDirective; import graphql.schema.GraphQLAppliedDirectiveArgument; import graphql.schema.GraphQLArgument; @@ -92,6 +93,7 @@ import java.util.function.Consumer; import static graphql.Assert.assertNotNull; +import static graphql.parser.ParserEnvironment.newParserEnvironment; import static graphql.schema.GraphQLArgument.newArgument; import static graphql.schema.GraphQLTypeUtil.unwrapNonNull; import static graphql.schema.GraphQLTypeUtil.unwrapNonNullAs; @@ -715,7 +717,8 @@ private static String rewriteQuery(String query, GraphQLSchema schema, Map astNodeToNewName = new LinkedHashMap<>(); Map variableNames = new LinkedHashMap<>(); Map fieldToFieldDefinition = new LinkedHashMap<>(); - Document document = new Parser().parseDocument(query); + + Document document = Parser.parse(newParserEnvironment().document(query).build()); assertUniqueOperation(document); QueryTraverser queryTraverser = QueryTraverser.newQueryTraverser().document(document).schema(schema).variables(variables).build(); queryTraverser.visitDepthFirst(new QueryVisitor() {