...

Source file src/github.com/vektah/gqlparser/v2/parser/schema.go

Documentation: github.com/vektah/gqlparser/v2/parser

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

View as plain text