UNPKG

4.52 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.FieldsOnCorrectTypeRule = FieldsOnCorrectTypeRule;
7
8var _arrayFrom = _interopRequireDefault(require("../../polyfills/arrayFrom.js"));
9
10var _didYouMean = _interopRequireDefault(require("../../jsutils/didYouMean.js"));
11
12var _suggestionList = _interopRequireDefault(require("../../jsutils/suggestionList.js"));
13
14var _naturalCompare = _interopRequireDefault(require("../../jsutils/naturalCompare.js"));
15
16var _GraphQLError = require("../../error/GraphQLError.js");
17
18var _definition = require("../../type/definition.js");
19
20function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
21
22/**
23 * Fields on correct type
24 *
25 * A GraphQL document is only valid if all fields selected are defined by the
26 * parent type, or are an allowed meta field such as __typename.
27 */
28function FieldsOnCorrectTypeRule(context) {
29 return {
30 Field: function Field(node) {
31 var type = context.getParentType();
32
33 if (type) {
34 var fieldDef = context.getFieldDef();
35
36 if (!fieldDef) {
37 // This field doesn't exist, lets look for suggestions.
38 var schema = context.getSchema();
39 var fieldName = node.name.value; // First determine if there are any suggested types to condition on.
40
41 var suggestion = (0, _didYouMean.default)('to use an inline fragment on', getSuggestedTypeNames(schema, type, fieldName)); // If there are no suggested types, then perhaps this was a typo?
42
43 if (suggestion === '') {
44 suggestion = (0, _didYouMean.default)(getSuggestedFieldNames(type, fieldName));
45 } // Report an error, including helpful suggestions.
46
47
48 context.reportError(new _GraphQLError.GraphQLError("Cannot query field \"".concat(fieldName, "\" on type \"").concat(type.name, "\".") + suggestion, node));
49 }
50 }
51 }
52 };
53}
54/**
55 * Go through all of the implementations of type, as well as the interfaces that
56 * they implement. If any of those types include the provided field, suggest them,
57 * sorted by how often the type is referenced.
58 */
59
60
61function getSuggestedTypeNames(schema, type, fieldName) {
62 if (!(0, _definition.isAbstractType)(type)) {
63 // Must be an Object type, which does not have possible fields.
64 return [];
65 }
66
67 var suggestedTypes = new Set();
68 var usageCount = Object.create(null);
69
70 for (var _i2 = 0, _schema$getPossibleTy2 = schema.getPossibleTypes(type); _i2 < _schema$getPossibleTy2.length; _i2++) {
71 var possibleType = _schema$getPossibleTy2[_i2];
72
73 if (!possibleType.getFields()[fieldName]) {
74 continue;
75 } // This object type defines this field.
76
77
78 suggestedTypes.add(possibleType);
79 usageCount[possibleType.name] = 1;
80
81 for (var _i4 = 0, _possibleType$getInte2 = possibleType.getInterfaces(); _i4 < _possibleType$getInte2.length; _i4++) {
82 var _usageCount$possibleI;
83
84 var possibleInterface = _possibleType$getInte2[_i4];
85
86 if (!possibleInterface.getFields()[fieldName]) {
87 continue;
88 } // This interface type defines this field.
89
90
91 suggestedTypes.add(possibleInterface);
92 usageCount[possibleInterface.name] = ((_usageCount$possibleI = usageCount[possibleInterface.name]) !== null && _usageCount$possibleI !== void 0 ? _usageCount$possibleI : 0) + 1;
93 }
94 }
95
96 return (0, _arrayFrom.default)(suggestedTypes).sort(function (typeA, typeB) {
97 // Suggest both interface and object types based on how common they are.
98 var usageCountDiff = usageCount[typeB.name] - usageCount[typeA.name];
99
100 if (usageCountDiff !== 0) {
101 return usageCountDiff;
102 } // Suggest super types first followed by subtypes
103
104
105 if ((0, _definition.isInterfaceType)(typeA) && schema.isSubType(typeA, typeB)) {
106 return -1;
107 }
108
109 if ((0, _definition.isInterfaceType)(typeB) && schema.isSubType(typeB, typeA)) {
110 return 1;
111 }
112
113 return (0, _naturalCompare.default)(typeA.name, typeB.name);
114 }).map(function (x) {
115 return x.name;
116 });
117}
118/**
119 * For the field name provided, determine if there are any similar field names
120 * that may be the result of a typo.
121 */
122
123
124function getSuggestedFieldNames(type, fieldName) {
125 if ((0, _definition.isObjectType)(type) || (0, _definition.isInterfaceType)(type)) {
126 var possibleFieldNames = Object.keys(type.getFields());
127 return (0, _suggestionList.default)(fieldName, possibleFieldNames);
128 } // Otherwise, must be a Union type, which does not define fields.
129
130
131 return [];
132}