UNPKG

11 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.visitWithTypeInfo = visitWithTypeInfo;
7exports.TypeInfo = void 0;
8
9var _find = _interopRequireDefault(require("../polyfills/find.js"));
10
11var _kinds = require("../language/kinds.js");
12
13var _ast = require("../language/ast.js");
14
15var _visitor = require("../language/visitor.js");
16
17var _definition = require("../type/definition.js");
18
19var _introspection = require("../type/introspection.js");
20
21var _typeFromAST = require("./typeFromAST.js");
22
23function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
24
25/**
26 * TypeInfo is a utility class which, given a GraphQL schema, can keep track
27 * of the current field and type definitions at any point in a GraphQL document
28 * AST during a recursive descent by calling `enter(node)` and `leave(node)`.
29 */
30var TypeInfo = /*#__PURE__*/function () {
31 function TypeInfo(schema, // NOTE: this experimental optional second parameter is only needed in order
32 // to support non-spec-compliant code bases. You should never need to use it.
33 // It may disappear in the future.
34 getFieldDefFn, // Initial type may be provided in rare cases to facilitate traversals
35 // beginning somewhere other than documents.
36 initialType) {
37 this._schema = schema;
38 this._typeStack = [];
39 this._parentTypeStack = [];
40 this._inputTypeStack = [];
41 this._fieldDefStack = [];
42 this._defaultValueStack = [];
43 this._directive = null;
44 this._argument = null;
45 this._enumValue = null;
46 this._getFieldDef = getFieldDefFn !== null && getFieldDefFn !== void 0 ? getFieldDefFn : getFieldDef;
47
48 if (initialType) {
49 if ((0, _definition.isInputType)(initialType)) {
50 this._inputTypeStack.push(initialType);
51 }
52
53 if ((0, _definition.isCompositeType)(initialType)) {
54 this._parentTypeStack.push(initialType);
55 }
56
57 if ((0, _definition.isOutputType)(initialType)) {
58 this._typeStack.push(initialType);
59 }
60 }
61 }
62
63 var _proto = TypeInfo.prototype;
64
65 _proto.getType = function getType() {
66 if (this._typeStack.length > 0) {
67 return this._typeStack[this._typeStack.length - 1];
68 }
69 };
70
71 _proto.getParentType = function getParentType() {
72 if (this._parentTypeStack.length > 0) {
73 return this._parentTypeStack[this._parentTypeStack.length - 1];
74 }
75 };
76
77 _proto.getInputType = function getInputType() {
78 if (this._inputTypeStack.length > 0) {
79 return this._inputTypeStack[this._inputTypeStack.length - 1];
80 }
81 };
82
83 _proto.getParentInputType = function getParentInputType() {
84 if (this._inputTypeStack.length > 1) {
85 return this._inputTypeStack[this._inputTypeStack.length - 2];
86 }
87 };
88
89 _proto.getFieldDef = function getFieldDef() {
90 if (this._fieldDefStack.length > 0) {
91 return this._fieldDefStack[this._fieldDefStack.length - 1];
92 }
93 };
94
95 _proto.getDefaultValue = function getDefaultValue() {
96 if (this._defaultValueStack.length > 0) {
97 return this._defaultValueStack[this._defaultValueStack.length - 1];
98 }
99 };
100
101 _proto.getDirective = function getDirective() {
102 return this._directive;
103 };
104
105 _proto.getArgument = function getArgument() {
106 return this._argument;
107 };
108
109 _proto.getEnumValue = function getEnumValue() {
110 return this._enumValue;
111 };
112
113 _proto.enter = function enter(node) {
114 var schema = this._schema; // Note: many of the types below are explicitly typed as "mixed" to drop
115 // any assumptions of a valid schema to ensure runtime types are properly
116 // checked before continuing since TypeInfo is used as part of validation
117 // which occurs before guarantees of schema and document validity.
118
119 switch (node.kind) {
120 case _kinds.Kind.SELECTION_SET:
121 {
122 var namedType = (0, _definition.getNamedType)(this.getType());
123
124 this._parentTypeStack.push((0, _definition.isCompositeType)(namedType) ? namedType : undefined);
125
126 break;
127 }
128
129 case _kinds.Kind.FIELD:
130 {
131 var parentType = this.getParentType();
132 var fieldDef;
133 var fieldType;
134
135 if (parentType) {
136 fieldDef = this._getFieldDef(schema, parentType, node);
137
138 if (fieldDef) {
139 fieldType = fieldDef.type;
140 }
141 }
142
143 this._fieldDefStack.push(fieldDef);
144
145 this._typeStack.push((0, _definition.isOutputType)(fieldType) ? fieldType : undefined);
146
147 break;
148 }
149
150 case _kinds.Kind.DIRECTIVE:
151 this._directive = schema.getDirective(node.name.value);
152 break;
153
154 case _kinds.Kind.OPERATION_DEFINITION:
155 {
156 var type;
157
158 switch (node.operation) {
159 case 'query':
160 type = schema.getQueryType();
161 break;
162
163 case 'mutation':
164 type = schema.getMutationType();
165 break;
166
167 case 'subscription':
168 type = schema.getSubscriptionType();
169 break;
170 }
171
172 this._typeStack.push((0, _definition.isObjectType)(type) ? type : undefined);
173
174 break;
175 }
176
177 case _kinds.Kind.INLINE_FRAGMENT:
178 case _kinds.Kind.FRAGMENT_DEFINITION:
179 {
180 var typeConditionAST = node.typeCondition;
181 var outputType = typeConditionAST ? (0, _typeFromAST.typeFromAST)(schema, typeConditionAST) : (0, _definition.getNamedType)(this.getType());
182
183 this._typeStack.push((0, _definition.isOutputType)(outputType) ? outputType : undefined);
184
185 break;
186 }
187
188 case _kinds.Kind.VARIABLE_DEFINITION:
189 {
190 var inputType = (0, _typeFromAST.typeFromAST)(schema, node.type);
191
192 this._inputTypeStack.push((0, _definition.isInputType)(inputType) ? inputType : undefined);
193
194 break;
195 }
196
197 case _kinds.Kind.ARGUMENT:
198 {
199 var _this$getDirective;
200
201 var argDef;
202 var argType;
203 var fieldOrDirective = (_this$getDirective = this.getDirective()) !== null && _this$getDirective !== void 0 ? _this$getDirective : this.getFieldDef();
204
205 if (fieldOrDirective) {
206 argDef = (0, _find.default)(fieldOrDirective.args, function (arg) {
207 return arg.name === node.name.value;
208 });
209
210 if (argDef) {
211 argType = argDef.type;
212 }
213 }
214
215 this._argument = argDef;
216
217 this._defaultValueStack.push(argDef ? argDef.defaultValue : undefined);
218
219 this._inputTypeStack.push((0, _definition.isInputType)(argType) ? argType : undefined);
220
221 break;
222 }
223
224 case _kinds.Kind.LIST:
225 {
226 var listType = (0, _definition.getNullableType)(this.getInputType());
227 var itemType = (0, _definition.isListType)(listType) ? listType.ofType : listType; // List positions never have a default value.
228
229 this._defaultValueStack.push(undefined);
230
231 this._inputTypeStack.push((0, _definition.isInputType)(itemType) ? itemType : undefined);
232
233 break;
234 }
235
236 case _kinds.Kind.OBJECT_FIELD:
237 {
238 var objectType = (0, _definition.getNamedType)(this.getInputType());
239 var inputFieldType;
240 var inputField;
241
242 if ((0, _definition.isInputObjectType)(objectType)) {
243 inputField = objectType.getFields()[node.name.value];
244
245 if (inputField) {
246 inputFieldType = inputField.type;
247 }
248 }
249
250 this._defaultValueStack.push(inputField ? inputField.defaultValue : undefined);
251
252 this._inputTypeStack.push((0, _definition.isInputType)(inputFieldType) ? inputFieldType : undefined);
253
254 break;
255 }
256
257 case _kinds.Kind.ENUM:
258 {
259 var enumType = (0, _definition.getNamedType)(this.getInputType());
260 var enumValue;
261
262 if ((0, _definition.isEnumType)(enumType)) {
263 enumValue = enumType.getValue(node.value);
264 }
265
266 this._enumValue = enumValue;
267 break;
268 }
269 }
270 };
271
272 _proto.leave = function leave(node) {
273 switch (node.kind) {
274 case _kinds.Kind.SELECTION_SET:
275 this._parentTypeStack.pop();
276
277 break;
278
279 case _kinds.Kind.FIELD:
280 this._fieldDefStack.pop();
281
282 this._typeStack.pop();
283
284 break;
285
286 case _kinds.Kind.DIRECTIVE:
287 this._directive = null;
288 break;
289
290 case _kinds.Kind.OPERATION_DEFINITION:
291 case _kinds.Kind.INLINE_FRAGMENT:
292 case _kinds.Kind.FRAGMENT_DEFINITION:
293 this._typeStack.pop();
294
295 break;
296
297 case _kinds.Kind.VARIABLE_DEFINITION:
298 this._inputTypeStack.pop();
299
300 break;
301
302 case _kinds.Kind.ARGUMENT:
303 this._argument = null;
304
305 this._defaultValueStack.pop();
306
307 this._inputTypeStack.pop();
308
309 break;
310
311 case _kinds.Kind.LIST:
312 case _kinds.Kind.OBJECT_FIELD:
313 this._defaultValueStack.pop();
314
315 this._inputTypeStack.pop();
316
317 break;
318
319 case _kinds.Kind.ENUM:
320 this._enumValue = null;
321 break;
322 }
323 };
324
325 return TypeInfo;
326}();
327/**
328 * Not exactly the same as the executor's definition of getFieldDef, in this
329 * statically evaluated environment we do not always have an Object type,
330 * and need to handle Interface and Union types.
331 */
332
333
334exports.TypeInfo = TypeInfo;
335
336function getFieldDef(schema, parentType, fieldNode) {
337 var name = fieldNode.name.value;
338
339 if (name === _introspection.SchemaMetaFieldDef.name && schema.getQueryType() === parentType) {
340 return _introspection.SchemaMetaFieldDef;
341 }
342
343 if (name === _introspection.TypeMetaFieldDef.name && schema.getQueryType() === parentType) {
344 return _introspection.TypeMetaFieldDef;
345 }
346
347 if (name === _introspection.TypeNameMetaFieldDef.name && (0, _definition.isCompositeType)(parentType)) {
348 return _introspection.TypeNameMetaFieldDef;
349 }
350
351 if ((0, _definition.isObjectType)(parentType) || (0, _definition.isInterfaceType)(parentType)) {
352 return parentType.getFields()[name];
353 }
354}
355/**
356 * Creates a new visitor instance which maintains a provided TypeInfo instance
357 * along with visiting visitor.
358 */
359
360
361function visitWithTypeInfo(typeInfo, visitor) {
362 return {
363 enter: function enter(node) {
364 typeInfo.enter(node);
365 var fn = (0, _visitor.getVisitFn)(visitor, node.kind,
366 /* isLeaving */
367 false);
368
369 if (fn) {
370 var result = fn.apply(visitor, arguments);
371
372 if (result !== undefined) {
373 typeInfo.leave(node);
374
375 if ((0, _ast.isNode)(result)) {
376 typeInfo.enter(result);
377 }
378 }
379
380 return result;
381 }
382 },
383 leave: function leave(node) {
384 var fn = (0, _visitor.getVisitFn)(visitor, node.kind,
385 /* isLeaving */
386 true);
387 var result;
388
389 if (fn) {
390 result = fn.apply(visitor, arguments);
391 }
392
393 typeInfo.leave(node);
394 return result;
395 }
396 };
397}