@@ -72,9 +72,9 @@ type NamedType interface {
7272//
7373// http://facebook.github.io/graphql/draft/#sec-Scalars
7474type Scalar struct {
75- Name string
76- Desc string
77- // TODO: Add a list of directives?
75+ Name string
76+ Desc string
77+ Directives common. DirectiveList
7878}
7979
8080// Object types represent a list of named fields, each of which yield a value of a specific type.
@@ -89,7 +89,7 @@ type Object struct {
8989 Interfaces []* Interface
9090 Fields FieldList
9191 Desc string
92- // TODO: Add a list of directives?
92+ Directives common. DirectiveList
9393
9494 interfaceNames []string
9595}
@@ -105,7 +105,7 @@ type Interface struct {
105105 PossibleTypes []* Object
106106 Fields FieldList // NOTE: the spec refers to this as `FieldsDefinition`.
107107 Desc string
108- // TODO: Add a list of directives?
108+ Directives common. DirectiveList
109109}
110110
111111// Union types represent objects that could be one of a list of GraphQL object types, but provides no
@@ -119,7 +119,7 @@ type Union struct {
119119 Name string
120120 PossibleTypes []* Object // NOTE: the spec refers to this as `UnionMemberTypes`.
121121 Desc string
122- // TODO: Add a list of directives?
122+ Directives common. DirectiveList
123123
124124 typeNames []string
125125}
@@ -130,10 +130,10 @@ type Union struct {
130130//
131131// http://facebook.github.io/graphql/draft/#sec-Enums
132132type Enum struct {
133- Name string
134- Values []* EnumValue // NOTE: the spec refers to this as `EnumValuesDefinition`.
135- Desc string
136- // TODO: Add a list of directives?
133+ Name string
134+ Values []* EnumValue // NOTE: the spec refers to this as `EnumValuesDefinition`.
135+ Desc string
136+ Directives common. DirectiveList
137137}
138138
139139// EnumValue types are unique values that may be serialized as a string: the name of the
@@ -144,7 +144,6 @@ type EnumValue struct {
144144 Name string
145145 Directives common.DirectiveList
146146 Desc string
147- // TODO: Add a list of directives?
148147}
149148
150149// InputObject types define a set of input fields; the input fields are either scalars, enums, or
@@ -154,19 +153,19 @@ type EnumValue struct {
154153//
155154// http://facebook.github.io/graphql/draft/#sec-Input-Objects
156155type InputObject struct {
157- Name string
158- Desc string
159- Values common.InputValueList
160- // TODO: Add a list of directives?
156+ Name string
157+ Desc string
158+ Values common.InputValueList
159+ Directives common. DirectiveList
161160}
162161
163162// Extension type defines a GraphQL type extension.
164163// Schemas, Objects, Inputs and Scalars can be extended.
165164//
166165// https://facebook.github.io/graphql/draft/#sec-Type-System-Extensions
167166type Extension struct {
168- Type NamedType
169- // TODO: Add a list of directives
167+ Type NamedType
168+ Directives common. DirectiveList
170169}
171170
172171// FieldsList is a list of an Object's Fields.
@@ -314,6 +313,14 @@ func (s *Schema) Parse(schemaString string, useStringDescriptions bool) error {
314313
315314 for _ , obj := range s .objects {
316315 obj .Interfaces = make ([]* Interface , len (obj .interfaceNames ))
316+ if err := resolveDirectives (s , obj .Directives , "OBJECT" ); err != nil {
317+ return err
318+ }
319+ for _ , field := range obj .Fields {
320+ if err := resolveDirectives (s , field .Directives , "FIELD_DEFINITION" ); err != nil {
321+ return err
322+ }
323+ }
317324 for i , intfName := range obj .interfaceNames {
318325 t , ok := s .Types [intfName ]
319326 if ! ok {
@@ -334,6 +341,9 @@ func (s *Schema) Parse(schemaString string, useStringDescriptions bool) error {
334341 }
335342
336343 for _ , union := range s .unions {
344+ if err := resolveDirectives (s , union .Directives , "UNION" ); err != nil {
345+ return err
346+ }
337347 union .PossibleTypes = make ([]* Object , len (union .typeNames ))
338348 for i , name := range union .typeNames {
339349 t , ok := s .Types [name ]
@@ -349,8 +359,11 @@ func (s *Schema) Parse(schemaString string, useStringDescriptions bool) error {
349359 }
350360
351361 for _ , enum := range s .enums {
362+ if err := resolveDirectives (s , enum .Directives , "ENUM" ); err != nil {
363+ return err
364+ }
352365 for _ , value := range enum .Values {
353- if err := resolveDirectives (s , value .Directives ); err != nil {
366+ if err := resolveDirectives (s , value .Directives , "ENUM_VALUE" ); err != nil {
354367 return err
355368 }
356369 }
@@ -469,19 +482,29 @@ func resolveField(s *Schema, f *Field) error {
469482 return err
470483 }
471484 f .Type = t
472- if err := resolveDirectives (s , f .Directives ); err != nil {
485+ if err := resolveDirectives (s , f .Directives , "FIELD_DEFINITION" ); err != nil {
473486 return err
474487 }
475488 return resolveInputObject (s , f .Args )
476489}
477490
478- func resolveDirectives (s * Schema , directives common.DirectiveList ) error {
491+ func resolveDirectives (s * Schema , directives common.DirectiveList , loc string ) error {
479492 for _ , d := range directives {
480493 dirName := d .Name .Name
481494 dd , ok := s .Directives [dirName ]
482495 if ! ok {
483496 return errors .Errorf ("directive %q not found" , dirName )
484497 }
498+ validLoc := false
499+ for _ , l := range dd .Locs {
500+ if l == loc {
501+ validLoc = true
502+ break
503+ }
504+ }
505+ if ! validLoc {
506+ return errors .Errorf ("invalid location %q for directive %q (must be one of %v)" , loc , dirName , dd .Locs )
507+ }
485508 for _ , arg := range d .Args {
486509 if dd .Args .Get (arg .Name .Name ) == nil {
487510 return errors .Errorf ("invalid argument %q for directive %q" , arg .Name .Name , dirName )
@@ -554,7 +577,8 @@ func parseSchema(s *Schema, l *common.Lexer) {
554577
555578 case "scalar" :
556579 name := l .ConsumeIdent ()
557- s .Types [name ] = & Scalar {Name : name , Desc : desc }
580+ directives := common .ParseDirectives (l )
581+ s .Types [name ] = & Scalar {Name : name , Desc : desc , Directives : directives }
558582
559583 case "directive" :
560584 directive := parseDirectiveDef (l )
@@ -574,16 +598,30 @@ func parseSchema(s *Schema, l *common.Lexer) {
574598func parseObjectDef (l * common.Lexer ) * Object {
575599 object := & Object {Name : l .ConsumeIdent ()}
576600
577- if l .Peek () == scanner .Ident {
578- l .ConsumeKeyword ("implements" )
601+ for {
602+ if l .Peek () == '{' {
603+ break
604+ }
579605
580- for l .Peek () != '{' {
581- if l .Peek () == '&' {
582- l .ConsumeToken ('&' )
583- }
606+ if l .Peek () == '@' {
607+ object .Directives = common .ParseDirectives (l )
608+ continue
609+ }
610+
611+ if l .Peek () == scanner .Ident {
612+ l .ConsumeKeyword ("implements" )
584613
585- object .interfaceNames = append (object .interfaceNames , l .ConsumeIdent ())
614+ for l .Peek () != '{' && l .Peek () != '@' {
615+ if l .Peek () == '&' {
616+ l .ConsumeToken ('&' )
617+ }
618+
619+ object .interfaceNames = append (object .interfaceNames , l .ConsumeIdent ())
620+ }
621+ continue
586622 }
623+
624+ l .SyntaxError (fmt .Sprintf (`unexpected %q, expecting "implements", "directive" or "{"` , l .Peek ()))
587625 }
588626
589627 l .ConsumeToken ('{' )
@@ -596,6 +634,7 @@ func parseObjectDef(l *common.Lexer) *Object {
596634func parseInterfaceDef (l * common.Lexer ) * Interface {
597635 i := & Interface {Name : l .ConsumeIdent ()}
598636
637+ i .Directives = common .ParseDirectives (l )
599638 l .ConsumeToken ('{' )
600639 i .Fields = parseFieldsDef (l )
601640 l .ConsumeToken ('}' )
@@ -606,6 +645,7 @@ func parseInterfaceDef(l *common.Lexer) *Interface {
606645func parseUnionDef (l * common.Lexer ) * Union {
607646 union := & Union {Name : l .ConsumeIdent ()}
608647
648+ union .Directives = common .ParseDirectives (l )
609649 l .ConsumeToken ('=' )
610650 union .typeNames = []string {l .ConsumeIdent ()}
611651 for l .Peek () == '|' {
@@ -619,6 +659,7 @@ func parseUnionDef(l *common.Lexer) *Union {
619659func parseInputDef (l * common.Lexer ) * InputObject {
620660 i := & InputObject {}
621661 i .Name = l .ConsumeIdent ()
662+ i .Directives = common .ParseDirectives (l )
622663 l .ConsumeToken ('{' )
623664 for l .Peek () != '}' {
624665 i .Values = append (i .Values , common .ParseInputValue (l ))
@@ -630,6 +671,7 @@ func parseInputDef(l *common.Lexer) *InputObject {
630671func parseEnumDef (l * common.Lexer ) * Enum {
631672 enum := & Enum {Name : l .ConsumeIdent ()}
632673
674+ enum .Directives = common .ParseDirectives (l )
633675 l .ConsumeToken ('{' )
634676 for l .Peek () != '}' {
635677 v := & EnumValue {
0 commit comments