text: "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 || 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 argDef;
            var argType;
            var fieldOrDirective = 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;
      }
    };
  }
  