aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/vektah/gqlparser/validator/rules/fields_on_correct_type.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/vektah/gqlparser/validator/rules/fields_on_correct_type.go')
-rw-r--r--vendor/github.com/vektah/gqlparser/validator/rules/fields_on_correct_type.go86
1 files changed, 86 insertions, 0 deletions
diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/fields_on_correct_type.go b/vendor/github.com/vektah/gqlparser/validator/rules/fields_on_correct_type.go
new file mode 100644
index 00000000..69148d52
--- /dev/null
+++ b/vendor/github.com/vektah/gqlparser/validator/rules/fields_on_correct_type.go
@@ -0,0 +1,86 @@
+package validator
+
+import (
+ "fmt"
+ "sort"
+
+ "github.com/vektah/gqlparser/ast"
+ . "github.com/vektah/gqlparser/validator"
+)
+
+func init() {
+ AddRule("FieldsOnCorrectType", func(observers *Events, addError AddErrFunc) {
+ observers.OnField(func(walker *Walker, field *ast.Field) {
+ if field.ObjectDefinition == nil || field.Definition != nil {
+ return
+ }
+
+ message := fmt.Sprintf(`Cannot query field "%s" on type "%s".`, field.Name, field.ObjectDefinition.Name)
+
+ if suggestedTypeNames := getSuggestedTypeNames(walker, field.ObjectDefinition, field.Name); suggestedTypeNames != nil {
+ message += " Did you mean to use an inline fragment on " + QuotedOrList(suggestedTypeNames...) + "?"
+ } else if suggestedFieldNames := getSuggestedFieldNames(field.ObjectDefinition, field.Name); suggestedFieldNames != nil {
+ message += " Did you mean " + QuotedOrList(suggestedFieldNames...) + "?"
+ }
+
+ addError(
+ Message(message),
+ At(field.Position),
+ )
+ })
+ })
+}
+
+// Go through all of the implementations of type, as well as the interfaces
+// that they implement. If any of those types include the provided field,
+// suggest them, sorted by how often the type is referenced, starting
+// with Interfaces.
+func getSuggestedTypeNames(walker *Walker, parent *ast.Definition, name string) []string {
+ if !parent.IsAbstractType() {
+ return nil
+ }
+
+ var suggestedObjectTypes []string
+ var suggestedInterfaceTypes []string
+ interfaceUsageCount := map[string]int{}
+
+ for _, possibleType := range walker.Schema.GetPossibleTypes(parent) {
+ field := possibleType.Fields.ForName(name)
+ if field == nil {
+ continue
+ }
+
+ suggestedObjectTypes = append(suggestedObjectTypes, possibleType.Name)
+
+ for _, possibleInterface := range possibleType.Interfaces {
+ interfaceField := walker.Schema.Types[possibleInterface]
+ if interfaceField != nil && interfaceField.Fields.ForName(name) != nil {
+ if interfaceUsageCount[possibleInterface] == 0 {
+ suggestedInterfaceTypes = append(suggestedInterfaceTypes, possibleInterface)
+ }
+ interfaceUsageCount[possibleInterface]++
+ }
+ }
+ }
+
+ sort.SliceStable(suggestedInterfaceTypes, func(i, j int) bool {
+ return interfaceUsageCount[suggestedInterfaceTypes[i]] > interfaceUsageCount[suggestedInterfaceTypes[j]]
+ })
+
+ return append(suggestedInterfaceTypes, suggestedObjectTypes...)
+}
+
+// For the field name provided, determine if there are any similar field names
+// that may be the result of a typo.
+func getSuggestedFieldNames(parent *ast.Definition, name string) []string {
+ if parent.Kind != ast.Object && parent.Kind != ast.Interface {
+ return nil
+ }
+
+ var possibleFieldNames []string
+ for _, field := range parent.Fields {
+ possibleFieldNames = append(possibleFieldNames, field.Name)
+ }
+
+ return SuggestionList(name, possibleFieldNames)
+}