schema.go

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