1package parser
2
3import (
4 . "github.com/vektah/gqlparser/ast"
5 "github.com/vektah/gqlparser/gqlerror"
6 "github.com/vektah/gqlparser/lexer"
7)
8
9func ParseSchema(source *Source) (*SchemaDocument, *gqlerror.Error) {
10 p := parser{
11 lexer: lexer.New(source),
12 }
13 return p.parseSchemaDocument(), p.err
14}
15
16func (p *parser) parseSchemaDocument() *SchemaDocument {
17 var doc SchemaDocument
18 doc.Position = p.peekPos()
19 for p.peek().Kind != lexer.EOF {
20 if p.err != nil {
21 return nil
22 }
23
24 var description string
25 if p.peek().Kind == lexer.BlockString || p.peek().Kind == lexer.String {
26 description = p.parseDescription()
27 }
28
29 if p.peek().Kind != lexer.Name {
30 p.unexpectedError()
31 break
32 }
33
34 switch p.peek().Value {
35 case "scalar", "type", "interface", "union", "enum", "input":
36 doc.Definitions = append(doc.Definitions, p.parseTypeSystemDefinition(description))
37 case "schema":
38 doc.Schema = append(doc.Schema, p.parseSchemaDefinition(description))
39 case "directive":
40 doc.Directives = append(doc.Directives, p.parseDirectiveDefinition(description))
41 case "extend":
42 if description != "" {
43 p.unexpectedToken(p.prev)
44 }
45 p.parseTypeSystemExtension(&doc)
46 default:
47 p.unexpectedError()
48 return nil
49 }
50 }
51
52 return &doc
53}
54
55func (p *parser) parseDescription() string {
56 token := p.peek()
57
58 if token.Kind != lexer.BlockString && token.Kind != lexer.String {
59 return ""
60 }
61
62 return p.next().Value
63}
64
65func (p *parser) parseTypeSystemDefinition(description string) *Definition {
66 tok := p.peek()
67 if tok.Kind != lexer.Name {
68 p.unexpectedError()
69 return nil
70 }
71
72 switch tok.Value {
73 case "scalar":
74 return p.parseScalarTypeDefinition(description)
75 case "type":
76 return p.parseObjectTypeDefinition(description)
77 case "interface":
78 return p.parseInterfaceTypeDefinition(description)
79 case "union":
80 return p.parseUnionTypeDefinition(description)
81 case "enum":
82 return p.parseEnumTypeDefinition(description)
83 case "input":
84 return p.parseInputObjectTypeDefinition(description)
85 default:
86 p.unexpectedError()
87 return nil
88 }
89}
90
91func (p *parser) parseSchemaDefinition(description string) *SchemaDefinition {
92 p.expectKeyword("schema")
93
94 def := SchemaDefinition{Description: description}
95 def.Position = p.peekPos()
96 def.Description = description
97 def.Directives = p.parseDirectives(true)
98
99 p.many(lexer.BraceL, lexer.BraceR, func() {
100 def.OperationTypes = append(def.OperationTypes, p.parseOperationTypeDefinition())
101 })
102 return &def
103}
104
105func (p *parser) parseOperationTypeDefinition() *OperationTypeDefinition {
106 var op OperationTypeDefinition
107 op.Position = p.peekPos()
108 op.Operation = p.parseOperationType()
109 p.expect(lexer.Colon)
110 op.Type = p.parseName()
111 return &op
112}
113
114func (p *parser) parseScalarTypeDefinition(description string) *Definition {
115 p.expectKeyword("scalar")
116
117 var def Definition
118 def.Position = p.peekPos()
119 def.Kind = Scalar
120 def.Description = description
121 def.Name = p.parseName()
122 def.Directives = p.parseDirectives(true)
123 return &def
124}
125
126func (p *parser) parseObjectTypeDefinition(description string) *Definition {
127 p.expectKeyword("type")
128
129 var def Definition
130 def.Position = p.peekPos()
131 def.Kind = Object
132 def.Description = description
133 def.Name = p.parseName()
134 def.Interfaces = p.parseImplementsInterfaces()
135 def.Directives = p.parseDirectives(true)
136 def.Fields = p.parseFieldsDefinition()
137 return &def
138}
139
140func (p *parser) parseImplementsInterfaces() []string {
141 var types []string
142 if p.peek().Value == "implements" {
143 p.next()
144 // optional leading ampersand
145 p.skip(lexer.Amp)
146
147 types = append(types, p.parseName())
148 for p.skip(lexer.Amp) && p.err == nil {
149 types = append(types, p.parseName())
150 }
151 }
152 return types
153}
154
155func (p *parser) parseFieldsDefinition() FieldList {
156 var defs FieldList
157 p.many(lexer.BraceL, lexer.BraceR, func() {
158 defs = append(defs, p.parseFieldDefinition())
159 })
160 return defs
161}
162
163func (p *parser) parseFieldDefinition() *FieldDefinition {
164 var def FieldDefinition
165 def.Position = p.peekPos()
166 def.Description = p.parseDescription()
167 def.Name = p.parseName()
168 def.Arguments = p.parseArgumentDefs()
169 p.expect(lexer.Colon)
170 def.Type = p.parseTypeReference()
171 def.Directives = p.parseDirectives(true)
172
173 return &def
174}
175
176func (p *parser) parseArgumentDefs() ArgumentDefinitionList {
177 var args ArgumentDefinitionList
178 p.many(lexer.ParenL, lexer.ParenR, func() {
179 args = append(args, p.parseArgumentDef())
180 })
181 return args
182}
183
184func (p *parser) parseArgumentDef() *ArgumentDefinition {
185 var def ArgumentDefinition
186 def.Position = p.peekPos()
187 def.Description = p.parseDescription()
188 def.Name = p.parseName()
189 p.expect(lexer.Colon)
190 def.Type = p.parseTypeReference()
191 if p.skip(lexer.Equals) {
192 def.DefaultValue = p.parseValueLiteral(true)
193 }
194 def.Directives = p.parseDirectives(true)
195 return &def
196}
197
198func (p *parser) parseInputValueDef() *FieldDefinition {
199 var def FieldDefinition
200 def.Position = p.peekPos()
201 def.Description = p.parseDescription()
202 def.Name = p.parseName()
203 p.expect(lexer.Colon)
204 def.Type = p.parseTypeReference()
205 if p.skip(lexer.Equals) {
206 def.DefaultValue = p.parseValueLiteral(true)
207 }
208 def.Directives = p.parseDirectives(true)
209 return &def
210}
211
212func (p *parser) parseInterfaceTypeDefinition(description string) *Definition {
213 p.expectKeyword("interface")
214
215 var def Definition
216 def.Position = p.peekPos()
217 def.Kind = Interface
218 def.Description = description
219 def.Name = p.parseName()
220 def.Directives = p.parseDirectives(true)
221 def.Fields = p.parseFieldsDefinition()
222 return &def
223}
224
225func (p *parser) parseUnionTypeDefinition(description string) *Definition {
226 p.expectKeyword("union")
227
228 var def Definition
229 def.Position = p.peekPos()
230 def.Kind = Union
231 def.Description = description
232 def.Name = p.parseName()
233 def.Directives = p.parseDirectives(true)
234 def.Types = p.parseUnionMemberTypes()
235 return &def
236}
237
238func (p *parser) parseUnionMemberTypes() []string {
239 var types []string
240 if p.skip(lexer.Equals) {
241 // optional leading pipe
242 p.skip(lexer.Pipe)
243
244 types = append(types, p.parseName())
245 for p.skip(lexer.Pipe) && p.err == nil {
246 types = append(types, p.parseName())
247 }
248 }
249 return types
250}
251
252func (p *parser) parseEnumTypeDefinition(description string) *Definition {
253 p.expectKeyword("enum")
254
255 var def Definition
256 def.Position = p.peekPos()
257 def.Kind = Enum
258 def.Description = description
259 def.Name = p.parseName()
260 def.Directives = p.parseDirectives(true)
261 def.EnumValues = p.parseEnumValuesDefinition()
262 return &def
263}
264
265func (p *parser) parseEnumValuesDefinition() EnumValueList {
266 var values EnumValueList
267 p.many(lexer.BraceL, lexer.BraceR, func() {
268 values = append(values, p.parseEnumValueDefinition())
269 })
270 return values
271}
272
273func (p *parser) parseEnumValueDefinition() *EnumValueDefinition {
274 return &EnumValueDefinition{
275 Position: p.peekPos(),
276 Description: p.parseDescription(),
277 Name: p.parseName(),
278 Directives: p.parseDirectives(true),
279 }
280}
281
282func (p *parser) parseInputObjectTypeDefinition(description string) *Definition {
283 p.expectKeyword("input")
284
285 var def Definition
286 def.Position = p.peekPos()
287 def.Kind = InputObject
288 def.Description = description
289 def.Name = p.parseName()
290 def.Directives = p.parseDirectives(true)
291 def.Fields = p.parseInputFieldsDefinition()
292 return &def
293}
294
295func (p *parser) parseInputFieldsDefinition() FieldList {
296 var values FieldList
297 p.many(lexer.BraceL, lexer.BraceR, func() {
298 values = append(values, p.parseInputValueDef())
299 })
300 return values
301}
302
303func (p *parser) parseTypeSystemExtension(doc *SchemaDocument) {
304 p.expectKeyword("extend")
305
306 switch p.peek().Value {
307 case "schema":
308 doc.SchemaExtension = append(doc.SchemaExtension, p.parseSchemaExtension())
309 case "scalar":
310 doc.Extensions = append(doc.Extensions, p.parseScalarTypeExtension())
311 case "type":
312 doc.Extensions = append(doc.Extensions, p.parseObjectTypeExtension())
313 case "interface":
314 doc.Extensions = append(doc.Extensions, p.parseInterfaceTypeExtension())
315 case "union":
316 doc.Extensions = append(doc.Extensions, p.parseUnionTypeExtension())
317 case "enum":
318 doc.Extensions = append(doc.Extensions, p.parseEnumTypeExtension())
319 case "input":
320 doc.Extensions = append(doc.Extensions, p.parseInputObjectTypeExtension())
321 default:
322 p.unexpectedError()
323 }
324}
325
326func (p *parser) parseSchemaExtension() *SchemaDefinition {
327 p.expectKeyword("schema")
328
329 var def SchemaDefinition
330 def.Position = p.peekPos()
331 def.Directives = p.parseDirectives(true)
332 p.many(lexer.BraceL, lexer.BraceR, func() {
333 def.OperationTypes = append(def.OperationTypes, p.parseOperationTypeDefinition())
334 })
335 if len(def.Directives) == 0 && len(def.OperationTypes) == 0 {
336 p.unexpectedError()
337 }
338 return &def
339}
340
341func (p *parser) parseScalarTypeExtension() *Definition {
342 p.expectKeyword("scalar")
343
344 var def Definition
345 def.Position = p.peekPos()
346 def.Kind = Scalar
347 def.Name = p.parseName()
348 def.Directives = p.parseDirectives(true)
349 if len(def.Directives) == 0 {
350 p.unexpectedError()
351 }
352 return &def
353}
354
355func (p *parser) parseObjectTypeExtension() *Definition {
356 p.expectKeyword("type")
357
358 var def Definition
359 def.Position = p.peekPos()
360 def.Kind = Object
361 def.Name = p.parseName()
362 def.Interfaces = p.parseImplementsInterfaces()
363 def.Directives = p.parseDirectives(true)
364 def.Fields = p.parseFieldsDefinition()
365 if len(def.Interfaces) == 0 && len(def.Directives) == 0 && len(def.Fields) == 0 {
366 p.unexpectedError()
367 }
368 return &def
369}
370
371func (p *parser) parseInterfaceTypeExtension() *Definition {
372 p.expectKeyword("interface")
373
374 var def Definition
375 def.Position = p.peekPos()
376 def.Kind = Interface
377 def.Name = p.parseName()
378 def.Directives = p.parseDirectives(true)
379 def.Fields = p.parseFieldsDefinition()
380 if len(def.Directives) == 0 && len(def.Fields) == 0 {
381 p.unexpectedError()
382 }
383 return &def
384}
385
386func (p *parser) parseUnionTypeExtension() *Definition {
387 p.expectKeyword("union")
388
389 var def Definition
390 def.Position = p.peekPos()
391 def.Kind = Union
392 def.Name = p.parseName()
393 def.Directives = p.parseDirectives(true)
394 def.Types = p.parseUnionMemberTypes()
395
396 if len(def.Directives) == 0 && len(def.Types) == 0 {
397 p.unexpectedError()
398 }
399 return &def
400}
401
402func (p *parser) parseEnumTypeExtension() *Definition {
403 p.expectKeyword("enum")
404
405 var def Definition
406 def.Position = p.peekPos()
407 def.Kind = Enum
408 def.Name = p.parseName()
409 def.Directives = p.parseDirectives(true)
410 def.EnumValues = p.parseEnumValuesDefinition()
411 if len(def.Directives) == 0 && len(def.EnumValues) == 0 {
412 p.unexpectedError()
413 }
414 return &def
415}
416
417func (p *parser) parseInputObjectTypeExtension() *Definition {
418 p.expectKeyword("input")
419
420 var def Definition
421 def.Position = p.peekPos()
422 def.Kind = InputObject
423 def.Name = p.parseName()
424 def.Directives = p.parseDirectives(false)
425 def.Fields = p.parseInputFieldsDefinition()
426 if len(def.Directives) == 0 && len(def.Fields) == 0 {
427 p.unexpectedError()
428 }
429 return &def
430}
431
432func (p *parser) parseDirectiveDefinition(description string) *DirectiveDefinition {
433 p.expectKeyword("directive")
434 p.expect(lexer.At)
435
436 var def DirectiveDefinition
437 def.Position = p.peekPos()
438 def.Description = description
439 def.Name = p.parseName()
440 def.Arguments = p.parseArgumentDefs()
441
442 p.expectKeyword("on")
443 def.Locations = p.parseDirectiveLocations()
444 return &def
445}
446
447func (p *parser) parseDirectiveLocations() []DirectiveLocation {
448 p.skip(lexer.Pipe)
449
450 locations := []DirectiveLocation{p.parseDirectiveLocation()}
451
452 for p.skip(lexer.Pipe) && p.err == nil {
453 locations = append(locations, p.parseDirectiveLocation())
454 }
455
456 return locations
457}
458
459func (p *parser) parseDirectiveLocation() DirectiveLocation {
460 name := p.expect(lexer.Name)
461
462 switch name.Value {
463 case `QUERY`:
464 return LocationQuery
465 case `MUTATION`:
466 return LocationMutation
467 case `SUBSCRIPTION`:
468 return LocationSubscription
469 case `FIELD`:
470 return LocationField
471 case `FRAGMENT_DEFINITION`:
472 return LocationFragmentDefinition
473 case `FRAGMENT_SPREAD`:
474 return LocationFragmentSpread
475 case `INLINE_FRAGMENT`:
476 return LocationInlineFragment
477 case `SCHEMA`:
478 return LocationSchema
479 case `SCALAR`:
480 return LocationScalar
481 case `OBJECT`:
482 return LocationObject
483 case `FIELD_DEFINITION`:
484 return LocationFieldDefinition
485 case `ARGUMENT_DEFINITION`:
486 return LocationArgumentDefinition
487 case `INTERFACE`:
488 return LocationInterface
489 case `UNION`:
490 return LocationUnion
491 case `ENUM`:
492 return LocationEnum
493 case `ENUM_VALUE`:
494 return LocationEnumValue
495 case `INPUT_OBJECT`:
496 return LocationInputObject
497 case `INPUT_FIELD_DEFINITION`:
498 return LocationInputFieldDefinition
499 }
500
501 p.unexpectedToken(name)
502 return ""
503}