1 package parser
2
3 import (
4 "github.com/vektah/gqlparser/v2/lexer"
5
6
7 . "github.com/vektah/gqlparser/v2/ast"
8 )
9
10 func ParseQuery(source *Source) (*QueryDocument, error) {
11 p := parser{
12 lexer: lexer.New(source),
13 }
14 return p.parseQueryDocument(), p.err
15 }
16
17 func (p *parser) parseQueryDocument() *QueryDocument {
18 var doc QueryDocument
19 for p.peek().Kind != lexer.EOF {
20 if p.err != nil {
21 return &doc
22 }
23 doc.Position = p.peekPos()
24 switch p.peek().Kind {
25 case lexer.Name:
26 switch p.peek().Value {
27 case "query", "mutation", "subscription":
28 doc.Operations = append(doc.Operations, p.parseOperationDefinition())
29 case "fragment":
30 doc.Fragments = append(doc.Fragments, p.parseFragmentDefinition())
31 default:
32 p.unexpectedError()
33 }
34 case lexer.BraceL:
35 doc.Operations = append(doc.Operations, p.parseOperationDefinition())
36 default:
37 p.unexpectedError()
38 }
39 }
40
41 return &doc
42 }
43
44 func (p *parser) parseOperationDefinition() *OperationDefinition {
45 if p.peek().Kind == lexer.BraceL {
46 return &OperationDefinition{
47 Position: p.peekPos(),
48 Comment: p.comment,
49 Operation: Query,
50 SelectionSet: p.parseRequiredSelectionSet(),
51 }
52 }
53
54 var od OperationDefinition
55 od.Position = p.peekPos()
56 od.Comment = p.comment
57 od.Operation = p.parseOperationType()
58
59 if p.peek().Kind == lexer.Name {
60 od.Name = p.next().Value
61 }
62
63 od.VariableDefinitions = p.parseVariableDefinitions()
64 od.Directives = p.parseDirectives(false)
65 od.SelectionSet = p.parseRequiredSelectionSet()
66
67 return &od
68 }
69
70 func (p *parser) parseOperationType() Operation {
71 tok := p.next()
72 switch tok.Value {
73 case "query":
74 return Query
75 case "mutation":
76 return Mutation
77 case "subscription":
78 return Subscription
79 }
80 p.unexpectedToken(tok)
81 return ""
82 }
83
84 func (p *parser) parseVariableDefinitions() VariableDefinitionList {
85 var defs []*VariableDefinition
86 p.many(lexer.ParenL, lexer.ParenR, func() {
87 defs = append(defs, p.parseVariableDefinition())
88 })
89
90 return defs
91 }
92
93 func (p *parser) parseVariableDefinition() *VariableDefinition {
94 var def VariableDefinition
95 def.Position = p.peekPos()
96 def.Comment = p.comment
97 def.Variable = p.parseVariable()
98
99 p.expect(lexer.Colon)
100
101 def.Type = p.parseTypeReference()
102
103 if p.skip(lexer.Equals) {
104 def.DefaultValue = p.parseValueLiteral(true)
105 }
106
107 def.Directives = p.parseDirectives(false)
108
109 return &def
110 }
111
112 func (p *parser) parseVariable() string {
113 p.expect(lexer.Dollar)
114 return p.parseName()
115 }
116
117 func (p *parser) parseOptionalSelectionSet() SelectionSet {
118 var selections []Selection
119 p.some(lexer.BraceL, lexer.BraceR, func() {
120 selections = append(selections, p.parseSelection())
121 })
122
123 return selections
124 }
125
126 func (p *parser) parseRequiredSelectionSet() SelectionSet {
127 if p.peek().Kind != lexer.BraceL {
128 p.error(p.peek(), "Expected %s, found %s", lexer.BraceL, p.peek().Kind.String())
129 return nil
130 }
131
132 var selections []Selection
133 p.some(lexer.BraceL, lexer.BraceR, func() {
134 selections = append(selections, p.parseSelection())
135 })
136
137 return selections
138 }
139
140 func (p *parser) parseSelection() Selection {
141 if p.peek().Kind == lexer.Spread {
142 return p.parseFragment()
143 }
144 return p.parseField()
145 }
146
147 func (p *parser) parseField() *Field {
148 var field Field
149 field.Position = p.peekPos()
150 field.Comment = p.comment
151 field.Alias = p.parseName()
152
153 if p.skip(lexer.Colon) {
154 field.Name = p.parseName()
155 } else {
156 field.Name = field.Alias
157 }
158
159 field.Arguments = p.parseArguments(false)
160 field.Directives = p.parseDirectives(false)
161 if p.peek().Kind == lexer.BraceL {
162 field.SelectionSet = p.parseOptionalSelectionSet()
163 }
164
165 return &field
166 }
167
168 func (p *parser) parseArguments(isConst bool) ArgumentList {
169 var arguments ArgumentList
170 p.many(lexer.ParenL, lexer.ParenR, func() {
171 arguments = append(arguments, p.parseArgument(isConst))
172 })
173
174 return arguments
175 }
176
177 func (p *parser) parseArgument(isConst bool) *Argument {
178 arg := Argument{}
179 arg.Position = p.peekPos()
180 arg.Comment = p.comment
181 arg.Name = p.parseName()
182 p.expect(lexer.Colon)
183
184 arg.Value = p.parseValueLiteral(isConst)
185 return &arg
186 }
187
188 func (p *parser) parseFragment() Selection {
189 _, comment := p.expect(lexer.Spread)
190
191 if peek := p.peek(); peek.Kind == lexer.Name && peek.Value != "on" {
192 return &FragmentSpread{
193 Position: p.peekPos(),
194 Comment: comment,
195 Name: p.parseFragmentName(),
196 Directives: p.parseDirectives(false),
197 }
198 }
199
200 var def InlineFragment
201 def.Position = p.peekPos()
202 def.Comment = comment
203 if p.peek().Value == "on" {
204 p.next()
205
206 def.TypeCondition = p.parseName()
207 }
208
209 def.Directives = p.parseDirectives(false)
210 def.SelectionSet = p.parseRequiredSelectionSet()
211 return &def
212 }
213
214 func (p *parser) parseFragmentDefinition() *FragmentDefinition {
215 var def FragmentDefinition
216 def.Position = p.peekPos()
217 def.Comment = p.comment
218 p.expectKeyword("fragment")
219
220 def.Name = p.parseFragmentName()
221 def.VariableDefinition = p.parseVariableDefinitions()
222
223 p.expectKeyword("on")
224
225 def.TypeCondition = p.parseName()
226 def.Directives = p.parseDirectives(false)
227 def.SelectionSet = p.parseRequiredSelectionSet()
228 return &def
229 }
230
231 func (p *parser) parseFragmentName() string {
232 if p.peek().Value == "on" {
233 p.unexpectedError()
234 return ""
235 }
236
237 return p.parseName()
238 }
239
240 func (p *parser) parseValueLiteral(isConst bool) *Value {
241 token := p.peek()
242
243 var kind ValueKind
244 switch token.Kind {
245 case lexer.BracketL:
246 return p.parseList(isConst)
247 case lexer.BraceL:
248 return p.parseObject(isConst)
249 case lexer.Dollar:
250 if isConst {
251 p.unexpectedError()
252 return nil
253 }
254 return &Value{Position: &token.Pos, Comment: p.comment, Raw: p.parseVariable(), Kind: Variable}
255 case lexer.Int:
256 kind = IntValue
257 case lexer.Float:
258 kind = FloatValue
259 case lexer.String:
260 kind = StringValue
261 case lexer.BlockString:
262 kind = BlockValue
263 case lexer.Name:
264 switch token.Value {
265 case "true", "false":
266 kind = BooleanValue
267 case "null":
268 kind = NullValue
269 default:
270 kind = EnumValue
271 }
272 default:
273 p.unexpectedError()
274 return nil
275 }
276
277 p.next()
278
279 return &Value{Position: &token.Pos, Comment: p.comment, Raw: token.Value, Kind: kind}
280 }
281
282 func (p *parser) parseList(isConst bool) *Value {
283 var values ChildValueList
284 pos := p.peekPos()
285 comment := p.comment
286 p.many(lexer.BracketL, lexer.BracketR, func() {
287 values = append(values, &ChildValue{Value: p.parseValueLiteral(isConst)})
288 })
289
290 return &Value{Children: values, Kind: ListValue, Position: pos, Comment: comment}
291 }
292
293 func (p *parser) parseObject(isConst bool) *Value {
294 var fields ChildValueList
295 pos := p.peekPos()
296 comment := p.comment
297 p.many(lexer.BraceL, lexer.BraceR, func() {
298 fields = append(fields, p.parseObjectField(isConst))
299 })
300
301 return &Value{Children: fields, Kind: ObjectValue, Position: pos, Comment: comment}
302 }
303
304 func (p *parser) parseObjectField(isConst bool) *ChildValue {
305 field := ChildValue{}
306 field.Position = p.peekPos()
307 field.Comment = p.comment
308 field.Name = p.parseName()
309
310 p.expect(lexer.Colon)
311
312 field.Value = p.parseValueLiteral(isConst)
313 return &field
314 }
315
316 func (p *parser) parseDirectives(isConst bool) []*Directive {
317 var directives []*Directive
318
319 for p.peek().Kind == lexer.At {
320 if p.err != nil {
321 break
322 }
323 directives = append(directives, p.parseDirective(isConst))
324 }
325 return directives
326 }
327
328 func (p *parser) parseDirective(isConst bool) *Directive {
329 p.expect(lexer.At)
330
331 return &Directive{
332 Position: p.peekPos(),
333 Name: p.parseName(),
334 Arguments: p.parseArguments(isConst),
335 }
336 }
337
338 func (p *parser) parseTypeReference() *Type {
339 var typ Type
340
341 if p.skip(lexer.BracketL) {
342 typ.Position = p.peekPos()
343 typ.Elem = p.parseTypeReference()
344 p.expect(lexer.BracketR)
345 } else {
346 typ.Position = p.peekPos()
347 typ.NamedType = p.parseName()
348 }
349
350 if p.skip(lexer.Bang) {
351 typ.NonNull = true
352 }
353 return &typ
354 }
355
356 func (p *parser) parseName() string {
357 token, _ := p.expect(lexer.Name)
358
359 return token.Value
360 }
361
View as plain text