Skip to content

Commit d5e4ea5

Browse files
authored
Do not capture Ignored characters by default (#2394)
* Ignored character support * Javadoc - its important * Javadoc - its important thats it written right
1 parent 89f328c commit d5e4ea5

6 files changed

Lines changed: 279 additions & 39 deletions

File tree

src/main/java/graphql/language/IgnoredChar.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
import java.io.Serializable;
66
import java.util.Objects;
77

8+
/**
9+
* Graphql syntax has a series of characters, such as spaces, new lines and commas that are not considered relevant
10+
* to the syntax. However they can be captured and associated with the AST elements they belong to.
11+
*
12+
* This costs more memory but for certain use cases (like editors) this maybe be useful
13+
*/
814
@PublicApi
915
public class IgnoredChar implements Serializable {
1016

@@ -38,10 +44,10 @@ public SourceLocation getSourceLocation() {
3844
@Override
3945
public String toString() {
4046
return "IgnoredChar{" +
41-
"value='" + value + '\'' +
42-
", kind=" + kind +
43-
", sourceLocation=" + sourceLocation +
44-
'}';
47+
"value='" + value + '\'' +
48+
", kind=" + kind +
49+
", sourceLocation=" + sourceLocation +
50+
'}';
4551
}
4652

4753
@Override
@@ -54,8 +60,8 @@ public boolean equals(Object o) {
5460
}
5561
IgnoredChar that = (IgnoredChar) o;
5662
return Objects.equals(value, that.value) &&
57-
kind == that.kind &&
58-
Objects.equals(sourceLocation, that.sourceLocation);
63+
kind == that.kind &&
64+
Objects.equals(sourceLocation, that.sourceLocation);
5965
}
6066

6167
@Override

src/main/java/graphql/language/IgnoredChars.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88

99
import static graphql.collect.ImmutableKit.emptyList;
1010

11+
/**
12+
* Graphql syntax has a series of characters, such as spaces, new lines and commas that are not considered relevant
13+
* to the syntax. However they can be captured and associated with the AST elements they belong to.
14+
*
15+
* This costs more memory but for certain use cases (like editors) this maybe be useful
16+
*/
1117
@PublicApi
1218
public class IgnoredChars implements Serializable {
1319

src/main/java/graphql/parser/GraphqlAntlrToLanguage.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,17 @@ public class GraphqlAntlrToLanguage {
8686
private static final int CHANNEL_IGNORED_CHARS = 3;
8787
private final CommonTokenStream tokens;
8888
private final MultiSourceReader multiSourceReader;
89+
private final boolean captureIgnoredChars;
8990

9091

9192
public GraphqlAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader) {
93+
this(tokens, multiSourceReader, null);
94+
}
95+
96+
public GraphqlAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader, Boolean captureIgnoredChars) {
9297
this.tokens = tokens;
9398
this.multiSourceReader = multiSourceReader;
99+
this.captureIgnoredChars = captureIgnoredChars == null ? Parser.getCaptureIgnoredChars() : captureIgnoredChars;
94100
}
95101

96102
//MARKER START: Here GraphqlOperation.g4 specific methods begin
@@ -774,6 +780,9 @@ protected void addCommonData(NodeBuilder nodeBuilder, ParserRuleContext parserRu
774780
}
775781

776782
private void addIgnoredChars(ParserRuleContext ctx, NodeBuilder nodeBuilder) {
783+
if (!captureIgnoredChars) {
784+
return;
785+
}
777786
Token start = ctx.getStart();
778787
int tokenStartIndex = start.getTokenIndex();
779788
List<Token> leftChannel = tokens.getHiddenTokensToLeft(tokenStartIndex, CHANNEL_IGNORED_CHARS);

src/main/java/graphql/parser/InvalidSyntaxException.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@
22

33

44
import graphql.GraphQLException;
5-
import graphql.Internal;
65
import graphql.InvalidSyntaxError;
6+
import graphql.PublicApi;
77
import graphql.language.SourceLocation;
88

99
import java.util.Collections;
1010
import java.util.List;
1111

12-
@Internal
12+
/**
13+
* This exception is thrown by the {@link Parser} if the graphql syntax is not valid
14+
*/
15+
@PublicApi
1316
public class InvalidSyntaxException extends GraphQLException {
1417

1518
private final String message;

src/main/java/graphql/parser/Parser.java

Lines changed: 163 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,108 @@
2323
import java.util.List;
2424
import java.util.function.BiFunction;
2525

26+
/**
27+
* This can parse graphql syntax, both Query syntax and Schema Definition Language (SDL) syntax, into an
28+
* Abstract Syntax Tree (AST) represented by a {@link Document}
29+
* <p>
30+
* You should not generally need to call this class as the {@link graphql.GraphQL} code sets this up for you
31+
* but if you are doing specific graphql utilities this class is essential.
32+
*
33+
* Graphql syntax has a series of characters, such as spaces, new lines and commas that are not considered relevant
34+
* to the syntax. However they can be captured and associated with the AST elements they belong to.
35+
*
36+
* This costs more memory but for certain use cases (like editors) this maybe be useful. We have chosen to no capture
37+
* ignored characters by default but you can turn this on, either per parse or statically for the whole JVM
38+
* via {@link #setCaptureIgnoredChars(boolean)}
39+
*
40+
* @see graphql.language.IgnoredChar
41+
*/
2642
@PublicApi
2743
public class Parser {
2844

45+
private static boolean captureIgnoredChars = false;
2946

30-
public static Document parse(String input) {
47+
/**
48+
* By default the Parser will not capture ignored characters. A static holds this default
49+
* value in a JVM wide basis.
50+
*
51+
* Significant memory savings can be made if we do NOT capture ignored characters,
52+
* especially in SDL parsing.
53+
*
54+
* @return the static default value on whether to capture ignored chars
55+
*
56+
* @see graphql.language.IgnoredChar
57+
*/
58+
public static boolean getCaptureIgnoredChars() {
59+
return captureIgnoredChars;
60+
}
61+
62+
/**
63+
* By default the Parser will not capture ignored characters. A static holds this default
64+
* value in a JVM wide basis.
65+
*
66+
* Significant memory savings can be made if we do NOT capture ignored characters,
67+
* especially in SDL parsing. So we have set this to false by default.
68+
*
69+
* This static can be set to true to allow the behavior of version 16.x or before.
70+
*
71+
* @param flag - whether to capture ignored characters in AST elements or not
72+
*
73+
* @see graphql.language.IgnoredChar
74+
*/
75+
public static void setCaptureIgnoredChars(boolean flag) {
76+
captureIgnoredChars = flag;
77+
}
78+
79+
/**
80+
* Parses a string input into a graphql AST {@link Document}
81+
*
82+
* @param input the input to parse
83+
*
84+
* @return an AST {@link Document}
85+
*
86+
* @throws InvalidSyntaxException if the input is not valid graphql syntax
87+
*/
88+
public static Document parse(String input) throws InvalidSyntaxException {
3189
return new Parser().parseDocument(input);
3290
}
3391

34-
public static Value<?> parseValue(String input) {
92+
/**
93+
* Parses a string input into a graphql AST {@link Value}
94+
*
95+
* @param input the input to parse
96+
*
97+
* @return an AST {@link Value}
98+
*
99+
* @throws InvalidSyntaxException if the input is not valid graphql syntax
100+
*/
101+
public static Value<?> parseValue(String input) throws InvalidSyntaxException {
35102
return new Parser().parseValueImpl(input);
36103
}
37104

105+
/**
106+
* Parses a string input into a graphql AST {@link Document}
107+
*
108+
* @param input the input to parse
109+
*
110+
* @return an AST {@link Document}
111+
*
112+
* @throws InvalidSyntaxException if the input is not valid graphql syntax
113+
*/
38114
public Document parseDocument(String input) throws InvalidSyntaxException {
39115
return parseDocument(input, null);
40116
}
41117

118+
/**
119+
* Parses a string input into a graphql AST {@link Document}
120+
*
121+
* @param input the input to parse
122+
* @param sourceName - the name to attribute to the input text in {@link SourceLocation#getSourceName()}
123+
*
124+
* @return an AST {@link Document}
125+
*
126+
* @throws InvalidSyntaxException if the input is not valid graphql syntax
127+
*/
42128
public Document parseDocument(String input, String sourceName) throws InvalidSyntaxException {
43129
MultiSourceReader multiSourceReader = MultiSourceReader.newMultiSourceReader()
44130
.string(input, sourceName)
@@ -47,29 +133,76 @@ public Document parseDocument(String input, String sourceName) throws InvalidSyn
47133
return parseDocument(multiSourceReader);
48134
}
49135

50-
public Document parseDocument(Reader reader) {
136+
/**
137+
* Parses a string input into a graphql AST {@link Document}
138+
*
139+
* @param input the input to parse
140+
* @param captureIgnoredChars whether to capture characters that are otherwise ignored in graphql syntax against
141+
* each AST element
142+
*
143+
* @return an AST {@link Document}
144+
*
145+
* @throws InvalidSyntaxException if the input is not valid graphql syntax
146+
*/
147+
public Document parseDocument(String input, boolean captureIgnoredChars) throws InvalidSyntaxException {
148+
MultiSourceReader multiSourceReader = MultiSourceReader.newMultiSourceReader()
149+
.string(input, null)
150+
.trackData(true)
151+
.build();
152+
return parseDocument(multiSourceReader, captureIgnoredChars);
153+
}
154+
155+
/**
156+
* Parses reader input into a graphql AST {@link Document}
157+
*
158+
* @param reader the reader input to parse
159+
*
160+
* @return an AST {@link Document}
161+
*
162+
* @throws InvalidSyntaxException if the input is not valid graphql syntax
163+
*/
164+
public Document parseDocument(Reader reader) throws InvalidSyntaxException {
165+
return parseDocumentImpl(reader, null);
166+
}
167+
168+
/**
169+
* Parses reader input into a graphql AST {@link Document}
170+
*
171+
* @param reader the reader input to parse
172+
* @param captureIgnoredChars whether to capture characters that are otherwise ignored in graphql syntax against
173+
* each AST element
174+
*
175+
* @return an AST {@link Document}
176+
*
177+
* @throws InvalidSyntaxException if the input is not valid graphql syntax
178+
*/
179+
public Document parseDocument(Reader reader, boolean captureIgnoredChars) throws InvalidSyntaxException {
180+
return parseDocumentImpl(reader, captureIgnoredChars);
181+
}
182+
183+
private Document parseDocumentImpl(Reader reader, Boolean captureIgnoredChars) throws InvalidSyntaxException {
51184
BiFunction<GraphqlParser, GraphqlAntlrToLanguage, Object[]> nodeFunction = (parser, toLanguage) -> {
52185
GraphqlParser.DocumentContext documentContext = parser.document();
53186
Document doc = toLanguage.createDocument(documentContext);
54187
return new Object[]{documentContext, doc};
55188
};
56-
return (Document) parseImpl(reader, nodeFunction);
189+
return (Document) parseImpl(reader, nodeFunction, captureIgnoredChars);
57190
}
58191

59-
private Value<?> parseValueImpl(String input) {
192+
private Value<?> parseValueImpl(String input) throws InvalidSyntaxException {
60193
BiFunction<GraphqlParser, GraphqlAntlrToLanguage, Object[]> nodeFunction = (parser, toLanguage) -> {
61194
GraphqlParser.ValueContext documentContext = parser.value();
62-
Value value = toLanguage.createValue(documentContext);
195+
Value<?> value = toLanguage.createValue(documentContext);
63196
return new Object[]{documentContext, value};
64197
};
65198
MultiSourceReader multiSourceReader = MultiSourceReader.newMultiSourceReader()
66199
.string(input, null)
67200
.trackData(true)
68201
.build();
69-
return (Value<?>) parseImpl(multiSourceReader, nodeFunction);
202+
return (Value<?>) parseImpl(multiSourceReader, nodeFunction, null);
70203
}
71204

72-
private Node parseImpl(Reader reader, BiFunction<GraphqlParser, GraphqlAntlrToLanguage, Object[]> nodeFunction) throws InvalidSyntaxException {
205+
private Node<?> parseImpl(Reader reader, BiFunction<GraphqlParser, GraphqlAntlrToLanguage, Object[]> nodeFunction, Boolean captureIgnoredChars) throws InvalidSyntaxException {
73206
MultiSourceReader multiSourceReader;
74207
if (reader instanceof MultiSourceReader) {
75208
multiSourceReader = (MultiSourceReader) reader;
@@ -104,10 +237,14 @@ public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int
104237
ExtendedBailStrategy bailStrategy = new ExtendedBailStrategy(multiSourceReader);
105238
parser.setErrorHandler(bailStrategy);
106239

240+
// preserve old protected call semantics - remove at some point
107241
GraphqlAntlrToLanguage toLanguage = getAntlrToLanguage(tokens, multiSourceReader);
242+
if (toLanguage == null) {
243+
toLanguage = getAntlrToLanguage(tokens, multiSourceReader, captureIgnoredChars);
244+
}
108245
Object[] contextAndNode = nodeFunction.apply(parser, toLanguage);
109246
ParserRuleContext parserRuleContext = (ParserRuleContext) contextAndNode[0];
110-
Node node = (Node) contextAndNode[1];
247+
Node<?> node = (Node<?>) contextAndNode[1];
111248

112249
Token stop = parserRuleContext.getStop();
113250
List<Token> allTokens = tokens.getTokens();
@@ -133,8 +270,24 @@ public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int
133270
* @param multiSourceReader the source of the query document
134271
*
135272
* @return a new GraphqlAntlrToLanguage instance
273+
*
274+
* @deprecated - really should use {@link #getAntlrToLanguage(CommonTokenStream, MultiSourceReader, Boolean)}
136275
*/
276+
@Deprecated
137277
protected GraphqlAntlrToLanguage getAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader) {
138-
return new GraphqlAntlrToLanguage(tokens, multiSourceReader);
278+
return null;
279+
}
280+
281+
/**
282+
* Allows you to override the ANTLR to AST code.
283+
*
284+
* @param tokens the token stream
285+
* @param multiSourceReader the source of the query document
286+
* @param captureIgnoredChars - whether ignored characters should be captured in the AST elements
287+
*
288+
* @return a new GraphqlAntlrToLanguage instance
289+
*/
290+
protected GraphqlAntlrToLanguage getAntlrToLanguage(CommonTokenStream tokens, MultiSourceReader multiSourceReader, Boolean captureIgnoredChars) {
291+
return new GraphqlAntlrToLanguage(tokens, multiSourceReader, captureIgnoredChars);
139292
}
140293
}

0 commit comments

Comments
 (0)