mirror of
https://github.com/stashapp/stash.git
synced 2025-12-19 05:14:38 +03:00
Stash box client interface (#751)
* Add gql client generation files * Update dependencies * Add stash-box client generation to the makefile * Move scraped scene object matchers to models * Add stash-box to scrape with dropdown * Add scrape scene from fingerprint in UI
This commit is contained in:
136
vendor/github.com/vektah/gqlparser/v2/parser/parser.go
generated
vendored
Normal file
136
vendor/github.com/vektah/gqlparser/v2/parser/parser.go
generated
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
"github.com/vektah/gqlparser/v2/lexer"
|
||||
)
|
||||
|
||||
type parser struct {
|
||||
lexer lexer.Lexer
|
||||
err *gqlerror.Error
|
||||
|
||||
peeked bool
|
||||
peekToken lexer.Token
|
||||
peekError *gqlerror.Error
|
||||
|
||||
prev lexer.Token
|
||||
}
|
||||
|
||||
func (p *parser) peekPos() *ast.Position {
|
||||
if p.err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
peek := p.peek()
|
||||
return &peek.Pos
|
||||
}
|
||||
|
||||
func (p *parser) peek() lexer.Token {
|
||||
if p.err != nil {
|
||||
return p.prev
|
||||
}
|
||||
|
||||
if !p.peeked {
|
||||
p.peekToken, p.peekError = p.lexer.ReadToken()
|
||||
p.peeked = true
|
||||
}
|
||||
|
||||
return p.peekToken
|
||||
}
|
||||
|
||||
func (p *parser) error(tok lexer.Token, format string, args ...interface{}) {
|
||||
if p.err != nil {
|
||||
return
|
||||
}
|
||||
p.err = gqlerror.ErrorLocf(tok.Pos.Src.Name, tok.Pos.Line, tok.Pos.Column, format, args...)
|
||||
}
|
||||
|
||||
func (p *parser) next() lexer.Token {
|
||||
if p.err != nil {
|
||||
return p.prev
|
||||
}
|
||||
if p.peeked {
|
||||
p.peeked = false
|
||||
p.prev, p.err = p.peekToken, p.peekError
|
||||
} else {
|
||||
p.prev, p.err = p.lexer.ReadToken()
|
||||
}
|
||||
return p.prev
|
||||
}
|
||||
|
||||
func (p *parser) expectKeyword(value string) lexer.Token {
|
||||
tok := p.peek()
|
||||
if tok.Kind == lexer.Name && tok.Value == value {
|
||||
return p.next()
|
||||
}
|
||||
|
||||
p.error(tok, "Expected %s, found %s", strconv.Quote(value), tok.String())
|
||||
return tok
|
||||
}
|
||||
|
||||
func (p *parser) expect(kind lexer.Type) lexer.Token {
|
||||
tok := p.peek()
|
||||
if tok.Kind == kind {
|
||||
return p.next()
|
||||
}
|
||||
|
||||
p.error(tok, "Expected %s, found %s", kind, tok.Kind.String())
|
||||
return tok
|
||||
}
|
||||
|
||||
func (p *parser) skip(kind lexer.Type) bool {
|
||||
if p.err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
tok := p.peek()
|
||||
|
||||
if tok.Kind != kind {
|
||||
return false
|
||||
}
|
||||
p.next()
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *parser) unexpectedError() {
|
||||
p.unexpectedToken(p.peek())
|
||||
}
|
||||
|
||||
func (p *parser) unexpectedToken(tok lexer.Token) {
|
||||
p.error(tok, "Unexpected %s", tok.String())
|
||||
}
|
||||
|
||||
func (p *parser) many(start lexer.Type, end lexer.Type, cb func()) {
|
||||
hasDef := p.skip(start)
|
||||
if !hasDef {
|
||||
return
|
||||
}
|
||||
|
||||
for p.peek().Kind != end && p.err == nil {
|
||||
cb()
|
||||
}
|
||||
p.next()
|
||||
}
|
||||
|
||||
func (p *parser) some(start lexer.Type, end lexer.Type, cb func()) {
|
||||
hasDef := p.skip(start)
|
||||
if !hasDef {
|
||||
return
|
||||
}
|
||||
|
||||
called := false
|
||||
for p.peek().Kind != end && p.err == nil {
|
||||
called = true
|
||||
cb()
|
||||
}
|
||||
|
||||
if !called {
|
||||
p.error(p.peek(), "expected at least one definition, found %s", p.peek().Kind.String())
|
||||
return
|
||||
}
|
||||
|
||||
p.next()
|
||||
}
|
||||
348
vendor/github.com/vektah/gqlparser/v2/parser/query.go
generated
vendored
Normal file
348
vendor/github.com/vektah/gqlparser/v2/parser/query.go
generated
vendored
Normal file
@@ -0,0 +1,348 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
"github.com/vektah/gqlparser/v2/lexer"
|
||||
|
||||
. "github.com/vektah/gqlparser/v2/ast"
|
||||
)
|
||||
|
||||
func ParseQuery(source *Source) (*QueryDocument, *gqlerror.Error) {
|
||||
p := parser{
|
||||
lexer: lexer.New(source),
|
||||
}
|
||||
return p.parseQueryDocument(), p.err
|
||||
}
|
||||
|
||||
func (p *parser) parseQueryDocument() *QueryDocument {
|
||||
var doc QueryDocument
|
||||
for p.peek().Kind != lexer.EOF {
|
||||
if p.err != nil {
|
||||
return &doc
|
||||
}
|
||||
doc.Position = p.peekPos()
|
||||
switch p.peek().Kind {
|
||||
case lexer.Name:
|
||||
switch p.peek().Value {
|
||||
case "query", "mutation", "subscription":
|
||||
doc.Operations = append(doc.Operations, p.parseOperationDefinition())
|
||||
case "fragment":
|
||||
doc.Fragments = append(doc.Fragments, p.parseFragmentDefinition())
|
||||
default:
|
||||
p.unexpectedError()
|
||||
}
|
||||
case lexer.BraceL:
|
||||
doc.Operations = append(doc.Operations, p.parseOperationDefinition())
|
||||
default:
|
||||
p.unexpectedError()
|
||||
}
|
||||
}
|
||||
|
||||
return &doc
|
||||
}
|
||||
|
||||
func (p *parser) parseOperationDefinition() *OperationDefinition {
|
||||
if p.peek().Kind == lexer.BraceL {
|
||||
return &OperationDefinition{
|
||||
Position: p.peekPos(),
|
||||
Operation: Query,
|
||||
SelectionSet: p.parseRequiredSelectionSet(),
|
||||
}
|
||||
}
|
||||
|
||||
var od OperationDefinition
|
||||
od.Position = p.peekPos()
|
||||
od.Operation = p.parseOperationType()
|
||||
|
||||
if p.peek().Kind == lexer.Name {
|
||||
od.Name = p.next().Value
|
||||
}
|
||||
|
||||
od.VariableDefinitions = p.parseVariableDefinitions()
|
||||
od.Directives = p.parseDirectives(false)
|
||||
od.SelectionSet = p.parseRequiredSelectionSet()
|
||||
|
||||
return &od
|
||||
}
|
||||
|
||||
func (p *parser) parseOperationType() Operation {
|
||||
tok := p.next()
|
||||
switch tok.Value {
|
||||
case "query":
|
||||
return Query
|
||||
case "mutation":
|
||||
return Mutation
|
||||
case "subscription":
|
||||
return Subscription
|
||||
}
|
||||
p.unexpectedToken(tok)
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *parser) parseVariableDefinitions() VariableDefinitionList {
|
||||
var defs []*VariableDefinition
|
||||
p.many(lexer.ParenL, lexer.ParenR, func() {
|
||||
defs = append(defs, p.parseVariableDefinition())
|
||||
})
|
||||
|
||||
return defs
|
||||
}
|
||||
|
||||
func (p *parser) parseVariableDefinition() *VariableDefinition {
|
||||
var def VariableDefinition
|
||||
def.Position = p.peekPos()
|
||||
def.Variable = p.parseVariable()
|
||||
|
||||
p.expect(lexer.Colon)
|
||||
|
||||
def.Type = p.parseTypeReference()
|
||||
|
||||
if p.skip(lexer.Equals) {
|
||||
def.DefaultValue = p.parseValueLiteral(true)
|
||||
}
|
||||
|
||||
return &def
|
||||
}
|
||||
|
||||
func (p *parser) parseVariable() string {
|
||||
p.expect(lexer.Dollar)
|
||||
return p.parseName()
|
||||
}
|
||||
|
||||
func (p *parser) parseOptionalSelectionSet() SelectionSet {
|
||||
var selections []Selection
|
||||
p.some(lexer.BraceL, lexer.BraceR, func() {
|
||||
selections = append(selections, p.parseSelection())
|
||||
})
|
||||
|
||||
return SelectionSet(selections)
|
||||
}
|
||||
|
||||
func (p *parser) parseRequiredSelectionSet() SelectionSet {
|
||||
if p.peek().Kind != lexer.BraceL {
|
||||
p.error(p.peek(), "Expected %s, found %s", lexer.BraceL, p.peek().Kind.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
var selections []Selection
|
||||
p.some(lexer.BraceL, lexer.BraceR, func() {
|
||||
selections = append(selections, p.parseSelection())
|
||||
})
|
||||
|
||||
return SelectionSet(selections)
|
||||
}
|
||||
|
||||
func (p *parser) parseSelection() Selection {
|
||||
if p.peek().Kind == lexer.Spread {
|
||||
return p.parseFragment()
|
||||
}
|
||||
return p.parseField()
|
||||
}
|
||||
|
||||
func (p *parser) parseField() *Field {
|
||||
var field Field
|
||||
field.Position = p.peekPos()
|
||||
field.Alias = p.parseName()
|
||||
|
||||
if p.skip(lexer.Colon) {
|
||||
field.Name = p.parseName()
|
||||
} else {
|
||||
field.Name = field.Alias
|
||||
}
|
||||
|
||||
field.Arguments = p.parseArguments(false)
|
||||
field.Directives = p.parseDirectives(false)
|
||||
if p.peek().Kind == lexer.BraceL {
|
||||
field.SelectionSet = p.parseOptionalSelectionSet()
|
||||
}
|
||||
|
||||
return &field
|
||||
}
|
||||
|
||||
func (p *parser) parseArguments(isConst bool) ArgumentList {
|
||||
var arguments ArgumentList
|
||||
p.many(lexer.ParenL, lexer.ParenR, func() {
|
||||
arguments = append(arguments, p.parseArgument(isConst))
|
||||
})
|
||||
|
||||
return arguments
|
||||
}
|
||||
|
||||
func (p *parser) parseArgument(isConst bool) *Argument {
|
||||
arg := Argument{}
|
||||
arg.Position = p.peekPos()
|
||||
arg.Name = p.parseName()
|
||||
p.expect(lexer.Colon)
|
||||
|
||||
arg.Value = p.parseValueLiteral(isConst)
|
||||
return &arg
|
||||
}
|
||||
|
||||
func (p *parser) parseFragment() Selection {
|
||||
p.expect(lexer.Spread)
|
||||
|
||||
if peek := p.peek(); peek.Kind == lexer.Name && peek.Value != "on" {
|
||||
return &FragmentSpread{
|
||||
Position: p.peekPos(),
|
||||
Name: p.parseFragmentName(),
|
||||
Directives: p.parseDirectives(false),
|
||||
}
|
||||
}
|
||||
|
||||
var def InlineFragment
|
||||
def.Position = p.peekPos()
|
||||
if p.peek().Value == "on" {
|
||||
p.next() // "on"
|
||||
|
||||
def.TypeCondition = p.parseName()
|
||||
}
|
||||
|
||||
def.Directives = p.parseDirectives(false)
|
||||
def.SelectionSet = p.parseRequiredSelectionSet()
|
||||
return &def
|
||||
}
|
||||
|
||||
func (p *parser) parseFragmentDefinition() *FragmentDefinition {
|
||||
var def FragmentDefinition
|
||||
def.Position = p.peekPos()
|
||||
p.expectKeyword("fragment")
|
||||
|
||||
def.Name = p.parseFragmentName()
|
||||
def.VariableDefinition = p.parseVariableDefinitions()
|
||||
|
||||
p.expectKeyword("on")
|
||||
|
||||
def.TypeCondition = p.parseName()
|
||||
def.Directives = p.parseDirectives(false)
|
||||
def.SelectionSet = p.parseRequiredSelectionSet()
|
||||
return &def
|
||||
}
|
||||
|
||||
func (p *parser) parseFragmentName() string {
|
||||
if p.peek().Value == "on" {
|
||||
p.unexpectedError()
|
||||
return ""
|
||||
}
|
||||
|
||||
return p.parseName()
|
||||
}
|
||||
|
||||
func (p *parser) parseValueLiteral(isConst bool) *Value {
|
||||
token := p.peek()
|
||||
|
||||
var kind ValueKind
|
||||
switch token.Kind {
|
||||
case lexer.BracketL:
|
||||
return p.parseList(isConst)
|
||||
case lexer.BraceL:
|
||||
return p.parseObject(isConst)
|
||||
case lexer.Dollar:
|
||||
if isConst {
|
||||
p.unexpectedError()
|
||||
return nil
|
||||
}
|
||||
return &Value{Position: &token.Pos, Raw: p.parseVariable(), Kind: Variable}
|
||||
case lexer.Int:
|
||||
kind = IntValue
|
||||
case lexer.Float:
|
||||
kind = FloatValue
|
||||
case lexer.String:
|
||||
kind = StringValue
|
||||
case lexer.BlockString:
|
||||
kind = BlockValue
|
||||
case lexer.Name:
|
||||
switch token.Value {
|
||||
case "true", "false":
|
||||
kind = BooleanValue
|
||||
case "null":
|
||||
kind = NullValue
|
||||
default:
|
||||
kind = EnumValue
|
||||
}
|
||||
default:
|
||||
p.unexpectedError()
|
||||
return nil
|
||||
}
|
||||
|
||||
p.next()
|
||||
|
||||
return &Value{Position: &token.Pos, Raw: token.Value, Kind: kind}
|
||||
}
|
||||
|
||||
func (p *parser) parseList(isConst bool) *Value {
|
||||
var values ChildValueList
|
||||
pos := p.peekPos()
|
||||
p.many(lexer.BracketL, lexer.BracketR, func() {
|
||||
values = append(values, &ChildValue{Value: p.parseValueLiteral(isConst)})
|
||||
})
|
||||
|
||||
return &Value{Children: values, Kind: ListValue, Position: pos}
|
||||
}
|
||||
|
||||
func (p *parser) parseObject(isConst bool) *Value {
|
||||
var fields ChildValueList
|
||||
pos := p.peekPos()
|
||||
p.many(lexer.BraceL, lexer.BraceR, func() {
|
||||
fields = append(fields, p.parseObjectField(isConst))
|
||||
})
|
||||
|
||||
return &Value{Children: fields, Kind: ObjectValue, Position: pos}
|
||||
}
|
||||
|
||||
func (p *parser) parseObjectField(isConst bool) *ChildValue {
|
||||
field := ChildValue{}
|
||||
field.Position = p.peekPos()
|
||||
field.Name = p.parseName()
|
||||
|
||||
p.expect(lexer.Colon)
|
||||
|
||||
field.Value = p.parseValueLiteral(isConst)
|
||||
return &field
|
||||
}
|
||||
|
||||
func (p *parser) parseDirectives(isConst bool) []*Directive {
|
||||
var directives []*Directive
|
||||
|
||||
for p.peek().Kind == lexer.At {
|
||||
if p.err != nil {
|
||||
break
|
||||
}
|
||||
directives = append(directives, p.parseDirective(isConst))
|
||||
}
|
||||
return directives
|
||||
}
|
||||
|
||||
func (p *parser) parseDirective(isConst bool) *Directive {
|
||||
p.expect(lexer.At)
|
||||
|
||||
return &Directive{
|
||||
Position: p.peekPos(),
|
||||
Name: p.parseName(),
|
||||
Arguments: p.parseArguments(isConst),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parser) parseTypeReference() *Type {
|
||||
var typ Type
|
||||
|
||||
if p.skip(lexer.BracketL) {
|
||||
typ.Position = p.peekPos()
|
||||
typ.Elem = p.parseTypeReference()
|
||||
p.expect(lexer.BracketR)
|
||||
} else {
|
||||
typ.Position = p.peekPos()
|
||||
typ.NamedType = p.parseName()
|
||||
}
|
||||
|
||||
if p.skip(lexer.Bang) {
|
||||
typ.Position = p.peekPos()
|
||||
typ.NonNull = true
|
||||
}
|
||||
return &typ
|
||||
}
|
||||
|
||||
func (p *parser) parseName() string {
|
||||
token := p.expect(lexer.Name)
|
||||
|
||||
return token.Value
|
||||
}
|
||||
520
vendor/github.com/vektah/gqlparser/v2/parser/query_test.yml
generated
vendored
Normal file
520
vendor/github.com/vektah/gqlparser/v2/parser/query_test.yml
generated
vendored
Normal file
@@ -0,0 +1,520 @@
|
||||
parser provides useful errors:
|
||||
- name: unclosed paren
|
||||
input: '{'
|
||||
error:
|
||||
message: "Expected Name, found <EOF>"
|
||||
locations: [{line: 1, column: 2}]
|
||||
|
||||
- name: missing on in fragment
|
||||
input: |
|
||||
{ ...MissingOn }
|
||||
fragment MissingOn Type
|
||||
error:
|
||||
message: 'Expected "on", found Name "Type"'
|
||||
locations: [{ line: 2, column: 20 }]
|
||||
|
||||
- name: missing name after alias
|
||||
input: '{ field: {} }'
|
||||
error:
|
||||
message: "Expected Name, found {"
|
||||
locations: [{ line: 1, column: 10 }]
|
||||
|
||||
- name: not an operation
|
||||
input: 'notanoperation Foo { field }'
|
||||
error:
|
||||
message: 'Unexpected Name "notanoperation"'
|
||||
locations: [{ line: 1, column: 1 }]
|
||||
|
||||
- name: a wild splat appears
|
||||
input: '...'
|
||||
error:
|
||||
message: 'Unexpected ...'
|
||||
locations: [{ line: 1, column: 1}]
|
||||
|
||||
variables:
|
||||
- name: are allowed in args
|
||||
input: '{ field(complex: { a: { b: [ $var ] } }) }'
|
||||
|
||||
- name: are not allowed in default args
|
||||
input: 'query Foo($x: Complex = { a: { b: [ $var ] } }) { field }'
|
||||
error:
|
||||
message: 'Unexpected $'
|
||||
locations: [{ line: 1, column: 37 }]
|
||||
|
||||
fragments:
|
||||
- name: can not be named 'on'
|
||||
input: 'fragment on on on { on }'
|
||||
error:
|
||||
message: 'Unexpected Name "on"'
|
||||
locations: [{ line: 1, column: 10 }]
|
||||
|
||||
- name: can not spread fragments called 'on'
|
||||
input: '{ ...on }'
|
||||
error:
|
||||
message: 'Expected Name, found }'
|
||||
locations: [{ line: 1, column: 9 }]
|
||||
|
||||
encoding:
|
||||
- name: multibyte characters are supported
|
||||
input: |
|
||||
# This comment has a ਊ multi-byte character.
|
||||
{ field(arg: "Has a ਊ multi-byte character.") }
|
||||
ast: |
|
||||
<QueryDocument>
|
||||
Operations: [OperationDefinition]
|
||||
- <OperationDefinition>
|
||||
Operation: Operation("query")
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "field"
|
||||
Name: "field"
|
||||
Arguments: [Argument]
|
||||
- <Argument>
|
||||
Name: "arg"
|
||||
Value: "Has a ਊ multi-byte character."
|
||||
|
||||
keywords are allowed anywhere a name is:
|
||||
- name: on
|
||||
input: |
|
||||
query on {
|
||||
... a
|
||||
... on on { field }
|
||||
}
|
||||
fragment a on Type {
|
||||
on(on: $on)
|
||||
@on(on: on)
|
||||
}
|
||||
|
||||
- name: subscription
|
||||
input: |
|
||||
query subscription {
|
||||
... subscription
|
||||
... on subscription { field }
|
||||
}
|
||||
fragment subscription on Type {
|
||||
subscription(subscription: $subscription)
|
||||
@subscription(subscription: subscription)
|
||||
}
|
||||
|
||||
- name: true
|
||||
input: |
|
||||
query true {
|
||||
... true
|
||||
... on true { field }
|
||||
}
|
||||
fragment true on Type {
|
||||
true(true: $true)
|
||||
@true(true: true)
|
||||
}
|
||||
|
||||
operations:
|
||||
- name: anonymous mutation
|
||||
input: 'mutation { mutationField }'
|
||||
|
||||
- name: named mutation
|
||||
input: 'mutation Foo { mutationField }'
|
||||
|
||||
- name: anonymous subscription
|
||||
input: 'subscription { subscriptionField }'
|
||||
|
||||
- name: named subscription
|
||||
input: 'subscription Foo { subscriptionField }'
|
||||
|
||||
|
||||
ast:
|
||||
- name: simple query
|
||||
input: |
|
||||
{
|
||||
node(id: 4) {
|
||||
id,
|
||||
name
|
||||
}
|
||||
}
|
||||
ast: |
|
||||
<QueryDocument>
|
||||
Operations: [OperationDefinition]
|
||||
- <OperationDefinition>
|
||||
Operation: Operation("query")
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "node"
|
||||
Name: "node"
|
||||
Arguments: [Argument]
|
||||
- <Argument>
|
||||
Name: "id"
|
||||
Value: 4
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "id"
|
||||
Name: "id"
|
||||
- <Field>
|
||||
Alias: "name"
|
||||
Name: "name"
|
||||
|
||||
- name: nameless query with no variables
|
||||
input: |
|
||||
query {
|
||||
node {
|
||||
id
|
||||
}
|
||||
}
|
||||
ast: |
|
||||
<QueryDocument>
|
||||
Operations: [OperationDefinition]
|
||||
- <OperationDefinition>
|
||||
Operation: Operation("query")
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "node"
|
||||
Name: "node"
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "id"
|
||||
Name: "id"
|
||||
|
||||
- name: fragment defined variables
|
||||
input: 'fragment a($v: Boolean = false) on t { f(v: $v) }'
|
||||
ast: |
|
||||
<QueryDocument>
|
||||
Fragments: [FragmentDefinition]
|
||||
- <FragmentDefinition>
|
||||
Name: "a"
|
||||
VariableDefinition: [VariableDefinition]
|
||||
- <VariableDefinition>
|
||||
Variable: "v"
|
||||
Type: Boolean
|
||||
DefaultValue: false
|
||||
TypeCondition: "t"
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "f"
|
||||
Name: "f"
|
||||
Arguments: [Argument]
|
||||
- <Argument>
|
||||
Name: "v"
|
||||
Value: $v
|
||||
|
||||
|
||||
values:
|
||||
- name: null
|
||||
input: '{ f(id: null) }'
|
||||
ast: |
|
||||
<QueryDocument>
|
||||
Operations: [OperationDefinition]
|
||||
- <OperationDefinition>
|
||||
Operation: Operation("query")
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "f"
|
||||
Name: "f"
|
||||
Arguments: [Argument]
|
||||
- <Argument>
|
||||
Name: "id"
|
||||
Value: null
|
||||
|
||||
- name: strings
|
||||
input: '{ f(long: """long""", short: "short") } '
|
||||
ast: |
|
||||
<QueryDocument>
|
||||
Operations: [OperationDefinition]
|
||||
- <OperationDefinition>
|
||||
Operation: Operation("query")
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "f"
|
||||
Name: "f"
|
||||
Arguments: [Argument]
|
||||
- <Argument>
|
||||
Name: "long"
|
||||
Value: "long"
|
||||
- <Argument>
|
||||
Name: "short"
|
||||
Value: "short"
|
||||
|
||||
- name: list
|
||||
input: '{ f(id: [1,2]) }'
|
||||
ast: |
|
||||
<QueryDocument>
|
||||
Operations: [OperationDefinition]
|
||||
- <OperationDefinition>
|
||||
Operation: Operation("query")
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "f"
|
||||
Name: "f"
|
||||
Arguments: [Argument]
|
||||
- <Argument>
|
||||
Name: "id"
|
||||
Value: [1,2]
|
||||
|
||||
types:
|
||||
- name: common types
|
||||
input: 'query ($string: String, $int: Int, $arr: [Arr], $notnull: [Arr!]!) { f }'
|
||||
ast: |
|
||||
<QueryDocument>
|
||||
Operations: [OperationDefinition]
|
||||
- <OperationDefinition>
|
||||
Operation: Operation("query")
|
||||
VariableDefinitions: [VariableDefinition]
|
||||
- <VariableDefinition>
|
||||
Variable: "string"
|
||||
Type: String
|
||||
- <VariableDefinition>
|
||||
Variable: "int"
|
||||
Type: Int
|
||||
- <VariableDefinition>
|
||||
Variable: "arr"
|
||||
Type: [Arr]
|
||||
- <VariableDefinition>
|
||||
Variable: "notnull"
|
||||
Type: [Arr!]!
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "f"
|
||||
Name: "f"
|
||||
|
||||
large queries:
|
||||
- name: kitchen sink
|
||||
input: |
|
||||
# Copyright (c) 2015-present, Facebook, Inc.
|
||||
#
|
||||
# This source code is licensed under the MIT license found in the
|
||||
# LICENSE file in the root directory of this source tree.
|
||||
|
||||
query queryName($foo: ComplexType, $site: Site = MOBILE) {
|
||||
whoever123is: node(id: [123, 456]) {
|
||||
id ,
|
||||
... on User @defer {
|
||||
field2 {
|
||||
id ,
|
||||
alias: field1(first:10, after:$foo,) @include(if: $foo) {
|
||||
id,
|
||||
...frag
|
||||
}
|
||||
}
|
||||
}
|
||||
... @skip(unless: $foo) {
|
||||
id
|
||||
}
|
||||
... {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutation likeStory {
|
||||
like(story: 123) @defer {
|
||||
story {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
subscription StoryLikeSubscription($input: StoryLikeSubscribeInput) {
|
||||
storyLikeSubscribe(input: $input) {
|
||||
story {
|
||||
likers {
|
||||
count
|
||||
}
|
||||
likeSentence {
|
||||
text
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fragment frag on Friend {
|
||||
foo(size: $size, bar: $b, obj: {key: "value", block: """
|
||||
block string uses \"""
|
||||
"""})
|
||||
}
|
||||
|
||||
{
|
||||
unnamed(truthy: true, falsey: false, nullish: null),
|
||||
query
|
||||
}
|
||||
ast: |
|
||||
<QueryDocument>
|
||||
Operations: [OperationDefinition]
|
||||
- <OperationDefinition>
|
||||
Operation: Operation("query")
|
||||
Name: "queryName"
|
||||
VariableDefinitions: [VariableDefinition]
|
||||
- <VariableDefinition>
|
||||
Variable: "foo"
|
||||
Type: ComplexType
|
||||
- <VariableDefinition>
|
||||
Variable: "site"
|
||||
Type: Site
|
||||
DefaultValue: MOBILE
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "whoever123is"
|
||||
Name: "node"
|
||||
Arguments: [Argument]
|
||||
- <Argument>
|
||||
Name: "id"
|
||||
Value: [123,456]
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "id"
|
||||
Name: "id"
|
||||
- <InlineFragment>
|
||||
TypeCondition: "User"
|
||||
Directives: [Directive]
|
||||
- <Directive>
|
||||
Name: "defer"
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "field2"
|
||||
Name: "field2"
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "id"
|
||||
Name: "id"
|
||||
- <Field>
|
||||
Alias: "alias"
|
||||
Name: "field1"
|
||||
Arguments: [Argument]
|
||||
- <Argument>
|
||||
Name: "first"
|
||||
Value: 10
|
||||
- <Argument>
|
||||
Name: "after"
|
||||
Value: $foo
|
||||
Directives: [Directive]
|
||||
- <Directive>
|
||||
Name: "include"
|
||||
Arguments: [Argument]
|
||||
- <Argument>
|
||||
Name: "if"
|
||||
Value: $foo
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "id"
|
||||
Name: "id"
|
||||
- <FragmentSpread>
|
||||
Name: "frag"
|
||||
- <InlineFragment>
|
||||
Directives: [Directive]
|
||||
- <Directive>
|
||||
Name: "skip"
|
||||
Arguments: [Argument]
|
||||
- <Argument>
|
||||
Name: "unless"
|
||||
Value: $foo
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "id"
|
||||
Name: "id"
|
||||
- <InlineFragment>
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "id"
|
||||
Name: "id"
|
||||
- <OperationDefinition>
|
||||
Operation: Operation("mutation")
|
||||
Name: "likeStory"
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "like"
|
||||
Name: "like"
|
||||
Arguments: [Argument]
|
||||
- <Argument>
|
||||
Name: "story"
|
||||
Value: 123
|
||||
Directives: [Directive]
|
||||
- <Directive>
|
||||
Name: "defer"
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "story"
|
||||
Name: "story"
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "id"
|
||||
Name: "id"
|
||||
- <OperationDefinition>
|
||||
Operation: Operation("subscription")
|
||||
Name: "StoryLikeSubscription"
|
||||
VariableDefinitions: [VariableDefinition]
|
||||
- <VariableDefinition>
|
||||
Variable: "input"
|
||||
Type: StoryLikeSubscribeInput
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "storyLikeSubscribe"
|
||||
Name: "storyLikeSubscribe"
|
||||
Arguments: [Argument]
|
||||
- <Argument>
|
||||
Name: "input"
|
||||
Value: $input
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "story"
|
||||
Name: "story"
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "likers"
|
||||
Name: "likers"
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "count"
|
||||
Name: "count"
|
||||
- <Field>
|
||||
Alias: "likeSentence"
|
||||
Name: "likeSentence"
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "text"
|
||||
Name: "text"
|
||||
- <OperationDefinition>
|
||||
Operation: Operation("query")
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "unnamed"
|
||||
Name: "unnamed"
|
||||
Arguments: [Argument]
|
||||
- <Argument>
|
||||
Name: "truthy"
|
||||
Value: true
|
||||
- <Argument>
|
||||
Name: "falsey"
|
||||
Value: false
|
||||
- <Argument>
|
||||
Name: "nullish"
|
||||
Value: null
|
||||
- <Field>
|
||||
Alias: "query"
|
||||
Name: "query"
|
||||
Fragments: [FragmentDefinition]
|
||||
- <FragmentDefinition>
|
||||
Name: "frag"
|
||||
TypeCondition: "Friend"
|
||||
SelectionSet: [Selection]
|
||||
- <Field>
|
||||
Alias: "foo"
|
||||
Name: "foo"
|
||||
Arguments: [Argument]
|
||||
- <Argument>
|
||||
Name: "size"
|
||||
Value: $size
|
||||
- <Argument>
|
||||
Name: "bar"
|
||||
Value: $b
|
||||
- <Argument>
|
||||
Name: "obj"
|
||||
Value: {key:"value",block:"block string uses \"\"\""}
|
||||
|
||||
fuzzer:
|
||||
- name: 01
|
||||
input: '{__typename{...}}'
|
||||
error:
|
||||
message: 'Expected {, found }'
|
||||
locations: [{ line: 1, column: 16 }]
|
||||
|
||||
- name: 02
|
||||
input: '{...{__typename{...{}}}}'
|
||||
error:
|
||||
message: 'expected at least one definition, found }'
|
||||
locations: [{ line: 1, column: 21 }]
|
||||
527
vendor/github.com/vektah/gqlparser/v2/parser/schema.go
generated
vendored
Normal file
527
vendor/github.com/vektah/gqlparser/v2/parser/schema.go
generated
vendored
Normal file
@@ -0,0 +1,527 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
. "github.com/vektah/gqlparser/v2/ast"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
"github.com/vektah/gqlparser/v2/lexer"
|
||||
)
|
||||
|
||||
func ParseSchema(source *Source) (*SchemaDocument, *gqlerror.Error) {
|
||||
p := parser{
|
||||
lexer: lexer.New(source),
|
||||
}
|
||||
ast, err := p.parseSchemaDocument(), p.err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, def := range ast.Definitions {
|
||||
def.BuiltIn = source.BuiltIn
|
||||
}
|
||||
for _, def := range ast.Extensions {
|
||||
def.BuiltIn = source.BuiltIn
|
||||
}
|
||||
|
||||
return ast, nil
|
||||
}
|
||||
|
||||
func ParseSchemas(inputs ...*Source) (*SchemaDocument, *gqlerror.Error) {
|
||||
ast := &SchemaDocument{}
|
||||
for _, input := range inputs {
|
||||
inputAst, err := ParseSchema(input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ast.Merge(inputAst)
|
||||
}
|
||||
return ast, nil
|
||||
}
|
||||
|
||||
func (p *parser) parseSchemaDocument() *SchemaDocument {
|
||||
var doc SchemaDocument
|
||||
doc.Position = p.peekPos()
|
||||
for p.peek().Kind != lexer.EOF {
|
||||
if p.err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var description string
|
||||
if p.peek().Kind == lexer.BlockString || p.peek().Kind == lexer.String {
|
||||
description = p.parseDescription()
|
||||
}
|
||||
|
||||
if p.peek().Kind != lexer.Name {
|
||||
p.unexpectedError()
|
||||
break
|
||||
}
|
||||
|
||||
switch p.peek().Value {
|
||||
case "scalar", "type", "interface", "union", "enum", "input":
|
||||
doc.Definitions = append(doc.Definitions, p.parseTypeSystemDefinition(description))
|
||||
case "schema":
|
||||
doc.Schema = append(doc.Schema, p.parseSchemaDefinition(description))
|
||||
case "directive":
|
||||
doc.Directives = append(doc.Directives, p.parseDirectiveDefinition(description))
|
||||
case "extend":
|
||||
if description != "" {
|
||||
p.unexpectedToken(p.prev)
|
||||
}
|
||||
p.parseTypeSystemExtension(&doc)
|
||||
default:
|
||||
p.unexpectedError()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return &doc
|
||||
}
|
||||
|
||||
func (p *parser) parseDescription() string {
|
||||
token := p.peek()
|
||||
|
||||
if token.Kind != lexer.BlockString && token.Kind != lexer.String {
|
||||
return ""
|
||||
}
|
||||
|
||||
return p.next().Value
|
||||
}
|
||||
|
||||
func (p *parser) parseTypeSystemDefinition(description string) *Definition {
|
||||
tok := p.peek()
|
||||
if tok.Kind != lexer.Name {
|
||||
p.unexpectedError()
|
||||
return nil
|
||||
}
|
||||
|
||||
switch tok.Value {
|
||||
case "scalar":
|
||||
return p.parseScalarTypeDefinition(description)
|
||||
case "type":
|
||||
return p.parseObjectTypeDefinition(description)
|
||||
case "interface":
|
||||
return p.parseInterfaceTypeDefinition(description)
|
||||
case "union":
|
||||
return p.parseUnionTypeDefinition(description)
|
||||
case "enum":
|
||||
return p.parseEnumTypeDefinition(description)
|
||||
case "input":
|
||||
return p.parseInputObjectTypeDefinition(description)
|
||||
default:
|
||||
p.unexpectedError()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parser) parseSchemaDefinition(description string) *SchemaDefinition {
|
||||
p.expectKeyword("schema")
|
||||
|
||||
def := SchemaDefinition{Description: description}
|
||||
def.Position = p.peekPos()
|
||||
def.Description = description
|
||||
def.Directives = p.parseDirectives(true)
|
||||
|
||||
p.some(lexer.BraceL, lexer.BraceR, func() {
|
||||
def.OperationTypes = append(def.OperationTypes, p.parseOperationTypeDefinition())
|
||||
})
|
||||
return &def
|
||||
}
|
||||
|
||||
func (p *parser) parseOperationTypeDefinition() *OperationTypeDefinition {
|
||||
var op OperationTypeDefinition
|
||||
op.Position = p.peekPos()
|
||||
op.Operation = p.parseOperationType()
|
||||
p.expect(lexer.Colon)
|
||||
op.Type = p.parseName()
|
||||
return &op
|
||||
}
|
||||
|
||||
func (p *parser) parseScalarTypeDefinition(description string) *Definition {
|
||||
p.expectKeyword("scalar")
|
||||
|
||||
var def Definition
|
||||
def.Position = p.peekPos()
|
||||
def.Kind = Scalar
|
||||
def.Description = description
|
||||
def.Name = p.parseName()
|
||||
def.Directives = p.parseDirectives(true)
|
||||
return &def
|
||||
}
|
||||
|
||||
func (p *parser) parseObjectTypeDefinition(description string) *Definition {
|
||||
p.expectKeyword("type")
|
||||
|
||||
var def Definition
|
||||
def.Position = p.peekPos()
|
||||
def.Kind = Object
|
||||
def.Description = description
|
||||
def.Name = p.parseName()
|
||||
def.Interfaces = p.parseImplementsInterfaces()
|
||||
def.Directives = p.parseDirectives(true)
|
||||
def.Fields = p.parseFieldsDefinition()
|
||||
return &def
|
||||
}
|
||||
|
||||
func (p *parser) parseImplementsInterfaces() []string {
|
||||
var types []string
|
||||
if p.peek().Value == "implements" {
|
||||
p.next()
|
||||
// optional leading ampersand
|
||||
p.skip(lexer.Amp)
|
||||
|
||||
types = append(types, p.parseName())
|
||||
for p.skip(lexer.Amp) && p.err == nil {
|
||||
types = append(types, p.parseName())
|
||||
}
|
||||
}
|
||||
return types
|
||||
}
|
||||
|
||||
func (p *parser) parseFieldsDefinition() FieldList {
|
||||
var defs FieldList
|
||||
p.some(lexer.BraceL, lexer.BraceR, func() {
|
||||
defs = append(defs, p.parseFieldDefinition())
|
||||
})
|
||||
return defs
|
||||
}
|
||||
|
||||
func (p *parser) parseFieldDefinition() *FieldDefinition {
|
||||
var def FieldDefinition
|
||||
def.Position = p.peekPos()
|
||||
def.Description = p.parseDescription()
|
||||
def.Name = p.parseName()
|
||||
def.Arguments = p.parseArgumentDefs()
|
||||
p.expect(lexer.Colon)
|
||||
def.Type = p.parseTypeReference()
|
||||
def.Directives = p.parseDirectives(true)
|
||||
|
||||
return &def
|
||||
}
|
||||
|
||||
func (p *parser) parseArgumentDefs() ArgumentDefinitionList {
|
||||
var args ArgumentDefinitionList
|
||||
p.some(lexer.ParenL, lexer.ParenR, func() {
|
||||
args = append(args, p.parseArgumentDef())
|
||||
})
|
||||
return args
|
||||
}
|
||||
|
||||
func (p *parser) parseArgumentDef() *ArgumentDefinition {
|
||||
var def ArgumentDefinition
|
||||
def.Position = p.peekPos()
|
||||
def.Description = p.parseDescription()
|
||||
def.Name = p.parseName()
|
||||
p.expect(lexer.Colon)
|
||||
def.Type = p.parseTypeReference()
|
||||
if p.skip(lexer.Equals) {
|
||||
def.DefaultValue = p.parseValueLiteral(true)
|
||||
}
|
||||
def.Directives = p.parseDirectives(true)
|
||||
return &def
|
||||
}
|
||||
|
||||
func (p *parser) parseInputValueDef() *FieldDefinition {
|
||||
var def FieldDefinition
|
||||
def.Position = p.peekPos()
|
||||
def.Description = p.parseDescription()
|
||||
def.Name = p.parseName()
|
||||
p.expect(lexer.Colon)
|
||||
def.Type = p.parseTypeReference()
|
||||
if p.skip(lexer.Equals) {
|
||||
def.DefaultValue = p.parseValueLiteral(true)
|
||||
}
|
||||
def.Directives = p.parseDirectives(true)
|
||||
return &def
|
||||
}
|
||||
|
||||
func (p *parser) parseInterfaceTypeDefinition(description string) *Definition {
|
||||
p.expectKeyword("interface")
|
||||
|
||||
var def Definition
|
||||
def.Position = p.peekPos()
|
||||
def.Kind = Interface
|
||||
def.Description = description
|
||||
def.Name = p.parseName()
|
||||
def.Directives = p.parseDirectives(true)
|
||||
def.Fields = p.parseFieldsDefinition()
|
||||
return &def
|
||||
}
|
||||
|
||||
func (p *parser) parseUnionTypeDefinition(description string) *Definition {
|
||||
p.expectKeyword("union")
|
||||
|
||||
var def Definition
|
||||
def.Position = p.peekPos()
|
||||
def.Kind = Union
|
||||
def.Description = description
|
||||
def.Name = p.parseName()
|
||||
def.Directives = p.parseDirectives(true)
|
||||
def.Types = p.parseUnionMemberTypes()
|
||||
return &def
|
||||
}
|
||||
|
||||
func (p *parser) parseUnionMemberTypes() []string {
|
||||
var types []string
|
||||
if p.skip(lexer.Equals) {
|
||||
// optional leading pipe
|
||||
p.skip(lexer.Pipe)
|
||||
|
||||
types = append(types, p.parseName())
|
||||
for p.skip(lexer.Pipe) && p.err == nil {
|
||||
types = append(types, p.parseName())
|
||||
}
|
||||
}
|
||||
return types
|
||||
}
|
||||
|
||||
func (p *parser) parseEnumTypeDefinition(description string) *Definition {
|
||||
p.expectKeyword("enum")
|
||||
|
||||
var def Definition
|
||||
def.Position = p.peekPos()
|
||||
def.Kind = Enum
|
||||
def.Description = description
|
||||
def.Name = p.parseName()
|
||||
def.Directives = p.parseDirectives(true)
|
||||
def.EnumValues = p.parseEnumValuesDefinition()
|
||||
return &def
|
||||
}
|
||||
|
||||
func (p *parser) parseEnumValuesDefinition() EnumValueList {
|
||||
var values EnumValueList
|
||||
p.some(lexer.BraceL, lexer.BraceR, func() {
|
||||
values = append(values, p.parseEnumValueDefinition())
|
||||
})
|
||||
return values
|
||||
}
|
||||
|
||||
func (p *parser) parseEnumValueDefinition() *EnumValueDefinition {
|
||||
return &EnumValueDefinition{
|
||||
Position: p.peekPos(),
|
||||
Description: p.parseDescription(),
|
||||
Name: p.parseName(),
|
||||
Directives: p.parseDirectives(true),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parser) parseInputObjectTypeDefinition(description string) *Definition {
|
||||
p.expectKeyword("input")
|
||||
|
||||
var def Definition
|
||||
def.Position = p.peekPos()
|
||||
def.Kind = InputObject
|
||||
def.Description = description
|
||||
def.Name = p.parseName()
|
||||
def.Directives = p.parseDirectives(true)
|
||||
def.Fields = p.parseInputFieldsDefinition()
|
||||
return &def
|
||||
}
|
||||
|
||||
func (p *parser) parseInputFieldsDefinition() FieldList {
|
||||
var values FieldList
|
||||
p.some(lexer.BraceL, lexer.BraceR, func() {
|
||||
values = append(values, p.parseInputValueDef())
|
||||
})
|
||||
return values
|
||||
}
|
||||
|
||||
func (p *parser) parseTypeSystemExtension(doc *SchemaDocument) {
|
||||
p.expectKeyword("extend")
|
||||
|
||||
switch p.peek().Value {
|
||||
case "schema":
|
||||
doc.SchemaExtension = append(doc.SchemaExtension, p.parseSchemaExtension())
|
||||
case "scalar":
|
||||
doc.Extensions = append(doc.Extensions, p.parseScalarTypeExtension())
|
||||
case "type":
|
||||
doc.Extensions = append(doc.Extensions, p.parseObjectTypeExtension())
|
||||
case "interface":
|
||||
doc.Extensions = append(doc.Extensions, p.parseInterfaceTypeExtension())
|
||||
case "union":
|
||||
doc.Extensions = append(doc.Extensions, p.parseUnionTypeExtension())
|
||||
case "enum":
|
||||
doc.Extensions = append(doc.Extensions, p.parseEnumTypeExtension())
|
||||
case "input":
|
||||
doc.Extensions = append(doc.Extensions, p.parseInputObjectTypeExtension())
|
||||
default:
|
||||
p.unexpectedError()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parser) parseSchemaExtension() *SchemaDefinition {
|
||||
p.expectKeyword("schema")
|
||||
|
||||
var def SchemaDefinition
|
||||
def.Position = p.peekPos()
|
||||
def.Directives = p.parseDirectives(true)
|
||||
p.some(lexer.BraceL, lexer.BraceR, func() {
|
||||
def.OperationTypes = append(def.OperationTypes, p.parseOperationTypeDefinition())
|
||||
})
|
||||
if len(def.Directives) == 0 && len(def.OperationTypes) == 0 {
|
||||
p.unexpectedError()
|
||||
}
|
||||
return &def
|
||||
}
|
||||
|
||||
func (p *parser) parseScalarTypeExtension() *Definition {
|
||||
p.expectKeyword("scalar")
|
||||
|
||||
var def Definition
|
||||
def.Position = p.peekPos()
|
||||
def.Kind = Scalar
|
||||
def.Name = p.parseName()
|
||||
def.Directives = p.parseDirectives(true)
|
||||
if len(def.Directives) == 0 {
|
||||
p.unexpectedError()
|
||||
}
|
||||
return &def
|
||||
}
|
||||
|
||||
func (p *parser) parseObjectTypeExtension() *Definition {
|
||||
p.expectKeyword("type")
|
||||
|
||||
var def Definition
|
||||
def.Position = p.peekPos()
|
||||
def.Kind = Object
|
||||
def.Name = p.parseName()
|
||||
def.Interfaces = p.parseImplementsInterfaces()
|
||||
def.Directives = p.parseDirectives(true)
|
||||
def.Fields = p.parseFieldsDefinition()
|
||||
if len(def.Interfaces) == 0 && len(def.Directives) == 0 && len(def.Fields) == 0 {
|
||||
p.unexpectedError()
|
||||
}
|
||||
return &def
|
||||
}
|
||||
|
||||
func (p *parser) parseInterfaceTypeExtension() *Definition {
|
||||
p.expectKeyword("interface")
|
||||
|
||||
var def Definition
|
||||
def.Position = p.peekPos()
|
||||
def.Kind = Interface
|
||||
def.Name = p.parseName()
|
||||
def.Directives = p.parseDirectives(true)
|
||||
def.Fields = p.parseFieldsDefinition()
|
||||
if len(def.Directives) == 0 && len(def.Fields) == 0 {
|
||||
p.unexpectedError()
|
||||
}
|
||||
return &def
|
||||
}
|
||||
|
||||
func (p *parser) parseUnionTypeExtension() *Definition {
|
||||
p.expectKeyword("union")
|
||||
|
||||
var def Definition
|
||||
def.Position = p.peekPos()
|
||||
def.Kind = Union
|
||||
def.Name = p.parseName()
|
||||
def.Directives = p.parseDirectives(true)
|
||||
def.Types = p.parseUnionMemberTypes()
|
||||
|
||||
if len(def.Directives) == 0 && len(def.Types) == 0 {
|
||||
p.unexpectedError()
|
||||
}
|
||||
return &def
|
||||
}
|
||||
|
||||
func (p *parser) parseEnumTypeExtension() *Definition {
|
||||
p.expectKeyword("enum")
|
||||
|
||||
var def Definition
|
||||
def.Position = p.peekPos()
|
||||
def.Kind = Enum
|
||||
def.Name = p.parseName()
|
||||
def.Directives = p.parseDirectives(true)
|
||||
def.EnumValues = p.parseEnumValuesDefinition()
|
||||
if len(def.Directives) == 0 && len(def.EnumValues) == 0 {
|
||||
p.unexpectedError()
|
||||
}
|
||||
return &def
|
||||
}
|
||||
|
||||
func (p *parser) parseInputObjectTypeExtension() *Definition {
|
||||
p.expectKeyword("input")
|
||||
|
||||
var def Definition
|
||||
def.Position = p.peekPos()
|
||||
def.Kind = InputObject
|
||||
def.Name = p.parseName()
|
||||
def.Directives = p.parseDirectives(false)
|
||||
def.Fields = p.parseInputFieldsDefinition()
|
||||
if len(def.Directives) == 0 && len(def.Fields) == 0 {
|
||||
p.unexpectedError()
|
||||
}
|
||||
return &def
|
||||
}
|
||||
|
||||
func (p *parser) parseDirectiveDefinition(description string) *DirectiveDefinition {
|
||||
p.expectKeyword("directive")
|
||||
p.expect(lexer.At)
|
||||
|
||||
var def DirectiveDefinition
|
||||
def.Position = p.peekPos()
|
||||
def.Description = description
|
||||
def.Name = p.parseName()
|
||||
def.Arguments = p.parseArgumentDefs()
|
||||
|
||||
p.expectKeyword("on")
|
||||
def.Locations = p.parseDirectiveLocations()
|
||||
return &def
|
||||
}
|
||||
|
||||
func (p *parser) parseDirectiveLocations() []DirectiveLocation {
|
||||
p.skip(lexer.Pipe)
|
||||
|
||||
locations := []DirectiveLocation{p.parseDirectiveLocation()}
|
||||
|
||||
for p.skip(lexer.Pipe) && p.err == nil {
|
||||
locations = append(locations, p.parseDirectiveLocation())
|
||||
}
|
||||
|
||||
return locations
|
||||
}
|
||||
|
||||
func (p *parser) parseDirectiveLocation() DirectiveLocation {
|
||||
name := p.expect(lexer.Name)
|
||||
|
||||
switch name.Value {
|
||||
case `QUERY`:
|
||||
return LocationQuery
|
||||
case `MUTATION`:
|
||||
return LocationMutation
|
||||
case `SUBSCRIPTION`:
|
||||
return LocationSubscription
|
||||
case `FIELD`:
|
||||
return LocationField
|
||||
case `FRAGMENT_DEFINITION`:
|
||||
return LocationFragmentDefinition
|
||||
case `FRAGMENT_SPREAD`:
|
||||
return LocationFragmentSpread
|
||||
case `INLINE_FRAGMENT`:
|
||||
return LocationInlineFragment
|
||||
case `SCHEMA`:
|
||||
return LocationSchema
|
||||
case `SCALAR`:
|
||||
return LocationScalar
|
||||
case `OBJECT`:
|
||||
return LocationObject
|
||||
case `FIELD_DEFINITION`:
|
||||
return LocationFieldDefinition
|
||||
case `ARGUMENT_DEFINITION`:
|
||||
return LocationArgumentDefinition
|
||||
case `INTERFACE`:
|
||||
return LocationInterface
|
||||
case `UNION`:
|
||||
return LocationUnion
|
||||
case `ENUM`:
|
||||
return LocationEnum
|
||||
case `ENUM_VALUE`:
|
||||
return LocationEnumValue
|
||||
case `INPUT_OBJECT`:
|
||||
return LocationInputObject
|
||||
case `INPUT_FIELD_DEFINITION`:
|
||||
return LocationInputFieldDefinition
|
||||
}
|
||||
|
||||
p.unexpectedToken(name)
|
||||
return ""
|
||||
}
|
||||
540
vendor/github.com/vektah/gqlparser/v2/parser/schema_test.yml
generated
vendored
Normal file
540
vendor/github.com/vektah/gqlparser/v2/parser/schema_test.yml
generated
vendored
Normal file
@@ -0,0 +1,540 @@
|
||||
object types:
|
||||
- name: simple
|
||||
input: |
|
||||
type Hello {
|
||||
world: String
|
||||
}
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Definitions: [Definition]
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("OBJECT")
|
||||
Name: "Hello"
|
||||
Fields: [FieldDefinition]
|
||||
- <FieldDefinition>
|
||||
Name: "world"
|
||||
Type: String
|
||||
|
||||
- name: with description
|
||||
input: |
|
||||
"Description"
|
||||
type Hello {
|
||||
world: String
|
||||
}
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Definitions: [Definition]
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("OBJECT")
|
||||
Description: "Description"
|
||||
Name: "Hello"
|
||||
Fields: [FieldDefinition]
|
||||
- <FieldDefinition>
|
||||
Name: "world"
|
||||
Type: String
|
||||
|
||||
- name: with block description
|
||||
input: |
|
||||
"""
|
||||
Description
|
||||
"""
|
||||
# Even with comments between them
|
||||
type Hello {
|
||||
world: String
|
||||
}
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Definitions: [Definition]
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("OBJECT")
|
||||
Description: "Description"
|
||||
Name: "Hello"
|
||||
Fields: [FieldDefinition]
|
||||
- <FieldDefinition>
|
||||
Name: "world"
|
||||
Type: String
|
||||
- name: with field arg
|
||||
input: |
|
||||
type Hello {
|
||||
world(flag: Boolean): String
|
||||
}
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Definitions: [Definition]
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("OBJECT")
|
||||
Name: "Hello"
|
||||
Fields: [FieldDefinition]
|
||||
- <FieldDefinition>
|
||||
Name: "world"
|
||||
Arguments: [ArgumentDefinition]
|
||||
- <ArgumentDefinition>
|
||||
Name: "flag"
|
||||
Type: Boolean
|
||||
Type: String
|
||||
|
||||
- name: with field arg and default value
|
||||
input: |
|
||||
type Hello {
|
||||
world(flag: Boolean = true): String
|
||||
}
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Definitions: [Definition]
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("OBJECT")
|
||||
Name: "Hello"
|
||||
Fields: [FieldDefinition]
|
||||
- <FieldDefinition>
|
||||
Name: "world"
|
||||
Arguments: [ArgumentDefinition]
|
||||
- <ArgumentDefinition>
|
||||
Name: "flag"
|
||||
DefaultValue: true
|
||||
Type: Boolean
|
||||
Type: String
|
||||
|
||||
- name: with field list arg
|
||||
input: |
|
||||
type Hello {
|
||||
world(things: [String]): String
|
||||
}
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Definitions: [Definition]
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("OBJECT")
|
||||
Name: "Hello"
|
||||
Fields: [FieldDefinition]
|
||||
- <FieldDefinition>
|
||||
Name: "world"
|
||||
Arguments: [ArgumentDefinition]
|
||||
- <ArgumentDefinition>
|
||||
Name: "things"
|
||||
Type: [String]
|
||||
Type: String
|
||||
|
||||
- name: with two args
|
||||
input: |
|
||||
type Hello {
|
||||
world(argOne: Boolean, argTwo: Int): String
|
||||
}
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Definitions: [Definition]
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("OBJECT")
|
||||
Name: "Hello"
|
||||
Fields: [FieldDefinition]
|
||||
- <FieldDefinition>
|
||||
Name: "world"
|
||||
Arguments: [ArgumentDefinition]
|
||||
- <ArgumentDefinition>
|
||||
Name: "argOne"
|
||||
Type: Boolean
|
||||
- <ArgumentDefinition>
|
||||
Name: "argTwo"
|
||||
Type: Int
|
||||
Type: String
|
||||
- name: must define one or more fields
|
||||
input: |
|
||||
type Hello {}
|
||||
error:
|
||||
message: "expected at least one definition, found }"
|
||||
locations: [{ line: 1, column: 13 }]
|
||||
|
||||
type extensions:
|
||||
- name: Object extension
|
||||
input: |
|
||||
extend type Hello {
|
||||
world: String
|
||||
}
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Extensions: [Definition]
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("OBJECT")
|
||||
Name: "Hello"
|
||||
Fields: [FieldDefinition]
|
||||
- <FieldDefinition>
|
||||
Name: "world"
|
||||
Type: String
|
||||
|
||||
- name: without any fields
|
||||
input: "extend type Hello implements Greeting"
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Extensions: [Definition]
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("OBJECT")
|
||||
Name: "Hello"
|
||||
Interfaces: [string]
|
||||
- "Greeting"
|
||||
|
||||
- name: without fields twice
|
||||
input: |
|
||||
extend type Hello implements Greeting
|
||||
extend type Hello implements SecondGreeting
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Extensions: [Definition]
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("OBJECT")
|
||||
Name: "Hello"
|
||||
Interfaces: [string]
|
||||
- "Greeting"
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("OBJECT")
|
||||
Name: "Hello"
|
||||
Interfaces: [string]
|
||||
- "SecondGreeting"
|
||||
|
||||
- name: without anything errors
|
||||
input: "extend type Hello"
|
||||
error:
|
||||
message: "Unexpected <EOF>"
|
||||
locations: [{ line: 1, column: 18 }]
|
||||
|
||||
- name: can have descriptions # hmm, this might not be spec compliant...
|
||||
input: |
|
||||
"Description"
|
||||
extend type Hello {
|
||||
world: String
|
||||
}
|
||||
error:
|
||||
message: 'Unexpected String "Description"'
|
||||
locations: [{ line: 1, column: 2 }]
|
||||
|
||||
- name: can not have descriptions on types
|
||||
input: |
|
||||
extend "Description" type Hello {
|
||||
world: String
|
||||
}
|
||||
error:
|
||||
message: Unexpected String "Description"
|
||||
locations: [{ line: 1, column: 9 }]
|
||||
|
||||
schema definition:
|
||||
- name: simple
|
||||
input: |
|
||||
schema {
|
||||
query: Query
|
||||
}
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Schema: [SchemaDefinition]
|
||||
- <SchemaDefinition>
|
||||
OperationTypes: [OperationTypeDefinition]
|
||||
- <OperationTypeDefinition>
|
||||
Operation: Operation("query")
|
||||
Type: "Query"
|
||||
|
||||
schema extensions:
|
||||
- name: simple
|
||||
input: |
|
||||
extend schema {
|
||||
mutation: Mutation
|
||||
}
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
SchemaExtension: [SchemaDefinition]
|
||||
- <SchemaDefinition>
|
||||
OperationTypes: [OperationTypeDefinition]
|
||||
- <OperationTypeDefinition>
|
||||
Operation: Operation("mutation")
|
||||
Type: "Mutation"
|
||||
|
||||
- name: directive only
|
||||
input: "extend schema @directive"
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
SchemaExtension: [SchemaDefinition]
|
||||
- <SchemaDefinition>
|
||||
Directives: [Directive]
|
||||
- <Directive>
|
||||
Name: "directive"
|
||||
|
||||
- name: without anything errors
|
||||
input: "extend schema"
|
||||
error:
|
||||
message: "Unexpected <EOF>"
|
||||
locations: [{ line: 1, column: 14}]
|
||||
|
||||
type extensions:
|
||||
- name: all can have directives
|
||||
input: |
|
||||
extend scalar Foo @deprecated
|
||||
extend type Foo @deprecated
|
||||
extend interface Foo @deprecated
|
||||
extend union Foo @deprecated
|
||||
extend enum Foo @deprecated
|
||||
extend input Foo @deprecated
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Extensions: [Definition]
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("SCALAR")
|
||||
Name: "Foo"
|
||||
Directives: [Directive]
|
||||
- <Directive>
|
||||
Name: "deprecated"
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("OBJECT")
|
||||
Name: "Foo"
|
||||
Directives: [Directive]
|
||||
- <Directive>
|
||||
Name: "deprecated"
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("INTERFACE")
|
||||
Name: "Foo"
|
||||
Directives: [Directive]
|
||||
- <Directive>
|
||||
Name: "deprecated"
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("UNION")
|
||||
Name: "Foo"
|
||||
Directives: [Directive]
|
||||
- <Directive>
|
||||
Name: "deprecated"
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("ENUM")
|
||||
Name: "Foo"
|
||||
Directives: [Directive]
|
||||
- <Directive>
|
||||
Name: "deprecated"
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("INPUT_OBJECT")
|
||||
Name: "Foo"
|
||||
Directives: [Directive]
|
||||
- <Directive>
|
||||
Name: "deprecated"
|
||||
|
||||
|
||||
inheritance:
|
||||
- name: single
|
||||
input: "type Hello implements World { field: String }"
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Definitions: [Definition]
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("OBJECT")
|
||||
Name: "Hello"
|
||||
Interfaces: [string]
|
||||
- "World"
|
||||
Fields: [FieldDefinition]
|
||||
- <FieldDefinition>
|
||||
Name: "field"
|
||||
Type: String
|
||||
|
||||
- name: multi
|
||||
input: "type Hello implements Wo & rld { field: String }"
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Definitions: [Definition]
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("OBJECT")
|
||||
Name: "Hello"
|
||||
Interfaces: [string]
|
||||
- "Wo"
|
||||
- "rld"
|
||||
Fields: [FieldDefinition]
|
||||
- <FieldDefinition>
|
||||
Name: "field"
|
||||
Type: String
|
||||
|
||||
- name: multi with leading amp
|
||||
input: "type Hello implements & Wo & rld { field: String }"
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Definitions: [Definition]
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("OBJECT")
|
||||
Name: "Hello"
|
||||
Interfaces: [string]
|
||||
- "Wo"
|
||||
- "rld"
|
||||
Fields: [FieldDefinition]
|
||||
- <FieldDefinition>
|
||||
Name: "field"
|
||||
Type: String
|
||||
|
||||
enums:
|
||||
- name: single value
|
||||
input: "enum Hello { WORLD }"
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Definitions: [Definition]
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("ENUM")
|
||||
Name: "Hello"
|
||||
EnumValues: [EnumValueDefinition]
|
||||
- <EnumValueDefinition>
|
||||
Name: "WORLD"
|
||||
|
||||
- name: double value
|
||||
input: "enum Hello { WO, RLD }"
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Definitions: [Definition]
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("ENUM")
|
||||
Name: "Hello"
|
||||
EnumValues: [EnumValueDefinition]
|
||||
- <EnumValueDefinition>
|
||||
Name: "WO"
|
||||
- <EnumValueDefinition>
|
||||
Name: "RLD"
|
||||
- name: must define one or more unique enum values
|
||||
input: |
|
||||
enum Hello {}
|
||||
error:
|
||||
message: "expected at least one definition, found }"
|
||||
locations: [{ line: 1, column: 13 }]
|
||||
|
||||
interface:
|
||||
- name: simple
|
||||
input: |
|
||||
interface Hello {
|
||||
world: String
|
||||
}
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Definitions: [Definition]
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("INTERFACE")
|
||||
Name: "Hello"
|
||||
Fields: [FieldDefinition]
|
||||
- <FieldDefinition>
|
||||
Name: "world"
|
||||
Type: String
|
||||
- name: must define one or more fields
|
||||
input: |
|
||||
interface Hello {}
|
||||
error:
|
||||
message: "expected at least one definition, found }"
|
||||
locations: [{ line: 1, column: 18 }]
|
||||
|
||||
unions:
|
||||
- name: simple
|
||||
input: "union Hello = World"
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Definitions: [Definition]
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("UNION")
|
||||
Name: "Hello"
|
||||
Types: [string]
|
||||
- "World"
|
||||
|
||||
- name: with two types
|
||||
input: "union Hello = Wo | Rld"
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Definitions: [Definition]
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("UNION")
|
||||
Name: "Hello"
|
||||
Types: [string]
|
||||
- "Wo"
|
||||
- "Rld"
|
||||
|
||||
- name: with leading pipe
|
||||
input: "union Hello = | Wo | Rld"
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Definitions: [Definition]
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("UNION")
|
||||
Name: "Hello"
|
||||
Types: [string]
|
||||
- "Wo"
|
||||
- "Rld"
|
||||
|
||||
- name: cant be empty
|
||||
input: "union Hello = || Wo | Rld"
|
||||
error:
|
||||
message: "Expected Name, found |"
|
||||
locations: [{ line: 1, column: 16 }]
|
||||
|
||||
- name: cant double pipe
|
||||
input: "union Hello = Wo || Rld"
|
||||
error:
|
||||
message: "Expected Name, found |"
|
||||
locations: [{ line: 1, column: 19 }]
|
||||
|
||||
- name: cant have trailing pipe
|
||||
input: "union Hello = | Wo | Rld |"
|
||||
error:
|
||||
message: "Expected Name, found <EOF>"
|
||||
locations: [{ line: 1, column: 27 }]
|
||||
|
||||
scalar:
|
||||
- name: simple
|
||||
input: "scalar Hello"
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Definitions: [Definition]
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("SCALAR")
|
||||
Name: "Hello"
|
||||
|
||||
input object:
|
||||
- name: simple
|
||||
input: |
|
||||
input Hello {
|
||||
world: String
|
||||
}
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Definitions: [Definition]
|
||||
- <Definition>
|
||||
Kind: DefinitionKind("INPUT_OBJECT")
|
||||
Name: "Hello"
|
||||
Fields: [FieldDefinition]
|
||||
- <FieldDefinition>
|
||||
Name: "world"
|
||||
Type: String
|
||||
|
||||
- name: can not have args
|
||||
input: |
|
||||
input Hello {
|
||||
world(foo: Int): String
|
||||
}
|
||||
error:
|
||||
message: "Expected :, found ("
|
||||
locations: [{ line: 2, column: 8 }]
|
||||
- name: must define one or more input fields
|
||||
input: |
|
||||
input Hello {}
|
||||
error:
|
||||
message: "expected at least one definition, found }"
|
||||
locations: [{ line: 1, column: 14 }]
|
||||
|
||||
directives:
|
||||
- name: simple
|
||||
input: directive @foo on FIELD
|
||||
ast: |
|
||||
<SchemaDocument>
|
||||
Directives: [DirectiveDefinition]
|
||||
- <DirectiveDefinition>
|
||||
Name: "foo"
|
||||
Locations: [DirectiveLocation]
|
||||
- DirectiveLocation("FIELD")
|
||||
|
||||
- name: invalid location
|
||||
input: "directive @foo on FIELD | INCORRECT_LOCATION"
|
||||
error:
|
||||
message: 'Unexpected Name "INCORRECT_LOCATION"'
|
||||
locations: [{ line: 1, column: 27 }]
|
||||
|
||||
fuzzer:
|
||||
- name: 1
|
||||
input: "type o{d(g:["
|
||||
error:
|
||||
message: 'Expected Name, found <EOF>'
|
||||
locations: [{ line: 1, column: 13 }]
|
||||
- name: 2
|
||||
input: "\"\"\"\r"
|
||||
error:
|
||||
message: 'Unexpected <Invalid>'
|
||||
locations: [{ line: 1, column: 5 }]
|
||||
Reference in New Issue
Block a user