text: "use strict";
  
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  exports.TypeMapper = void 0;
  
  var _parser = require("graphql/language/parser");
  
  var _language = require("graphql/language");
  
  var _buildASTSchema = require("graphql/utilities/buildASTSchema");
  
  var _keyValMap = _interopRequireDefault(require("graphql/jsutils/keyValMap"));
  
  var _invariant = _interopRequireDefault(require("graphql/jsutils/invariant"));
  
  var _values = require("graphql/execution/values");
  
  var _misc = require("./utils/misc");
  
  var _find = _interopRequireDefault(require("./utils/polyfills/find"));
  
  var _graphql = require("./graphql");
  
  var _json = _interopRequireDefault(require("./type/json"));
  
  var _date = _interopRequireDefault(require("./type/date"));
  
  var _buffer = _interopRequireDefault(require("./type/buffer"));
  
  var _ObjectTypeComposer = require("./ObjectTypeComposer");
  
  var _InputTypeComposer = require("./InputTypeComposer");
  
  var _ScalarTypeComposer = require("./ScalarTypeComposer");
  
  var _EnumTypeComposer = require("./EnumTypeComposer");
  
  var _InterfaceTypeComposer = require("./InterfaceTypeComposer");
  
  var _UnionTypeComposer = require("./UnionTypeComposer");
  
  var _Resolver = require("./Resolver");
  
  var _TypeStorage = require("./TypeStorage");
  
  var _is = require("./utils/is");
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
  
  function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
  
  // solve Flow reqursion limit, do not import from graphql.js
  function isOutputType(type) {
    return type instanceof _graphql.GraphQLScalarType || type instanceof _graphql.GraphQLObjectType || type instanceof _graphql.GraphQLInterfaceType || type instanceof _graphql.GraphQLUnionType || type instanceof _graphql.GraphQLEnumType || type instanceof _graphql.GraphQLNonNull && isOutputType(type.ofType) || type instanceof _graphql.GraphQLList && isOutputType(type.ofType);
  } // solve Flow reqursion limit, do not import from graphql.js
  
  
  function isInputType(type) {
    return type instanceof _graphql.GraphQLScalarType || type instanceof _graphql.GraphQLEnumType || type instanceof _graphql.GraphQLInputObjectType || type instanceof _graphql.GraphQLNonNull && isInputType(type.ofType) || type instanceof _graphql.GraphQLList && isInputType(type.ofType);
  }
  
  const RegexpOutputTypeDefinition = /type\s[^{]+\{[^}]+\}/im;
  const RegexpInputTypeDefinition = /input\s[^{]+\{[^}]+\}/im;
  const RegexpEnumTypeDefinition = /enum\s[^{]+\{[^}]+\}/im;
  const RegexpScalarTypeDefinition = /scalar\s/im;
  const RegexpInterfaceTypeDefinition = /interface\s/im;
  
  class TypeMapper {
    constructor(schemaComposer) {
      if (!schemaComposer) {
        throw new Error('TypeMapper must have SchemaComposer instance.');
      }
  
      this.schemaComposer = schemaComposer;
      this.initScalars(); // alive proper Flow type casting in autosuggestions for class with Generics
  
      /* :: return this; */
    }
  
    initScalars() {
      const scalars = [['String', _graphql.GraphQLString], ['Float', _graphql.GraphQLFloat], ['Int', _graphql.GraphQLInt], ['Boolean', _graphql.GraphQLBoolean], ['ID', _graphql.GraphQLID], ['JSON', _json.default], ['Json', _json.default], ['Date', _date.default], ['Buffer', _buffer.default]];
      scalars.forEach(([name, type]) => {
        this.schemaComposer.set(name, type);
      });
    }
  
    get(name) {
      const schemaType = this.schemaComposer.get(name);
  
      if ((0, _graphql.isNamedType)(schemaType) || (0, _graphql.isScalarType)(schemaType)) {
        return schemaType;
      }
  
      return schemaType.getType();
    }
  
    set(name, type) {
      this.schemaComposer.set(name, type);
    }
  
    has(name) {
      return this.schemaComposer.has(name);
    }
  
    getWrapped(str) {
      const typeAST = (0, _parser.parseType)(str);
      return this.typeFromAST(typeAST);
    }
  
    createType(str) {
      if (this.has(str)) {
        return this.schemaComposer.getAnyTC(str);
      }
  
      const astDocument = (0, _parser.parse)(str);
  
      if (!astDocument || astDocument.kind !== 'Document') {
        throw new Error('You should provide correct type syntax. ' + "Eg. createType('type IntRange { min: Int, max: Int }')");
      }
  
      const types = this.parseTypes(astDocument);
      const type = types[0];
  
      if (type) {
        this.set(type.getTypeName(), type); // Also keep type string representation for avoiding duplicates type defs for same strings
  
        this.set(str, type);
        return type;
      }
  
      return undefined;
    }
  
    isTypeDefinitionString(str) {
      return RegexpOutputTypeDefinition.test(str) || RegexpInputTypeDefinition.test(str) || RegexpEnumTypeDefinition.test(str) || RegexpScalarTypeDefinition.test(str) || RegexpInterfaceTypeDefinition.test(str);
    }
  
    createGraphQLType(str) {
      const type = this.createType(str);
  
      if (type) {
        return type.getType();
      }
  
      return undefined;
    }
  
    parseTypesFromString(str) {
      const astDocument = (0, _parser.parse)(str);
  
      if (!astDocument || astDocument.kind !== 'Document') {
        throw new Error('You should provide correct SDL syntax.');
      }
  
      const types = this.parseTypes(astDocument);
      const typeStorage = new _TypeStorage.TypeStorage();
      types.forEach(type => {
        typeStorage.set(type.getTypeName(), type);
      });
      return typeStorage;
    }
  
    convertOutputType(composeType) {
      if (this.schemaComposer.hasInstance(composeType, _ObjectTypeComposer.ObjectTypeComposer)) {
        return this.schemaComposer.getOTC(composeType).getType();
      } else if (typeof composeType === 'string') {
        const type = this.isTypeDefinitionString(composeType) ? this.createGraphQLType(composeType) : this.getWrapped(composeType);
  
        if (!type) {
          throw new Error(`Cannot convert to OutputType the following string: '${composeType}'`);
        }
  
        if (!(type instanceof _graphql.GraphQLObjectType)) {
          throw new Error(`Cannot convert to OutputType the following object: '${(0, _misc.inspect)(type)}'`);
        }
  
        return type;
      } else if (composeType instanceof _graphql.GraphQLObjectType) {
        return composeType;
      } else if (composeType instanceof _ObjectTypeComposer.ObjectTypeComposer) {
        return composeType.getType();
      }
  
      throw new Error(`Cannot convert to OutputType the following object: '${(0, _misc.inspect)(composeType)}'`);
    }
  
    convertOutputFieldConfig(composeFC, fieldName = '', typeName = '') {
      (0, _invariant.default)(composeFC, `You provide empty argument field config for ${typeName}.${fieldName}`);
      let composeType;
      let copyProps;
      let copyArgs;
  
      if (composeFC instanceof _graphql.GraphQLList || composeFC instanceof _graphql.GraphQLNonNull) {
        return {
          type: composeFC
        };
      } else if ((0, _is.isFunction)(composeFC)) {
        return composeFC;
      } else if (composeFC instanceof _Resolver.Resolver) {
        return composeFC.getFieldConfig();
      } else if (composeFC instanceof _ObjectTypeComposer.ObjectTypeComposer || composeFC instanceof _EnumTypeComposer.EnumTypeComposer || composeFC instanceof _InterfaceTypeComposer.InterfaceTypeComposer || composeFC instanceof _UnionTypeComposer.UnionTypeComposer || composeFC instanceof _ScalarTypeComposer.ScalarTypeComposer) {
        return {
          type: composeFC.getType(),
          description: composeFC.getDescription()
        };
      } else if (Array.isArray(composeFC)) {
        composeType = composeFC;
      } else if (composeFC.type) {
        const _ref = composeFC,
              type = _ref.type,
              args = _ref.args,
              rest = _objectWithoutProperties(_ref, ["type", "args"]);
  
        composeType = type;
        copyProps = rest;
        copyArgs = args;
      } else {
        composeType = composeFC;
      }
  
      let wrapWithList = 0;
  
      while (Array.isArray(composeType)) {
        if (composeType.length !== 1) {
          throw new Error(`${typeName}.${fieldName} can accept Array exact with one output type definition`);
        }
  
        wrapWithList += 1;
        composeType = composeType[0];
      }
  
      if (composeType instanceof _InputTypeComposer.InputTypeComposer) {
        throw new Error(`You cannot provide InputTypeComposer to the field '${typeName}.${fieldName}'. It should be OutputType.`);
      }
  
      const fieldConfig = {};
  
      if (typeof composeType === 'string') {
        if (RegexpInputTypeDefinition.test(composeType)) {
          throw new Error(`${typeName}.${fieldName} should be OutputType, but got following type definition '${composeType}'`);
        }
  
        if (this.schemaComposer.has(composeType)) {
          fieldConfig.type = this.schemaComposer.getAnyTC(composeType).getType();
  
          if (!isOutputType(fieldConfig.type)) {
            throw new Error(`${typeName}.${fieldName} cannot convert to OutputType the following type: '${fieldConfig.type.toString()}'`);
          }
        } else {
          const type = this.isTypeDefinitionString(composeType) ? this.createGraphQLType(composeType) : this.getWrapped(composeType);
  
          if (!type) {
            throw new Error(`${typeName}.${fieldName} cannot convert to OutputType the following string: '${composeType}'`);
          }
  
          fieldConfig.type = type;
        }
      } else if (composeType instanceof _ObjectTypeComposer.ObjectTypeComposer || composeType instanceof _EnumTypeComposer.EnumTypeComposer || composeType instanceof _InterfaceTypeComposer.InterfaceTypeComposer || composeType instanceof _UnionTypeComposer.UnionTypeComposer || composeType instanceof _ScalarTypeComposer.ScalarTypeComposer) {
        fieldConfig.type = composeType.getType();
      } else if (composeType instanceof _Resolver.Resolver) {
        fieldConfig.type = composeType.getType();
      } else {
        fieldConfig.type = composeType;
      }
  
      if (!fieldConfig.type) {
        throw new Error(`${typeName}.${fieldName} must have some 'type'`);
      }
  
      if (!(0, _is.isFunction)(fieldConfig.type)) {
        if (!isOutputType(fieldConfig.type)) {
          throw new Error(`${typeName}.${fieldName} provided incorrect OutputType: '${(0, _misc.inspect)(composeType)}'`);
        }
  
        if (wrapWithList > 0) {
          for (let i = 0; i < wrapWithList; i++) {
            fieldConfig.type = new _graphql.GraphQLList(fieldConfig.type);
          }
        }
      }
  
      if (copyArgs) {
        const args = this.convertArgConfigMap(copyArgs, fieldName, typeName);
        fieldConfig.args = args;
      }
  
      if ((0, _is.isObject)(copyProps)) {
        // copy all other props
        for (const prop in copyProps) {
          if (copyProps.hasOwnProperty(prop)) {
            fieldConfig[prop] = copyProps[prop];
          }
        }
      }
  
      return fieldConfig;
    }
  
    convertOutputFieldConfigMap(composeFields, typeName = '') {
      const fields = {};
      Object.keys(composeFields).forEach(name => {
        fields[name] = this.convertOutputFieldConfig(composeFields[name], name, typeName);
      });
      return fields;
    }
  
    convertArgConfig(composeAC, argName = '', fieldName = '', typeName = '') {
      (0, _invariant.default)(composeAC, `You provide empty argument config for ${typeName}.${fieldName}.${argName}`);
      let composeType;
      let copyProps;
  
      if (composeAC instanceof _graphql.GraphQLList || composeAC instanceof _graphql.GraphQLNonNull) {
        return {
          type: composeAC
        };
      } else if (composeAC instanceof _InputTypeComposer.InputTypeComposer || composeAC instanceof _EnumTypeComposer.EnumTypeComposer || composeAC instanceof _ScalarTypeComposer.ScalarTypeComposer) {
        return {
          type: composeAC.getType(),
          description: composeAC.getDescription()
        };
      } else if (Array.isArray(composeAC)) {
        composeType = composeAC;
      } else if ((0, _is.isFunction)(composeAC)) {
        return composeAC;
      } else if (composeAC.type) {
        const _ref2 = composeAC,
              type = _ref2.type,
              rest = _objectWithoutProperties(_ref2, ["type"]);
  
        composeType = type;
        copyProps = rest;
      } else {
        composeType = composeAC;
      }
  
      let wrapWithList = 0;
  
      while (Array.isArray(composeType)) {
        if (composeType.length !== 1) {
          throw new Error(`${typeName}.${fieldName}@${argName} can accept Array exact with one input type definition`);
        }
  
        wrapWithList += 1;
        composeType = composeType[0];
      }
  
      if (composeType instanceof _ObjectTypeComposer.ObjectTypeComposer) {
        throw new Error(`You cannot provide ObjectTypeComposer to the arg '${typeName}.${fieldName}.@${argName}'. It should be InputType.`);
      }
  
      const argConfig = {};
  
      if (typeof composeType === 'string') {
        if (RegexpOutputTypeDefinition.test(composeType)) {
          throw new Error(`${typeName}.${fieldName}@${argName} should be InputType, but got output type definition '${composeType}'`);
        }
  
        if (this.schemaComposer.has(composeType)) {
          argConfig.type = this.schemaComposer.getAnyTC(composeType).getType();
  
          if (!isInputType(argConfig.type)) {
            throw new Error(`${typeName}.${fieldName}@${argName} cannot convert to InputType the following type: '${argConfig.type.toString()}'`);
          }
        } else {
          const type = this.isTypeDefinitionString(composeType) ? this.createGraphQLType(composeType) : this.getWrapped(composeType);
  
          if (!type) {
            throw new Error(`${typeName}.${fieldName}@${argName} cannot convert to InputType the following string: '${composeType}'`);
          }
  
          argConfig.type = type;
        }
      } else if (composeType instanceof _InputTypeComposer.InputTypeComposer || composeType instanceof _EnumTypeComposer.EnumTypeComposer || composeType instanceof _ScalarTypeComposer.ScalarTypeComposer) {
        argConfig.type = composeType.getType();
      } else {
        argConfig.type = composeType;
      }
  
      if (!argConfig.type) {
        throw new Error(`${typeName}.${fieldName}@${argName} must have some 'type'`);
      }
  
      if (!(0, _is.isFunction)(argConfig.type)) {
        if (!isInputType(argConfig.type)) {
          throw new Error(`${typeName}.${fieldName}@${argName} provided incorrect InputType: '${(0, _misc.inspect)(composeType)}'`);
        }
  
        if (wrapWithList > 0) {
          for (let i = 0; i < wrapWithList; i++) {
            argConfig.type = new _graphql.GraphQLList(argConfig.type);
          }
        }
      }
  
      if ((0, _is.isObject)(copyProps)) {
        // copy all other props
        for (const prop in copyProps) {
          if (copyProps.hasOwnProperty(prop)) {
            argConfig[prop] = copyProps[prop];
          }
        }
      }
  
      return argConfig;
    }
  
    convertArgConfigMap(composeArgsConfigMap, fieldName = '', typeName = '') {
      const argsConfigMap = {};
  
      if (composeArgsConfigMap) {
        Object.keys(composeArgsConfigMap).forEach(argName => {
          argsConfigMap[argName] = this.convertArgConfig(composeArgsConfigMap[argName], argName, fieldName, typeName);
        });
      }
  
      return argsConfigMap;
    }
  
    convertInputFieldConfig(composeIFC, fieldName = '', typeName = '') {
      (0, _invariant.default)(composeIFC, `You provide empty input field config for ${typeName}.${fieldName}`);
      let composeType;
      let copyProps;
  
      if (composeIFC instanceof _graphql.GraphQLList || composeIFC instanceof _graphql.GraphQLNonNull) {
        return {
          type: composeIFC
        };
      } else if (composeIFC instanceof _InputTypeComposer.InputTypeComposer || composeIFC instanceof _EnumTypeComposer.EnumTypeComposer || composeIFC instanceof _ScalarTypeComposer.ScalarTypeComposer) {
        return {
          type: composeIFC.getType(),
          description: composeIFC.getDescription()
        };
      } else if (Array.isArray(composeIFC)) {
        composeType = composeIFC;
      } else if ((0, _is.isFunction)(composeIFC)) {
        return composeIFC;
      } else if (composeIFC.type) {
        const _ref3 = composeIFC,
              type = _ref3.type,
              rest = _objectWithoutProperties(_ref3, ["type"]);
  
        composeType = composeIFC.type;
        copyProps = rest;
      } else {
        composeType = composeIFC;
      }
  
      let wrapWithList = 0;
  
      while (Array.isArray(composeType)) {
        if (composeType.length !== 1) {
          throw new Error(`${typeName}.${fieldName} can accept Array exact with one input type definition`);
        }
  
        wrapWithList += 1;
        composeType = composeType[0];
      }
  
      if (composeType instanceof _ObjectTypeComposer.ObjectTypeComposer) {
        throw new Error(`You cannot provide ObjectTypeComposer to the field '${typeName}.${fieldName}'. It should be InputType.`);
      }
  
      const fieldConfig = {};
  
      if (typeof composeType === 'string') {
        if (RegexpOutputTypeDefinition.test(composeType)) {
          throw new Error(`${typeName}.${fieldName} should be InputType, but got output type definition '${composeType}'`);
        }
  
        if (this.schemaComposer.has(composeType)) {
          fieldConfig.type = this.schemaComposer.getAnyTC(composeType).getType();
  
          if (!isInputType(fieldConfig.type)) {
            throw new Error(`${typeName}.${fieldName} cannot convert to InputType the following type: '${fieldConfig.type.toString()}'`);
          }
        } else {
          const type = this.isTypeDefinitionString(composeType) ? this.createGraphQLType(composeType) : this.getWrapped(composeType);
  
          if (!type) {
            throw new Error(`${typeName}.${fieldName} cannot convert to InputType the following string: '${composeType}'`);
          }
  
          fieldConfig.type = type;
        }
      } else if (composeType instanceof _InputTypeComposer.InputTypeComposer || composeType instanceof _EnumTypeComposer.EnumTypeComposer || composeType instanceof _ScalarTypeComposer.ScalarTypeComposer) {
        fieldConfig.type = composeType.getType();
      } else {
        fieldConfig.type = composeType;
      }
  
      if (!fieldConfig.type) {
        throw new Error(`${typeName}.${fieldName} must have some 'type'`);
      }
  
      if (!(0, _is.isFunction)(fieldConfig.type)) {
        if (!isInputType(fieldConfig.type)) {
          throw new Error(`${typeName}.${fieldName} provided incorrect InputType: '${(0, _misc.inspect)(composeType)}'`);
        }
  
        if (wrapWithList > 0) {
          for (let i = 0; i < wrapWithList; i++) {
            fieldConfig.type = new _graphql.GraphQLList(fieldConfig.type);
          }
        }
      }
  
      if ((0, _is.isObject)(copyProps)) {
        // copy all other props
        for (const prop in copyProps) {
          if (copyProps.hasOwnProperty(prop)) {
            fieldConfig[prop] = copyProps[prop];
          }
        }
      }
  
      return fieldConfig;
    }
  
    convertInputFieldConfigMap(composeFields, typeName = '') {
      const fields = {};
      Object.keys(composeFields).forEach(name => {
        fields[name] = this.convertInputFieldConfig(composeFields[name], name, typeName);
      });
      return fields;
    }
    /**
     * -----------------------------------------------
     * Internal methods
     * -----------------------------------------------
     */
  
  
    convertInterfaceType(composeType) {
      if (this.schemaComposer.hasInstance(composeType, _InterfaceTypeComposer.InterfaceTypeComposer)) {
        return this.schemaComposer.getIFTC(composeType).getType();
      } else if (typeof composeType === 'string') {
        const type = RegexpInterfaceTypeDefinition.test(composeType) ? this.createGraphQLType(composeType) : this.getWrapped(composeType);
  
        if (!type) {
          throw new Error(`Cannot convert to InterfaceType the following string: '${composeType}'`);
        }
  
        if (!(type instanceof _graphql.GraphQLInterfaceType)) {
          throw new Error(`Cannot convert to InterfaceType the following object: '${(0, _misc.inspect)(type)}'`);
        }
  
        return type;
      } else if (composeType instanceof _graphql.GraphQLInterfaceType) {
        return composeType;
      } else if (composeType instanceof _InterfaceTypeComposer.InterfaceTypeComposer) {
        return composeType.getType();
      }
  
      throw new Error(`Cannot convert to InterfaceType the following object: '${(0, _misc.inspect)(composeType)}'`);
    }
  
    parseTypes(astDocument) {
      const types = [];
  
      for (let i = 0; i < astDocument.definitions.length; i++) {
        const def = astDocument.definitions[i];
        const type = this.makeSchemaDef(def);
  
        if (type) {
          types[i] = type;
        }
      }
  
      return types;
    }
  
    typeFromAST(inputTypeAST) {
      let innerType;
  
      if (inputTypeAST.kind === _language.Kind.LIST_TYPE) {
        innerType = this.typeFromAST(inputTypeAST.type);
        return innerType && new _graphql.GraphQLList(innerType);
      }
  
      if (inputTypeAST.kind === _language.Kind.NON_NULL_TYPE) {
        innerType = this.typeFromAST(inputTypeAST.type);
        return innerType && new _graphql.GraphQLNonNull(innerType);
      }
  
      (0, _invariant.default)(inputTypeAST.kind === _language.Kind.NAMED_TYPE, 'Must be a named type.');
      return this.get(inputTypeAST.name.value);
    }
  
    typeDefNamed(typeName) {
      const type = this.get(typeName);
  
      if (type && (0, _graphql.isNamedType)(type)) {
        return type;
      } else if (type) {
        return type.getType();
      }
  
      if (typeName === 'Query') {
        return this.schemaComposer.Query.getType();
      }
  
      if (typeName === 'Mutation') {
        return this.schemaComposer.Mutation.getType();
      }
  
      if (typeName === 'Subscription') {
        return this.schemaComposer.Subscription.getType();
      }
  
      throw new Error(`Cannot find type with name '${typeName}' in SchemaComposer.`);
    }
  
    makeSchemaDef(def) {
      if (!def) {
        throw new Error('def must be defined');
      }
  
      switch (def.kind) {
        case _language.Kind.OBJECT_TYPE_DEFINITION:
          return this.makeTypeDef(def);
  
        case _language.Kind.INTERFACE_TYPE_DEFINITION:
          return this.makeInterfaceDef(def);
  
        case _language.Kind.ENUM_TYPE_DEFINITION:
          return this.makeEnumDef(def);
  
        case _language.Kind.UNION_TYPE_DEFINITION:
          return this.makeUnionDef(def);
  
        case _language.Kind.SCALAR_TYPE_DEFINITION:
          return this.makeScalarDef(def);
  
        case _language.Kind.SCHEMA_DEFINITION:
          this.checkSchemaDef(def);
          return null;
  
        case _language.Kind.DIRECTIVE_DEFINITION:
          {
            const directive = this.makeDirectiveDef(def);
            if (directive) this.schemaComposer.addDirective(directive);
            return null;
          }
  
        case _language.Kind.INPUT_OBJECT_TYPE_DEFINITION:
          return this.makeInputObjectDef(def);
  
        default:
          throw new Error(`Type kind "${def.kind}" not supported.`);
      }
    }
  
    makeArguments(values) {
      if (!values) {
        return {};
      }
  
      const result = {};
      values.forEach(value => {
        const key = value.name.value;
        let val;
        const typeName = this.getNamedTypeAST(value.type).name.value;
        const type = this.produceType(value.type);
        const ac = {
          type,
          description: (0, _buildASTSchema.getDescription)(value)
        };
  
        if (value.directives) {
          const directives = this.parseDirectives(value.directives);
  
          if (directives) {
            ac.extensions = {
              directives
            };
            const data = directives.find(d => d.name === 'default');
  
            if (data) {
              ac.defaultValue = data.args.value;
            }
          }
        }
  
        if (value.defaultValue) {
          const typeDef = this.typeDefNamed(typeName);
          const wrappedType = this.buildWrappedTypeDef(typeDef, value.type);
  
          if (isInputType(wrappedType)) {
            ac.defaultValue = (0, _graphql.valueFromAST)(value.defaultValue, wrappedType);
          } else {
            throw new Error('Non-input type as an argument.');
          }
        }
  
        result[key] = ac;
      });
      return result;
    }
  
    makeFieldDefMap(def) {
      if (!def.fields) return {};
      return (0, _keyValMap.default)(def.fields, field => field.name.value, field => {
        const fc = {
          type: this.produceType(field.type),
          description: (0, _buildASTSchema.getDescription)(field),
          args: this.makeArguments(field.arguments),
          deprecationReason: this.getDeprecationReason(field.directives),
          astNode: field
        };
  
        if (field.directives) {
          const directives = this.parseDirectives(field.directives);
  
          if (directives) {
            fc.extensions = {
              directives
            };
          }
        }
  
        return fc;
      });
    }
  
    makeInputFieldDef(def) {
      if (!def.fields) return {};
      return (0, _keyValMap.default)(def.fields, field => field.name.value, field => {
        const fc = {
          type: this.produceType(field.type),
          description: (0, _buildASTSchema.getDescription)(field),
          deprecationReason: this.getDeprecationReason(field.directives),
          astNode: field
        };
  
        if (field.directives) {
          const directives = this.parseDirectives(field.directives);
  
          if (directives) {
            fc.extensions = {
              directives
            };
            const data = directives.find(d => d.name === 'default');
  
            if (data) {
              fc.defaultValue = data.args.value;
            }
          }
        }
  
        return fc;
      });
    }
  
    makeEnumDef(def) {
      const tc = this.schemaComposer.createEnumTC({
        name: def.name.value,
        description: (0, _buildASTSchema.getDescription)(def),
        values: !def.values ? {} : (0, _keyValMap.default)(def.values, enumValue => enumValue.name.value, enumValue => {
          const ec = {
            description: (0, _buildASTSchema.getDescription)(enumValue),
            deprecationReason: this.getDeprecationReason(enumValue.directives)
          };
  
          if (enumValue.directives) {
            const directives = this.parseDirectives(enumValue.directives);
  
            if (directives) {
              ec.extensions = {
                directives
              };
            }
          }
  
          return ec;
        }),
        astNode: def
      });
  
      if (def.directives) {
        tc.setExtension('directives', this.parseDirectives(def.directives));
      }
  
      return tc;
    }
  
    makeInputObjectDef(def) {
      const tc = this.schemaComposer.createInputTC({
        name: def.name.value,
        description: (0, _buildASTSchema.getDescription)(def),
        fields: this.makeInputFieldDef(def),
        astNode: def
      });
  
      if (def.directives) {
        tc.setExtension('directives', this.parseDirectives(def.directives));
      }
  
      return tc;
    }
  
    makeDirectiveDef(def) {
      const locations = def.locations.map(({
        value
      }) => value);
      const args = {};
      (def.arguments || []).forEach(value => {
        const key = value.name.value;
        let val;
        const typeName = this.getNamedTypeAST(value.type).name.value;
        const typeDef = this.typeDefNamed(typeName);
        const wrappedType = this.buildWrappedTypeDef(typeDef, value.type);
  
        if (isInputType(wrappedType)) {
          val = {
            type: wrappedType,
            description: (0, _buildASTSchema.getDescription)(value)
          };
        } else {
          throw new Error('Non-input type as an argument.');
        }
  
        args[key] = val;
      });
      return new _graphql.GraphQLDirective({
        name: def.name.value,
        description: (0, _buildASTSchema.getDescription)(def),
        locations,
        args,
        astNode: def
      });
    }
  
    makeScalarDef(def) {
      const tc = this.schemaComposer.createScalarTC({
        name: def.name.value,
        description: (0, _buildASTSchema.getDescription)(def),
        serialize: v => v,
        astNode: def
      });
  
      if (def.directives) {
        tc.setExtension('directives', this.parseDirectives(def.directives));
      }
  
      return tc;
    }
  
    makeImplementedInterfaces(def) {
      return (def.interfaces || []).map(iface => {
        const name = this.getNamedTypeAST(iface).name.value;
        return this.schemaComposer.getIFTC(name).getType();
      });
    }
  
    makeTypeDef(def) {
      const tc = this.schemaComposer.createObjectTC({
        name: def.name.value,
        description: (0, _buildASTSchema.getDescription)(def),
        fields: this.makeFieldDefMap(def),
        interfaces: () => this.makeImplementedInterfaces(def),
        astNode: def
      });
  
      if (def.directives) {
        tc.setExtension('directives', this.parseDirectives(def.directives));
      }
  
      return tc;
    }
  
    makeInterfaceDef(def) {
      const tc = this.schemaComposer.createInterfaceTC({
        name: def.name.value,
        description: (0, _buildASTSchema.getDescription)(def),
        fields: this.makeFieldDefMap(def),
        astNode: def
      });
  
      if (def.directives) {
        tc.setExtension('directives', this.parseDirectives(def.directives));
      }
  
      return tc;
    }
  
    makeUnionDef(def) {
      const types = def.types;
      const tc = this.schemaComposer.createUnionTC({
        name: def.name.value,
        description: (0, _buildASTSchema.getDescription)(def),
        types: (types || []).map(ref => this.getNamedTypeAST(ref).name.value),
        astNode: def
      });
  
      if (def.directives) {
        tc.setExtension('directives', this.parseDirectives(def.directives));
      }
  
      return tc;
    }
  
    checkSchemaDef(def) {
      const validNames = {
        query: 'Query',
        mutation: 'Mutation',
        subscription: 'Subscription'
      };
      def.operationTypes.forEach(d => {
        if (d.operation) {
          const validTypeName = validNames[d.operation];
          const actualTypeName = d.type.name.value;
  
          if (actualTypeName !== validTypeName) {
            throw new Error(`Incorrect type name '${actualTypeName}' for '${d.operation}'. The valid definition is "schema { ${d.operation}: ${validTypeName} }"`);
          }
        }
      });
    }
  
    getNamedTypeAST(typeAST) {
      let namedType = typeAST;
  
      while (namedType.kind === _language.Kind.LIST_TYPE || namedType.kind === _language.Kind.NON_NULL_TYPE) {
        namedType = namedType.type;
      }
  
      return namedType;
    }
  
    buildWrappedType(innerType, inputTypeAST) {
      if (inputTypeAST.kind === _language.Kind.LIST_TYPE) {
        const wrappedType = this.buildWrappedType(innerType, inputTypeAST.type);
        return `[${wrappedType}]`;
      }
  
      if (inputTypeAST.kind === _language.Kind.NON_NULL_TYPE) {
        const wrappedType = this.buildWrappedType(innerType, inputTypeAST.type);
        return `${wrappedType}!`;
      }
  
      return innerType.toString();
    }
  
    buildWrappedTypeDef(innerType, inputTypeAST) {
      if (inputTypeAST.kind === _language.Kind.LIST_TYPE) {
        return new _graphql.GraphQLList(this.buildWrappedTypeDef(innerType, inputTypeAST.type));
      }
  
      if (inputTypeAST.kind === _language.Kind.NON_NULL_TYPE) {
        const wrappedType = this.buildWrappedTypeDef(innerType, inputTypeAST.type);
        (0, _invariant.default)(!(wrappedType instanceof _graphql.GraphQLNonNull), 'No nesting nonnull.');
        return new _graphql.GraphQLNonNull(wrappedType);
      }
  
      return innerType;
    }
  
    produceType(typeAST) {
      const typeName = this.getNamedTypeAST(typeAST).name.value;
      return this.buildWrappedType(typeName, typeAST);
    }
  
    getDeprecationReason(directives) {
      const deprecatedAST = directives && (0, _find.default)(directives, directive => directive.name.value === _graphql.GraphQLDeprecatedDirective.name);
  
      if (!deprecatedAST) {
        return;
      }
  
      const _getArgumentValues = (0, _values.getArgumentValues)(_graphql.GraphQLDeprecatedDirective, deprecatedAST),
            reason = _getArgumentValues.reason;
  
      return reason; // eslint-disable-line
    }
  
    parseDirectives(directives) {
      const result = [];
      directives.forEach(directive => {
        const name = directive.name.value;
  
        const directiveDef = this.schemaComposer._getDirective(name);
  
        const args = directiveDef ? (0, _values.getArgumentValues)(directiveDef, directive) : (0, _keyValMap.default)(directive.arguments || [], arg => arg.name.value, arg => _json.default.parseLiteral(arg.value));
        result.push({
          name,
          args
        });
      });
      return result;
    }
  
  }
  
  exports.TypeMapper = TypeMapper;