Skip to content

Commit 5d39618

Browse files
author
Robert Mosolgo
authored
Merge pull request #2510 from andrewdotn/master
Fix parsing of escaped backslashes
2 parents 7c17f05 + 18176d9 commit 5d39618

File tree

4 files changed

+152
-106
lines changed

4 files changed

+152
-106
lines changed

lib/graphql/language/lexer.rb

Lines changed: 106 additions & 105 deletions
Large diffs are not rendered by default.

lib/graphql/language/lexer.rl

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,17 @@
3535
RBRACKET = ']';
3636
COLON = ':';
3737
QUOTE = '"';
38+
BACKSLASH = '\\';
39+
# Could limit to hex here, but “bad unicode escape” on 0XXF is probably a
40+
# more helpful error than “unknown char”
41+
UNICODE_ESCAPE = '\\u' [0-9A-Za-z]{4};
42+
# https://graphql.github.io/graphql-spec/June2018/#sec-String-Value
43+
STRING_ESCAPE = '\\' [\\/bfnrt];
3844
BLOCK_QUOTE = '"""';
3945
ESCAPED_BLOCK_QUOTE = '\\"""';
4046
BLOCK_STRING_CHAR = (ESCAPED_BLOCK_QUOTE | ^QUOTE | QUOTE{1,2} ^QUOTE);
4147
ESCAPED_QUOTE = '\\"';
42-
STRING_CHAR = (ESCAPED_QUOTE | ^QUOTE);
48+
STRING_CHAR = ((ESCAPED_QUOTE | ^QUOTE) - BACKSLASH) | UNICODE_ESCAPE | STRING_ESCAPE;
4349
VAR_SIGN = '$';
4450
DIR_SIGN = '@';
4551
ELLIPSIS = '...';
@@ -53,6 +59,11 @@
5359
# catch-all for anything else. must be at the bottom for precedence.
5460
UNKNOWN_CHAR = /./;
5561

62+
# Used with ragel -V for graphviz visualization
63+
str := |*
64+
QUOTED_STRING => { emit_string(ts, te, meta, block: false) };
65+
*|;
66+
5667
main := |*
5768
INT => { emit(:INT, ts, te, meta) };
5869
FLOAT => { emit(:FLOAT, ts, te, meta) };

spec/graphql/language/lexer_spec.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@
3232
assert_equal 'c', tokens[1].value
3333
end
3434

35+
it "handles escaped backslashes before escaped quotes" do
36+
tokens = subject.tokenize('text: "b\\\\", otherText: "a"')
37+
assert_equal ['text', ':', 'b\\', 'otherText', ':', 'a',], tokens.map(&:value)
38+
end
39+
3540
describe "block strings" do
3641
let(:query_string) { %|{ a(b: """\nc\n \\""" d\n""" """""e""""")}|}
3742

@@ -60,6 +65,11 @@
6065

6166
assert_equal '', tokens[0].value
6267
end
68+
69+
it "tokenizes escaped backslashes at the end of blocks" do
70+
tokens = subject.tokenize('text: """b\\\\""", otherText: "a"')
71+
assert_equal ['text', ':', 'b\\', 'otherText', ':', 'a',], tokens.map(&:value)
72+
end
6373
end
6474

6575
it "unescapes escaped characters" do

spec/graphql/language/parser_spec.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,30 @@
122122
end
123123
end
124124

125+
it "parses backslashes in arguments" do
126+
document = subject.parse <<-GRAPHQL
127+
query {
128+
item(text: "a", otherText: "b\\\\") {
129+
text
130+
otherText
131+
}
132+
}
133+
GRAPHQL
134+
assert_equal "b\\", document.definitions[0].selections[0].arguments[1].value
135+
end
136+
137+
it "parses backslases in non-last arguments" do
138+
document = subject.parse <<-GRAPHQL
139+
query {
140+
item(text: "b\\\\", otherText: "a") {
141+
text
142+
otherText
143+
}
144+
}
145+
GRAPHQL
146+
assert_equal "b\\", document.definitions[0].selections[0].arguments[0].value
147+
end
148+
125149
it "parses the test schema" do
126150
schema = Dummy::Schema
127151
schema_string = GraphQL::Schema::Printer.print_schema(schema)

0 commit comments

Comments
 (0)