| "use strict"; |
| |
| Object.defineProperty(exports, "__esModule", { |
| value: true |
| }); |
| exports.visitWithTypeInfo = visitWithTypeInfo; |
| exports.TypeInfo = void 0; |
| |
| var _find = _interopRequireDefault(require("../polyfills/find")); |
| |
| var _kinds = require("../language/kinds"); |
| |
| var _visitor = require("../language/visitor"); |
| |
| var _ast = require("../language/ast"); |
| |
| var _definition = require("../type/definition"); |
| |
| var _introspection = require("../type/introspection"); |
| |
| var _typeFromAST = require("./typeFromAST"); |
| |
| function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } |
| |
| /** |
| * TypeInfo is a utility class which, given a GraphQL schema, can keep track |
| * of the current field and type definitions at any point in a GraphQL document |
| * AST during a recursive descent by calling `enter(node)` and `leave(node)`. |
| */ |
| var TypeInfo = |
| /*#__PURE__*/ |
| function () { |
| function TypeInfo(schema, // NOTE: this experimental optional second parameter is only needed in order |
| // to support non-spec-compliant code bases. You should never need to use it. |
| // It may disappear in the future. |
| getFieldDefFn, // Initial type may be provided in rare cases to facilitate traversals |
| // beginning somewhere other than documents. |
| initialType) { |
| this._schema = schema; |
| this._typeStack = []; |
| this._parentTypeStack = []; |
| this._inputTypeStack = []; |
| this._fieldDefStack = []; |
| this._defaultValueStack = []; |
| this._directive = null; |
| this._argument = null; |
| this._enumValue = null; |
| this._getFieldDef = getFieldDefFn !== null && getFieldDefFn !== void 0 ? getFieldDefFn : getFieldDef; |
| |
| if (initialType) { |
| if ((0, _definition.isInputType)(initialType)) { |
| this._inputTypeStack.push(initialType); |
| } |
| |
| if ((0, _definition.isCompositeType)(initialType)) { |
| this._parentTypeStack.push(initialType); |
| } |
| |
| if ((0, _definition.isOutputType)(initialType)) { |
| this._typeStack.push(initialType); |
| } |
| } |
| } |
| |
| var _proto = TypeInfo.prototype; |
| |
| _proto.getType = function getType() { |
| if (this._typeStack.length > 0) { |
| return this._typeStack[this._typeStack.length - 1]; |
| } |
| }; |
| |
| _proto.getParentType = function getParentType() { |
| if (this._parentTypeStack.length > 0) { |
| return this._parentTypeStack[this._parentTypeStack.length - 1]; |
| } |
| }; |
| |
| _proto.getInputType = function getInputType() { |
| if (this._inputTypeStack.length > 0) { |
| return this._inputTypeStack[this._inputTypeStack.length - 1]; |
| } |
| }; |
| |
| _proto.getParentInputType = function getParentInputType() { |
| if (this._inputTypeStack.length > 1) { |
| return this._inputTypeStack[this._inputTypeStack.length - 2]; |
| } |
| }; |
| |
| _proto.getFieldDef = function getFieldDef() { |
| if (this._fieldDefStack.length > 0) { |
| return this._fieldDefStack[this._fieldDefStack.length - 1]; |
| } |
| }; |
| |
| _proto.getDefaultValue = function getDefaultValue() { |
| if (this._defaultValueStack.length > 0) { |
| return this._defaultValueStack[this._defaultValueStack.length - 1]; |
| } |
| }; |
| |
| _proto.getDirective = function getDirective() { |
| return this._directive; |
| }; |
| |
| _proto.getArgument = function getArgument() { |
| return this._argument; |
| }; |
| |
| _proto.getEnumValue = function getEnumValue() { |
| return this._enumValue; |
| }; |
| |
| _proto.enter = function enter(node) { |
| var schema = this._schema; // Note: many of the types below are explicitly typed as "mixed" to drop |
| // any assumptions of a valid schema to ensure runtime types are properly |
| // checked before continuing since TypeInfo is used as part of validation |
| // which occurs before guarantees of schema and document validity. |
| |
| switch (node.kind) { |
| case _kinds.Kind.SELECTION_SET: |
| { |
| var namedType = (0, _definition.getNamedType)(this.getType()); |
| |
| this._parentTypeStack.push((0, _definition.isCompositeType)(namedType) ? namedType : undefined); |
| |
| break; |
| } |
| |
| case _kinds.Kind.FIELD: |
| { |
| var parentType = this.getParentType(); |
| var fieldDef; |
| var fieldType; |
| |
| if (parentType) { |
| fieldDef = this._getFieldDef(schema, parentType, node); |
| |
| if (fieldDef) { |
| fieldType = fieldDef.type; |
| } |
| } |
| |
| this._fieldDefStack.push(fieldDef); |
| |
| this._typeStack.push((0, _definition.isOutputType)(fieldType) ? fieldType : undefined); |
| |
| break; |
| } |
| |
| case _kinds.Kind.DIRECTIVE: |
| this._directive = schema.getDirective(node.name.value); |
| break; |
| |
| case _kinds.Kind.OPERATION_DEFINITION: |
| { |
| var type; |
| |
| switch (node.operation) { |
| case 'query': |
| type = schema.getQueryType(); |
| break; |
| |
| case 'mutation': |
| type = schema.getMutationType(); |
| break; |
| |
| case 'subscription': |
| type = schema.getSubscriptionType(); |
| break; |
| } |
| |
| this._typeStack.push((0, _definition.isObjectType)(type) ? type : undefined); |
| |
| break; |
| } |
| |
| case _kinds.Kind.INLINE_FRAGMENT: |
| case _kinds.Kind.FRAGMENT_DEFINITION: |
| { |
| var typeConditionAST = node.typeCondition; |
| var outputType = typeConditionAST ? (0, _typeFromAST.typeFromAST)(schema, typeConditionAST) : (0, _definition.getNamedType)(this.getType()); |
| |
| this._typeStack.push((0, _definition.isOutputType)(outputType) ? outputType : undefined); |
| |
| break; |
| } |
| |
| case _kinds.Kind.VARIABLE_DEFINITION: |
| { |
| var inputType = (0, _typeFromAST.typeFromAST)(schema, node.type); |
| |
| this._inputTypeStack.push((0, _definition.isInputType)(inputType) ? inputType : undefined); |
| |
| break; |
| } |
| |
| case _kinds.Kind.ARGUMENT: |
| { |
| var _this$getDirective; |
| |
| var argDef; |
| var argType; |
| var fieldOrDirective = (_this$getDirective = this.getDirective()) !== null && _this$getDirective !== void 0 ? _this$getDirective : this.getFieldDef(); |
| |
| if (fieldOrDirective) { |
| argDef = (0, _find.default)(fieldOrDirective.args, function (arg) { |
| return arg.name === node.name.value; |
| }); |
| |
| if (argDef) { |
| argType = argDef.type; |
| } |
| } |
| |
| this._argument = argDef; |
| |
| this._defaultValueStack.push(argDef ? argDef.defaultValue : undefined); |
| |
| this._inputTypeStack.push((0, _definition.isInputType)(argType) ? argType : undefined); |
| |
| break; |
| } |
| |
| case _kinds.Kind.LIST: |
| { |
| var listType = (0, _definition.getNullableType)(this.getInputType()); |
| var itemType = (0, _definition.isListType)(listType) ? listType.ofType : listType; // List positions never have a default value. |
| |
| this._defaultValueStack.push(undefined); |
| |
| this._inputTypeStack.push((0, _definition.isInputType)(itemType) ? itemType : undefined); |
| |
| break; |
| } |
| |
| case _kinds.Kind.OBJECT_FIELD: |
| { |
| var objectType = (0, _definition.getNamedType)(this.getInputType()); |
| var inputFieldType; |
| var inputField; |
| |
| if ((0, _definition.isInputObjectType)(objectType)) { |
| inputField = objectType.getFields()[node.name.value]; |
| |
| if (inputField) { |
| inputFieldType = inputField.type; |
| } |
| } |
| |
| this._defaultValueStack.push(inputField ? inputField.defaultValue : undefined); |
| |
| this._inputTypeStack.push((0, _definition.isInputType)(inputFieldType) ? inputFieldType : undefined); |
| |
| break; |
| } |
| |
| case _kinds.Kind.ENUM: |
| { |
| var enumType = (0, _definition.getNamedType)(this.getInputType()); |
| var enumValue; |
| |
| if ((0, _definition.isEnumType)(enumType)) { |
| enumValue = enumType.getValue(node.value); |
| } |
| |
| this._enumValue = enumValue; |
| break; |
| } |
| } |
| }; |
| |
| _proto.leave = function leave(node) { |
| switch (node.kind) { |
| case _kinds.Kind.SELECTION_SET: |
| this._parentTypeStack.pop(); |
| |
| break; |
| |
| case _kinds.Kind.FIELD: |
| this._fieldDefStack.pop(); |
| |
| this._typeStack.pop(); |
| |
| break; |
| |
| case _kinds.Kind.DIRECTIVE: |
| this._directive = null; |
| break; |
| |
| case _kinds.Kind.OPERATION_DEFINITION: |
| case _kinds.Kind.INLINE_FRAGMENT: |
| case _kinds.Kind.FRAGMENT_DEFINITION: |
| this._typeStack.pop(); |
| |
| break; |
| |
| case _kinds.Kind.VARIABLE_DEFINITION: |
| this._inputTypeStack.pop(); |
| |
| break; |
| |
| case _kinds.Kind.ARGUMENT: |
| this._argument = null; |
| |
| this._defaultValueStack.pop(); |
| |
| this._inputTypeStack.pop(); |
| |
| break; |
| |
| case _kinds.Kind.LIST: |
| case _kinds.Kind.OBJECT_FIELD: |
| this._defaultValueStack.pop(); |
| |
| this._inputTypeStack.pop(); |
| |
| break; |
| |
| case _kinds.Kind.ENUM: |
| this._enumValue = null; |
| break; |
| } |
| }; |
| |
| return TypeInfo; |
| }(); |
| /** |
| * Not exactly the same as the executor's definition of getFieldDef, in this |
| * statically evaluated environment we do not always have an Object type, |
| * and need to handle Interface and Union types. |
| */ |
| |
| |
| exports.TypeInfo = TypeInfo; |
| |
| function getFieldDef(schema, parentType, fieldNode) { |
| var name = fieldNode.name.value; |
| |
| if (name === _introspection.SchemaMetaFieldDef.name && schema.getQueryType() === parentType) { |
| return _introspection.SchemaMetaFieldDef; |
| } |
| |
| if (name === _introspection.TypeMetaFieldDef.name && schema.getQueryType() === parentType) { |
| return _introspection.TypeMetaFieldDef; |
| } |
| |
| if (name === _introspection.TypeNameMetaFieldDef.name && (0, _definition.isCompositeType)(parentType)) { |
| return _introspection.TypeNameMetaFieldDef; |
| } |
| |
| if ((0, _definition.isObjectType)(parentType) || (0, _definition.isInterfaceType)(parentType)) { |
| return parentType.getFields()[name]; |
| } |
| } |
| /** |
| * Creates a new visitor instance which maintains a provided TypeInfo instance |
| * along with visiting visitor. |
| */ |
| |
| |
| function visitWithTypeInfo(typeInfo, visitor) { |
| return { |
| enter: function enter(node) { |
| typeInfo.enter(node); |
| var fn = (0, _visitor.getVisitFn)(visitor, node.kind, |
| /* isLeaving */ |
| false); |
| |
| if (fn) { |
| var result = fn.apply(visitor, arguments); |
| |
| if (result !== undefined) { |
| typeInfo.leave(node); |
| |
| if ((0, _ast.isNode)(result)) { |
| typeInfo.enter(result); |
| } |
| } |
| |
| return result; |
| } |
| }, |
| leave: function leave(node) { |
| var fn = (0, _visitor.getVisitFn)(visitor, node.kind, |
| /* isLeaving */ |
| true); |
| var result; |
| |
| if (fn) { |
| result = fn.apply(visitor, arguments); |
| } |
| |
| typeInfo.leave(node); |
| return result; |
| } |
| }; |
| } |