possible_fragment_spreads.go

 1package validator
 2
 3import (
 4	"github.com/vektah/gqlparser/ast"
 5	. "github.com/vektah/gqlparser/validator"
 6)
 7
 8func init() {
 9	AddRule("PossibleFragmentSpreads", func(observers *Events, addError AddErrFunc) {
10
11		validate := func(walker *Walker, parentDef *ast.Definition, fragmentName string, emitError func()) {
12			if parentDef == nil {
13				return
14			}
15
16			var parentDefs []*ast.Definition
17			switch parentDef.Kind {
18			case ast.Object:
19				parentDefs = []*ast.Definition{parentDef}
20			case ast.Interface, ast.Union:
21				parentDefs = walker.Schema.GetPossibleTypes(parentDef)
22			default:
23				panic("unexpected type")
24			}
25
26			fragmentDefType := walker.Schema.Types[fragmentName]
27			if fragmentDefType == nil {
28				return
29			}
30			if !fragmentDefType.IsCompositeType() {
31				// checked by FragmentsOnCompositeTypes
32				return
33			}
34			fragmentDefs := walker.Schema.GetPossibleTypes(fragmentDefType)
35
36			for _, fragmentDef := range fragmentDefs {
37				for _, parentDef := range parentDefs {
38					if parentDef.Name == fragmentDef.Name {
39						return
40					}
41				}
42			}
43
44			emitError()
45		}
46
47		observers.OnInlineFragment(func(walker *Walker, inlineFragment *ast.InlineFragment) {
48			validate(walker, inlineFragment.ObjectDefinition, inlineFragment.TypeCondition, func() {
49				addError(
50					Message(`Fragment cannot be spread here as objects of type "%s" can never be of type "%s".`, inlineFragment.ObjectDefinition.Name, inlineFragment.TypeCondition),
51					At(inlineFragment.Position),
52				)
53			})
54		})
55
56		observers.OnFragmentSpread(func(walker *Walker, fragmentSpread *ast.FragmentSpread) {
57			if fragmentSpread.Definition == nil {
58				return
59			}
60			validate(walker, fragmentSpread.ObjectDefinition, fragmentSpread.Definition.TypeCondition, func() {
61				addError(
62					Message(`Fragment "%s" cannot be spread here as objects of type "%s" can never be of type "%s".`, fragmentSpread.Name, fragmentSpread.ObjectDefinition.Name, fragmentSpread.Definition.TypeCondition),
63					At(fragmentSpread.Position),
64				)
65			})
66		})
67	})
68}