diff options
Diffstat (limited to 'vendor/github.com/graph-gophers/graphql-go/internal/schema')
-rw-r--r-- | vendor/github.com/graph-gophers/graphql-go/internal/schema/meta.go | 203 | ||||
-rw-r--r-- | vendor/github.com/graph-gophers/graphql-go/internal/schema/schema.go | 586 |
2 files changed, 789 insertions, 0 deletions
diff --git a/vendor/github.com/graph-gophers/graphql-go/internal/schema/meta.go b/vendor/github.com/graph-gophers/graphql-go/internal/schema/meta.go new file mode 100644 index 00000000..9f5bba56 --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/internal/schema/meta.go @@ -0,0 +1,203 @@ +package schema + +import ( + "github.com/graph-gophers/graphql-go/types" +) + +func init() { + _ = newMeta() +} + +// newMeta initializes an instance of the meta Schema. +func newMeta() *types.Schema { + s := &types.Schema{ + EntryPointNames: make(map[string]string), + Types: make(map[string]types.NamedType), + Directives: make(map[string]*types.DirectiveDefinition), + } + + err := Parse(s, metaSrc, false) + if err != nil { + panic(err) + } + return s +} + +var metaSrc = ` + # The ` + "`" + `Int` + "`" + ` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1. + scalar Int + + # The ` + "`" + `Float` + "`" + ` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). + scalar Float + + # The ` + "`" + `String` + "`" + ` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text. + scalar String + + # The ` + "`" + `Boolean` + "`" + ` scalar type represents ` + "`" + `true` + "`" + ` or ` + "`" + `false` + "`" + `. + scalar Boolean + + # The ` + "`" + `ID` + "`" + ` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as ` + "`" + `"4"` + "`" + `) or integer (such as ` + "`" + `4` + "`" + `) input value will be accepted as an ID. + scalar ID + + # Directs the executor to include this field or fragment only when the ` + "`" + `if` + "`" + ` argument is true. + directive @include( + # Included when true. + if: Boolean! + ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + + # Directs the executor to skip this field or fragment when the ` + "`" + `if` + "`" + ` argument is true. + directive @skip( + # Skipped when true. + if: Boolean! + ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + + # Marks an element of a GraphQL schema as no longer supported. + directive @deprecated( + # Explains why this element was deprecated, usually also including a suggestion + # for how to access supported similar data. Formatted in + # [Markdown](https://daringfireball.net/projects/markdown/). + reason: String = "No longer supported" + ) on FIELD_DEFINITION | ENUM_VALUE + + # A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. + # + # In some cases, you need to provide options to alter GraphQL's execution behavior + # in ways field arguments will not suffice, such as conditionally including or + # skipping a field. Directives provide this by describing additional information + # to the executor. + type __Directive { + name: String! + description: String + locations: [__DirectiveLocation!]! + args: [__InputValue!]! + } + + # A Directive can be adjacent to many parts of the GraphQL language, a + # __DirectiveLocation describes one such possible adjacencies. + enum __DirectiveLocation { + # Location adjacent to a query operation. + QUERY + # Location adjacent to a mutation operation. + MUTATION + # Location adjacent to a subscription operation. + SUBSCRIPTION + # Location adjacent to a field. + FIELD + # Location adjacent to a fragment definition. + FRAGMENT_DEFINITION + # Location adjacent to a fragment spread. + FRAGMENT_SPREAD + # Location adjacent to an inline fragment. + INLINE_FRAGMENT + # Location adjacent to a schema definition. + SCHEMA + # Location adjacent to a scalar definition. + SCALAR + # Location adjacent to an object type definition. + OBJECT + # Location adjacent to a field definition. + FIELD_DEFINITION + # Location adjacent to an argument definition. + ARGUMENT_DEFINITION + # Location adjacent to an interface definition. + INTERFACE + # Location adjacent to a union definition. + UNION + # Location adjacent to an enum definition. + ENUM + # Location adjacent to an enum value definition. + ENUM_VALUE + # Location adjacent to an input object type definition. + INPUT_OBJECT + # Location adjacent to an input object field definition. + INPUT_FIELD_DEFINITION + } + + # One possible value for a given Enum. Enum values are unique values, not a + # placeholder for a string or numeric value. However an Enum value is returned in + # a JSON response as a string. + type __EnumValue { + name: String! + description: String + isDeprecated: Boolean! + deprecationReason: String + } + + # Object and Interface types are described by a list of Fields, each of which has + # a name, potentially a list of arguments, and a return type. + type __Field { + name: String! + description: String + args: [__InputValue!]! + type: __Type! + isDeprecated: Boolean! + deprecationReason: String + } + + # Arguments provided to Fields or Directives and the input fields of an + # InputObject are represented as Input Values which describe their type and + # optionally a default value. + type __InputValue { + name: String! + description: String + type: __Type! + # A GraphQL-formatted string representing the default value for this input value. + defaultValue: String + } + + # A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all + # available types and directives on the server, as well as the entry points for + # query, mutation, and subscription operations. + type __Schema { + # A list of all types supported by this server. + types: [__Type!]! + # The type that query operations will be rooted at. + queryType: __Type! + # If this server supports mutation, the type that mutation operations will be rooted at. + mutationType: __Type + # If this server support subscription, the type that subscription operations will be rooted at. + subscriptionType: __Type + # A list of all directives supported by this server. + directives: [__Directive!]! + } + + # The fundamental unit of any GraphQL Schema is the type. There are many kinds of + # types in GraphQL as represented by the ` + "`" + `__TypeKind` + "`" + ` enum. + # + # Depending on the kind of a type, certain fields describe information about that + # type. Scalar types provide no information beyond a name and description, while + # Enum types provide their values. Object and Interface types provide the fields + # they describe. Abstract types, Union and Interface, provide the Object types + # possible at runtime. List and NonNull types compose other types. + type __Type { + kind: __TypeKind! + name: String + description: String + fields(includeDeprecated: Boolean = false): [__Field!] + interfaces: [__Type!] + possibleTypes: [__Type!] + enumValues(includeDeprecated: Boolean = false): [__EnumValue!] + inputFields: [__InputValue!] + ofType: __Type + } + + # An enum describing what kind of type a given ` + "`" + `__Type` + "`" + ` is. + enum __TypeKind { + # Indicates this type is a scalar. + SCALAR + # Indicates this type is an object. ` + "`" + `fields` + "`" + ` and ` + "`" + `interfaces` + "`" + ` are valid fields. + OBJECT + # Indicates this type is an interface. ` + "`" + `fields` + "`" + ` and ` + "`" + `possibleTypes` + "`" + ` are valid fields. + INTERFACE + # Indicates this type is a union. ` + "`" + `possibleTypes` + "`" + ` is a valid field. + UNION + # Indicates this type is an enum. ` + "`" + `enumValues` + "`" + ` is a valid field. + ENUM + # Indicates this type is an input object. ` + "`" + `inputFields` + "`" + ` is a valid field. + INPUT_OBJECT + # Indicates this type is a list. ` + "`" + `ofType` + "`" + ` is a valid field. + LIST + # Indicates this type is a non-null. ` + "`" + `ofType` + "`" + ` is a valid field. + NON_NULL + } +` diff --git a/vendor/github.com/graph-gophers/graphql-go/internal/schema/schema.go b/vendor/github.com/graph-gophers/graphql-go/internal/schema/schema.go new file mode 100644 index 00000000..fb301c46 --- /dev/null +++ b/vendor/github.com/graph-gophers/graphql-go/internal/schema/schema.go @@ -0,0 +1,586 @@ +package schema + +import ( + "fmt" + "text/scanner" + + "github.com/graph-gophers/graphql-go/errors" + "github.com/graph-gophers/graphql-go/internal/common" + "github.com/graph-gophers/graphql-go/types" +) + +// New initializes an instance of Schema. +func New() *types.Schema { + s := &types.Schema{ + EntryPointNames: make(map[string]string), + Types: make(map[string]types.NamedType), + Directives: make(map[string]*types.DirectiveDefinition), + } + m := newMeta() + for n, t := range m.Types { + s.Types[n] = t + } + for n, d := range m.Directives { + s.Directives[n] = d + } + return s +} + +func Parse(s *types.Schema, schemaString string, useStringDescriptions bool) error { + l := common.NewLexer(schemaString, useStringDescriptions) + err := l.CatchSyntaxError(func() { parseSchema(s, l) }) + if err != nil { + return err + } + + if err := mergeExtensions(s); err != nil { + return err + } + + for _, t := range s.Types { + if err := resolveNamedType(s, t); err != nil { + return err + } + } + for _, d := range s.Directives { + for _, arg := range d.Arguments { + t, err := common.ResolveType(arg.Type, s.Resolve) + if err != nil { + return err + } + arg.Type = t + } + } + + // https://graphql.github.io/graphql-spec/June2018/#sec-Root-Operation-Types + // > While any type can be the root operation type for a GraphQL operation, the type system definition language can + // > omit the schema definition when the query, mutation, and subscription root types are named Query, Mutation, + // > and Subscription respectively. + if len(s.EntryPointNames) == 0 { + if _, ok := s.Types["Query"]; ok { + s.EntryPointNames["query"] = "Query" + } + if _, ok := s.Types["Mutation"]; ok { + s.EntryPointNames["mutation"] = "Mutation" + } + if _, ok := s.Types["Subscription"]; ok { + s.EntryPointNames["subscription"] = "Subscription" + } + } + s.EntryPoints = make(map[string]types.NamedType) + for key, name := range s.EntryPointNames { + t, ok := s.Types[name] + if !ok { + return errors.Errorf("type %q not found", name) + } + s.EntryPoints[key] = t + } + + // Interface types need validation: https://spec.graphql.org/draft/#sec-Interfaces.Interfaces-Implementing-Interfaces + for _, typeDef := range s.Types { + switch t := typeDef.(type) { + case *types.InterfaceTypeDefinition: + for i, implements := range t.Interfaces { + typ, ok := s.Types[implements.Name] + if !ok { + return errors.Errorf("interface %q not found", implements) + } + inteface, ok := typ.(*types.InterfaceTypeDefinition) + if !ok { + return errors.Errorf("type %q is not an interface", inteface) + } + + for _, f := range inteface.Fields.Names() { + if t.Fields.Get(f) == nil { + return errors.Errorf("interface %q expects field %q but %q does not provide it", inteface.Name, f, t.Name) + } + } + + t.Interfaces[i] = inteface + } + default: + continue + } + } + + for _, obj := range s.Objects { + obj.Interfaces = make([]*types.InterfaceTypeDefinition, len(obj.InterfaceNames)) + if err := resolveDirectives(s, obj.Directives, "OBJECT"); err != nil { + return err + } + for _, field := range obj.Fields { + if err := resolveDirectives(s, field.Directives, "FIELD_DEFINITION"); err != nil { + return err + } + } + for i, intfName := range obj.InterfaceNames { + t, ok := s.Types[intfName] + if !ok { + return errors.Errorf("interface %q not found", intfName) + } + intf, ok := t.(*types.InterfaceTypeDefinition) + if !ok { + return errors.Errorf("type %q is not an interface", intfName) + } + for _, f := range intf.Fields.Names() { + if obj.Fields.Get(f) == nil { + return errors.Errorf("interface %q expects field %q but %q does not provide it", intfName, f, obj.Name) + } + } + obj.Interfaces[i] = intf + intf.PossibleTypes = append(intf.PossibleTypes, obj) + } + } + + for _, union := range s.Unions { + if err := resolveDirectives(s, union.Directives, "UNION"); err != nil { + return err + } + union.UnionMemberTypes = make([]*types.ObjectTypeDefinition, len(union.TypeNames)) + for i, name := range union.TypeNames { + t, ok := s.Types[name] + if !ok { + return errors.Errorf("object type %q not found", name) + } + obj, ok := t.(*types.ObjectTypeDefinition) + if !ok { + return errors.Errorf("type %q is not an object", name) + } + union.UnionMemberTypes[i] = obj + } + } + + for _, enum := range s.Enums { + if err := resolveDirectives(s, enum.Directives, "ENUM"); err != nil { + return err + } + for _, value := range enum.EnumValuesDefinition { + if err := resolveDirectives(s, value.Directives, "ENUM_VALUE"); err != nil { + return err + } + } + } + + return nil +} + +func ParseSchema(schemaString string, useStringDescriptions bool) (*types.Schema, error) { + s := New() + err := Parse(s, schemaString, useStringDescriptions) + return s, err +} + +func mergeExtensions(s *types.Schema) error { + for _, ext := range s.Extensions { + typ := s.Types[ext.Type.TypeName()] + if typ == nil { + return fmt.Errorf("trying to extend unknown type %q", ext.Type.TypeName()) + } + + if typ.Kind() != ext.Type.Kind() { + return fmt.Errorf("trying to extend type %q with type %q", typ.Kind(), ext.Type.Kind()) + } + + switch og := typ.(type) { + case *types.ObjectTypeDefinition: + e := ext.Type.(*types.ObjectTypeDefinition) + + for _, field := range e.Fields { + if og.Fields.Get(field.Name) != nil { + return fmt.Errorf("extended field %q already exists", field.Name) + } + } + og.Fields = append(og.Fields, e.Fields...) + + for _, en := range e.InterfaceNames { + for _, on := range og.InterfaceNames { + if on == en { + return fmt.Errorf("interface %q implemented in the extension is already implemented in %q", on, og.Name) + } + } + } + og.InterfaceNames = append(og.InterfaceNames, e.InterfaceNames...) + + case *types.InputObject: + e := ext.Type.(*types.InputObject) + + for _, field := range e.Values { + if og.Values.Get(field.Name.Name) != nil { + return fmt.Errorf("extended field %q already exists", field.Name) + } + } + og.Values = append(og.Values, e.Values...) + + case *types.InterfaceTypeDefinition: + e := ext.Type.(*types.InterfaceTypeDefinition) + + for _, field := range e.Fields { + if og.Fields.Get(field.Name) != nil { + return fmt.Errorf("extended field %s already exists", field.Name) + } + } + og.Fields = append(og.Fields, e.Fields...) + + case *types.Union: + e := ext.Type.(*types.Union) + + for _, en := range e.TypeNames { + for _, on := range og.TypeNames { + if on == en { + return fmt.Errorf("union type %q already declared in %q", on, og.Name) + } + } + } + og.TypeNames = append(og.TypeNames, e.TypeNames...) + + case *types.EnumTypeDefinition: + e := ext.Type.(*types.EnumTypeDefinition) + + for _, en := range e.EnumValuesDefinition { + for _, on := range og.EnumValuesDefinition { + if on.EnumValue == en.EnumValue { + return fmt.Errorf("enum value %q already declared in %q", on.EnumValue, og.Name) + } + } + } + og.EnumValuesDefinition = append(og.EnumValuesDefinition, e.EnumValuesDefinition...) + default: + return fmt.Errorf(`unexpected %q, expecting "schema", "type", "enum", "interface", "union" or "input"`, og.TypeName()) + } + } + + return nil +} + +func resolveNamedType(s *types.Schema, t types.NamedType) error { + switch t := t.(type) { + case *types.ObjectTypeDefinition: + for _, f := range t.Fields { + if err := resolveField(s, f); err != nil { + return err + } + } + case *types.InterfaceTypeDefinition: + for _, f := range t.Fields { + if err := resolveField(s, f); err != nil { + return err + } + } + case *types.InputObject: + if err := resolveInputObject(s, t.Values); err != nil { + return err + } + } + return nil +} + +func resolveField(s *types.Schema, f *types.FieldDefinition) error { + t, err := common.ResolveType(f.Type, s.Resolve) + if err != nil { + return err + } + f.Type = t + if err := resolveDirectives(s, f.Directives, "FIELD_DEFINITION"); err != nil { + return err + } + return resolveInputObject(s, f.Arguments) +} + +func resolveDirectives(s *types.Schema, directives types.DirectiveList, loc string) error { + for _, d := range directives { + dirName := d.Name.Name + dd, ok := s.Directives[dirName] + if !ok { + return errors.Errorf("directive %q not found", dirName) + } + validLoc := false + for _, l := range dd.Locations { + if l == loc { + validLoc = true + break + } + } + if !validLoc { + return errors.Errorf("invalid location %q for directive %q (must be one of %v)", loc, dirName, dd.Locations) + } + for _, arg := range d.Arguments { + if dd.Arguments.Get(arg.Name.Name) == nil { + return errors.Errorf("invalid argument %q for directive %q", arg.Name.Name, dirName) + } + } + for _, arg := range dd.Arguments { + if _, ok := d.Arguments.Get(arg.Name.Name); !ok { + d.Arguments = append(d.Arguments, &types.Argument{Name: arg.Name, Value: arg.Default}) + } + } + } + return nil +} + +func resolveInputObject(s *types.Schema, values types.ArgumentsDefinition) error { + for _, v := range values { + t, err := common.ResolveType(v.Type, s.Resolve) + if err != nil { + return err + } + v.Type = t + } + return nil +} + +func parseSchema(s *types.Schema, l *common.Lexer) { + l.ConsumeWhitespace() + + for l.Peek() != scanner.EOF { + desc := l.DescComment() + switch x := l.ConsumeIdent(); x { + + case "schema": + l.ConsumeToken('{') + for l.Peek() != '}' { + + name := l.ConsumeIdent() + l.ConsumeToken(':') + typ := l.ConsumeIdent() + s.EntryPointNames[name] = typ + } + l.ConsumeToken('}') + + case "type": + obj := parseObjectDef(l) + obj.Desc = desc + s.Types[obj.Name] = obj + s.Objects = append(s.Objects, obj) + + case "interface": + iface := parseInterfaceDef(l) + iface.Desc = desc + s.Types[iface.Name] = iface + + case "union": + union := parseUnionDef(l) + union.Desc = desc + s.Types[union.Name] = union + s.Unions = append(s.Unions, union) + + case "enum": + enum := parseEnumDef(l) + enum.Desc = desc + s.Types[enum.Name] = enum + s.Enums = append(s.Enums, enum) + + case "input": + input := parseInputDef(l) + input.Desc = desc + s.Types[input.Name] = input + + case "scalar": + loc := l.Location() + name := l.ConsumeIdent() + directives := common.ParseDirectives(l) + s.Types[name] = &types.ScalarTypeDefinition{Name: name, Desc: desc, Directives: directives, Loc: loc} + + case "directive": + directive := parseDirectiveDef(l) + directive.Desc = desc + s.Directives[directive.Name] = directive + + case "extend": + parseExtension(s, l) + + default: + // TODO: Add support for type extensions. + l.SyntaxError(fmt.Sprintf(`unexpected %q, expecting "schema", "type", "enum", "interface", "union", "input", "scalar" or "directive"`, x)) + } + } +} + +func parseObjectDef(l *common.Lexer) *types.ObjectTypeDefinition { + object := &types.ObjectTypeDefinition{Loc: l.Location(), Name: l.ConsumeIdent()} + + for { + if l.Peek() == '{' { + break + } + + if l.Peek() == '@' { + object.Directives = common.ParseDirectives(l) + continue + } + + if l.Peek() == scanner.Ident { + l.ConsumeKeyword("implements") + + for l.Peek() != '{' && l.Peek() != '@' { + if l.Peek() == '&' { + l.ConsumeToken('&') + } + + object.InterfaceNames = append(object.InterfaceNames, l.ConsumeIdent()) + } + continue + } + + } + l.ConsumeToken('{') + object.Fields = parseFieldsDef(l) + l.ConsumeToken('}') + + return object + +} + +func parseInterfaceDef(l *common.Lexer) *types.InterfaceTypeDefinition { + i := &types.InterfaceTypeDefinition{Loc: l.Location(), Name: l.ConsumeIdent()} + + if l.Peek() == scanner.Ident { + l.ConsumeKeyword("implements") + i.Interfaces = append(i.Interfaces, &types.InterfaceTypeDefinition{Name: l.ConsumeIdent()}) + + for l.Peek() == '&' { + l.ConsumeToken('&') + i.Interfaces = append(i.Interfaces, &types.InterfaceTypeDefinition{Name: l.ConsumeIdent()}) + } + } + + i.Directives = common.ParseDirectives(l) + + l.ConsumeToken('{') + i.Fields = parseFieldsDef(l) + l.ConsumeToken('}') + + return i +} + +func parseUnionDef(l *common.Lexer) *types.Union { + union := &types.Union{Loc: l.Location(), Name: l.ConsumeIdent()} + + union.Directives = common.ParseDirectives(l) + l.ConsumeToken('=') + union.TypeNames = []string{l.ConsumeIdent()} + for l.Peek() == '|' { + l.ConsumeToken('|') + union.TypeNames = append(union.TypeNames, l.ConsumeIdent()) + } + + return union +} + +func parseInputDef(l *common.Lexer) *types.InputObject { + i := &types.InputObject{} + i.Loc = l.Location() + i.Name = l.ConsumeIdent() + i.Directives = common.ParseDirectives(l) + l.ConsumeToken('{') + for l.Peek() != '}' { + i.Values = append(i.Values, common.ParseInputValue(l)) + } + l.ConsumeToken('}') + return i +} + +func parseEnumDef(l *common.Lexer) *types.EnumTypeDefinition { + enum := &types.EnumTypeDefinition{Loc: l.Location(), Name: l.ConsumeIdent()} + + enum.Directives = common.ParseDirectives(l) + l.ConsumeToken('{') + for l.Peek() != '}' { + v := &types.EnumValueDefinition{ + Desc: l.DescComment(), + Loc: l.Location(), + EnumValue: l.ConsumeIdent(), + Directives: common.ParseDirectives(l), + } + + enum.EnumValuesDefinition = append(enum.EnumValuesDefinition, v) + } + l.ConsumeToken('}') + return enum +} +func parseDirectiveDef(l *common.Lexer) *types.DirectiveDefinition { + l.ConsumeToken('@') + loc := l.Location() + d := &types.DirectiveDefinition{Name: l.ConsumeIdent(), Loc: loc} + + if l.Peek() == '(' { + l.ConsumeToken('(') + for l.Peek() != ')' { + v := common.ParseInputValue(l) + d.Arguments = append(d.Arguments, v) + } + l.ConsumeToken(')') + } + + l.ConsumeKeyword("on") + + for { + loc := l.ConsumeIdent() + d.Locations = append(d.Locations, loc) + if l.Peek() != '|' { + break + } + l.ConsumeToken('|') + } + return d +} + +func parseExtension(s *types.Schema, l *common.Lexer) { + loc := l.Location() + switch x := l.ConsumeIdent(); x { + case "schema": + l.ConsumeToken('{') + for l.Peek() != '}' { + name := l.ConsumeIdent() + l.ConsumeToken(':') + typ := l.ConsumeIdent() + s.EntryPointNames[name] = typ + } + l.ConsumeToken('}') + + case "type": + obj := parseObjectDef(l) + s.Extensions = append(s.Extensions, &types.Extension{Type: obj, Loc: loc}) + + case "interface": + iface := parseInterfaceDef(l) + s.Extensions = append(s.Extensions, &types.Extension{Type: iface, Loc: loc}) + + case "union": + union := parseUnionDef(l) + s.Extensions = append(s.Extensions, &types.Extension{Type: union, Loc: loc}) + + case "enum": + enum := parseEnumDef(l) + s.Extensions = append(s.Extensions, &types.Extension{Type: enum, Loc: loc}) + + case "input": + input := parseInputDef(l) + s.Extensions = append(s.Extensions, &types.Extension{Type: input, Loc: loc}) + + default: + // TODO: Add ScalarTypeDefinition when adding directives + l.SyntaxError(fmt.Sprintf(`unexpected %q, expecting "schema", "type", "enum", "interface", "union" or "input"`, x)) + } +} + +func parseFieldsDef(l *common.Lexer) types.FieldsDefinition { + var fields types.FieldsDefinition + for l.Peek() != '}' { + f := &types.FieldDefinition{} + f.Desc = l.DescComment() + f.Loc = l.Location() + f.Name = l.ConsumeIdent() + if l.Peek() == '(' { + l.ConsumeToken('(') + for l.Peek() != ')' { + f.Arguments = append(f.Arguments, common.ParseInputValue(l)) + } + l.ConsumeToken(')') + } + l.ConsumeToken(':') + f.Type = common.ParseType(l) + f.Directives = common.ParseDirectives(l) + fields = append(fields, f) + } + return fields +} |