UNPKG

10.5 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.TypeInfo = undefined;
7
8var _kinds = require('../language/kinds');
9
10var Kind = _interopRequireWildcard(_kinds);
11
12var _definition = require('../type/definition');
13
14var _introspection = require('../type/introspection');
15
16var _typeFromAST = require('./typeFromAST');
17
18var _find = require('../jsutils/find');
19
20var _find2 = _interopRequireDefault(_find);
21
22function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
23
24function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
25
26function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /**
27 * Copyright (c) 2015-present, Facebook, Inc.
28 *
29 * This source code is licensed under the MIT license found in the
30 * LICENSE file in the root directory of this source tree.
31 *
32 *
33 */
34
35/**
36 * TypeInfo is a utility class which, given a GraphQL schema, can keep track
37 * of the current field and type definitions at any point in a GraphQL document
38 * AST during a recursive descent by calling `enter(node)` and `leave(node)`.
39 */
40var TypeInfo = exports.TypeInfo = function () {
41 function TypeInfo(schema,
42 // NOTE: this experimental optional second parameter is only needed in order
43 // to support non-spec-compliant codebases. You should never need to use it.
44 getFieldDefFn,
45 // Initial type may be provided in rare cases to facilitate traversals
46 initialType) {
47 _classCallCheck(this, TypeInfo);
48
49 this._schema = schema;
50 this._typeStack = [];
51 this._parentTypeStack = [];
52 this._inputTypeStack = [];
53 this._fieldDefStack = [];
54 this._directive = null;
55 this._argument = null;
56 this._enumValue = null;
57 this._getFieldDef = getFieldDefFn || getFieldDef;
58 if (initialType) {
59 if ((0, _definition.isInputType)(initialType)) {
60 this._inputTypeStack.push(initialType);
61 }
62 if ((0, _definition.isCompositeType)(initialType)) {
63 this._parentTypeStack.push(initialType);
64 }
65 if ((0, _definition.isOutputType)(initialType)) {
66 this._typeStack.push(initialType);
67 }
68 }
69 }
70
71 TypeInfo.prototype.getType = function getType() {
72 if (this._typeStack.length > 0) {
73 return this._typeStack[this._typeStack.length - 1];
74 }
75 };
76
77 TypeInfo.prototype.getParentType = function getParentType() {
78 if (this._parentTypeStack.length > 0) {
79 return this._parentTypeStack[this._parentTypeStack.length - 1];
80 }
81 };
82
83 TypeInfo.prototype.getInputType = function getInputType() {
84 if (this._inputTypeStack.length > 0) {
85 return this._inputTypeStack[this._inputTypeStack.length - 1];
86 }
87 };
88
89 TypeInfo.prototype.getParentInputType = function getParentInputType() {
90 if (this._inputTypeStack.length > 1) {
91 return this._inputTypeStack[this._inputTypeStack.length - 2];
92 }
93 };
94
95 TypeInfo.prototype.getFieldDef = function getFieldDef() {
96 if (this._fieldDefStack.length > 0) {
97 return this._fieldDefStack[this._fieldDefStack.length - 1];
98 }
99 };
100
101 TypeInfo.prototype.getDirective = function getDirective() {
102 return this._directive;
103 };
104
105 TypeInfo.prototype.getArgument = function getArgument() {
106 return this._argument;
107 };
108
109 TypeInfo.prototype.getEnumValue = function getEnumValue() {
110 return this._enumValue;
111 };
112
113 // Flow does not yet handle this case.
114
115
116 TypeInfo.prototype.enter = function enter(node /* ASTNode */) {
117 var schema = this._schema;
118 // Note: many of the types below are explicitly typed as "mixed" to drop
119 // any assumptions of a valid schema to ensure runtime types are properly
120 // checked before continuing since TypeInfo is used as part of validation
121 // which occurs before guarantees of schema and document validity.
122 switch (node.kind) {
123 case Kind.SELECTION_SET:
124 var namedType = (0, _definition.getNamedType)(this.getType());
125 this._parentTypeStack.push((0, _definition.isCompositeType)(namedType) ? namedType : undefined);
126 break;
127 case Kind.FIELD:
128 var parentType = this.getParentType();
129 var fieldDef = void 0;
130 var fieldType = void 0;
131 if (parentType) {
132 fieldDef = this._getFieldDef(schema, parentType, node);
133 if (fieldDef) {
134 fieldType = fieldDef.type;
135 }
136 }
137 this._fieldDefStack.push(fieldDef);
138 this._typeStack.push((0, _definition.isOutputType)(fieldType) ? fieldType : undefined);
139 break;
140 case Kind.DIRECTIVE:
141 this._directive = schema.getDirective(node.name.value);
142 break;
143 case Kind.OPERATION_DEFINITION:
144 var type = void 0;
145 if (node.operation === 'query') {
146 type = schema.getQueryType();
147 } else if (node.operation === 'mutation') {
148 type = schema.getMutationType();
149 } else if (node.operation === 'subscription') {
150 type = schema.getSubscriptionType();
151 }
152 this._typeStack.push((0, _definition.isObjectType)(type) ? type : undefined);
153 break;
154 case Kind.INLINE_FRAGMENT:
155 case Kind.FRAGMENT_DEFINITION:
156 var typeConditionAST = node.typeCondition;
157 var outputType = typeConditionAST ? (0, _typeFromAST.typeFromAST)(schema, typeConditionAST) : (0, _definition.getNamedType)(this.getType());
158 this._typeStack.push((0, _definition.isOutputType)(outputType) ? outputType : undefined);
159 break;
160 case Kind.VARIABLE_DEFINITION:
161 var inputType = (0, _typeFromAST.typeFromAST)(schema, node.type);
162 this._inputTypeStack.push((0, _definition.isInputType)(inputType) ? inputType : undefined);
163 break;
164 case Kind.ARGUMENT:
165 var argDef = void 0;
166 var argType = void 0;
167 var fieldOrDirective = this.getDirective() || this.getFieldDef();
168 if (fieldOrDirective) {
169 argDef = (0, _find2.default)(fieldOrDirective.args, function (arg) {
170 return arg.name === node.name.value;
171 });
172 if (argDef) {
173 argType = argDef.type;
174 }
175 }
176 this._argument = argDef;
177 this._inputTypeStack.push((0, _definition.isInputType)(argType) ? argType : undefined);
178 break;
179 case Kind.LIST:
180 var listType = (0, _definition.getNullableType)(this.getInputType());
181 var itemType = (0, _definition.isListType)(listType) ? listType.ofType : listType;
182 this._inputTypeStack.push((0, _definition.isInputType)(itemType) ? itemType : undefined);
183 break;
184 case Kind.OBJECT_FIELD:
185 var objectType = (0, _definition.getNamedType)(this.getInputType());
186 var inputFieldType = void 0;
187 if ((0, _definition.isInputObjectType)(objectType)) {
188 var inputField = objectType.getFields()[node.name.value];
189 if (inputField) {
190 inputFieldType = inputField.type;
191 }
192 }
193 this._inputTypeStack.push((0, _definition.isInputType)(inputFieldType) ? inputFieldType : undefined);
194 break;
195 case Kind.ENUM:
196 var enumType = (0, _definition.getNamedType)(this.getInputType());
197 var enumValue = void 0;
198 if ((0, _definition.isEnumType)(enumType)) {
199 enumValue = enumType.getValue(node.value);
200 }
201 this._enumValue = enumValue;
202 break;
203 }
204 };
205
206 TypeInfo.prototype.leave = function leave(node) {
207 switch (node.kind) {
208 case Kind.SELECTION_SET:
209 this._parentTypeStack.pop();
210 break;
211 case Kind.FIELD:
212 this._fieldDefStack.pop();
213 this._typeStack.pop();
214 break;
215 case Kind.DIRECTIVE:
216 this._directive = null;
217 break;
218 case Kind.OPERATION_DEFINITION:
219 case Kind.INLINE_FRAGMENT:
220 case Kind.FRAGMENT_DEFINITION:
221 this._typeStack.pop();
222 break;
223 case Kind.VARIABLE_DEFINITION:
224 this._inputTypeStack.pop();
225 break;
226 case Kind.ARGUMENT:
227 this._argument = null;
228 this._inputTypeStack.pop();
229 break;
230 case Kind.LIST:
231 case Kind.OBJECT_FIELD:
232 this._inputTypeStack.pop();
233 break;
234 case Kind.ENUM:
235 this._enumValue = null;
236 break;
237 }
238 };
239
240 return TypeInfo;
241}();
242
243/**
244 * Not exactly the same as the executor's definition of getFieldDef, in this
245 * statically evaluated environment we do not always have an Object type,
246 * and need to handle Interface and Union types.
247 */
248
249
250function getFieldDef(schema, parentType, fieldNode) {
251 var name = fieldNode.name.value;
252 if (name === _introspection.SchemaMetaFieldDef.name && schema.getQueryType() === parentType) {
253 return _introspection.SchemaMetaFieldDef;
254 }
255 if (name === _introspection.TypeMetaFieldDef.name && schema.getQueryType() === parentType) {
256 return _introspection.TypeMetaFieldDef;
257 }
258 if (name === _introspection.TypeNameMetaFieldDef.name && (0, _definition.isCompositeType)(parentType)) {
259 return _introspection.TypeNameMetaFieldDef;
260 }
261 if ((0, _definition.isObjectType)(parentType) || (0, _definition.isInterfaceType)(parentType)) {
262 return parentType.getFields()[name];
263 }
264}
\No newline at end of file