1package graphql
2
3import (
4 "fmt"
5 "math"
6 "sort"
7 "strings"
8
9 "github.com/graphql-go/graphql/gqlerrors"
10 "github.com/graphql-go/graphql/language/ast"
11 "github.com/graphql-go/graphql/language/kinds"
12 "github.com/graphql-go/graphql/language/printer"
13 "github.com/graphql-go/graphql/language/visitor"
14)
15
16// SpecifiedRules set includes all validation rules defined by the GraphQL spec.
17var SpecifiedRules = []ValidationRuleFn{
18 ArgumentsOfCorrectTypeRule,
19 DefaultValuesOfCorrectTypeRule,
20 FieldsOnCorrectTypeRule,
21 FragmentsOnCompositeTypesRule,
22 KnownArgumentNamesRule,
23 KnownDirectivesRule,
24 KnownFragmentNamesRule,
25 KnownTypeNamesRule,
26 LoneAnonymousOperationRule,
27 NoFragmentCyclesRule,
28 NoUndefinedVariablesRule,
29 NoUnusedFragmentsRule,
30 NoUnusedVariablesRule,
31 OverlappingFieldsCanBeMergedRule,
32 PossibleFragmentSpreadsRule,
33 ProvidedNonNullArgumentsRule,
34 ScalarLeafsRule,
35 UniqueArgumentNamesRule,
36 UniqueFragmentNamesRule,
37 UniqueInputFieldNamesRule,
38 UniqueOperationNamesRule,
39 UniqueVariableNamesRule,
40 VariablesAreInputTypesRule,
41 VariablesInAllowedPositionRule,
42}
43
44type ValidationRuleInstance struct {
45 VisitorOpts *visitor.VisitorOptions
46}
47type ValidationRuleFn func(context *ValidationContext) *ValidationRuleInstance
48
49func newValidationError(message string, nodes []ast.Node) *gqlerrors.Error {
50 return gqlerrors.NewError(
51 message,
52 nodes,
53 "",
54 nil,
55 []int{},
56 nil, // TODO: this is interim, until we port "better-error-messages-for-inputs"
57 )
58}
59
60func reportError(context *ValidationContext, message string, nodes []ast.Node) (string, interface{}) {
61 context.ReportError(newValidationError(message, nodes))
62 return visitor.ActionNoChange, nil
63}
64
65// ArgumentsOfCorrectTypeRule Argument values of correct type
66//
67// A GraphQL document is only valid if all field argument literal values are
68// of the type expected by their position.
69func ArgumentsOfCorrectTypeRule(context *ValidationContext) *ValidationRuleInstance {
70 visitorOpts := &visitor.VisitorOptions{
71 KindFuncMap: map[string]visitor.NamedVisitFuncs{
72 kinds.Argument: {
73 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
74 if argAST, ok := p.Node.(*ast.Argument); ok {
75 value := argAST.Value
76 argDef := context.Argument()
77 if argDef != nil {
78 isValid, messages := isValidLiteralValue(argDef.Type, value)
79 if !isValid {
80 argNameValue := ""
81 if argAST.Name != nil {
82 argNameValue = argAST.Name.Value
83 }
84
85 messagesStr := ""
86 if len(messages) > 0 {
87 messagesStr = "\n" + strings.Join(messages, "\n")
88 }
89 reportError(
90 context,
91 fmt.Sprintf(`Argument "%v" has invalid value %v.%v`,
92 argNameValue, printer.Print(value), messagesStr),
93 []ast.Node{value},
94 )
95 }
96
97 }
98 }
99 return visitor.ActionSkip, nil
100 },
101 },
102 },
103 }
104 return &ValidationRuleInstance{
105 VisitorOpts: visitorOpts,
106 }
107}
108
109// DefaultValuesOfCorrectTypeRule Variable default values of correct type
110//
111// A GraphQL document is only valid if all variable default values are of the
112// type expected by their definition.
113func DefaultValuesOfCorrectTypeRule(context *ValidationContext) *ValidationRuleInstance {
114 visitorOpts := &visitor.VisitorOptions{
115 KindFuncMap: map[string]visitor.NamedVisitFuncs{
116 kinds.VariableDefinition: {
117 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
118 if varDefAST, ok := p.Node.(*ast.VariableDefinition); ok {
119 name := ""
120 if varDefAST.Variable != nil && varDefAST.Variable.Name != nil {
121 name = varDefAST.Variable.Name.Value
122 }
123 defaultValue := varDefAST.DefaultValue
124 ttype := context.InputType()
125
126 if ttype, ok := ttype.(*NonNull); ok && defaultValue != nil {
127 reportError(
128 context,
129 fmt.Sprintf(`Variable "$%v" of type "%v" is required and will not use the default value. Perhaps you meant to use type "%v".`,
130 name, ttype, ttype.OfType),
131 []ast.Node{defaultValue},
132 )
133 }
134 isValid, messages := isValidLiteralValue(ttype, defaultValue)
135 if ttype != nil && defaultValue != nil && !isValid {
136 messagesStr := ""
137 if len(messages) > 0 {
138 messagesStr = "\n" + strings.Join(messages, "\n")
139 }
140 reportError(
141 context,
142 fmt.Sprintf(`Variable "$%v" has invalid default value: %v.%v`,
143 name, printer.Print(defaultValue), messagesStr),
144 []ast.Node{defaultValue},
145 )
146 }
147 }
148 return visitor.ActionSkip, nil
149 },
150 },
151 kinds.SelectionSet: {
152 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
153 return visitor.ActionSkip, nil
154 },
155 },
156 kinds.FragmentDefinition: {
157 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
158 return visitor.ActionSkip, nil
159 },
160 },
161 },
162 }
163 return &ValidationRuleInstance{
164 VisitorOpts: visitorOpts,
165 }
166}
167func quoteStrings(slice []string) []string {
168 quoted := []string{}
169 for _, s := range slice {
170 quoted = append(quoted, fmt.Sprintf(`"%v"`, s))
171 }
172 return quoted
173}
174
175// quotedOrList Given [ A, B, C ] return '"A", "B", or "C"'.
176// Notice oxford comma
177func quotedOrList(slice []string) string {
178 maxLength := 5
179 if len(slice) == 0 {
180 return ""
181 }
182 quoted := quoteStrings(slice)
183 if maxLength > len(quoted) {
184 maxLength = len(quoted)
185 }
186 if maxLength > 2 {
187 return fmt.Sprintf("%v, or %v", strings.Join(quoted[0:maxLength-1], ", "), quoted[maxLength-1])
188 }
189 if maxLength > 1 {
190 return fmt.Sprintf("%v or %v", strings.Join(quoted[0:maxLength-1], ", "), quoted[maxLength-1])
191 }
192 return quoted[0]
193}
194func UndefinedFieldMessage(fieldName string, ttypeName string, suggestedTypeNames []string, suggestedFieldNames []string) string {
195 message := fmt.Sprintf(`Cannot query field "%v" on type "%v".`, fieldName, ttypeName)
196 if len(suggestedTypeNames) > 0 {
197 message = fmt.Sprintf(`%v Did you mean to use an inline fragment on %v?`, message, quotedOrList(suggestedTypeNames))
198 } else if len(suggestedFieldNames) > 0 {
199 message = fmt.Sprintf(`%v Did you mean %v?`, message, quotedOrList(suggestedFieldNames))
200 }
201 return message
202}
203
204// FieldsOnCorrectTypeRule Fields on correct type
205//
206// A GraphQL document is only valid if all fields selected are defined by the
207// parent type, or are an allowed meta field such as __typenamme
208func FieldsOnCorrectTypeRule(context *ValidationContext) *ValidationRuleInstance {
209 visitorOpts := &visitor.VisitorOptions{
210 KindFuncMap: map[string]visitor.NamedVisitFuncs{
211 kinds.Field: {
212 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
213 var action = visitor.ActionNoChange
214 var result interface{}
215 if node, ok := p.Node.(*ast.Field); ok {
216 ttype := context.ParentType()
217 if ttype == nil {
218 return action, result
219 }
220 if t, ok := ttype.(*Object); ok && t == nil {
221 return action, result
222 }
223 if t, ok := ttype.(*Interface); ok && t == nil {
224 return action, result
225 }
226 if t, ok := ttype.(*Union); ok && t == nil {
227 return action, result
228 }
229 fieldDef := context.FieldDef()
230 if fieldDef == nil {
231 // This field doesn't exist, lets look for suggestions.
232 nodeName := ""
233 if node.Name != nil {
234 nodeName = node.Name.Value
235 }
236 // First determine if there are any suggested types to condition on.
237 suggestedTypeNames := getSuggestedTypeNames(context.Schema(), ttype, nodeName)
238
239 // If there are no suggested types, then perhaps this was a typo?
240 suggestedFieldNames := []string{}
241 if len(suggestedTypeNames) == 0 {
242 suggestedFieldNames = getSuggestedFieldNames(context.Schema(), ttype, nodeName)
243 }
244 reportError(
245 context,
246 UndefinedFieldMessage(nodeName, ttype.Name(), suggestedTypeNames, suggestedFieldNames),
247 []ast.Node{node},
248 )
249 }
250 }
251 return action, result
252 },
253 },
254 },
255 }
256 return &ValidationRuleInstance{
257 VisitorOpts: visitorOpts,
258 }
259}
260
261// getSuggestedTypeNames Go through all of the implementations of type, as well as the interfaces
262// that they implement. If any of those types include the provided field,
263// suggest them, sorted by how often the type is referenced, starting
264// with Interfaces.
265func getSuggestedTypeNames(schema *Schema, ttype Output, fieldName string) []string {
266
267 possibleTypes := schema.PossibleTypes(ttype)
268
269 suggestedObjectTypes := []string{}
270 suggestedInterfaces := []*suggestedInterface{}
271 // stores a map of interface name => index in suggestedInterfaces
272 suggestedInterfaceMap := map[string]int{}
273 // stores a maps of object name => true to remove duplicates from results
274 suggestedObjectMap := map[string]bool{}
275
276 for _, possibleType := range possibleTypes {
277 if field, ok := possibleType.Fields()[fieldName]; !ok || field == nil {
278 continue
279 }
280 // This object type defines this field.
281 suggestedObjectTypes = append(suggestedObjectTypes, possibleType.Name())
282 suggestedObjectMap[possibleType.Name()] = true
283
284 for _, possibleInterface := range possibleType.Interfaces() {
285 if field, ok := possibleInterface.Fields()[fieldName]; !ok || field == nil {
286 continue
287 }
288
289 // This interface type defines this field.
290
291 // - find the index of the suggestedInterface and retrieving the interface
292 // - increase count
293 index, ok := suggestedInterfaceMap[possibleInterface.Name()]
294 if !ok {
295 suggestedInterfaces = append(suggestedInterfaces, &suggestedInterface{
296 name: possibleInterface.Name(),
297 count: 0,
298 })
299 index = len(suggestedInterfaces) - 1
300 suggestedInterfaceMap[possibleInterface.Name()] = index
301 }
302 if index < len(suggestedInterfaces) {
303 s := suggestedInterfaces[index]
304 if s.name == possibleInterface.Name() {
305 s.count = s.count + 1
306 }
307 }
308 }
309 }
310
311 // sort results (by count usage for interfaces, alphabetical order for objects)
312 sort.Sort(suggestedInterfaceSortedSlice(suggestedInterfaces))
313 sort.Sort(sort.StringSlice(suggestedObjectTypes))
314
315 // return concatenated slices of both interface and object type names
316 // and removing duplicates
317 // ordered by: interface (sorted) and object (sorted)
318 results := []string{}
319 for _, s := range suggestedInterfaces {
320 if _, ok := suggestedObjectMap[s.name]; !ok {
321 results = append(results, s.name)
322
323 }
324 }
325 results = append(results, suggestedObjectTypes...)
326 return results
327}
328
329// getSuggestedFieldNames For the field name provided, determine if there are any similar field names
330// that may be the result of a typo.
331func getSuggestedFieldNames(schema *Schema, ttype Output, fieldName string) []string {
332
333 fields := FieldDefinitionMap{}
334 switch ttype := ttype.(type) {
335 case *Object:
336 fields = ttype.Fields()
337 case *Interface:
338 fields = ttype.Fields()
339 default:
340 return []string{}
341 }
342
343 possibleFieldNames := []string{}
344 for possibleFieldName := range fields {
345 possibleFieldNames = append(possibleFieldNames, possibleFieldName)
346 }
347 return suggestionList(fieldName, possibleFieldNames)
348}
349
350// suggestedInterface an internal struct to sort interface by usage count
351type suggestedInterface struct {
352 name string
353 count int
354}
355type suggestedInterfaceSortedSlice []*suggestedInterface
356
357func (s suggestedInterfaceSortedSlice) Len() int {
358 return len(s)
359}
360func (s suggestedInterfaceSortedSlice) Swap(i, j int) {
361 s[i], s[j] = s[j], s[i]
362}
363func (s suggestedInterfaceSortedSlice) Less(i, j int) bool {
364 if s[i].count == s[j].count {
365 return s[i].name < s[j].name
366 }
367 return s[i].count > s[j].count
368}
369
370// FragmentsOnCompositeTypesRule Fragments on composite type
371//
372// Fragments use a type condition to determine if they apply, since fragments
373// can only be spread into a composite type (object, interface, or union), the
374// type condition must also be a composite type.
375func FragmentsOnCompositeTypesRule(context *ValidationContext) *ValidationRuleInstance {
376 visitorOpts := &visitor.VisitorOptions{
377 KindFuncMap: map[string]visitor.NamedVisitFuncs{
378 kinds.InlineFragment: {
379 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
380 if node, ok := p.Node.(*ast.InlineFragment); ok {
381 ttype := context.Type()
382 if node.TypeCondition != nil && ttype != nil && !IsCompositeType(ttype) {
383 reportError(
384 context,
385 fmt.Sprintf(`Fragment cannot condition on non composite type "%v".`, ttype),
386 []ast.Node{node.TypeCondition},
387 )
388 }
389 }
390 return visitor.ActionNoChange, nil
391 },
392 },
393 kinds.FragmentDefinition: {
394 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
395 if node, ok := p.Node.(*ast.FragmentDefinition); ok {
396 ttype := context.Type()
397 if ttype != nil && !IsCompositeType(ttype) {
398 nodeName := ""
399 if node.Name != nil {
400 nodeName = node.Name.Value
401 }
402 reportError(
403 context,
404 fmt.Sprintf(`Fragment "%v" cannot condition on non composite type "%v".`, nodeName, printer.Print(node.TypeCondition)),
405 []ast.Node{node.TypeCondition},
406 )
407 }
408 }
409 return visitor.ActionNoChange, nil
410 },
411 },
412 },
413 }
414 return &ValidationRuleInstance{
415 VisitorOpts: visitorOpts,
416 }
417}
418
419func unknownArgMessage(argName string, fieldName string, parentTypeName string, suggestedArgs []string) string {
420 message := fmt.Sprintf(`Unknown argument "%v" on field "%v" of type "%v".`, argName, fieldName, parentTypeName)
421
422 if len(suggestedArgs) > 0 {
423 message = fmt.Sprintf(`%v Did you mean %v?`, message, quotedOrList(suggestedArgs))
424 }
425
426 return message
427}
428
429func unknownDirectiveArgMessage(argName string, directiveName string, suggestedArgs []string) string {
430 message := fmt.Sprintf(`Unknown argument "%v" on directive "@%v".`, argName, directiveName)
431
432 if len(suggestedArgs) > 0 {
433 message = fmt.Sprintf(`%v Did you mean %v?`, message, quotedOrList(suggestedArgs))
434 }
435
436 return message
437}
438
439// KnownArgumentNamesRule Known argument names
440//
441// A GraphQL field is only valid if all supplied arguments are defined by
442// that field.
443func KnownArgumentNamesRule(context *ValidationContext) *ValidationRuleInstance {
444 visitorOpts := &visitor.VisitorOptions{
445 KindFuncMap: map[string]visitor.NamedVisitFuncs{
446 kinds.Argument: {
447 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
448 var action = visitor.ActionNoChange
449 var result interface{}
450 if node, ok := p.Node.(*ast.Argument); ok {
451 var argumentOf ast.Node
452 if len(p.Ancestors) > 0 {
453 argumentOf = p.Ancestors[len(p.Ancestors)-1]
454 }
455 if argumentOf == nil {
456 return action, result
457 }
458 var fieldArgDef *Argument
459 if argumentOf.GetKind() == kinds.Field {
460 fieldDef := context.FieldDef()
461 if fieldDef == nil {
462 return action, result
463 }
464 nodeName := ""
465 if node.Name != nil {
466 nodeName = node.Name.Value
467 }
468 argNames := []string{}
469 for _, arg := range fieldDef.Args {
470 argNames = append(argNames, arg.Name())
471 if arg.Name() == nodeName {
472 fieldArgDef = arg
473 }
474 }
475 if fieldArgDef == nil {
476 parentType := context.ParentType()
477 parentTypeName := ""
478 if parentType != nil {
479 parentTypeName = parentType.Name()
480 }
481 reportError(
482 context,
483 unknownArgMessage(nodeName, fieldDef.Name, parentTypeName, suggestionList(nodeName, argNames)),
484 []ast.Node{node},
485 )
486 }
487 } else if argumentOf.GetKind() == kinds.Directive {
488 directive := context.Directive()
489 if directive == nil {
490 return action, result
491 }
492 nodeName := ""
493 if node.Name != nil {
494 nodeName = node.Name.Value
495 }
496 argNames := []string{}
497 var directiveArgDef *Argument
498 for _, arg := range directive.Args {
499 argNames = append(argNames, arg.Name())
500 if arg.Name() == nodeName {
501 directiveArgDef = arg
502 }
503 }
504 if directiveArgDef == nil {
505 reportError(
506 context,
507 unknownDirectiveArgMessage(nodeName, directive.Name, suggestionList(nodeName, argNames)),
508 []ast.Node{node},
509 )
510 }
511 }
512
513 }
514 return action, result
515 },
516 },
517 },
518 }
519 return &ValidationRuleInstance{
520 VisitorOpts: visitorOpts,
521 }
522}
523
524func MisplaceDirectiveMessage(directiveName string, location string) string {
525 return fmt.Sprintf(`Directive "%v" may not be used on %v.`, directiveName, location)
526}
527
528// KnownDirectivesRule Known directives
529//
530// A GraphQL document is only valid if all `@directives` are known by the
531// schema and legally positioned.
532func KnownDirectivesRule(context *ValidationContext) *ValidationRuleInstance {
533 visitorOpts := &visitor.VisitorOptions{
534 KindFuncMap: map[string]visitor.NamedVisitFuncs{
535 kinds.Directive: {
536 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
537 var action = visitor.ActionNoChange
538 var result interface{}
539 if node, ok := p.Node.(*ast.Directive); ok {
540
541 nodeName := ""
542 if node.Name != nil {
543 nodeName = node.Name.Value
544 }
545
546 var directiveDef *Directive
547 for _, def := range context.Schema().Directives() {
548 if def.Name == nodeName {
549 directiveDef = def
550 }
551 }
552 if directiveDef == nil {
553 return reportError(
554 context,
555 fmt.Sprintf(`Unknown directive "%v".`, nodeName),
556 []ast.Node{node},
557 )
558 }
559
560 candidateLocation := getDirectiveLocationForASTPath(p.Ancestors)
561
562 directiveHasLocation := false
563 for _, loc := range directiveDef.Locations {
564 if loc == candidateLocation {
565 directiveHasLocation = true
566 break
567 }
568 }
569
570 if candidateLocation == "" {
571 reportError(
572 context,
573 MisplaceDirectiveMessage(nodeName, node.GetKind()),
574 []ast.Node{node},
575 )
576 } else if !directiveHasLocation {
577 reportError(
578 context,
579 MisplaceDirectiveMessage(nodeName, candidateLocation),
580 []ast.Node{node},
581 )
582 }
583
584 }
585 return action, result
586 },
587 },
588 },
589 }
590 return &ValidationRuleInstance{
591 VisitorOpts: visitorOpts,
592 }
593}
594
595func getDirectiveLocationForASTPath(ancestors []ast.Node) string {
596 var appliedTo ast.Node
597 if len(ancestors) > 0 {
598 appliedTo = ancestors[len(ancestors)-1]
599 }
600 if appliedTo == nil {
601 return ""
602 }
603 kind := appliedTo.GetKind()
604 if kind == kinds.OperationDefinition {
605 appliedTo, _ := appliedTo.(*ast.OperationDefinition)
606 if appliedTo.Operation == ast.OperationTypeQuery {
607 return DirectiveLocationQuery
608 }
609 if appliedTo.Operation == ast.OperationTypeMutation {
610 return DirectiveLocationMutation
611 }
612 if appliedTo.Operation == ast.OperationTypeSubscription {
613 return DirectiveLocationSubscription
614 }
615 }
616 if kind == kinds.Field {
617 return DirectiveLocationField
618 }
619 if kind == kinds.FragmentSpread {
620 return DirectiveLocationFragmentSpread
621 }
622 if kind == kinds.InlineFragment {
623 return DirectiveLocationInlineFragment
624 }
625 if kind == kinds.FragmentDefinition {
626 return DirectiveLocationFragmentDefinition
627 }
628 if kind == kinds.SchemaDefinition {
629 return DirectiveLocationSchema
630 }
631 if kind == kinds.ScalarDefinition {
632 return DirectiveLocationScalar
633 }
634 if kind == kinds.ObjectDefinition {
635 return DirectiveLocationObject
636 }
637 if kind == kinds.FieldDefinition {
638 return DirectiveLocationFieldDefinition
639 }
640 if kind == kinds.InterfaceDefinition {
641 return DirectiveLocationInterface
642 }
643 if kind == kinds.UnionDefinition {
644 return DirectiveLocationUnion
645 }
646 if kind == kinds.EnumDefinition {
647 return DirectiveLocationEnum
648 }
649 if kind == kinds.EnumValueDefinition {
650 return DirectiveLocationEnumValue
651 }
652 if kind == kinds.InputObjectDefinition {
653 return DirectiveLocationInputObject
654 }
655 if kind == kinds.InputValueDefinition {
656 var parentNode ast.Node
657 if len(ancestors) >= 3 {
658 parentNode = ancestors[len(ancestors)-3]
659 }
660 if parentNode.GetKind() == kinds.InputObjectDefinition {
661 return DirectiveLocationInputFieldDefinition
662 } else {
663 return DirectiveLocationArgumentDefinition
664 }
665 }
666 return ""
667}
668
669// KnownFragmentNamesRule Known fragment names
670//
671// A GraphQL document is only valid if all `...Fragment` fragment spreads refer
672// to fragments defined in the same document.
673func KnownFragmentNamesRule(context *ValidationContext) *ValidationRuleInstance {
674 visitorOpts := &visitor.VisitorOptions{
675 KindFuncMap: map[string]visitor.NamedVisitFuncs{
676 kinds.FragmentSpread: {
677 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
678 var action = visitor.ActionNoChange
679 var result interface{}
680 if node, ok := p.Node.(*ast.FragmentSpread); ok {
681
682 fragmentName := ""
683 if node.Name != nil {
684 fragmentName = node.Name.Value
685 }
686
687 fragment := context.Fragment(fragmentName)
688 if fragment == nil {
689 reportError(
690 context,
691 fmt.Sprintf(`Unknown fragment "%v".`, fragmentName),
692 []ast.Node{node.Name},
693 )
694 }
695 }
696 return action, result
697 },
698 },
699 },
700 }
701 return &ValidationRuleInstance{
702 VisitorOpts: visitorOpts,
703 }
704}
705
706func unknownTypeMessage(typeName string, suggestedTypes []string) string {
707 message := fmt.Sprintf(`Unknown type "%v".`, typeName)
708 if len(suggestedTypes) > 0 {
709 message = fmt.Sprintf(`%v Did you mean %v?`, message, quotedOrList(suggestedTypes))
710 }
711
712 return message
713}
714
715// KnownTypeNamesRule Known type names
716//
717// A GraphQL document is only valid if referenced types (specifically
718// variable definitions and fragment conditions) are defined by the type schema.
719func KnownTypeNamesRule(context *ValidationContext) *ValidationRuleInstance {
720 visitorOpts := &visitor.VisitorOptions{
721 KindFuncMap: map[string]visitor.NamedVisitFuncs{
722 kinds.ObjectDefinition: {
723 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
724 return visitor.ActionSkip, nil
725 },
726 },
727 kinds.InterfaceDefinition: {
728 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
729 return visitor.ActionSkip, nil
730 },
731 },
732 kinds.UnionDefinition: {
733 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
734 return visitor.ActionSkip, nil
735 },
736 },
737 kinds.InputObjectDefinition: {
738 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
739 return visitor.ActionSkip, nil
740 },
741 },
742 kinds.Named: {
743 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
744 if node, ok := p.Node.(*ast.Named); ok {
745 typeNameValue := ""
746 typeName := node.Name
747 if typeName != nil {
748 typeNameValue = typeName.Value
749 }
750 ttype := context.Schema().Type(typeNameValue)
751 if ttype == nil {
752 suggestedTypes := []string{}
753 for key := range context.Schema().TypeMap() {
754 suggestedTypes = append(suggestedTypes, key)
755 }
756 reportError(
757 context,
758 unknownTypeMessage(typeNameValue, suggestionList(typeNameValue, suggestedTypes)),
759 []ast.Node{node},
760 )
761 }
762 }
763 return visitor.ActionNoChange, nil
764 },
765 },
766 },
767 }
768 return &ValidationRuleInstance{
769 VisitorOpts: visitorOpts,
770 }
771}
772
773// LoneAnonymousOperationRule Lone anonymous operation
774//
775// A GraphQL document is only valid if when it contains an anonymous operation
776// (the query short-hand) that it contains only that one operation definition.
777func LoneAnonymousOperationRule(context *ValidationContext) *ValidationRuleInstance {
778 var operationCount = 0
779 visitorOpts := &visitor.VisitorOptions{
780 KindFuncMap: map[string]visitor.NamedVisitFuncs{
781 kinds.Document: {
782 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
783 if node, ok := p.Node.(*ast.Document); ok {
784 operationCount = 0
785 for _, definition := range node.Definitions {
786 if definition.GetKind() == kinds.OperationDefinition {
787 operationCount = operationCount + 1
788 }
789 }
790 }
791 return visitor.ActionNoChange, nil
792 },
793 },
794 kinds.OperationDefinition: {
795 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
796 if node, ok := p.Node.(*ast.OperationDefinition); ok {
797 if node.Name == nil && operationCount > 1 {
798 reportError(
799 context,
800 `This anonymous operation must be the only defined operation.`,
801 []ast.Node{node},
802 )
803 }
804 }
805 return visitor.ActionNoChange, nil
806 },
807 },
808 },
809 }
810 return &ValidationRuleInstance{
811 VisitorOpts: visitorOpts,
812 }
813}
814
815func CycleErrorMessage(fragName string, spreadNames []string) string {
816 via := ""
817 if len(spreadNames) > 0 {
818 via = " via " + strings.Join(spreadNames, ", ")
819 }
820 return fmt.Sprintf(`Cannot spread fragment "%v" within itself%v.`, fragName, via)
821}
822
823// NoFragmentCyclesRule No fragment cycles
824func NoFragmentCyclesRule(context *ValidationContext) *ValidationRuleInstance {
825
826 // Tracks already visited fragments to maintain O(N) and to ensure that cycles
827 // are not redundantly reported.
828 visitedFrags := map[string]bool{}
829
830 // Array of AST nodes used to produce meaningful errors
831 spreadPath := []*ast.FragmentSpread{}
832
833 // Position in the spread path
834 spreadPathIndexByName := map[string]int{}
835
836 // This does a straight-forward DFS to find cycles.
837 // It does not terminate when a cycle was found but continues to explore
838 // the graph to find all possible cycles.
839 var detectCycleRecursive func(fragment *ast.FragmentDefinition)
840 detectCycleRecursive = func(fragment *ast.FragmentDefinition) {
841
842 fragmentName := ""
843 if fragment.Name != nil {
844 fragmentName = fragment.Name.Value
845 }
846 visitedFrags[fragmentName] = true
847
848 spreadNodes := context.FragmentSpreads(fragment.SelectionSet)
849 if len(spreadNodes) == 0 {
850 return
851 }
852
853 spreadPathIndexByName[fragmentName] = len(spreadPath)
854
855 for _, spreadNode := range spreadNodes {
856
857 spreadName := ""
858 if spreadNode.Name != nil {
859 spreadName = spreadNode.Name.Value
860 }
861 cycleIndex, ok := spreadPathIndexByName[spreadName]
862 if !ok {
863 spreadPath = append(spreadPath, spreadNode)
864 if visited, ok := visitedFrags[spreadName]; !ok || !visited {
865 spreadFragment := context.Fragment(spreadName)
866 if spreadFragment != nil {
867 detectCycleRecursive(spreadFragment)
868 }
869 }
870 spreadPath = spreadPath[:len(spreadPath)-1]
871 } else {
872 cyclePath := spreadPath[cycleIndex:]
873
874 spreadNames := []string{}
875 for _, s := range cyclePath {
876 name := ""
877 if s.Name != nil {
878 name = s.Name.Value
879 }
880 spreadNames = append(spreadNames, name)
881 }
882
883 nodes := []ast.Node{}
884 for _, c := range cyclePath {
885 nodes = append(nodes, c)
886 }
887 nodes = append(nodes, spreadNode)
888
889 reportError(
890 context,
891 CycleErrorMessage(spreadName, spreadNames),
892 nodes,
893 )
894 }
895
896 }
897 delete(spreadPathIndexByName, fragmentName)
898
899 }
900
901 visitorOpts := &visitor.VisitorOptions{
902 KindFuncMap: map[string]visitor.NamedVisitFuncs{
903 kinds.OperationDefinition: {
904 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
905 return visitor.ActionSkip, nil
906 },
907 },
908 kinds.FragmentDefinition: {
909 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
910 if node, ok := p.Node.(*ast.FragmentDefinition); ok && node != nil {
911 nodeName := ""
912 if node.Name != nil {
913 nodeName = node.Name.Value
914 }
915 if _, ok := visitedFrags[nodeName]; !ok {
916 detectCycleRecursive(node)
917 }
918 }
919 return visitor.ActionSkip, nil
920 },
921 },
922 },
923 }
924 return &ValidationRuleInstance{
925 VisitorOpts: visitorOpts,
926 }
927}
928
929func UndefinedVarMessage(varName string, opName string) string {
930 if opName != "" {
931 return fmt.Sprintf(`Variable "$%v" is not defined by operation "%v".`, varName, opName)
932 }
933 return fmt.Sprintf(`Variable "$%v" is not defined.`, varName)
934}
935
936// NoUndefinedVariablesRule No undefined variables
937//
938// A GraphQL operation is only valid if all variables encountered, both directly
939// and via fragment spreads, are defined by that operation.
940func NoUndefinedVariablesRule(context *ValidationContext) *ValidationRuleInstance {
941 var variableNameDefined = map[string]bool{}
942
943 visitorOpts := &visitor.VisitorOptions{
944 KindFuncMap: map[string]visitor.NamedVisitFuncs{
945 kinds.OperationDefinition: {
946 Enter: func(p visitor.VisitFuncParams) (string, interface{}) {
947 variableNameDefined = map[string]bool{}
948 return visitor.ActionNoChange, nil
949 },
950 Leave: func(p visitor.VisitFuncParams) (string, interface{}) {
951 if operation, ok := p.Node.(*ast.OperationDefinition); ok && operation != nil {
952 usages := context.RecursiveVariableUsages(operation)
953
954 for _, usage := range usages {
955 if usage == nil {
956 continue
957 }
958 if usage.Node == nil {
959 continue
960 }
961 varName := ""
962 if usage.Node.Name != nil {
963 varName = usage.Node.Name.Value
964 }
965 opName := ""
966 if operation.Name != nil {
967 opName = operation.Name.Value
968 }
969 if res, ok := variableNameDefined[varName]; !ok || !res {
970 reportError(
971 context,
972 UndefinedVarMessage(varName, opName),
973 []ast.Node{usage.Node, operation},
974 )
975 }
976 }
977 }
978 return visitor.ActionNoChange, nil
979 },
980 },
981 kinds.VariableDefinition: {
982 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
983 if node, ok := p.Node.(*ast.VariableDefinition); ok && node != nil {
984 variableName := ""
985 if node.Variable != nil && node.Variable.Name != nil {
986 variableName = node.Variable.Name.Value
987 }
988 variableNameDefined[variableName] = true
989 }
990 return visitor.ActionNoChange, nil
991 },
992 },
993 },
994 }
995 return &ValidationRuleInstance{
996 VisitorOpts: visitorOpts,
997 }
998}
999
1000// NoUnusedFragmentsRule No unused fragments
1001//
1002// A GraphQL document is only valid if all fragment definitions are spread
1003// within operations, or spread within other fragments spread within operations.
1004func NoUnusedFragmentsRule(context *ValidationContext) *ValidationRuleInstance {
1005
1006 var fragmentDefs = []*ast.FragmentDefinition{}
1007 var operationDefs = []*ast.OperationDefinition{}
1008
1009 visitorOpts := &visitor.VisitorOptions{
1010 KindFuncMap: map[string]visitor.NamedVisitFuncs{
1011 kinds.OperationDefinition: {
1012 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
1013 if node, ok := p.Node.(*ast.OperationDefinition); ok && node != nil {
1014 operationDefs = append(operationDefs, node)
1015 }
1016 return visitor.ActionSkip, nil
1017 },
1018 },
1019 kinds.FragmentDefinition: {
1020 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
1021 if node, ok := p.Node.(*ast.FragmentDefinition); ok && node != nil {
1022 fragmentDefs = append(fragmentDefs, node)
1023 }
1024 return visitor.ActionSkip, nil
1025 },
1026 },
1027 kinds.Document: {
1028 Leave: func(p visitor.VisitFuncParams) (string, interface{}) {
1029 fragmentNameUsed := map[string]bool{}
1030 for _, operation := range operationDefs {
1031 fragments := context.RecursivelyReferencedFragments(operation)
1032 for _, fragment := range fragments {
1033 fragName := ""
1034 if fragment.Name != nil {
1035 fragName = fragment.Name.Value
1036 }
1037 fragmentNameUsed[fragName] = true
1038 }
1039 }
1040
1041 for _, def := range fragmentDefs {
1042 defName := ""
1043 if def.Name != nil {
1044 defName = def.Name.Value
1045 }
1046
1047 isFragNameUsed, ok := fragmentNameUsed[defName]
1048 if !ok || isFragNameUsed != true {
1049 reportError(
1050 context,
1051 fmt.Sprintf(`Fragment "%v" is never used.`, defName),
1052 []ast.Node{def},
1053 )
1054 }
1055 }
1056 return visitor.ActionNoChange, nil
1057 },
1058 },
1059 },
1060 }
1061 return &ValidationRuleInstance{
1062 VisitorOpts: visitorOpts,
1063 }
1064}
1065
1066func UnusedVariableMessage(varName string, opName string) string {
1067 if opName != "" {
1068 return fmt.Sprintf(`Variable "$%v" is never used in operation "%v".`, varName, opName)
1069 }
1070 return fmt.Sprintf(`Variable "$%v" is never used.`, varName)
1071}
1072
1073// NoUnusedVariablesRule No unused variables
1074//
1075// A GraphQL operation is only valid if all variables defined by an operation
1076// are used, either directly or within a spread fragment.
1077func NoUnusedVariablesRule(context *ValidationContext) *ValidationRuleInstance {
1078
1079 var variableDefs = []*ast.VariableDefinition{}
1080
1081 visitorOpts := &visitor.VisitorOptions{
1082 KindFuncMap: map[string]visitor.NamedVisitFuncs{
1083 kinds.OperationDefinition: {
1084 Enter: func(p visitor.VisitFuncParams) (string, interface{}) {
1085 variableDefs = []*ast.VariableDefinition{}
1086 return visitor.ActionNoChange, nil
1087 },
1088 Leave: func(p visitor.VisitFuncParams) (string, interface{}) {
1089 if operation, ok := p.Node.(*ast.OperationDefinition); ok && operation != nil {
1090 variableNameUsed := map[string]bool{}
1091 usages := context.RecursiveVariableUsages(operation)
1092
1093 for _, usage := range usages {
1094 varName := ""
1095 if usage != nil && usage.Node != nil && usage.Node.Name != nil {
1096 varName = usage.Node.Name.Value
1097 }
1098 if varName != "" {
1099 variableNameUsed[varName] = true
1100 }
1101 }
1102 for _, variableDef := range variableDefs {
1103 variableName := ""
1104 if variableDef != nil && variableDef.Variable != nil && variableDef.Variable.Name != nil {
1105 variableName = variableDef.Variable.Name.Value
1106 }
1107 opName := ""
1108 if operation.Name != nil {
1109 opName = operation.Name.Value
1110 }
1111 if res, ok := variableNameUsed[variableName]; !ok || !res {
1112 reportError(
1113 context,
1114 UnusedVariableMessage(variableName, opName),
1115 []ast.Node{variableDef},
1116 )
1117 }
1118 }
1119
1120 }
1121
1122 return visitor.ActionNoChange, nil
1123 },
1124 },
1125 kinds.VariableDefinition: {
1126 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
1127 if def, ok := p.Node.(*ast.VariableDefinition); ok && def != nil {
1128 variableDefs = append(variableDefs, def)
1129 }
1130 return visitor.ActionNoChange, nil
1131 },
1132 },
1133 },
1134 }
1135 return &ValidationRuleInstance{
1136 VisitorOpts: visitorOpts,
1137 }
1138}
1139
1140func getFragmentType(context *ValidationContext, name string) Type {
1141 frag := context.Fragment(name)
1142 if frag == nil {
1143 return nil
1144 }
1145 ttype, _ := typeFromAST(*context.Schema(), frag.TypeCondition)
1146 return ttype
1147}
1148
1149func doTypesOverlap(schema *Schema, t1 Type, t2 Type) bool {
1150 if t1 == t2 {
1151 return true
1152 }
1153 if _, ok := t1.(*Object); ok {
1154 if _, ok := t2.(*Object); ok {
1155 return false
1156 }
1157 if t2, ok := t2.(Abstract); ok {
1158 for _, ttype := range schema.PossibleTypes(t2) {
1159 if ttype == t1 {
1160 return true
1161 }
1162 }
1163 return false
1164 }
1165 }
1166 if t1, ok := t1.(Abstract); ok {
1167 if _, ok := t2.(*Object); ok {
1168 for _, ttype := range schema.PossibleTypes(t1) {
1169 if ttype == t2 {
1170 return true
1171 }
1172 }
1173 return false
1174 }
1175 t1TypeNames := map[string]bool{}
1176 for _, ttype := range schema.PossibleTypes(t1) {
1177 t1TypeNames[ttype.Name()] = true
1178 }
1179 if t2, ok := t2.(Abstract); ok {
1180 for _, ttype := range schema.PossibleTypes(t2) {
1181 if hasT1TypeName, _ := t1TypeNames[ttype.Name()]; hasT1TypeName {
1182 return true
1183 }
1184 }
1185 return false
1186 }
1187 }
1188 return false
1189}
1190
1191// PossibleFragmentSpreadsRule Possible fragment spread
1192//
1193// A fragment spread is only valid if the type condition could ever possibly
1194// be true: if there is a non-empty intersection of the possible parent types,
1195// and possible types which pass the type condition.
1196func PossibleFragmentSpreadsRule(context *ValidationContext) *ValidationRuleInstance {
1197
1198 visitorOpts := &visitor.VisitorOptions{
1199 KindFuncMap: map[string]visitor.NamedVisitFuncs{
1200 kinds.InlineFragment: {
1201 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
1202 if node, ok := p.Node.(*ast.InlineFragment); ok && node != nil {
1203 fragType := context.Type()
1204 parentType, _ := context.ParentType().(Type)
1205
1206 if fragType != nil && parentType != nil && !doTypesOverlap(context.Schema(), fragType, parentType) {
1207 reportError(
1208 context,
1209 fmt.Sprintf(`Fragment cannot be spread here as objects of `+
1210 `type "%v" can never be of type "%v".`, parentType, fragType),
1211 []ast.Node{node},
1212 )
1213 }
1214 }
1215 return visitor.ActionNoChange, nil
1216 },
1217 },
1218 kinds.FragmentSpread: {
1219 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
1220 if node, ok := p.Node.(*ast.FragmentSpread); ok && node != nil {
1221 fragName := ""
1222 if node.Name != nil {
1223 fragName = node.Name.Value
1224 }
1225 fragType := getFragmentType(context, fragName)
1226 parentType, _ := context.ParentType().(Type)
1227 if fragType != nil && parentType != nil && !doTypesOverlap(context.Schema(), fragType, parentType) {
1228 reportError(
1229 context,
1230 fmt.Sprintf(`Fragment "%v" cannot be spread here as objects of `+
1231 `type "%v" can never be of type "%v".`, fragName, parentType, fragType),
1232 []ast.Node{node},
1233 )
1234 }
1235 }
1236 return visitor.ActionNoChange, nil
1237 },
1238 },
1239 },
1240 }
1241 return &ValidationRuleInstance{
1242 VisitorOpts: visitorOpts,
1243 }
1244}
1245
1246// ProvidedNonNullArgumentsRule Provided required arguments
1247//
1248// A field or directive is only valid if all required (non-null) field arguments
1249// have been provided.
1250func ProvidedNonNullArgumentsRule(context *ValidationContext) *ValidationRuleInstance {
1251
1252 visitorOpts := &visitor.VisitorOptions{
1253 KindFuncMap: map[string]visitor.NamedVisitFuncs{
1254 kinds.Field: {
1255 Leave: func(p visitor.VisitFuncParams) (string, interface{}) {
1256 // Validate on leave to allow for deeper errors to appear first.
1257 if fieldAST, ok := p.Node.(*ast.Field); ok && fieldAST != nil {
1258 fieldDef := context.FieldDef()
1259 if fieldDef == nil {
1260 return visitor.ActionSkip, nil
1261 }
1262
1263 argASTs := fieldAST.Arguments
1264
1265 argASTMap := map[string]*ast.Argument{}
1266 for _, arg := range argASTs {
1267 name := ""
1268 if arg.Name != nil {
1269 name = arg.Name.Value
1270 }
1271 argASTMap[name] = arg
1272 }
1273 for _, argDef := range fieldDef.Args {
1274 argAST, _ := argASTMap[argDef.Name()]
1275 if argAST == nil {
1276 if argDefType, ok := argDef.Type.(*NonNull); ok {
1277 fieldName := ""
1278 if fieldAST.Name != nil {
1279 fieldName = fieldAST.Name.Value
1280 }
1281 reportError(
1282 context,
1283 fmt.Sprintf(`Field "%v" argument "%v" of type "%v" `+
1284 `is required but not provided.`, fieldName, argDef.Name(), argDefType),
1285 []ast.Node{fieldAST},
1286 )
1287 }
1288 }
1289 }
1290 }
1291 return visitor.ActionNoChange, nil
1292 },
1293 },
1294 kinds.Directive: {
1295 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
1296 // Validate on leave to allow for deeper errors to appear first.
1297
1298 if directiveAST, ok := p.Node.(*ast.Directive); ok && directiveAST != nil {
1299 directiveDef := context.Directive()
1300 if directiveDef == nil {
1301 return visitor.ActionSkip, nil
1302 }
1303 argASTs := directiveAST.Arguments
1304
1305 argASTMap := map[string]*ast.Argument{}
1306 for _, arg := range argASTs {
1307 name := ""
1308 if arg.Name != nil {
1309 name = arg.Name.Value
1310 }
1311 argASTMap[name] = arg
1312 }
1313
1314 for _, argDef := range directiveDef.Args {
1315 argAST, _ := argASTMap[argDef.Name()]
1316 if argAST == nil {
1317 if argDefType, ok := argDef.Type.(*NonNull); ok {
1318 directiveName := ""
1319 if directiveAST.Name != nil {
1320 directiveName = directiveAST.Name.Value
1321 }
1322 reportError(
1323 context,
1324 fmt.Sprintf(`Directive "@%v" argument "%v" of type `+
1325 `"%v" is required but not provided.`, directiveName, argDef.Name(), argDefType),
1326 []ast.Node{directiveAST},
1327 )
1328 }
1329 }
1330 }
1331 }
1332 return visitor.ActionNoChange, nil
1333 },
1334 },
1335 },
1336 }
1337 return &ValidationRuleInstance{
1338 VisitorOpts: visitorOpts,
1339 }
1340}
1341
1342// ScalarLeafsRule Scalar leafs
1343//
1344// A GraphQL document is valid only if all leaf fields (fields without
1345// sub selections) are of scalar or enum types.
1346func ScalarLeafsRule(context *ValidationContext) *ValidationRuleInstance {
1347
1348 visitorOpts := &visitor.VisitorOptions{
1349 KindFuncMap: map[string]visitor.NamedVisitFuncs{
1350 kinds.Field: {
1351 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
1352 if node, ok := p.Node.(*ast.Field); ok && node != nil {
1353 nodeName := ""
1354 if node.Name != nil {
1355 nodeName = node.Name.Value
1356 }
1357 ttype := context.Type()
1358 if ttype != nil {
1359 if IsLeafType(ttype) {
1360 if node.SelectionSet != nil {
1361 reportError(
1362 context,
1363 fmt.Sprintf(`Field "%v" of type "%v" must not have a sub selection.`, nodeName, ttype),
1364 []ast.Node{node.SelectionSet},
1365 )
1366 }
1367 } else if node.SelectionSet == nil {
1368 reportError(
1369 context,
1370 fmt.Sprintf(`Field "%v" of type "%v" must have a sub selection.`, nodeName, ttype),
1371 []ast.Node{node},
1372 )
1373 }
1374 }
1375 }
1376 return visitor.ActionNoChange, nil
1377 },
1378 },
1379 },
1380 }
1381 return &ValidationRuleInstance{
1382 VisitorOpts: visitorOpts,
1383 }
1384}
1385
1386// UniqueArgumentNamesRule Unique argument names
1387//
1388// A GraphQL field or directive is only valid if all supplied arguments are
1389// uniquely named.
1390func UniqueArgumentNamesRule(context *ValidationContext) *ValidationRuleInstance {
1391 knownArgNames := map[string]*ast.Name{}
1392
1393 visitorOpts := &visitor.VisitorOptions{
1394 KindFuncMap: map[string]visitor.NamedVisitFuncs{
1395 kinds.Field: {
1396 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
1397 knownArgNames = map[string]*ast.Name{}
1398 return visitor.ActionNoChange, nil
1399 },
1400 },
1401 kinds.Directive: {
1402 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
1403 knownArgNames = map[string]*ast.Name{}
1404 return visitor.ActionNoChange, nil
1405 },
1406 },
1407 kinds.Argument: {
1408 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
1409 if node, ok := p.Node.(*ast.Argument); ok {
1410 argName := ""
1411 if node.Name != nil {
1412 argName = node.Name.Value
1413 }
1414 if nameAST, ok := knownArgNames[argName]; ok {
1415 reportError(
1416 context,
1417 fmt.Sprintf(`There can be only one argument named "%v".`, argName),
1418 []ast.Node{nameAST, node.Name},
1419 )
1420 } else {
1421 knownArgNames[argName] = node.Name
1422 }
1423 }
1424 return visitor.ActionSkip, nil
1425 },
1426 },
1427 },
1428 }
1429 return &ValidationRuleInstance{
1430 VisitorOpts: visitorOpts,
1431 }
1432}
1433
1434// UniqueFragmentNamesRule Unique fragment names
1435//
1436// A GraphQL document is only valid if all defined fragments have unique names.
1437func UniqueFragmentNamesRule(context *ValidationContext) *ValidationRuleInstance {
1438 knownFragmentNames := map[string]*ast.Name{}
1439
1440 visitorOpts := &visitor.VisitorOptions{
1441 KindFuncMap: map[string]visitor.NamedVisitFuncs{
1442 kinds.OperationDefinition: {
1443 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
1444 return visitor.ActionSkip, nil
1445 },
1446 },
1447 kinds.FragmentDefinition: {
1448 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
1449 if node, ok := p.Node.(*ast.FragmentDefinition); ok && node != nil {
1450 fragmentName := ""
1451 if node.Name != nil {
1452 fragmentName = node.Name.Value
1453 }
1454 if nameAST, ok := knownFragmentNames[fragmentName]; ok {
1455 reportError(
1456 context,
1457 fmt.Sprintf(`There can only be one fragment named "%v".`, fragmentName),
1458 []ast.Node{nameAST, node.Name},
1459 )
1460 } else {
1461 knownFragmentNames[fragmentName] = node.Name
1462 }
1463 }
1464 return visitor.ActionSkip, nil
1465 },
1466 },
1467 },
1468 }
1469 return &ValidationRuleInstance{
1470 VisitorOpts: visitorOpts,
1471 }
1472}
1473
1474// UniqueInputFieldNamesRule Unique input field names
1475//
1476// A GraphQL input object value is only valid if all supplied fields are
1477// uniquely named.
1478func UniqueInputFieldNamesRule(context *ValidationContext) *ValidationRuleInstance {
1479 knownNameStack := []map[string]*ast.Name{}
1480 knownNames := map[string]*ast.Name{}
1481
1482 visitorOpts := &visitor.VisitorOptions{
1483 KindFuncMap: map[string]visitor.NamedVisitFuncs{
1484 kinds.ObjectValue: {
1485 Enter: func(p visitor.VisitFuncParams) (string, interface{}) {
1486 knownNameStack = append(knownNameStack, knownNames)
1487 knownNames = map[string]*ast.Name{}
1488 return visitor.ActionNoChange, nil
1489 },
1490 Leave: func(p visitor.VisitFuncParams) (string, interface{}) {
1491 // pop
1492 knownNames, knownNameStack = knownNameStack[len(knownNameStack)-1], knownNameStack[:len(knownNameStack)-1]
1493 return visitor.ActionNoChange, nil
1494 },
1495 },
1496 kinds.ObjectField: {
1497 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
1498 if node, ok := p.Node.(*ast.ObjectField); ok {
1499 fieldName := ""
1500 if node.Name != nil {
1501 fieldName = node.Name.Value
1502 }
1503 if knownNameAST, ok := knownNames[fieldName]; ok {
1504 reportError(
1505 context,
1506 fmt.Sprintf(`There can be only one input field named "%v".`, fieldName),
1507 []ast.Node{knownNameAST, node.Name},
1508 )
1509 } else {
1510 knownNames[fieldName] = node.Name
1511 }
1512
1513 }
1514 return visitor.ActionSkip, nil
1515 },
1516 },
1517 },
1518 }
1519 return &ValidationRuleInstance{
1520 VisitorOpts: visitorOpts,
1521 }
1522}
1523
1524// UniqueOperationNamesRule Unique operation names
1525//
1526// A GraphQL document is only valid if all defined operations have unique names.
1527func UniqueOperationNamesRule(context *ValidationContext) *ValidationRuleInstance {
1528 knownOperationNames := make(map[string]ast.Node)
1529
1530 visitorOpts := &visitor.VisitorOptions{
1531 KindFuncMap: map[string]visitor.NamedVisitFuncs{
1532 kinds.OperationDefinition: {
1533 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
1534 if node, ok := p.Node.(*ast.OperationDefinition); ok && node != nil {
1535 operationName := ""
1536 if node.Name != nil {
1537 operationName = node.Name.Value
1538 }
1539 var errNode ast.Node = node
1540 if node.Name != nil {
1541 errNode = node.Name
1542 }
1543 if nameAST, ok := knownOperationNames[operationName]; ok {
1544 reportError(
1545 context,
1546 fmt.Sprintf(`There can only be one operation named "%v".`, operationName),
1547 []ast.Node{nameAST, errNode},
1548 )
1549 } else {
1550 knownOperationNames[operationName] = errNode
1551 }
1552 }
1553 return visitor.ActionSkip, nil
1554 },
1555 },
1556 kinds.FragmentDefinition: {
1557 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
1558 return visitor.ActionSkip, nil
1559 },
1560 },
1561 },
1562 }
1563 return &ValidationRuleInstance{
1564 VisitorOpts: visitorOpts,
1565 }
1566}
1567
1568// UniqueVariableNamesRule Unique variable names
1569//
1570// A GraphQL operation is only valid if all its variables are uniquely named.
1571func UniqueVariableNamesRule(context *ValidationContext) *ValidationRuleInstance {
1572 knownVariableNames := map[string]*ast.Name{}
1573
1574 visitorOpts := &visitor.VisitorOptions{
1575 KindFuncMap: map[string]visitor.NamedVisitFuncs{
1576 kinds.OperationDefinition: {
1577 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
1578 if node, ok := p.Node.(*ast.OperationDefinition); ok && node != nil {
1579 knownVariableNames = map[string]*ast.Name{}
1580 }
1581 return visitor.ActionNoChange, nil
1582 },
1583 },
1584 kinds.VariableDefinition: {
1585 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
1586 if node, ok := p.Node.(*ast.VariableDefinition); ok && node != nil {
1587 variableName := ""
1588 var variableNameAST *ast.Name
1589 if node.Variable != nil && node.Variable.Name != nil {
1590 variableNameAST = node.Variable.Name
1591 variableName = node.Variable.Name.Value
1592 }
1593 if nameAST, ok := knownVariableNames[variableName]; ok {
1594 reportError(
1595 context,
1596 fmt.Sprintf(`There can only be one variable named "%v".`, variableName),
1597 []ast.Node{nameAST, variableNameAST},
1598 )
1599 } else {
1600 knownVariableNames[variableName] = variableNameAST
1601 }
1602 }
1603 return visitor.ActionNoChange, nil
1604 },
1605 },
1606 },
1607 }
1608 return &ValidationRuleInstance{
1609 VisitorOpts: visitorOpts,
1610 }
1611}
1612
1613// VariablesAreInputTypesRule Variables are input types
1614//
1615// A GraphQL operation is only valid if all the variables it defines are of
1616// input types (scalar, enum, or input object).
1617func VariablesAreInputTypesRule(context *ValidationContext) *ValidationRuleInstance {
1618
1619 visitorOpts := &visitor.VisitorOptions{
1620 KindFuncMap: map[string]visitor.NamedVisitFuncs{
1621 kinds.VariableDefinition: {
1622 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
1623 if node, ok := p.Node.(*ast.VariableDefinition); ok && node != nil {
1624 ttype, _ := typeFromAST(*context.Schema(), node.Type)
1625
1626 // If the variable type is not an input type, return an error.
1627 if ttype != nil && !IsInputType(ttype) {
1628 variableName := ""
1629 if node.Variable != nil && node.Variable.Name != nil {
1630 variableName = node.Variable.Name.Value
1631 }
1632 reportError(
1633 context,
1634 fmt.Sprintf(`Variable "$%v" cannot be non-input type "%v".`,
1635 variableName, printer.Print(node.Type)),
1636 []ast.Node{node.Type},
1637 )
1638 }
1639 }
1640 return visitor.ActionNoChange, nil
1641 },
1642 },
1643 },
1644 }
1645 return &ValidationRuleInstance{
1646 VisitorOpts: visitorOpts,
1647 }
1648}
1649
1650// If a variable definition has a default value, it's effectively non-null.
1651func effectiveType(varType Type, varDef *ast.VariableDefinition) Type {
1652 if varDef.DefaultValue == nil {
1653 return varType
1654 }
1655 if _, ok := varType.(*NonNull); ok {
1656 return varType
1657 }
1658 return NewNonNull(varType)
1659}
1660
1661// VariablesInAllowedPositionRule Variables passed to field arguments conform to type
1662func VariablesInAllowedPositionRule(context *ValidationContext) *ValidationRuleInstance {
1663
1664 varDefMap := map[string]*ast.VariableDefinition{}
1665
1666 visitorOpts := &visitor.VisitorOptions{
1667 KindFuncMap: map[string]visitor.NamedVisitFuncs{
1668 kinds.OperationDefinition: {
1669 Enter: func(p visitor.VisitFuncParams) (string, interface{}) {
1670 varDefMap = map[string]*ast.VariableDefinition{}
1671 return visitor.ActionNoChange, nil
1672 },
1673 Leave: func(p visitor.VisitFuncParams) (string, interface{}) {
1674 if operation, ok := p.Node.(*ast.OperationDefinition); ok {
1675
1676 usages := context.RecursiveVariableUsages(operation)
1677 for _, usage := range usages {
1678 varName := ""
1679 if usage != nil && usage.Node != nil && usage.Node.Name != nil {
1680 varName = usage.Node.Name.Value
1681 }
1682 varDef, _ := varDefMap[varName]
1683 if varDef != nil && usage.Type != nil {
1684 varType, err := typeFromAST(*context.Schema(), varDef.Type)
1685 if err != nil {
1686 varType = nil
1687 }
1688 if varType != nil && !isTypeSubTypeOf(context.Schema(), effectiveType(varType, varDef), usage.Type) {
1689 reportError(
1690 context,
1691 fmt.Sprintf(`Variable "$%v" of type "%v" used in position `+
1692 `expecting type "%v".`, varName, varType, usage.Type),
1693 []ast.Node{varDef, usage.Node},
1694 )
1695 }
1696 }
1697 }
1698
1699 }
1700 return visitor.ActionNoChange, nil
1701 },
1702 },
1703 kinds.VariableDefinition: {
1704 Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
1705 if varDefAST, ok := p.Node.(*ast.VariableDefinition); ok {
1706 defName := ""
1707 if varDefAST.Variable != nil && varDefAST.Variable.Name != nil {
1708 defName = varDefAST.Variable.Name.Value
1709 }
1710 if defName != "" {
1711 varDefMap[defName] = varDefAST
1712 }
1713 }
1714 return visitor.ActionNoChange, nil
1715 },
1716 },
1717 },
1718 }
1719 return &ValidationRuleInstance{
1720 VisitorOpts: visitorOpts,
1721 }
1722}
1723
1724// Utility for validators which determines if a value literal AST is valid given
1725// an input type.
1726//
1727// Note that this only validates literal values, variables are assumed to
1728// provide values of the correct type.
1729func isValidLiteralValue(ttype Input, valueAST ast.Value) (bool, []string) {
1730 // A value must be provided if the type is non-null.
1731 if ttype, ok := ttype.(*NonNull); ok {
1732 if e := ttype.Error(); e != nil {
1733 return false, []string{e.Error()}
1734 }
1735 if valueAST == nil {
1736 if ttype.OfType.Name() != "" {
1737 return false, []string{fmt.Sprintf(`Expected "%v!", found null.`, ttype.OfType.Name())}
1738 }
1739 return false, []string{"Expected non-null value, found null."}
1740 }
1741 ofType, _ := ttype.OfType.(Input)
1742 return isValidLiteralValue(ofType, valueAST)
1743 }
1744
1745 if valueAST == nil {
1746 return true, nil
1747 }
1748
1749 // This function only tests literals, and assumes variables will provide
1750 // values of the correct type.
1751 if valueAST.GetKind() == kinds.Variable {
1752 return true, nil
1753 }
1754
1755 // Lists accept a non-list value as a list of one.
1756 if ttype, ok := ttype.(*List); ok {
1757 itemType, _ := ttype.OfType.(Input)
1758 if valueAST, ok := valueAST.(*ast.ListValue); ok {
1759 messagesReduce := []string{}
1760 for _, value := range valueAST.Values {
1761 _, messages := isValidLiteralValue(itemType, value)
1762 for idx, message := range messages {
1763 messagesReduce = append(messagesReduce, fmt.Sprintf(`In element #%v: %v`, idx+1, message))
1764 }
1765 }
1766 return (len(messagesReduce) == 0), messagesReduce
1767 }
1768 return isValidLiteralValue(itemType, valueAST)
1769
1770 }
1771
1772 // Input objects check each defined field and look for undefined fields.
1773 if ttype, ok := ttype.(*InputObject); ok {
1774 valueAST, ok := valueAST.(*ast.ObjectValue)
1775 if !ok {
1776 return false, []string{fmt.Sprintf(`Expected "%v", found not an object.`, ttype.Name())}
1777 }
1778 fields := ttype.Fields()
1779 messagesReduce := []string{}
1780
1781 // Ensure every provided field is defined.
1782 fieldASTs := valueAST.Fields
1783 fieldASTMap := map[string]*ast.ObjectField{}
1784 for _, fieldAST := range fieldASTs {
1785 fieldASTName := ""
1786 if fieldAST.Name != nil {
1787 fieldASTName = fieldAST.Name.Value
1788 }
1789
1790 fieldASTMap[fieldASTName] = fieldAST
1791
1792 field, ok := fields[fieldASTName]
1793 if !ok || field == nil {
1794 messagesReduce = append(messagesReduce, fmt.Sprintf(`In field "%v": Unknown field.`, fieldASTName))
1795 }
1796 }
1797 // Ensure every defined field is valid.
1798 for fieldName, field := range fields {
1799 fieldAST, _ := fieldASTMap[fieldName]
1800 var fieldASTValue ast.Value
1801 if fieldAST != nil {
1802 fieldASTValue = fieldAST.Value
1803 }
1804 if isValid, messages := isValidLiteralValue(field.Type, fieldASTValue); !isValid {
1805 for _, message := range messages {
1806 messagesReduce = append(messagesReduce, fmt.Sprintf("In field \"%v\": %v", fieldName, message))
1807 }
1808 }
1809 }
1810 return (len(messagesReduce) == 0), messagesReduce
1811 }
1812
1813 if ttype, ok := ttype.(*Scalar); ok {
1814 if isNullish(ttype.ParseLiteral(valueAST)) {
1815 return false, []string{fmt.Sprintf(`Expected type "%v", found %v.`, ttype.Name(), printer.Print(valueAST))}
1816 }
1817 }
1818 if ttype, ok := ttype.(*Enum); ok {
1819 if isNullish(ttype.ParseLiteral(valueAST)) {
1820 return false, []string{fmt.Sprintf(`Expected type "%v", found %v.`, ttype.Name(), printer.Print(valueAST))}
1821 }
1822 }
1823
1824 return true, nil
1825}
1826
1827// Internal struct to sort results from suggestionList()
1828type suggestionListResult struct {
1829 Options []string
1830 Distances []float64
1831}
1832
1833func (s suggestionListResult) Len() int {
1834 return len(s.Options)
1835}
1836func (s suggestionListResult) Swap(i, j int) {
1837 s.Options[i], s.Options[j] = s.Options[j], s.Options[i]
1838}
1839func (s suggestionListResult) Less(i, j int) bool {
1840 return s.Distances[i] < s.Distances[j]
1841}
1842
1843// suggestionList Given an invalid input string and a list of valid options, returns a filtered
1844// list of valid options sorted based on their similarity with the input.
1845func suggestionList(input string, options []string) []string {
1846 dists := []float64{}
1847 filteredOpts := []string{}
1848 inputThreshold := float64(len(input) / 2)
1849
1850 for _, opt := range options {
1851 dist := lexicalDistance(input, opt)
1852 threshold := math.Max(inputThreshold, float64(len(opt)/2))
1853 threshold = math.Max(threshold, 1)
1854 if dist <= threshold {
1855 filteredOpts = append(filteredOpts, opt)
1856 dists = append(dists, dist)
1857 }
1858 }
1859 //sort results
1860 suggested := suggestionListResult{filteredOpts, dists}
1861 sort.Sort(suggested)
1862 return suggested.Options
1863}
1864
1865// lexicalDistance Computes the lexical distance between strings A and B.
1866// The "distance" between two strings is given by counting the minimum number
1867// of edits needed to transform string A into string B. An edit can be an
1868// insertion, deletion, or substitution of a single character, or a swap of two
1869// adjacent characters.
1870// This distance can be useful for detecting typos in input or sorting
1871func lexicalDistance(a, b string) float64 {
1872 d := [][]float64{}
1873 aLen := len(a)
1874 bLen := len(b)
1875 for i := 0; i <= aLen; i++ {
1876 d = append(d, []float64{float64(i)})
1877 }
1878 for k := 1; k <= bLen; k++ {
1879 d[0] = append(d[0], float64(k))
1880 }
1881
1882 for i := 1; i <= aLen; i++ {
1883 for k := 1; k <= bLen; k++ {
1884 cost := 1.0
1885 if a[i-1] == b[k-1] {
1886 cost = 0.0
1887 }
1888 minCostFloat := math.Min(
1889 d[i-1][k]+1.0,
1890 d[i][k-1]+1.0,
1891 )
1892 minCostFloat = math.Min(
1893 minCostFloat,
1894 d[i-1][k-1]+cost,
1895 )
1896 d[i] = append(d[i], minCostFloat)
1897
1898 if i > 1 && k < 1 &&
1899 a[i-1] == b[k-2] &&
1900 a[i-2] == b[k-1] {
1901 d[i][k] = math.Min(d[i][k], d[i-2][k-2]+cost)
1902 }
1903 }
1904 }
1905
1906 return d[aLen][bLen]
1907}