...

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

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

     1  package parser
     2  
     3  import (
     4  	"github.com/vektah/gqlparser/v2/lexer"
     5  
     6  	//nolint:revive
     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() // "on"
   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