text: import { Kind, GraphQLDirective, valueFromASTUntyped, GraphQLInputObjectType, GraphQLScalarType, GraphQLUnionType, GraphQLEnumType, GraphQLInterfaceType, GraphQLObjectType, DirectiveLocation, TokenKind, getDirectiveValues, GraphQLDeprecatedDirective, isObjectType, isInputObjectType, isInterfaceType, isUnionType, isEnumType, isScalarType, isSchema, isNamedType, getNamedType, isSpecifiedScalarType, GraphQLSchema, isLeafType, print, specifiedDirectives, extendSchema } from 'graphql';
  import { createStub, createNamedStub, fieldToFieldConfig, inputFieldToFieldConfig, parseSelectionSet, parseFragmentToInlineFragment, concatInlineFragments, pruneSchema, filterSchema, getImplementingTypes, mapSchema, MapperKind, getDirectives, rewireTypes, mergeDeep, SchemaDirectiveVisitor } from '@graphql-tools/utils';
  import { buildDocumentFromTypeDefinitions, extendResolversFromInterfaces, addResolversToSchema, assertResolversPresent, addCatchUndefinedToSchema, addErrorLoggingToSchema, addSchemaLevelResolver, attachDirectiveResolvers } from '@graphql-tools/schema';
  import { wrapSchema, TransformCompositeFields } from '@graphql-tools/wrap';
  import { isSubschemaConfig, delegateToSchema, cloneSubschemaConfig } from '@graphql-tools/delegate';
  import { mergeType, mergeInputType, mergeInterface, mergeUnion, mergeEnum } from '@graphql-tools/merge';
  import { batchDelegateToSchema } from '@graphql-tools/batch-delegate';
  
  function extractTypeDefinitions(ast) {
      const typeDefs = ast.definitions.filter((def) => def.kind === Kind.OBJECT_TYPE_DEFINITION ||
          def.kind === Kind.INTERFACE_TYPE_DEFINITION ||
          def.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION ||
          def.kind === Kind.UNION_TYPE_DEFINITION ||
          def.kind === Kind.ENUM_TYPE_DEFINITION ||
          def.kind === Kind.SCALAR_TYPE_DEFINITION);
      return {
          ...ast,
          definitions: typeDefs,
      };
  }
  function extractDirectiveDefinitions(ast) {
      const directiveDefs = ast.definitions.filter((def) => def.kind === Kind.DIRECTIVE_DEFINITION);
      return {
          ...ast,
          definitions: directiveDefs,
      };
  }
  function extractSchemaDefinition(ast) {
      const schemaDefs = ast.definitions.filter((def) => def.kind === Kind.SCHEMA_DEFINITION);
      return schemaDefs.length ? schemaDefs[schemaDefs.length - 1] : null;
  }
  function extractSchemaExtensions(ast) {
      const schemaExtensions = ast.definitions.filter((def) => def.kind === Kind.SCHEMA_EXTENSION);
      return schemaExtensions;
  }
  function extractTypeExtensionDefinitions(ast) {
      const extensionDefs = ast.definitions.filter((def) => def.kind === Kind.OBJECT_TYPE_EXTENSION ||
          def.kind === Kind.INTERFACE_TYPE_EXTENSION ||
          def.kind === Kind.INPUT_OBJECT_TYPE_EXTENSION ||
          def.kind === Kind.UNION_TYPE_EXTENSION ||
          def.kind === Kind.ENUM_TYPE_EXTENSION ||
          def.kind === Kind.SCALAR_TYPE_EXTENSION);
      return {
          ...ast,
          definitions: extensionDefs,
      };
  }
  
  const backcompatOptions = { commentDescriptions: true };
  function typeFromAST(node) {
      switch (node.kind) {
          case Kind.OBJECT_TYPE_DEFINITION:
              return makeObjectType(node);
          case Kind.INTERFACE_TYPE_DEFINITION:
              return makeInterfaceType(node);
          case Kind.ENUM_TYPE_DEFINITION:
              return makeEnumType(node);
          case Kind.UNION_TYPE_DEFINITION:
              return makeUnionType(node);
          case Kind.SCALAR_TYPE_DEFINITION:
              return makeScalarType(node);
          case Kind.INPUT_OBJECT_TYPE_DEFINITION:
              return makeInputObjectType(node);
          case Kind.DIRECTIVE_DEFINITION:
              return makeDirective(node);
          default:
              return null;
      }
  }
  function makeObjectType(node) {
      const config = {
          name: node.name.value,
          description: getDescription(node, backcompatOptions),
          interfaces: () => node.interfaces.map(iface => createNamedStub(iface.name.value, 'interface')),
          fields: () => makeFields(node.fields),
          astNode: node,
      };
      return new GraphQLObjectType(config);
  }
  function makeInterfaceType(node) {
      var _a;
      const config = {
          name: node.name.value,
          description: getDescription(node, backcompatOptions),
          interfaces: (_a = node.interfaces) === null || _a === void 0 ? void 0 : _a.map(iface => createNamedStub(iface.name.value, 'interface')),
          fields: () => makeFields(node.fields),
          astNode: node,
      };
      return new GraphQLInterfaceType(config);
  }
  function makeEnumType(node) {
      const values = node.values.reduce((prev, value) => ({
          ...prev,
          [value.name.value]: {
              description: getDescription(value, backcompatOptions),
              deprecationReason: getDeprecationReason(value),
              astNode: value,
          },
      }), {});
      return new GraphQLEnumType({
          name: node.name.value,
          description: getDescription(node, backcompatOptions),
          values,
          astNode: node,
      });
  }
  function makeUnionType(node) {
      return new GraphQLUnionType({
          name: node.name.value,
          description: getDescription(node, backcompatOptions),
          types: () => node.types.map(type => createNamedStub(type.name.value, 'object')),
          astNode: node,
      });
  }
  function makeScalarType(node) {
      return new GraphQLScalarType({
          name: node.name.value,
          description: getDescription(node, backcompatOptions),
          astNode: node,
          // TODO: serialize default property setting can be dropped once
          // upstream graphql-js TypeScript typings are updated, likely in v16
          serialize: value => value,
      });
  }
  function makeInputObjectType(node) {
      return new GraphQLInputObjectType({
          name: node.name.value,
          description: getDescription(node, backcompatOptions),
          fields: () => makeValues(node.fields),
          astNode: node,
      });
  }
  function makeFields(nodes) {
      return nodes.reduce((prev, node) => ({
          ...prev,
          [node.name.value]: {
              type: createStub(node.type, 'output'),
              description: getDescription(node, backcompatOptions),
              args: makeValues(node.arguments),
              deprecationReason: getDeprecationReason(node),
              astNode: node,
          },
      }), {});
  }
  function makeValues(nodes) {
      return nodes.reduce((prev, node) => ({
          ...prev,
          [node.name.value]: {
              type: createStub(node.type, 'input'),
              defaultValue: node.defaultValue !== undefined ? valueFromASTUntyped(node.defaultValue) : undefined,
              description: getDescription(node, backcompatOptions),
              astNode: node,
          },
      }), {});
  }
  function makeDirective(node) {
      const locations = [];
      node.locations.forEach(location => {
          if (location.value in DirectiveLocation) {
              locations.push(location.value);
          }
      });
      return new GraphQLDirective({
          name: node.name.value,
          description: node.description != null ? node.description.value : null,
          locations,
          isRepeatable: node.repeatable,
          args: makeValues(node.arguments),
          astNode: node,
      });
  }
  // graphql < v13 does not export getDescription
  function getDescription(node, options) {
      if (node.description != null) {
          return node.description.value;
      }
      if (options.commentDescriptions) {
          const rawValue = getLeadingCommentBlock(node);
          if (rawValue !== undefined) {
              return dedentBlockStringValue(`\n${rawValue}`);
          }
      }
  }
  function getLeadingCommentBlock(node) {
      const loc = node.loc;
      if (!loc) {
          return;
      }
      const comments = [];
      let token = loc.startToken.prev;
      while (token != null &&
          token.kind === TokenKind.COMMENT &&
          token.next != null &&
          token.prev != null &&
          token.line + 1 === token.next.line &&
          token.line !== token.prev.line) {
          const value = String(token.value);
          comments.push(value);
          token = token.prev;
      }
      return comments.length > 0 ? comments.reverse().join('\n') : undefined;
  }
  function dedentBlockStringValue(rawString) {
      // Expand a block string's raw value into independent lines.
      const lines = rawString.split(/\r\n|[\n\r]/g);
      // Remove common indentation from all lines but first.
      const commonIndent = getBlockStringIndentation(lines);
      if (commonIndent !== 0) {
          for (let i = 1; i < lines.length; i++) {
              lines[i] = lines[i].slice(commonIndent);
          }
      }
      // Remove leading and trailing blank lines.
      while (lines.length > 0 && isBlank(lines[0])) {
          lines.shift();
      }
      while (lines.length > 0 && isBlank(lines[lines.length - 1])) {
          lines.pop();
      }
      // Return a string of the lines joined with U+000A.
      return lines.join('\n');
  }
  /**
   * @internal
   */
  function getBlockStringIndentation(lines) {
      let commonIndent = null;
      for (let i = 1; i < lines.length; i++) {
          const line = lines[i];
          const indent = leadingWhitespace(line);
          if (indent === line.length) {
              continue; // skip empty lines
          }
          if (commonIndent === null || indent < commonIndent) {
              commonIndent = indent;
              if (commonIndent === 0) {
                  break;
              }
          }
      }
      return commonIndent === null ? 0 : commonIndent;
  }
  function leadingWhitespace(str) {
      let i = 0;
      while (i < str.length && (str[i] === ' ' || str[i] === '\t')) {
          i++;
      }
      return i;
  }
  function isBlank(str) {
      return leadingWhitespace(str) === str.length;
  }
  function getDeprecationReason(node) {
      const deprecated = getDirectiveValues(GraphQLDeprecatedDirective, node);
      return deprecated === null || deprecated === void 0 ? void 0 : deprecated.reason;
  }
  
  function mergeCandidates(typeName, candidates, typeMergingOptions) {
      const initialCandidateType = candidates[0].type;
      if (candidates.some(candidate => candidate.type.constructor !== initialCandidateType.constructor)) {
          throw new Error(`Cannot merge different type categories into common type ${typeName}.`);
      }
      if (isObjectType(initialCandidateType)) {
          return mergeObjectTypeCandidates(typeName, candidates, typeMergingOptions);
      }
      else if (isInputObjectType(initialCandidateType)) {
          return mergeInputObjectTypeCandidates(typeName, candidates, typeMergingOptions);
      }
      else if (isInterfaceType(initialCandidateType)) {
          return mergeInterfaceTypeCandidates(typeName, candidates, typeMergingOptions);
      }
      else if (isUnionType(initialCandidateType)) {
          return mergeUnionTypeCandidates(typeName, candidates, typeMergingOptions);
      }
      else if (isEnumType(initialCandidateType)) {
          return mergeEnumTypeCandidates(typeName, candidates, typeMergingOptions);
      }
      else if (isScalarType(initialCandidateType)) {
          return mergeScalarTypeCandidates(typeName, candidates, typeMergingOptions);
      }
      else {
          // not reachable.
          throw new Error(`Type ${typeName} has unknown GraphQL type.`);
      }
  }
  function mergeObjectTypeCandidates(typeName, candidates, typeMergingOptions) {
      const description = mergeTypeDescriptions(candidates, typeMergingOptions);
      const fields = fieldConfigMapFromTypeCandidates(candidates, typeMergingOptions);
      const typeConfigs = candidates.map(candidate => candidate.type.toConfig());
      const interfaceMap = typeConfigs
          .map(typeConfig => typeConfig.interfaces)
          .reduce((acc, interfaces) => {
          if (interfaces != null) {
              interfaces.forEach(iface => {
                  acc[iface.name] = iface;
              });
          }
          return acc;
      }, Object.create(null));
      const interfaces = Object.keys(interfaceMap).map(interfaceName => interfaceMap[interfaceName]);
      const astNodes = pluck('astNode', candidates);
      const astNode = astNodes
          .slice(1)
          .reduce((acc, astNode) => mergeType(astNode, acc), astNodes[0]);
      const extensionASTNodes = [].concat(pluck('extensionASTNodes', candidates));
      const extensions = Object.assign({}, ...pluck('extensions', candidates));
      const typeConfig = {
          name: typeName,
          description,
          fields,
          interfaces,
          astNode,
          extensionASTNodes,
          extensions,
      };
      return new GraphQLObjectType(typeConfig);
  }
  function mergeInputObjectTypeCandidates(typeName, candidates, typeMergingOptions) {
      const description = mergeTypeDescriptions(candidates, typeMergingOptions);
      const fields = inputFieldConfigMapFromTypeCandidates(candidates, typeMergingOptions);
      const astNodes = pluck('astNode', candidates);
      const astNode = astNodes
          .slice(1)
          .reduce((acc, astNode) => mergeInputType(astNode, acc), astNodes[0]);
      const extensionASTNodes = [].concat(pluck('extensionASTNodes', candidates));
      const extensions = Object.assign({}, ...pluck('extensions', candidates));
      const typeConfig = {
          name: typeName,
          description,
          fields,
          astNode,
          extensionASTNodes,
          extensions,
      };
      return new GraphQLInputObjectType(typeConfig);
  }
  function pluck(typeProperty, candidates) {
      return candidates.map(candidate => candidate.type[typeProperty]).filter(value => value != null);
  }
  function mergeInterfaceTypeCandidates(typeName, candidates, typeMergingOptions) {
      const description = mergeTypeDescriptions(candidates, typeMergingOptions);
      const fields = fieldConfigMapFromTypeCandidates(candidates, typeMergingOptions);
      const typeConfigs = candidates.map(candidate => candidate.type.toConfig());
      const interfaceMap = typeConfigs
          .map(typeConfig => typeConfig.interfaces)
          .reduce((acc, interfaces) => {
          if (interfaces != null) {
              interfaces.forEach(iface => {
                  acc[iface.name] = iface;
              });
          }
          return acc;
      }, Object.create(null));
      const interfaces = Object.keys(interfaceMap).map(interfaceName => interfaceMap[interfaceName]);
      const astNodes = pluck('astNode', candidates);
      const astNode = astNodes
          .slice(1)
          .reduce((acc, astNode) => mergeInterface(astNode, acc, {}), astNodes[0]);
      const extensionASTNodes = [].concat(pluck('extensionASTNodes', candidates));
      const extensions = Object.assign({}, ...pluck('extensions', candidates));
      const typeConfig = {
          name: typeName,
          description,
          fields,
          interfaces,
          astNode,
          extensionASTNodes,
          extensions,
      };
      return new GraphQLInterfaceType(typeConfig);
  }
  function mergeUnionTypeCandidates(typeName, candidates, typeMergingOptions) {
      const description = mergeTypeDescriptions(candidates, typeMergingOptions);
      const typeConfigs = candidates.map(candidate => candidate.type.toConfig());
      const typeMap = typeConfigs.reduce((acc, typeConfig) => {
          typeConfig.types.forEach(type => {
              acc[type.name] = type;
          });
          return acc;
      }, Object.create(null));
      const types = Object.keys(typeMap).map(typeName => typeMap[typeName]);
      const astNodes = pluck('astNode', candidates);
      const astNode = astNodes
          .slice(1)
          .reduce((acc, astNode) => mergeUnion(astNode, acc), astNodes[0]);
      const extensionASTNodes = [].concat(pluck('extensionASTNodes', candidates));
      const extensions = Object.assign({}, ...pluck('extensions', candidates));
      const typeConfig = {
          name: typeName,
          description,
          types,
          astNode,
          extensionASTNodes,
          extensions,
      };
      return new GraphQLUnionType(typeConfig);
  }
  function mergeEnumTypeCandidates(typeName, candidates, typeMergingOptions) {
      const description = mergeTypeDescriptions(candidates, typeMergingOptions);
      const typeConfigs = candidates.map(candidate => candidate.type.toConfig());
      const values = typeConfigs.reduce((acc, typeConfig) => ({
          ...acc,
          ...typeConfig.values,
      }), {});
      const astNodes = pluck('astNode', candidates);
      const astNode = astNodes
          .slice(1)
          .reduce((acc, astNode) => mergeEnum(astNode, acc), astNodes[0]);
      const extensionASTNodes = [].concat(pluck('extensionASTNodes', candidates));
      const extensions = Object.assign({}, ...pluck('extensions', candidates));
      const typeConfig = {
          name: typeName,
          description,
          values,
          astNode,
          extensionASTNodes,
          extensions,
      };
      return new GraphQLEnumType(typeConfig);
  }
  function mergeScalarTypeCandidates(typeName, candidates, typeMergingOptions) {
      const description = mergeTypeDescriptions(candidates, typeMergingOptions);
      const serializeFns = pluck('serialize', candidates);
      const serialize = serializeFns[serializeFns.length - 1];
      const parseValueFns = pluck('parseValue', candidates);
      const parseValue = parseValueFns[parseValueFns.length - 1];
      const parseLiteralFns = pluck('parseLiteral', candidates);
      const parseLiteral = parseLiteralFns[parseLiteralFns.length - 1];
      const astNodes = pluck('astNode', candidates);
      const astNode = astNodes
          .slice(1)
          .reduce((acc, astNode) => mergeScalarTypeDefinitionNodes(acc, astNode), astNodes[0]);
      const extensionASTNodes = [].concat(pluck('extensionASTNodes', candidates));
      const extensions = Object.assign({}, ...pluck('extensions', candidates));
      const typeConfig = {
          name: typeName,
          description,
          serialize,
          parseValue,
          parseLiteral,
          astNode,
          extensionASTNodes,
          extensions,
      };
      return new GraphQLScalarType(typeConfig);
  }
  function mergeTypeDescriptions(candidates, typeMergingOptions) {
      var _a;
      const typeDescriptionsMerger = (_a = typeMergingOptions === null || typeMergingOptions === void 0 ? void 0 : typeMergingOptions.typeDescriptionsMerger) !== null && _a !== void 0 ? _a : defaultTypeDescriptionMerger;
      return typeDescriptionsMerger(candidates);
  }
  function defaultTypeDescriptionMerger(candidates) {
      return candidates[candidates.length - 1].type.description;
  }
  function fieldConfigMapFromTypeCandidates(candidates, typeMergingOptions) {
      const fieldConfigCandidatesMap = Object.create(null);
      candidates.forEach(candidate => {
          const fieldMap = candidate.type.getFields();
          Object.keys(fieldMap).forEach(fieldName => {
              const fieldConfigCandidate = {
                  fieldConfig: fieldToFieldConfig(fieldMap[fieldName]),
                  fieldName,
                  type: candidate.type,
                  subschema: candidate.subschema,
                  transformedSchema: candidate.transformedSchema,
              };
              if (fieldName in fieldConfigCandidatesMap) {
                  fieldConfigCandidatesMap[fieldName].push(fieldConfigCandidate);
              }
              else {
                  fieldConfigCandidatesMap[fieldName] = [fieldConfigCandidate];
              }
          });
      });
      const fieldConfigMap = Object.create(null);
      Object.keys(fieldConfigCandidatesMap).forEach(fieldName => {
          fieldConfigMap[fieldName] = mergeFieldConfigs(fieldConfigCandidatesMap[fieldName], typeMergingOptions);
      });
      return fieldConfigMap;
  }
  function mergeFieldConfigs(candidates, typeMergingOptions) {
      var _a;
      const fieldConfigMerger = (_a = typeMergingOptions === null || typeMergingOptions === void 0 ? void 0 : typeMergingOptions.fieldConfigMerger) !== null && _a !== void 0 ? _a : defaultFieldConfigMerger;
      return fieldConfigMerger(candidates);
  }
  function defaultFieldConfigMerger(candidates) {
      return candidates[candidates.length - 1].fieldConfig;
  }
  function inputFieldConfigMapFromTypeCandidates(candidates, typeMergingOptions) {
      const inputFieldConfigCandidatesMap = Object.create(null);
      candidates.forEach(candidate => {
          const inputFieldMap = candidate.type.getFields();
          Object.keys(inputFieldMap).forEach(fieldName => {
              const inputFieldConfigCandidate = {
                  inputFieldConfig: inputFieldToFieldConfig(inputFieldMap[fieldName]),
                  fieldName,
                  type: candidate.type,
                  subschema: candidate.subschema,
                  transformedSchema: candidate.transformedSchema,
              };
              if (fieldName in inputFieldConfigCandidatesMap) {
                  inputFieldConfigCandidatesMap[fieldName].push(inputFieldConfigCandidate);
              }
              else {
                  inputFieldConfigCandidatesMap[fieldName] = [inputFieldConfigCandidate];
              }
          });
      });
      const inputFieldConfigMap = Object.create(null);
      Object.keys(inputFieldConfigCandidatesMap).forEach(fieldName => {
          inputFieldConfigMap[fieldName] = mergeInputFieldConfigs(inputFieldConfigCandidatesMap[fieldName], typeMergingOptions);
      });
      return inputFieldConfigMap;
  }
  function mergeInputFieldConfigs(candidates, typeMergingOptions) {
      var _a;
      const inputFieldConfigMerger = (_a = typeMergingOptions === null || typeMergingOptions === void 0 ? void 0 : typeMergingOptions.inputFieldConfigMerger) !== null && _a !== void 0 ? _a : defaultInputFieldConfigMerger;
      return inputFieldConfigMerger(candidates);
  }
  function defaultInputFieldConfigMerger(candidates) {
      return candidates[candidates.length - 1].inputFieldConfig;
  }
  function mergeScalarTypeDefinitionNodes(targetNode, sourceNode) {
      var _a, _b, _c;
      return {
          ...targetNode,
          description: (_a = sourceNode.description) !== null && _a !== void 0 ? _a : targetNode.description,
          directives: ((_b = targetNode.directives) !== null && _b !== void 0 ? _b : []).concat((_c = sourceNode.directives) !== null && _c !== void 0 ? _c : []),
      };
  }
  
  function isDocumentNode(schemaLikeObject) {
      return schemaLikeObject.kind !== undefined;
  }
  function buildTypeCandidates({ schemaLikeObjects, transformedSchemas, extensions, directiveMap, schemaDefs, operationTypeNames, mergeDirectives, }) {
      const typeCandidates = Object.create(null);
      let schemaDef;
      let schemaExtensions = [];
      schemaLikeObjects.forEach(schemaLikeObject => {
          if (isDocumentNode(schemaLikeObject)) {
              schemaDef = extractSchemaDefinition(schemaLikeObject);
              schemaExtensions = schemaExtensions.concat(extractSchemaExtensions(schemaLikeObject));
          }
      });
      schemaDefs.schemaDef = schemaDef;
      schemaDefs.schemaExtensions = schemaExtensions;
      setOperationTypeNames(schemaDefs, operationTypeNames);
      schemaLikeObjects.forEach(schemaLikeObject => {
          if (isSchema(schemaLikeObject) || isSubschemaConfig(schemaLikeObject)) {
              const schema = wrapSchema(schemaLikeObject);
              transformedSchemas.set(schemaLikeObject, schema);
              const operationTypes = {
                  query: schema.getQueryType(),
                  mutation: schema.getMutationType(),
                  subscription: schema.getSubscriptionType(),
              };
              Object.keys(operationTypes).forEach(operationType => {
                  if (operationTypes[operationType] != null) {
                      addTypeCandidate(typeCandidates, operationTypeNames[operationType], {
                          type: operationTypes[operationType],
                          subschema: schemaLikeObject,
                          transformedSchema: schema,
                      });
                  }
              });
              if (mergeDirectives) {
                  schema.getDirectives().forEach(directive => {
                      directiveMap[directive.name] = directive;
                  });
              }
              const originalTypeMap = schema.getTypeMap();
              Object.keys(originalTypeMap).forEach(typeName => {
                  const type = originalTypeMap[typeName];
                  if (isNamedType(type) &&
                      getNamedType(type).name.slice(0, 2) !== '__' &&
                      type !== operationTypes.query &&
                      type !== operationTypes.mutation &&
                      type !== operationTypes.subscription) {
                      addTypeCandidate(typeCandidates, type.name, {
                          type,
                          subschema: schemaLikeObject,
                          transformedSchema: schema,
                      });
                  }
              });
          }
          else if (isDocumentNode(schemaLikeObject)) {
              const typesDocument = extractTypeDefinitions(schemaLikeObject);
              typesDocument.definitions.forEach(def => {
                  const type = typeFromAST(def);
                  if (type != null) {
                      addTypeCandidate(typeCandidates, type.name, {
                          type,
                      });
                  }
              });
              const directivesDocument = extractDirectiveDefinitions(schemaLikeObject);
              directivesDocument.definitions.forEach(def => {
                  const directive = typeFromAST(def);
                  directiveMap[directive.name] = directive;
              });
              const extensionsDocument = extractTypeExtensionDefinitions(schemaLikeObject);
              if (extensionsDocument.definitions.length > 0) {
                  extensions.push(extensionsDocument);
              }
          }
          else if (isNamedType(schemaLikeObject)) {
              addTypeCandidate(typeCandidates, schemaLikeObject.name, {
                  type: schemaLikeObject,
              });
          }
          else {
              throw new Error(`Invalid object ${schemaLikeObject}`);
          }
      });
      return typeCandidates;
  }
  function setOperationTypeNames({ schemaDef, schemaExtensions, }, operationTypeNames) {
      const allNodes = schemaExtensions.slice();
      if (schemaDef != null) {
          allNodes.unshift(schemaDef);
      }
      allNodes.forEach(node => {
          if (node.operationTypes != null) {
              node.operationTypes.forEach(operationType => {
                  operationTypeNames[operationType.operation] = operationType.type.name.value;
              });
          }
      });
  }
  function addTypeCandidate(typeCandidates, name, typeCandidate) {
      if (!(name in typeCandidates)) {
          typeCandidates[name] = [];
      }
      typeCandidates[name].push(typeCandidate);
  }
  function buildTypeMap({ typeCandidates, stitchingInfo, operationTypeNames, onTypeConflict, mergeTypes, typeMergingOptions, }) {
      const typeMap = Object.create(null);
      Object.keys(typeCandidates).forEach(typeName => {
          if (typeName === operationTypeNames.query ||
              typeName === operationTypeNames.mutation ||
              typeName === operationTypeNames.subscription ||
              (mergeTypes === true && !typeCandidates[typeName].some(candidate => isSpecifiedScalarType(candidate.type))) ||
              (typeof mergeTypes === 'function' && mergeTypes(typeCandidates[typeName], typeName)) ||
              (Array.isArray(mergeTypes) && mergeTypes.includes(typeName)) ||
              (stitchingInfo != null && typeName in stitchingInfo.mergedTypes)) {
              typeMap[typeName] = mergeCandidates(typeName, typeCandidates[typeName], typeMergingOptions);
          }
          else {
              const candidateSelector = onTypeConflict != null
                  ? onTypeConflictToCandidateSelector(onTypeConflict)
                  : (cands) => cands[cands.length - 1];
              typeMap[typeName] = candidateSelector(typeCandidates[typeName]).type;
          }
      });
      return typeMap;
  }
  function onTypeConflictToCandidateSelector(onTypeConflict) {
      return cands => cands.reduce((prev, next) => {
          const type = onTypeConflict(prev.type, next.type, {
              left: {
                  schema: prev.transformedSchema,
              },
              right: {
                  schema: next.transformedSchema,
              },
          });
          if (prev.type === type) {
              return prev;
          }
          else if (next.type === type) {
              return next;
          }
          return {
              schemaName: 'unknown',
              type,
          };
      });
  }
  
  function createStitchingInfo(transformedSubschemaConfigs, transformedSchemas, typeCandidates, mergeTypes) {
      const mergedTypes = createMergedTypes(typeCandidates, mergeTypes);
      const selectionSetsByField = Object.create(null);
      Object.entries(mergedTypes).forEach(([typeName, mergedTypeInfo]) => {
          if (mergedTypeInfo.selectionSets == null && mergedTypeInfo.fieldSelectionSets == null) {
              return;
          }
          selectionSetsByField[typeName] = Object.create(null);
          mergedTypeInfo.selectionSets.forEach((selectionSet, subschemaConfig) => {
              const schema = subschemaConfig.schema;
              const type = schema.getType(typeName);
              const fields = type.getFields();
              Object.keys(fields).forEach(fieldName => {
                  const field = fields[fieldName];
                  const fieldType = getNamedType(field.type);
                  if (selectionSet && isLeafType(fieldType) && selectionSetContainsTopLevelField(selectionSet, fieldName)) {
                      return;
                  }
                  if (selectionSetsByField[typeName][fieldName] == null) {
                      selectionSetsByField[typeName][fieldName] = {
                          kind: Kind.SELECTION_SET,
                          selections: [parseSelectionSet('{ __typename }').selections[0]],
                      };
                  }
                  selectionSetsByField[typeName][fieldName].selections = selectionSetsByField[typeName][fieldName].selections.concat(selectionSet.selections);
              });
          });
          mergedTypeInfo.fieldSelectionSets.forEach(selectionSetFieldMap => {
              Object.keys(selectionSetFieldMap).forEach(fieldName => {
                  if (selectionSetsByField[typeName][fieldName] == null) {
                      selectionSetsByField[typeName][fieldName] = {
                          kind: Kind.SELECTION_SET,
                          selections: [parseSelectionSet('{ __typename }').selections[0]],
                      };
                  }
                  selectionSetsByField[typeName][fieldName].selections = selectionSetsByField[typeName][fieldName].selections.concat(selectionSetFieldMap[fieldName].selections);
              });
          });
      });
      return {
          transformedSubschemaConfigs,
          transformedSchemas,
          fragmentsByField: undefined,
          selectionSetsByField,
          dynamicSelectionSetsByField: undefined,
          mergedTypes,
      };
  }
  function createMergedTypes(typeCandidates, mergeTypes) {
      const mergedTypes = Object.create(null);
      Object.keys(typeCandidates).forEach(typeName => {
          if (typeCandidates[typeName].length > 1 &&
              (isObjectType(typeCandidates[typeName][0].type) || isInterfaceType(typeCandidates[typeName][0].type))) {
              const typeCandidatesWithMergedTypeConfig = typeCandidates[typeName].filter(typeCandidate => typeCandidate.subschema != null &&
                  isSubschemaConfig(typeCandidate.subschema) &&
                  typeCandidate.subschema.merge != null &&
                  typeName in typeCandidate.subschema.merge);
              if (mergeTypes === true ||
                  (typeof mergeTypes === 'function' && mergeTypes(typeCandidates[typeName], typeName)) ||
                  (Array.isArray(mergeTypes) && mergeTypes.includes(typeName)) ||
                  typeCandidatesWithMergedTypeConfig.length) {
                  const targetSubschemas = [];
                  const typeMaps = new Map();
                  const supportedBySubschemas = Object.create({});
                  const selectionSets = new Map();
                  const fieldSelectionSets = new Map();
                  typeCandidates[typeName].forEach(typeCandidate => {
                      var _a;
                      const subschema = typeCandidate.subschema;
                      if (subschema == null) {
                          return;
                      }
                      typeMaps.set(subschema, typeCandidate.transformedSchema.getTypeMap());
                      if (!isSubschemaConfig(subschema)) {
                          return;
                      }
                      const mergedTypeConfig = (_a = subschema === null || subschema === void 0 ? void 0 : subschema.merge) === null || _a === void 0 ? void 0 : _a[typeName];
                      if (mergedTypeConfig == null) {
                          return;
                      }
                      if (mergedTypeConfig.selectionSet) {
                          const selectionSet = parseSelectionSet(mergedTypeConfig.selectionSet);
                          selectionSets.set(subschema, selectionSet);
                      }
                      if (mergedTypeConfig.fields) {
                          const parsedFieldSelectionSets = Object.create(null);
                          Object.keys(mergedTypeConfig.fields).forEach(fieldName => {
                              if (mergedTypeConfig.fields[fieldName].selectionSet) {
                                  const rawFieldSelectionSet = mergedTypeConfig.fields[fieldName].selectionSet;
                                  parsedFieldSelectionSets[fieldName] = parseSelectionSet(rawFieldSelectionSet);
                              }
                          });
                          fieldSelectionSets.set(subschema, parsedFieldSelectionSets);
                      }
                      if (mergedTypeConfig.computedFields) {
                          const parsedFieldSelectionSets = Object.create(null);
                          Object.keys(mergedTypeConfig.computedFields).forEach(fieldName => {
                              if (mergedTypeConfig.computedFields[fieldName].selectionSet) {
                                  const rawFieldSelectionSet = mergedTypeConfig.computedFields[fieldName].selectionSet;
                                  parsedFieldSelectionSets[fieldName] = parseSelectionSet(rawFieldSelectionSet);
                              }
                          });
                          fieldSelectionSets.set(subschema, parsedFieldSelectionSets);
                      }
                      if (mergedTypeConfig.resolve != null) {
                          targetSubschemas.push(subschema);
                      }
                      else if (mergedTypeConfig.key != null) {
                          mergedTypeConfig.resolve = (originalResult, context, info, subschema, selectionSet) => {
                              var _a;
                              return batchDelegateToSchema({
                                  schema: subschema,
                                  operation: 'query',
                                  fieldName: mergedTypeConfig.fieldName,
                                  key: mergedTypeConfig.key(originalResult),
                                  argsFromKeys: (_a = mergedTypeConfig.argsFromKeys) !== null && _a !== void 0 ? _a : mergedTypeConfig.args,
                                  valuesFromResults: mergedTypeConfig.valuesFromResults,
                                  selectionSet,
                                  context,
                                  info,
                                  skipTypeMerging: true,
                              });
                          };
                          targetSubschemas.push(subschema);
                      }
                      else if (mergedTypeConfig.fieldName != null) {
                          mergedTypeConfig.resolve = (originalResult, context, info, subschema, selectionSet) => delegateToSchema({
                              schema: subschema,
                              operation: 'query',
                              fieldName: mergedTypeConfig.fieldName,
                              returnType: getNamedType(info.returnType),
                              args: mergedTypeConfig.args(originalResult),
                              selectionSet,
                              context,
                              info,
                              skipTypeMerging: true,
                          });
                          targetSubschemas.push(subschema);
                      }
                      if (mergedTypeConfig.resolve == null) {
                          return;
                      }
                      const type = typeCandidate.transformedSchema.getType(typeName);
                      const fieldMap = type.getFields();
                      const selectionSet = selectionSets.get(subschema);
                      Object.keys(fieldMap).forEach(fieldName => {
                          const field = fieldMap[fieldName];
                          const fieldType = getNamedType(field.type);
                          if (selectionSet && isLeafType(fieldType) && selectionSetContainsTopLevelField(selectionSet, fieldName)) {
                              return;
                          }
                          if (!(fieldName in supportedBySubschemas)) {
                              supportedBySubschemas[fieldName] = [];
                          }
                          supportedBySubschemas[fieldName].push(subschema);
                      });
                  });
                  const sourceSubschemas = typeCandidates[typeName]
                      .filter(typeCandidate => typeCandidate.subschema != null)
                      .map(typeCandidate => typeCandidate.subschema);
                  const targetSubschemasBySubschema = new Map();
                  sourceSubschemas.forEach(subschema => {
                      const filteredSubschemas = targetSubschemas.filter(s => s !== subschema);
                      if (filteredSubschemas.length) {
                          targetSubschemasBySubschema.set(subschema, filteredSubschemas);
                      }
                  });
                  mergedTypes[typeName] = {
                      typeName,
                      targetSubschemas: targetSubschemasBySubschema,
                      typeMaps,
                      selectionSets,
                      fieldSelectionSets,
                      uniqueFields: Object.create({}),
                      nonUniqueFields: Object.create({}),
                  };
                  Object.keys(supportedBySubschemas).forEach(fieldName => {
                      if (supportedBySubschemas[fieldName].length === 1) {
                          mergedTypes[typeName].uniqueFields[fieldName] = supportedBySubschemas[fieldName][0];
                      }
                      else {
                          mergedTypes[typeName].nonUniqueFields[fieldName] = supportedBySubschemas[fieldName];
                      }
                  });
              }
          }
      });
      return mergedTypes;
  }
  function completeStitchingInfo(stitchingInfo, resolvers) {
      const selectionSetsByField = stitchingInfo.selectionSetsByField;
      const dynamicSelectionSetsByField = Object.create(null);
      const rawFragments = [];
      Object.keys(resolvers).forEach(typeName => {
          const type = resolvers[typeName];
          if (isScalarType(type)) {
              return;
          }
          Object.keys(type).forEach(fieldName => {
              const field = type[fieldName];
              if (field.selectionSet) {
                  if (typeof field.selectionSet === 'function') {
                      if (!(typeName in dynamicSelectionSetsByField)) {
                          dynamicSelectionSetsByField[typeName] = Object.create(null);
                      }
                      if (!(fieldName in dynamicSelectionSetsByField[typeName])) {
                          dynamicSelectionSetsByField[typeName][fieldName] = [];
                      }
                      dynamicSelectionSetsByField[typeName][fieldName].push(field.selectionSet);
                  }
                  else {
                      const selectionSet = parseSelectionSet(field.selectionSet);
                      if (!(typeName in selectionSetsByField)) {
                          selectionSetsByField[typeName] = Object.create(null);
                      }
                      if (!(fieldName in selectionSetsByField[typeName])) {
                          selectionSetsByField[typeName][fieldName] = {
                              kind: Kind.SELECTION_SET,
                              selections: [],
                          };
                      }
                      selectionSetsByField[typeName][fieldName].selections = selectionSetsByField[typeName][fieldName].selections.concat(selectionSet.selections);
                  }
              }
              if (field.fragment) {
                  rawFragments.push({
                      field: fieldName,
                      fragment: field.fragment,
                  });
              }
          });
      });
      Object.keys(selectionSetsByField).forEach(typeName => {
          const typeSelectionSets = selectionSetsByField[typeName];
          Object.keys(typeSelectionSets).forEach(fieldName => {
              const consolidatedSelections = new Map();
              const selectionSet = typeSelectionSets[fieldName];
              selectionSet.selections.forEach(selection => {
                  consolidatedSelections.set(print(selection), selection);
              });
              selectionSet.selections = Array.from(consolidatedSelections.values());
          });
      });
      const parsedFragments = Object.create(null);
      rawFragments.forEach(({ field, fragment }) => {
          const parsedFragment = parseFragmentToInlineFragment(fragment);
          const actualTypeName = parsedFragment.typeCondition.name.value;
          if (!(actualTypeName in parsedFragments)) {
              parsedFragments[actualTypeName] = Object.create(null);
          }
          if (!(field in parsedFragments[actualTypeName])) {
              parsedFragments[actualTypeName][field] = [];
          }
          parsedFragments[actualTypeName][field].push(parsedFragment);
      });
      const fragmentsByField = Object.create(null);
      Object.keys(parsedFragments).forEach(typeName => {
          Object.keys(parsedFragments[typeName]).forEach(field => {
              if (!(typeName in fragmentsByField)) {
                  fragmentsByField[typeName] = Object.create(null);
              }
              fragmentsByField[typeName][field] = concatInlineFragments(typeName, parsedFragments[typeName][field]);
          });
      });
      stitchingInfo.selectionSetsByField = selectionSetsByField;
      stitchingInfo.dynamicSelectionSetsByField = dynamicSelectionSetsByField;
      stitchingInfo.fragmentsByField = fragmentsByField;
      return stitchingInfo;
  }
  function addStitchingInfo(stitchedSchema, stitchingInfo) {
      return new GraphQLSchema({
          ...stitchedSchema.toConfig(),
          extensions: {
              ...stitchedSchema.extensions,
              stitchingInfo,
          },
      });
  }
  function selectionSetContainsTopLevelField(selectionSet, fieldName) {
      return selectionSet.selections.some(selection => selection.kind === Kind.FIELD && selection.name.value === fieldName);
  }
  
  function isolateComputedFields(subschemaConfig) {
      var _a;
      const baseSchemaTypes = {};
      const isolatedSchemaTypes = {};
      if (subschemaConfig.merge == null) {
          return [subschemaConfig];
      }
      Object.keys(subschemaConfig.merge).forEach((typeName) => {
          const mergedTypeConfig = subschemaConfig.merge[typeName];
          baseSchemaTypes[typeName] = mergedTypeConfig;
          if (mergedTypeConfig.computedFields) {
              const baseFields = {};
              const isolatedFields = {};
              Object.keys(mergedTypeConfig.computedFields).forEach((fieldName) => {
                  const mergedFieldConfig = mergedTypeConfig.computedFields[fieldName];
                  if (mergedFieldConfig.selectionSet) {
                      isolatedFields[fieldName] = mergedFieldConfig;
                  }
                  else {
                      baseFields[fieldName] = mergedFieldConfig;
                  }
              });
              const isolatedFieldCount = Object.keys(isolatedFields).length;
              const objectType = subschemaConfig.schema.getType(typeName);
              if (isolatedFieldCount && isolatedFieldCount !== Object.keys(objectType.getFields()).length) {
                  baseSchemaTypes[typeName] = {
                      ...mergedTypeConfig,
                      fields: Object.keys(baseFields).length ? baseFields : undefined,
                  };
                  isolatedSchemaTypes[typeName] = { ...mergedTypeConfig, fields: isolatedFields };
              }
          }
      });
      if (Object.keys(isolatedSchemaTypes).length) {
          const endpoint = (_a = subschemaConfig.endpoint) !== null && _a !== void 0 ? _a : {
              rootValue: subschemaConfig.rootValue,
              executor: subschemaConfig.executor,
              subscriber: subschemaConfig.subscriber,
              batch: subschemaConfig.batch,
              batchingOptions: subschemaConfig.batchingOptions,
          };
          return [
              filterBaseSubschema({ ...subschemaConfig, endpoint, merge: baseSchemaTypes }, isolatedSchemaTypes),
              filterIsolatedSubschema({ ...subschemaConfig, endpoint, merge: isolatedSchemaTypes }),
          ];
      }
      return [subschemaConfig];
  }
  function filterBaseSubschema(subschemaConfig, isolatedSchemaTypes) {
      var _a;
      const typesForInterface = {};
      const filteredSchema = pruneSchema(filterSchema({
          schema: subschemaConfig.schema,
          objectFieldFilter: (typeName, fieldName) => { var _a; return !((_a = isolatedSchemaTypes[typeName]) === null || _a === void 0 ? void 0 : _a.fields[fieldName]); },
          interfaceFieldFilter: (typeName, fieldName) => {
              if (!typesForInterface[typeName]) {
                  typesForInterface[typeName] = getImplementingTypes(typeName, subschemaConfig.schema);
              }
              return !typesForInterface[typeName].some(implementingTypeName => { var _a; return (_a = isolatedSchemaTypes[implementingTypeName]) === null || _a === void 0 ? void 0 : _a.fields[fieldName]; });
          },
      }));
      const filteredFields = {};
      Object.keys(filteredSchema.getTypeMap()).forEach(typeName => {
          const type = filteredSchema.getType(typeName);
          if (isObjectType(type) || isInterfaceType(type)) {
              filteredFields[typeName] = {};
              const fieldMap = type.getFields();
              Object.keys(fieldMap).forEach(fieldName => {
                  filteredFields[typeName][fieldName] = true;
              });
          }
      });
      const filteredSubschema = {
          ...subschemaConfig,
          merge: subschemaConfig.merge
              ? {
                  ...subschemaConfig.merge,
              }
              : undefined,
          transforms: ((_a = subschemaConfig.transforms) !== null && _a !== void 0 ? _a : []).concat([
              new TransformCompositeFields((typeName, fieldName) => { var _a; return (((_a = filteredFields[typeName]) === null || _a === void 0 ? void 0 : _a[fieldName]) ? undefined : null); }, (typeName, fieldName) => { var _a; return (((_a = filteredFields[typeName]) === null || _a === void 0 ? void 0 : _a[fieldName]) ? undefined : null); }),
          ]),
      };
      const remainingTypes = filteredSchema.getTypeMap();
      Object.keys(filteredSubschema.merge).forEach(mergeType => {
          if (!remainingTypes[mergeType]) {
              delete filteredSubschema.merge[mergeType];
          }
      });
      if (!Object.keys(filteredSubschema.merge).length) {
          delete filteredSubschema.merge;
      }
      return filteredSubschema;
  }
  function filterIsolatedSubschema(subschemaConfig) {
      var _a;
      const rootFields = {};
      Object.keys(subschemaConfig.merge).forEach(typeName => {
          rootFields[subschemaConfig.merge[typeName].fieldName] = true;
      });
      const interfaceFields = {};
      Object.keys(subschemaConfig.merge).forEach(typeName => {
          subschemaConfig.schema.getType(typeName).getInterfaces().forEach(int => {
              Object.keys(subschemaConfig.schema.getType(int.name).getFields()).forEach(intFieldName => {
                  if (subschemaConfig.merge[typeName].fields[intFieldName]) {
                      interfaceFields[int.name] = interfaceFields[int.name] || {};
                      interfaceFields[int.name][intFieldName] = true;
                  }
              });
          });
      });
      const filteredSchema = pruneSchema(filterSchema({
          schema: subschemaConfig.schema,
          rootFieldFilter: (operation, fieldName) => operation === 'Query' && rootFields[fieldName] != null,
          objectFieldFilter: (typeName, fieldName) => { var _a; return ((_a = subschemaConfig.merge[typeName]) === null || _a === void 0 ? void 0 : _a.fields[fieldName]) != null; },
          interfaceFieldFilter: (typeName, fieldName) => { var _a; return ((_a = interfaceFields[typeName]) === null || _a === void 0 ? void 0 : _a[fieldName]) != null; },
      }));
      const filteredFields = {};
      Object.keys(filteredSchema.getTypeMap()).forEach(typeName => {
          const type = filteredSchema.getType(typeName);
          if (isObjectType(type) || isInterfaceType(type)) {
              filteredFields[typeName] = {};
              const fieldMap = type.getFields();
              Object.keys(fieldMap).forEach(fieldName => {
                  filteredFields[typeName][fieldName] = true;
              });
          }
      });
      return {
          ...subschemaConfig,
          transforms: ((_a = subschemaConfig.transforms) !== null && _a !== void 0 ? _a : []).concat([
              new TransformCompositeFields((typeName, fieldName) => { var _a; return (((_a = filteredFields[typeName]) === null || _a === void 0 ? void 0 : _a[fieldName]) ? undefined : null); }, (typeName, fieldName) => { var _a; return (((_a = filteredFields[typeName]) === null || _a === void 0 ? void 0 : _a[fieldName]) ? undefined : null); }),
          ]),
      };
  }
  
  function computedDirectiveTransformer(computedDirectiveName) {
      return (subschemaConfig) => {
          const newSubschemaConfig = cloneSubschemaConfig(subschemaConfig);
          mapSchema(subschemaConfig.schema, {
              [MapperKind.OBJECT_FIELD]: (fieldConfig, fieldName, typeName, schema) => {
                  var _a, _b, _c, _d;
                  const mergeTypeConfig = (_a = newSubschemaConfig.merge) === null || _a === void 0 ? void 0 : _a[typeName];
                  if (mergeTypeConfig == null) {
                      return undefined;
                  }
                  const computed = getDirectives(schema, fieldConfig)[computedDirectiveName];
                  if (computed == null) {
                      return undefined;
                  }
                  const selectionSet = computed.fields != null ? `{ ${computed.fields} }` : computed.selectionSet;
                  if (selectionSet == null) {
                      return undefined;
                  }
                  mergeTypeConfig.computedFields = (_b = mergeTypeConfig.computedFields) !== null && _b !== void 0 ? _b : {};
                  mergeTypeConfig.computedFields[fieldName] = (_c = mergeTypeConfig.computedFields[fieldName]) !== null && _c !== void 0 ? _c : {};
                  const mergeFieldConfig = mergeTypeConfig.computedFields[fieldName];
                  mergeFieldConfig.selectionSet = (_d = mergeFieldConfig.selectionSet) !== null && _d !== void 0 ? _d : selectionSet;
                  return undefined;
              },
          });
          return newSubschemaConfig;
      };
  }
  
  const defaultSubschemaConfigTransforms = [computedDirectiveTransformer('computed')];
  
  function stitchSchemas({ subschemas = [], types = [], typeDefs, 
  // `schemas` to be removed in v7, replaces by subschemas, types, typeDefs
  schemas = [], onTypeConflict, mergeDirectives, mergeTypes = false, typeMergingOptions, subschemaConfigTransforms = defaultSubschemaConfigTransforms, resolvers = {}, schemaDirectives, inheritResolversFromInterfaces = false, logger, allowUndefinedInResolve = true, resolverValidationOptions = {}, directiveResolvers, schemaTransforms = [], parseOptions = {}, pruningOptions, }) {
      if (typeof resolverValidationOptions !== 'object') {
          throw new Error('Expected `resolverValidationOptions` to be an object');
      }
      let schemaLikeObjects = [];
      const transformedSubschemaConfigs = new Map();
      subschemas.forEach(subschemaOrSubschemaArray => {
          if (Array.isArray(subschemaOrSubschemaArray)) {
              subschemaOrSubschemaArray.forEach(s => {
                  schemaLikeObjects = schemaLikeObjects.concat(applySubschemaConfigTransforms(subschemaConfigTransforms, s, transformedSubschemaConfigs));
              });
          }
          else {
              schemaLikeObjects = schemaLikeObjects.concat(applySubschemaConfigTransforms(subschemaConfigTransforms, subschemaOrSubschemaArray, transformedSubschemaConfigs));
          }
      });
      // to be removed in v7
      schemas.forEach(schemaLikeObject => {
          if (!isSchema(schemaLikeObject) &&
              !isSubschemaConfig(schemaLikeObject) &&
              typeof schemaLikeObject !== 'string' &&
              !isDocumentNode$1(schemaLikeObject) &&
              !Array.isArray(schemaLikeObject)) {
              throw new Error('Invalid schema passed');
          }
      });
      // to be removed in v7
      schemas.forEach(schemaLikeObject => {
          if (isSchema(schemaLikeObject) || isSubschemaConfig(schemaLikeObject)) {
              schemaLikeObjects.push(schemaLikeObject);
          }
      });
      if ((typeDefs && !Array.isArray(typeDefs)) || (Array.isArray(typeDefs) && typeDefs.length)) {
          schemaLikeObjects.push(buildDocumentFromTypeDefinitions(typeDefs, parseOptions));
      }
      // to be removed in v7
      schemas.forEach(schemaLikeObject => {
          if (typeof schemaLikeObject === 'string' || isDocumentNode$1(schemaLikeObject)) {
              schemaLikeObjects.push(buildDocumentFromTypeDefinitions(schemaLikeObject, parseOptions));
          }
      });
      if (types != null) {
          schemaLikeObjects = schemaLikeObjects.concat(types);
      }
      // to be removed in v7
      schemas.forEach(schemaLikeObject => {
          if (Array.isArray(schemaLikeObject)) {
              schemaLikeObjects = schemaLikeObjects.concat(schemaLikeObject);
          }
      });
      const transformedSchemas = new Map();
      const extensions = [];
      const directives = [];
      const directiveMap = specifiedDirectives.reduce((acc, directive) => {
          acc[directive.name] = directive;
          return acc;
      }, Object.create(null));
      const schemaDefs = Object.create(null);
      const operationTypeNames = {
          query: 'Query',
          mutation: 'Mutation',
          subscription: 'Subscription',
      };
      const typeCandidates = buildTypeCandidates({
          schemaLikeObjects,
          transformedSchemas,
          extensions,
          directiveMap,
          schemaDefs,
          operationTypeNames,
          mergeDirectives,
      });
      Object.keys(directiveMap).forEach(directiveName => {
          directives.push(directiveMap[directiveName]);
      });
      let stitchingInfo = createStitchingInfo(transformedSubschemaConfigs, transformedSchemas, typeCandidates, mergeTypes);
      const typeMap = buildTypeMap({
          typeCandidates,
          stitchingInfo,
          operationTypeNames,
          onTypeConflict,
          mergeTypes,
          typeMergingOptions,
      });
      const { typeMap: newTypeMap, directives: newDirectives } = rewireTypes(typeMap, directives, { skipPruning: true });
      let schema = new GraphQLSchema({
          query: newTypeMap[operationTypeNames.query],
          mutation: newTypeMap[operationTypeNames.mutation],
          subscription: newTypeMap[operationTypeNames.subscription],
          types: Object.keys(newTypeMap).map(key => newTypeMap[key]),
          directives: newDirectives,
          astNode: schemaDefs.schemaDef,
          extensionASTNodes: schemaDefs.schemaExtensions,
          extensions: null,
      });
      extensions.forEach(extension => {
          schema = extendSchema(schema, extension, {
              commentDescriptions: true,
          });
      });
      // We allow passing in an array of resolver maps, in which case we merge them
      const resolverMap = Array.isArray(resolvers) ? resolvers.reduce(mergeDeep, {}) : resolvers;
      const finalResolvers = inheritResolversFromInterfaces
          ? extendResolversFromInterfaces(schema, resolverMap)
          : resolverMap;
      stitchingInfo = completeStitchingInfo(stitchingInfo, finalResolvers);
      schema = addResolversToSchema({
          schema,
          resolvers: finalResolvers,
          resolverValidationOptions,
          inheritResolversFromInterfaces: false,
      });
      assertResolversPresent(schema, resolverValidationOptions);
      schema = addStitchingInfo(schema, stitchingInfo);
      if (!allowUndefinedInResolve) {
          schema = addCatchUndefinedToSchema(schema);
      }
      if (logger != null) {
          schema = addErrorLoggingToSchema(schema, logger);
      }
      if (typeof finalResolvers['__schema'] === 'function') {
          // TODO a bit of a hack now, better rewrite generateSchema to attach it there.
          // not doing that now, because I'd have to rewrite a lot of tests.
          schema = addSchemaLevelResolver(schema, finalResolvers['__schema']);
      }
      schemaTransforms.forEach(schemaTransform => {
          schema = schemaTransform(schema);
      });
      if (directiveResolvers != null) {
          schema = attachDirectiveResolvers(schema, directiveResolvers);
      }
      if (schemaDirectives != null) {
          SchemaDirectiveVisitor.visitSchemaDirectives(schema, schemaDirectives);
      }
      return pruningOptions ? pruneSchema(schema, pruningOptions) : schema;
  }
  function applySubschemaConfigTransforms(subschemaConfigTransforms, subschemaOrSubschemaConfig, transformedSubschemaConfigs) {
      const subschemaConfig = isSubschemaConfig(subschemaOrSubschemaConfig)
          ? subschemaOrSubschemaConfig
          : { schema: subschemaOrSubschemaConfig };
      const newSubschemaConfig = subschemaConfigTransforms.reduce((acc, subschemaConfigTransform) => {
          return subschemaConfigTransform(acc);
      }, subschemaConfig);
      const subschemas = isolateComputedFields(newSubschemaConfig);
      const baseSubschema = subschemas[0];
      transformedSubschemaConfigs.set(subschemaConfig, baseSubschema);
      return subschemas;
  }
  function isDocumentNode$1(object) {
      return object.kind !== undefined;
  }
  
  const forwardArgsToSelectionSet = (selectionSet, mapping) => {
      const selectionSetDef = parseSelectionSet(selectionSet);
      return (field) => {
          const selections = selectionSetDef.selections.map((selectionNode) => {
              if (selectionNode.kind === Kind.FIELD) {
                  if (!mapping) {
                      return { ...selectionNode, arguments: field.arguments.slice() };
                  }
                  else if (selectionNode.name.value in mapping) {
                      const selectionArgs = mapping[selectionNode.name.value];
                      return {
                          ...selectionNode,
                          arguments: field.arguments.filter((arg) => selectionArgs.includes(arg.name.value)),
                      };
                  }
              }
              return selectionNode;
          });
          return { ...selectionSetDef, selections };
      };
  };
  
  export { computedDirectiveTransformer, defaultSubschemaConfigTransforms, forwardArgsToSelectionSet, isolateComputedFields, stitchSchemas };
  //# sourceMappingURL=index.esm.js.map
  