Skip to content

Commit 7b0e9da

Browse files
authored
Allow to parse more AST nodes (#306)
1 parent 8483d95 commit 7b0e9da

File tree

6 files changed

+438
-70
lines changed

6 files changed

+438
-70
lines changed

src/GraphQLParser.Tests/Extensions.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,15 @@ internal static class ParserTestExtensions
1919
/// <param name="options">Parser options.</param>
2020
/// <returns>AST (Abstract Syntax Tree) for GraphQL document.</returns>
2121
public static GraphQLDocument Parse(this string source, ParserOptions options = default) => Parser.Parse(source, options);
22+
23+
/// <summary>
24+
/// Generates AST based on input text.
25+
/// </summary>
26+
/// <typeparam name="T">Type of node to parse input text as.</typeparam>
27+
/// <param name="source">Input data as a sequence of characters.</param>
28+
/// <param name="options">Parser options.</param>
29+
/// <returns>AST (Abstract Syntax Tree) for GraphQL node.</returns>
30+
public static T Parse<T>(this string source, ParserOptions options = default)
31+
where T : ASTNode
32+
=> Parser.Parse<T>(source, options);
2233
}
Lines changed: 316 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
using GraphQLParser.Exceptions;
2+
3+
namespace GraphQLParser.Tests;
4+
5+
public class ParserTestsCustomAST
6+
{
7+
[Fact]
8+
public void Should_Throw_On_Comment()
9+
{
10+
string text = "# comment";
11+
Should.Throw<NotSupportedException>(() => text.Parse<GraphQLComment>());
12+
}
13+
14+
[Theory]
15+
[InlineData("null", ASTNodeKind.NullValue)]
16+
[InlineData("1", ASTNodeKind.IntValue)]
17+
[InlineData("1.1", ASTNodeKind.FloatValue)]
18+
[InlineData("\"abc\"", ASTNodeKind.StringValue, "abc")]
19+
[InlineData("\"escaped \\n\\r\\b\\t\\f\"", ASTNodeKind.StringValue, "escaped \n\r\b\t\f")]
20+
[InlineData("true", ASTNodeKind.BooleanValue)]
21+
[InlineData("RED", ASTNodeKind.EnumValue)]
22+
[InlineData("[ 1, 2, 3]", ASTNodeKind.ListValue)]
23+
[InlineData("{ a: 1, b: \"abc\", c: RED, d: $id }", ASTNodeKind.ObjectValue)]
24+
[InlineData("$id", ASTNodeKind.Variable)]
25+
public void Should_Parse_Value_Literal_But_Not_Entire_Document(string text, ASTNodeKind kind, string expected = null)
26+
{
27+
Should.Throw<GraphQLSyntaxErrorException>(() => Parser.Parse(text));
28+
29+
var value = Parser.Parse<GraphQLValue>(text);
30+
value.ShouldNotBeNull();
31+
value.Kind.ShouldBe(kind);
32+
if (expected != null)
33+
((GraphQLStringValue)value).Value.ShouldBe(expected);
34+
}
35+
36+
[Fact]
37+
public void Should_Parse_Variable()
38+
{
39+
string text = "$id";
40+
var ast = text.Parse<GraphQLVariable>().ShouldNotBeNull();
41+
ast.Name.Value.ShouldBe("id");
42+
}
43+
44+
[Fact]
45+
public void Should_Parse_Argument()
46+
{
47+
string text = "id: 5";
48+
var ast = text.Parse<GraphQLArgument>().ShouldNotBeNull();
49+
ast.Name.Value.ShouldBe("id");
50+
}
51+
52+
[Fact]
53+
public void Should_Parse_Arguments()
54+
{
55+
string text = "(id: 5 code: abc)";
56+
var ast = text.Parse<GraphQLArguments>().ShouldNotBeNull();
57+
ast.Items.Count.ShouldBe(2);
58+
}
59+
60+
[Fact]
61+
public void Should_Parse_Description()
62+
{
63+
string text = "\"blablalba\"";
64+
var ast = text.Parse<GraphQLDescription>().ShouldNotBeNull();
65+
ast.Value.ShouldBe("blablalba");
66+
}
67+
68+
[Fact]
69+
public void Should_Parse_Directive()
70+
{
71+
string text = "@my";
72+
var ast = text.Parse<GraphQLDirective>().ShouldNotBeNull();
73+
ast.Name.Value.ShouldBe("my");
74+
}
75+
76+
[Fact]
77+
public void Should_Parse_Directives()
78+
{
79+
string text = "@my @your";
80+
var ast = text.Parse<GraphQLDirectives>().ShouldNotBeNull();
81+
ast.Items.Count.ShouldBe(2);
82+
}
83+
84+
[Fact]
85+
public void Should_Parse_Field()
86+
{
87+
string text = "name";
88+
var ast = text.Parse<GraphQLField>().ShouldNotBeNull();
89+
ast.Name.Value.ShouldBe("name");
90+
}
91+
92+
[Fact]
93+
public void Should_Parse_SelectionSet()
94+
{
95+
string text = "{ a b }";
96+
var ast = text.Parse<GraphQLSelectionSet>().ShouldNotBeNull();
97+
ast.Selections.Count.ShouldBe(2);
98+
}
99+
100+
[Fact]
101+
public void Should_Parse_ArgumentsDefinition()
102+
{
103+
string text = "(size: Int)";
104+
var definition = text.Parse<GraphQLArgumentsDefinition>().ShouldNotBeNull();
105+
definition.Items.Count.ShouldBe(1);
106+
}
107+
108+
[Fact]
109+
public void Should_Parse_InputValueDefinition()
110+
{
111+
string text = "size: Int";
112+
var definition = text.Parse<GraphQLInputValueDefinition>().ShouldNotBeNull();
113+
definition.Name.Value.ShouldBe("size");
114+
}
115+
116+
[Fact]
117+
public void Should_Parse_DirectiveDefinition()
118+
{
119+
string text = "directive @my on FIELD";
120+
var definition = text.Parse<GraphQLDirectiveDefinition>().ShouldNotBeNull();
121+
definition.Name.Value.ShouldBe("my");
122+
}
123+
124+
[Fact]
125+
public void Should_Parse_EnumTypeDefinition()
126+
{
127+
string text = "enum Color { RED }";
128+
var definition = text.Parse<GraphQLEnumTypeDefinition>().ShouldNotBeNull();
129+
definition.Name.Value.ShouldBe("Color");
130+
}
131+
132+
[Fact]
133+
public void Should_Parse_EnumValueDefinition()
134+
{
135+
string text = "RED";
136+
var definition = text.Parse<GraphQLEnumValueDefinition>().ShouldNotBeNull();
137+
definition.Name.Value.ShouldBe("RED");
138+
}
139+
140+
[Fact]
141+
public void Should_Parse_EnumValuesDefinition()
142+
{
143+
string text = "{ RED GREEN }";
144+
var definition = text.Parse<GraphQLEnumValuesDefinition>().ShouldNotBeNull();
145+
definition.Items.Count.ShouldBe(2);
146+
}
147+
148+
[Fact]
149+
public void Should_Parse_FieldDefinition()
150+
{
151+
string text = "name: String";
152+
var definition = text.Parse<GraphQLFieldDefinition>().ShouldNotBeNull();
153+
definition.Name.Value.ShouldBe("name");
154+
}
155+
156+
[Fact]
157+
public void Should_Parse_FieldsDefinition()
158+
{
159+
string text = "{ name: String age: Int }";
160+
var definition = text.Parse<GraphQLFieldsDefinition>().ShouldNotBeNull();
161+
definition.Items.Count.ShouldBe(2);
162+
}
163+
164+
[Fact]
165+
public void Should_Parse_FragmentDefinition()
166+
{
167+
string text = "fragment frag on Person { name }";
168+
var definition = text.Parse<GraphQLFragmentDefinition>().ShouldNotBeNull();
169+
definition.FragmentName.Name.Value.ShouldBe("frag");
170+
}
171+
172+
[Fact]
173+
public void Should_Parse_InputFieldsDefinition()
174+
{
175+
string text = "{ name: String age: Int }";
176+
var definition = text.Parse<GraphQLInputFieldsDefinition>().ShouldNotBeNull();
177+
definition.Items.Count.ShouldBe(2);
178+
}
179+
180+
[Fact]
181+
public void Should_Parse_InputObjectTypeDefinition()
182+
{
183+
string text = "input Person { name: String }";
184+
var definition = text.Parse<GraphQLInputObjectTypeDefinition>().ShouldNotBeNull();
185+
definition.Name.Value.ShouldBe("Person");
186+
}
187+
188+
[Fact]
189+
public void Should_Parse_InterfaceTypeDefinition()
190+
{
191+
string text = "interface Person { name: String }";
192+
var definition = text.Parse<GraphQLInterfaceTypeDefinition>().ShouldNotBeNull();
193+
definition.Name.Value.ShouldBe("Person");
194+
}
195+
196+
[Fact]
197+
public void Should_Parse_ObjectTypeDefinition()
198+
{
199+
string text = "type Person { name: String }";
200+
var definition = text.Parse<GraphQLObjectTypeDefinition>().ShouldNotBeNull();
201+
definition.Name.Value.ShouldBe("Person");
202+
}
203+
204+
[Fact]
205+
public void Should_Parse_OperationDefinition()
206+
{
207+
string text = "mutation x { set(value: 1) }";
208+
var definition = text.Parse<GraphQLOperationDefinition>().ShouldNotBeNull();
209+
definition.Name.Value.ShouldBe("x");
210+
}
211+
212+
[Fact]
213+
public void Should_Parse_RootOperationTypeDefinition()
214+
{
215+
string text = "query: Q";
216+
var definition = text.Parse<GraphQLRootOperationTypeDefinition>().ShouldNotBeNull();
217+
definition.Operation.ShouldBe(OperationType.Query);
218+
}
219+
220+
[Fact]
221+
public void Should_Parse_ScalarTypeDefinition()
222+
{
223+
string text = "scalar JSON";
224+
var definition = text.Parse<GraphQLScalarTypeDefinition>().ShouldNotBeNull();
225+
definition.Name.Value.ShouldBe("JSON");
226+
}
227+
228+
[Fact]
229+
public void Should_Parse_SchemaDefinition()
230+
{
231+
string text = "schema { query: Q subscription: S }";
232+
var definition = text.Parse<GraphQLSchemaDefinition>().ShouldNotBeNull();
233+
definition.OperationTypes.Count.ShouldBe(2);
234+
}
235+
236+
[Fact]
237+
public void Should_Parse_UnionTypeDefinition()
238+
{
239+
string text = "union U = A | B";
240+
var definition = text.Parse<GraphQLUnionTypeDefinition>().ShouldNotBeNull();
241+
definition.Name.Value.ShouldBe("U");
242+
}
243+
244+
[Fact]
245+
public void Should_Parse_VariableDefinition()
246+
{
247+
string text = "$id: Int";
248+
var definition = text.Parse<GraphQLVariableDefinition>().ShouldNotBeNull();
249+
definition.Variable.Name.Value.ShouldBe("id");
250+
}
251+
252+
[Fact]
253+
public void Should_Parse_VariablesDefinition()
254+
{
255+
string text = "($id: Int, $amount: Float)";
256+
var definition = text.Parse<GraphQLVariablesDefinition>().ShouldNotBeNull();
257+
definition.Items.Count.ShouldBe(2);
258+
}
259+
260+
[Fact]
261+
public void Should_Parse_EnumTypeExtension()
262+
{
263+
string text = "extend enum Color { YELLOW }";
264+
var definition = text.Parse<GraphQLEnumTypeExtension>().ShouldNotBeNull();
265+
definition.Name.Value.ShouldBe("Color");
266+
}
267+
268+
[Fact]
269+
public void Should_Parse_InputObjectTypeExtension()
270+
{
271+
string text = "extend input Person { address: String }";
272+
var definition = text.Parse<GraphQLInputObjectTypeExtension>().ShouldNotBeNull();
273+
definition.Name.Value.ShouldBe("Person");
274+
}
275+
276+
[Fact]
277+
public void Should_Parse_InterfaceTypeExtension()
278+
{
279+
string text = "extend interface Person { address: String }";
280+
var definition = text.Parse<GraphQLInterfaceTypeExtension>().ShouldNotBeNull();
281+
definition.Name.Value.ShouldBe("Person");
282+
}
283+
284+
[Fact]
285+
public void Should_Parse_ObjectTypeExtension()
286+
{
287+
string text = "extend type Person { address: String }";
288+
var definition = text.Parse<GraphQLObjectTypeExtension>().ShouldNotBeNull();
289+
definition.Name.Value.ShouldBe("Person");
290+
}
291+
292+
[Fact]
293+
public void Should_Parse_ScalarTypeExtension()
294+
{
295+
string text = "extend scalar JSON @my";
296+
var definition = text.Parse<GraphQLScalarTypeExtension>().ShouldNotBeNull();
297+
definition.Name.Value.ShouldBe("JSON");
298+
}
299+
300+
[Fact]
301+
public void Should_Parse_SchemaExtension()
302+
{
303+
string text = "extend schema { subscription : S }";
304+
var definition = text.Parse<GraphQLSchemaExtension>().ShouldNotBeNull();
305+
definition.OperationTypes.Count.ShouldBe(1);
306+
}
307+
308+
[Fact]
309+
public void Should_Parse_UnionTypeExtension()
310+
{
311+
string text = "extend union U @my @external";
312+
var definition = text.Parse<GraphQLUnionTypeExtension>().ShouldNotBeNull();
313+
definition.Name.Value.ShouldBe("U");
314+
definition.Directives.Items.Count.ShouldBe(2);
315+
}
316+
}

src/GraphQLParser.Tests/ParserTests.Throw.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,8 +323,8 @@ public void Should_Throw_On_Unknown_Cases_From_ExpectOneOf()
323323
() =>
324324
{
325325
var context = new ParserContext("extend abc", default);
326-
context.ParseTypeExtension(new[] { "abc" });
326+
context.ParseTypeSystemExtension(new[] { "abc" });
327327
})
328-
.Message.ShouldBe("Unexpected keyword 'abc' in ParseTypeExtension.");
328+
.Message.ShouldBe("Unexpected keyword 'abc' in ParseTypeSystemExtension.");
329329
}
330330
}

src/GraphQLParser.Tests/ParserTests.cs

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System.Collections;
22
using System.Runtime.InteropServices;
3-
using GraphQLParser.Exceptions;
43

54
namespace GraphQLParser.Tests;
65

@@ -980,27 +979,6 @@ public void Should_Parse_Empty_Types(string text, ASTNodeKind kind)
980979
document.Definitions[0].Kind.ShouldBe(kind);
981980
}
982981

983-
[Theory]
984-
[InlineData("null", ASTNodeKind.NullValue)]
985-
[InlineData("1", ASTNodeKind.IntValue)]
986-
[InlineData("1.1", ASTNodeKind.FloatValue)]
987-
[InlineData("\"abc\"", ASTNodeKind.StringValue, "abc")]
988-
[InlineData("\"escaped \\n\\r\\b\\t\\f\"", ASTNodeKind.StringValue, "escaped \n\r\b\t\f")]
989-
[InlineData("true", ASTNodeKind.BooleanValue)]
990-
[InlineData("RED", ASTNodeKind.EnumValue)]
991-
[InlineData("[ 1, 2, 3]", ASTNodeKind.ListValue)]
992-
[InlineData("{ a: 1, b: \"abc\", c: RED}", ASTNodeKind.ObjectValue)]
993-
public void Should_Parse_Value_Literal_But_Not_Entire_Document(string text, ASTNodeKind kind, string expected = null)
994-
{
995-
Should.Throw<GraphQLSyntaxErrorException>(() => Parser.Parse(text));
996-
997-
var value = Parser.Parse<GraphQLValue>(text);
998-
value.ShouldNotBeNull();
999-
value.Kind.ShouldBe(kind);
1000-
if (expected != null)
1001-
((GraphQLStringValue)value).Value.ShouldBe(expected);
1002-
}
1003-
1004982
[Theory]
1005983
[InlineData(IgnoreOptions.None)]
1006984
[InlineData(IgnoreOptions.Comments)]

0 commit comments

Comments
 (0)