import { Kind, GraphQLDirective, valueFromASTUntyped, GraphQLInputObjectType, GraphQLScalarType, GraphQLUnionType, GraphQLEnumType, GraphQLInterfaceType, GraphQLObjectType, DirectiveLocation, TokenKind, getDirectiveValues, GraphQLDeprecatedDirective, isNonNullType, getNamedType, isEnumType, isScalarType, isListType, getNullableType, isObjectType, isInputObjectType, isInterfaceType, isUnionType, isNamedType, isSpecifiedScalarType, GraphQLList, GraphQLSchema, isLeafType, print, specifiedDirectives, extendSchema } from 'graphql';
import { createStub, createNamedStub, fieldToFieldConfig, inputFieldToFieldConfig, rewireTypes, parseSelectionSet, mapSchema, MapperKind, getDirectives, pruneSchema, filterSchema, getImplementingTypes, mergeDeep, SchemaDirectiveVisitor } from '@graphql-tools/utils/es5';
import { buildDocumentFromTypeDefinitions, extendResolversFromInterfaces, addResolversToSchema, assertResolversPresent, addCatchUndefinedToSchema, addErrorLoggingToSchema, addSchemaLevelResolver, attachDirectiveResolvers } from '@graphql-tools/schema/es5';
import { isSubschemaConfig, delegateToSchema, cloneSubschemaConfig, defaultMergedResolver, Subschema } from '@graphql-tools/delegate/es5';
import { __assign, __read, __spreadArray } from 'tslib';
import { wrapSchema, TransformCompositeFields } from '@graphql-tools/wrap/es5';
import { mergeType, mergeInputType, mergeInterface, mergeUnion, mergeEnum, mergeScalar } from '@graphql-tools/merge/es5';
import { batchDelegateToSchema } from '@graphql-tools/batch-delegate/es5';

var 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) {
    var config = {
        name: node.name.value,
        description: getDescription(node, backcompatOptions),
        interfaces: function () { return node.interfaces.map(function (iface) { return createNamedStub(iface.name.value, 'interface'); }); },
        fields: function () { return makeFields(node.fields); },
        astNode: node,
    };
    return new GraphQLObjectType(config);
}
function makeInterfaceType(node) {
    var _a;
    var config = {
        name: node.name.value,
        description: getDescription(node, backcompatOptions),
        interfaces: (_a = node.interfaces) === null || _a === void 0 ? void 0 : _a.map(function (iface) {
            return createNamedStub(iface.name.value, 'interface');
        }),
        fields: function () { return makeFields(node.fields); },
        astNode: node,
    };
    return new GraphQLInterfaceType(config);
}
function makeEnumType(node) {
    var values = node.values.reduce(function (prev, value) {
        var _a;
        return (__assign(__assign({}, prev), (_a = {}, _a[value.name.value] = {
            description: getDescription(value, backcompatOptions),
            deprecationReason: getDeprecationReason(value),
            astNode: value,
        }, _a)));
    }, {});
    return new GraphQLEnumType({
        name: node.name.value,
        description: getDescription(node, backcompatOptions),
        values: values,
        astNode: node,
    });
}
function makeUnionType(node) {
    return new GraphQLUnionType({
        name: node.name.value,
        description: getDescription(node, backcompatOptions),
        types: function () { return node.types.map(function (type) { return 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: function (value) { return value; },
    });
}
function makeInputObjectType(node) {
    return new GraphQLInputObjectType({
        name: node.name.value,
        description: getDescription(node, backcompatOptions),
        fields: function () { return makeValues(node.fields); },
        astNode: node,
    });
}
function makeFields(nodes) {
    return nodes.reduce(function (prev, node) {
        var _a;
        return (__assign(__assign({}, prev), (_a = {}, _a[node.name.value] = {
            type: createStub(node.type, 'output'),
            description: getDescription(node, backcompatOptions),
            args: makeValues(node.arguments),
            deprecationReason: getDeprecationReason(node),
            astNode: node,
        }, _a)));
    }, {});
}
function makeValues(nodes) {
    return nodes.reduce(function (prev, node) {
        var _a;
        return (__assign(__assign({}, prev), (_a = {}, _a[node.name.value] = {
            type: createStub(node.type, 'input'),
            defaultValue: node.defaultValue !== undefined ? valueFromASTUntyped(node.defaultValue) : undefined,
            description: getDescription(node, backcompatOptions),
            astNode: node,
        }, _a)));
    }, {});
}
function makeDirective(node) {
    var locations = [];
    node.locations.forEach(function (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: 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) {
        var rawValue = getLeadingCommentBlock(node);
        if (rawValue !== undefined) {
            return dedentBlockStringValue("\n" + rawValue);
        }
    }
}
function getLeadingCommentBlock(node) {
    var loc = node.loc;
    if (!loc) {
        return;
    }
    var comments = [];
    var 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) {
        var 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.
    var lines = rawString.split(/\r\n|[\n\r]/g);
    // Remove common indentation from all lines but first.
    var commonIndent = getBlockStringIndentation(lines);
    if (commonIndent !== 0) {
        for (var 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) {
    var commonIndent = null;
    for (var i = 1; i < lines.length; i++) {
        var line = lines[i];
        var 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) {
    var 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) {
    var deprecated = getDirectiveValues(GraphQLDeprecatedDirective, node);
    return deprecated === null || deprecated === void 0 ? void 0 : deprecated.reason;
}

var ValidationLevel;
(function (ValidationLevel) {
    ValidationLevel["Error"] = "error";
    ValidationLevel["Warn"] = "warn";
    ValidationLevel["Off"] = "off";
})(ValidationLevel || (ValidationLevel = {}));

function validateFieldConsistency(finalFieldConfig, candidates, typeMergingOptions) {
    var fieldNamespace = candidates[0].type.name + "." + candidates[0].fieldName;
    var finalFieldNull = isNonNullType(finalFieldConfig.type);
    validateTypeConsistency(finalFieldConfig, candidates.map(function (c) { return c.fieldConfig; }), 'field', fieldNamespace, typeMergingOptions);
    if (getValidationSettings(fieldNamespace, typeMergingOptions).strictNullComparison &&
        candidates.some(function (c) { return finalFieldNull !== isNonNullType(c.fieldConfig.type); })) {
        validationMessage("Nullability of field \"" + fieldNamespace + "\" does not match across subschemas. Disable typeMergingOptions.validationSettings.strictNullComparison to permit safe divergences.", fieldNamespace, typeMergingOptions);
    }
    else if (finalFieldNull && candidates.some(function (c) { return !isNonNullType(c.fieldConfig.type); })) {
        validationMessage("Canonical definition of field \"" + fieldNamespace + "\" is not-null while some subschemas permit null. This will be an automatic error in future versions.", fieldNamespace, typeMergingOptions);
    }
    var argCandidatesMap = Object.create(null);
    candidates.forEach(function (_a) {
        var fieldConfig = _a.fieldConfig;
        Object.entries(fieldConfig.args).forEach(function (_a) {
            var _b = __read(_a, 2), argName = _b[0], arg = _b[1];
            argCandidatesMap[argName] = argCandidatesMap[argName] || [];
            argCandidatesMap[argName].push(arg);
        });
    });
    if (Object.values(argCandidatesMap).some(function (argCandidates) { return candidates.length !== argCandidates.length; })) {
        validationMessage("Canonical definition of field \"" + fieldNamespace + "\" implements inconsistent argument names across subschemas. Input may be filtered from some requests.", fieldNamespace, typeMergingOptions);
    }
    Object.entries(argCandidatesMap).forEach(function (_a) {
        var _b = __read(_a, 2), argName = _b[0], argCandidates = _b[1];
        var argNamespace = fieldNamespace + "." + argName;
        var finalArgConfig = finalFieldConfig.args[argName] || argCandidates[argCandidates.length - 1];
        var finalArgType = getNamedType(finalArgConfig.type);
        var finalArgNull = isNonNullType(finalArgConfig.type);
        validateTypeConsistency(finalArgConfig, argCandidates, 'argument', argNamespace, typeMergingOptions);
        if (getValidationSettings(argNamespace, typeMergingOptions).strictNullComparison &&
            argCandidates.some(function (c) { return finalArgNull !== isNonNullType(c.type); })) {
            validationMessage("Nullability of argument \"" + argNamespace + "\" does not match across subschemas. Disable typeMergingOptions.validationSettings.strictNullComparison to permit safe divergences.", argNamespace, typeMergingOptions);
        }
        else if (!finalArgNull && argCandidates.some(function (c) { return isNonNullType(c.type); })) {
            validationMessage("Canonical definition of argument \"" + argNamespace + "\" permits null while some subschemas require not-null. This will be an automatic error in future versions.", argNamespace, typeMergingOptions);
        }
        if (isEnumType(finalArgType)) {
            validateInputEnumConsistency(finalArgType, argCandidates, typeMergingOptions);
        }
    });
}
function validateInputObjectConsistency(fieldInclusionMap, candidates, typeMergingOptions) {
    Object.entries(fieldInclusionMap).forEach(function (_a) {
        var _b = __read(_a, 2), fieldName = _b[0], count = _b[1];
        if (candidates.length !== count) {
            var namespace = candidates[0].type.name + "." + fieldName;
            validationMessage("Definition of input field \"" + namespace + "\" is not implemented by all subschemas. Input may be filtered from some requests.", namespace, typeMergingOptions);
        }
    });
}
function validateInputFieldConsistency(finalInputFieldConfig, candidates, typeMergingOptions) {
    var inputFieldNamespace = candidates[0].type.name + "." + candidates[0].fieldName;
    var inputFieldConfigs = candidates.map(function (c) { return c.inputFieldConfig; });
    var finalInputFieldType = getNamedType(finalInputFieldConfig.type);
    var finalInputFieldNull = isNonNullType(finalInputFieldConfig.type);
    validateTypeConsistency(finalInputFieldConfig, inputFieldConfigs, 'input field', inputFieldNamespace, typeMergingOptions);
    if (getValidationSettings(inputFieldNamespace, typeMergingOptions).strictNullComparison &&
        candidates.some(function (c) { return finalInputFieldNull !== isNonNullType(c.inputFieldConfig.type); })) {
        validationMessage("Nullability of input field \"" + inputFieldNamespace + "\" does not match across subschemas. Disable typeMergingOptions.validationSettings.strictNullComparison to permit safe divergences.", inputFieldNamespace, typeMergingOptions);
    }
    else if (!finalInputFieldNull && candidates.some(function (c) { return isNonNullType(c.inputFieldConfig.type); })) {
        validationMessage("Canonical definition of input field \"" + inputFieldNamespace + "\" permits null while some subschemas require not-null. This will be an automatic error in future versions.", inputFieldNamespace, typeMergingOptions);
    }
    if (isEnumType(finalInputFieldType)) {
        validateInputEnumConsistency(finalInputFieldType, inputFieldConfigs, typeMergingOptions);
    }
}
function validateTypeConsistency(finalElementConfig, candidates, definitionType, settingNamespace, typeMergingOptions) {
    var finalNamedType = getNamedType(finalElementConfig.type);
    var finalIsScalar = isScalarType(finalNamedType);
    var finalIsList = hasListType(finalElementConfig.type);
    candidates.forEach(function (c) {
        var _a, _b, _c;
        if (finalIsList !== hasListType(c.type)) {
            throw new Error("Definitions of " + definitionType + " \"" + settingNamespace + "\" implement inconsistent list types across subschemas and cannot be merged.");
        }
        var currentNamedType = getNamedType(c.type);
        if (finalNamedType.toString() !== currentNamedType.toString()) {
            var proxiableScalar = !!((_c = (_b = (_a = typeMergingOptions === null || typeMergingOptions === void 0 ? void 0 : typeMergingOptions.validationSettings) === null || _a === void 0 ? void 0 : _a.proxiableScalars) === null || _b === void 0 ? void 0 : _b[finalNamedType.toString()]) === null || _c === void 0 ? void 0 : _c.includes(currentNamedType.toString()));
            var bothScalars = finalIsScalar && isScalarType(currentNamedType);
            var permitScalar = proxiableScalar && bothScalars;
            if (proxiableScalar && !bothScalars) {
                throw new Error("Types " + finalNamedType + " and " + currentNamedType + " are not proxiable scalars.");
            }
            if (!permitScalar) {
                validationMessage("Definitions of " + definitionType + " \"" + settingNamespace + "\" implement inconsistent named types across subschemas. This will be an automatic error in future versions.", settingNamespace, typeMergingOptions);
            }
        }
    });
}
function hasListType(type) {
    return isListType(getNullableType(type));
}
function validateInputEnumConsistency(inputEnumType, candidates, typeMergingOptions) {
    var enumValueInclusionMap = Object.create(null);
    candidates.forEach(function (candidate) {
        var enumType = getNamedType(candidate.type);
        if (isEnumType(enumType)) {
            enumType.getValues().forEach(function (_a) {
                var value = _a.value;
                enumValueInclusionMap[value] = enumValueInclusionMap[value] || 0;
                enumValueInclusionMap[value] += 1;
            });
        }
    });
    if (Object.values(enumValueInclusionMap).some(function (count) { return candidates.length !== count; })) {
        validationMessage("Enum \"" + inputEnumType.name + "\" is used as an input with inconsistent values across subschemas. This will be an automatic error in future versions.", inputEnumType.name, typeMergingOptions);
    }
}
function validationMessage(message, settingNamespace, typeMergingOptions) {
    var _a;
    var override = "typeMergingOptions.validationScopes['" + settingNamespace + "'].validationLevel";
    var settings = getValidationSettings(settingNamespace, typeMergingOptions);
    switch ((_a = settings.validationLevel) !== null && _a !== void 0 ? _a : ValidationLevel.Warn) {
        case ValidationLevel.Off:
            return;
        case ValidationLevel.Error:
            throw new Error(message + " If this is intentional, you may disable this error by setting " + override + " = \"warn|off\"");
        default:
            console.warn(message + " To disable this warning or elevate it to an error, set " + override + " = \"error|off\"");
    }
}
function getValidationSettings(settingNamespace, typeMergingOptions) {
    var _a, _b, _c;
    return __assign(__assign({}, ((_a = typeMergingOptions === null || typeMergingOptions === void 0 ? void 0 : typeMergingOptions.validationSettings) !== null && _a !== void 0 ? _a : {})), ((_c = (_b = typeMergingOptions === null || typeMergingOptions === void 0 ? void 0 : typeMergingOptions.validationScopes) === null || _b === void 0 ? void 0 : _b[settingNamespace]) !== null && _c !== void 0 ? _c : {}));
}

function mergeCandidates(typeName, candidates, typeMergingOptions) {
    var initialCandidateType = candidates[0].type;
    if (candidates.some(function (candidate) { return 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) {
    candidates = orderedTypeCandidates(candidates, typeMergingOptions);
    var description = mergeTypeDescriptions(candidates, typeMergingOptions);
    var fields = fieldConfigMapFromTypeCandidates(candidates, typeMergingOptions);
    var typeConfigs = candidates.map(function (candidate) { return candidate.type.toConfig(); });
    var interfaceMap = typeConfigs
        .map(function (typeConfig) { return typeConfig.interfaces; })
        .reduce(function (acc, interfaces) {
        if (interfaces != null) {
            interfaces.forEach(function (iface) {
                acc[iface.name] = iface;
            });
        }
        return acc;
    }, Object.create(null));
    var interfaces = Object.keys(interfaceMap).map(function (interfaceName) { return interfaceMap[interfaceName]; });
    var astNodes = pluck('astNode', candidates);
    var fieldAstNodes = canonicalFieldNamesForType(candidates)
        .map(function (fieldName) { var _a; return (_a = fields[fieldName]) === null || _a === void 0 ? void 0 : _a.astNode; })
        .filter(function (n) { return n != null; });
    if (astNodes.length > 1 && fieldAstNodes.length) {
        astNodes.push(__assign(__assign({}, astNodes[astNodes.length - 1]), { fields: JSON.parse(JSON.stringify(fieldAstNodes)) }));
    }
    var astNode = astNodes
        .slice(1)
        .reduce(function (acc, astNode) {
        return mergeType(astNode, acc, { ignoreFieldConflicts: true });
    }, astNodes[0]);
    var extensionASTNodes = [].concat(pluck('extensionASTNodes', candidates));
    var extensions = Object.assign.apply(Object, __spreadArray([{}], __read(pluck('extensions', candidates))));
    var typeConfig = {
        name: typeName,
        description: description,
        fields: fields,
        interfaces: interfaces,
        astNode: astNode,
        extensionASTNodes: extensionASTNodes,
        extensions: extensions,
    };
    return new GraphQLObjectType(typeConfig);
}
function mergeInputObjectTypeCandidates(typeName, candidates, typeMergingOptions) {
    candidates = orderedTypeCandidates(candidates, typeMergingOptions);
    var description = mergeTypeDescriptions(candidates, typeMergingOptions);
    var fields = inputFieldConfigMapFromTypeCandidates(candidates, typeMergingOptions);
    var astNodes = pluck('astNode', candidates);
    var fieldAstNodes = canonicalFieldNamesForType(candidates)
        .map(function (fieldName) { var _a; return (_a = fields[fieldName]) === null || _a === void 0 ? void 0 : _a.astNode; })
        .filter(function (n) { return n != null; });
    if (astNodes.length > 1 && fieldAstNodes.length) {
        astNodes.push(__assign(__assign({}, astNodes[astNodes.length - 1]), { fields: JSON.parse(JSON.stringify(fieldAstNodes)) }));
    }
    var astNode = astNodes.slice(1).reduce(function (acc, astNode) {
        return mergeInputType(astNode, acc, {
            ignoreFieldConflicts: true,
        });
    }, astNodes[0]);
    var extensionASTNodes = [].concat(pluck('extensionASTNodes', candidates));
    var extensions = Object.assign.apply(Object, __spreadArray([{}], __read(pluck('extensions', candidates))));
    var typeConfig = {
        name: typeName,
        description: description,
        fields: fields,
        astNode: astNode,
        extensionASTNodes: extensionASTNodes,
        extensions: extensions,
    };
    return new GraphQLInputObjectType(typeConfig);
}
function pluck(typeProperty, candidates) {
    return candidates.map(function (candidate) { return candidate.type[typeProperty]; }).filter(function (value) { return value != null; });
}
function mergeInterfaceTypeCandidates(typeName, candidates, typeMergingOptions) {
    candidates = orderedTypeCandidates(candidates, typeMergingOptions);
    var description = mergeTypeDescriptions(candidates, typeMergingOptions);
    var fields = fieldConfigMapFromTypeCandidates(candidates, typeMergingOptions);
    var typeConfigs = candidates.map(function (candidate) { return candidate.type.toConfig(); });
    var interfaceMap = typeConfigs
        .map(function (typeConfig) { return typeConfig.interfaces; })
        .reduce(function (acc, interfaces) {
        if (interfaces != null) {
            interfaces.forEach(function (iface) {
                acc[iface.name] = iface;
            });
        }
        return acc;
    }, Object.create(null));
    var interfaces = Object.keys(interfaceMap).map(function (interfaceName) { return interfaceMap[interfaceName]; });
    var astNodes = pluck('astNode', candidates);
    var fieldAstNodes = canonicalFieldNamesForType(candidates)
        .map(function (fieldName) { var _a; return (_a = fields[fieldName]) === null || _a === void 0 ? void 0 : _a.astNode; })
        .filter(function (n) { return n != null; });
    if (astNodes.length > 1 && fieldAstNodes.length) {
        astNodes.push(__assign(__assign({}, astNodes[astNodes.length - 1]), { fields: JSON.parse(JSON.stringify(fieldAstNodes)) }));
    }
    var astNode = astNodes.slice(1).reduce(function (acc, astNode) {
        return mergeInterface(astNode, acc, {
            ignoreFieldConflicts: true,
        });
    }, astNodes[0]);
    var extensionASTNodes = [].concat(pluck('extensionASTNodes', candidates));
    var extensions = Object.assign.apply(Object, __spreadArray([{}], __read(pluck('extensions', candidates))));
    var typeConfig = {
        name: typeName,
        description: description,
        fields: fields,
        interfaces: interfaces,
        astNode: astNode,
        extensionASTNodes: extensionASTNodes,
        extensions: extensions,
    };
    return new GraphQLInterfaceType(typeConfig);
}
function mergeUnionTypeCandidates(typeName, candidates, typeMergingOptions) {
    candidates = orderedTypeCandidates(candidates, typeMergingOptions);
    var description = mergeTypeDescriptions(candidates, typeMergingOptions);
    var typeConfigs = candidates.map(function (candidate) { return candidate.type.toConfig(); });
    var typeMap = typeConfigs.reduce(function (acc, typeConfig) {
        typeConfig.types.forEach(function (type) {
            acc[type.name] = type;
        });
        return acc;
    }, Object.create(null));
    var types = Object.keys(typeMap).map(function (typeName) { return typeMap[typeName]; });
    var astNodes = pluck('astNode', candidates);
    var astNode = astNodes
        .slice(1)
        .reduce(function (acc, astNode) { return mergeUnion(astNode, acc); }, astNodes[0]);
    var extensionASTNodes = [].concat(pluck('extensionASTNodes', candidates));
    var extensions = Object.assign.apply(Object, __spreadArray([{}], __read(pluck('extensions', candidates))));
    var typeConfig = {
        name: typeName,
        description: description,
        types: types,
        astNode: astNode,
        extensionASTNodes: extensionASTNodes,
        extensions: extensions,
    };
    return new GraphQLUnionType(typeConfig);
}
function mergeEnumTypeCandidates(typeName, candidates, typeMergingOptions) {
    candidates = orderedTypeCandidates(candidates, typeMergingOptions);
    var description = mergeTypeDescriptions(candidates, typeMergingOptions);
    var values = enumValueConfigMapFromTypeCandidates(candidates, typeMergingOptions);
    var astNodes = pluck('astNode', candidates);
    var astNode = astNodes
        .slice(1)
        .reduce(function (acc, astNode) {
        return mergeEnum(astNode, acc, { consistentEnumMerge: true });
    }, astNodes[0]);
    var extensionASTNodes = [].concat(pluck('extensionASTNodes', candidates));
    var extensions = Object.assign.apply(Object, __spreadArray([{}], __read(pluck('extensions', candidates))));
    var typeConfig = {
        name: typeName,
        description: description,
        values: values,
        astNode: astNode,
        extensionASTNodes: extensionASTNodes,
        extensions: extensions,
    };
    return new GraphQLEnumType(typeConfig);
}
function enumValueConfigMapFromTypeCandidates(candidates, typeMergingOptions) {
    var enumValueConfigCandidatesMap = Object.create(null);
    candidates.forEach(function (candidate) {
        var valueMap = candidate.type.toConfig().values;
        Object.keys(valueMap).forEach(function (enumValue) {
            var enumValueConfigCandidate = {
                enumValueConfig: valueMap[enumValue],
                enumValue: enumValue,
                type: candidate.type,
                subschema: candidate.subschema,
                transformedSubschema: candidate.transformedSubschema,
            };
            if (enumValue in enumValueConfigCandidatesMap) {
                enumValueConfigCandidatesMap[enumValue].push(enumValueConfigCandidate);
            }
            else {
                enumValueConfigCandidatesMap[enumValue] = [enumValueConfigCandidate];
            }
        });
    });
    var enumValueConfigMap = Object.create(null);
    Object.keys(enumValueConfigCandidatesMap).forEach(function (enumValue) {
        var _a;
        var enumValueConfigMerger = (_a = typeMergingOptions === null || typeMergingOptions === void 0 ? void 0 : typeMergingOptions.enumValueConfigMerger) !== null && _a !== void 0 ? _a : defaultEnumValueConfigMerger;
        enumValueConfigMap[enumValue] = enumValueConfigMerger(enumValueConfigCandidatesMap[enumValue]);
    });
    return enumValueConfigMap;
}
function defaultEnumValueConfigMerger(candidates) {
    var preferred = candidates.find(function (_a) {
        var _b, _c;
        var type = _a.type, transformedSubschema = _a.transformedSubschema;
        return isSubschemaConfig(transformedSubschema) && ((_c = (_b = transformedSubschema.merge) === null || _b === void 0 ? void 0 : _b[type.name]) === null || _c === void 0 ? void 0 : _c.canonical);
    });
    return (preferred || candidates[candidates.length - 1]).enumValueConfig;
}
function mergeScalarTypeCandidates(typeName, candidates, typeMergingOptions) {
    candidates = orderedTypeCandidates(candidates, typeMergingOptions);
    var description = mergeTypeDescriptions(candidates, typeMergingOptions);
    var serializeFns = pluck('serialize', candidates);
    var serialize = serializeFns[serializeFns.length - 1];
    var parseValueFns = pluck('parseValue', candidates);
    var parseValue = parseValueFns[parseValueFns.length - 1];
    var parseLiteralFns = pluck('parseLiteral', candidates);
    var parseLiteral = parseLiteralFns[parseLiteralFns.length - 1];
    var astNodes = pluck('astNode', candidates);
    var astNode = astNodes
        .slice(1)
        .reduce(function (acc, astNode) { return mergeScalar(astNode, acc); }, astNodes[0]);
    var extensionASTNodes = [].concat(pluck('extensionASTNodes', candidates));
    var extensions = Object.assign.apply(Object, __spreadArray([{}], __read(pluck('extensions', candidates))));
    var typeConfig = {
        name: typeName,
        description: description,
        serialize: serialize,
        parseValue: parseValue,
        parseLiteral: parseLiteral,
        astNode: astNode,
        extensionASTNodes: extensionASTNodes,
        extensions: extensions,
    };
    return new GraphQLScalarType(typeConfig);
}
function orderedTypeCandidates(candidates, typeMergingOptions) {
    var _a;
    var typeCandidateMerger = (_a = typeMergingOptions === null || typeMergingOptions === void 0 ? void 0 : typeMergingOptions.typeCandidateMerger) !== null && _a !== void 0 ? _a : defaultTypeCandidateMerger;
    var candidate = typeCandidateMerger(candidates);
    return candidates.filter(function (c) { return c !== candidate; }).concat([candidate]);
}
function defaultTypeCandidateMerger(candidates) {
    var canonical = candidates.filter(function (_a) {
        var _b, _c;
        var type = _a.type, transformedSubschema = _a.transformedSubschema;
        return isSubschemaConfig(transformedSubschema) ? (_c = (_b = transformedSubschema.merge) === null || _b === void 0 ? void 0 : _b[type.name]) === null || _c === void 0 ? void 0 : _c.canonical : false;
    });
    if (canonical.length > 1) {
        throw new Error("Multiple canonical definitions for \"" + canonical[0].type.name + "\"");
    }
    else if (canonical.length) {
        return canonical[0];
    }
    return candidates[candidates.length - 1];
}
function mergeTypeDescriptions(candidates, typeMergingOptions) {
    var _a;
    var 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) {
    var fieldConfigCandidatesMap = Object.create(null);
    candidates.forEach(function (candidate) {
        var fieldMap = candidate.type.getFields();
        Object.keys(fieldMap).forEach(function (fieldName) {
            var fieldConfigCandidate = {
                fieldConfig: fieldToFieldConfig(fieldMap[fieldName]),
                fieldName: fieldName,
                type: candidate.type,
                subschema: candidate.subschema,
                transformedSubschema: candidate.transformedSubschema,
            };
            if (fieldName in fieldConfigCandidatesMap) {
                fieldConfigCandidatesMap[fieldName].push(fieldConfigCandidate);
            }
            else {
                fieldConfigCandidatesMap[fieldName] = [fieldConfigCandidate];
            }
        });
    });
    var fieldConfigMap = Object.create(null);
    Object.keys(fieldConfigCandidatesMap).forEach(function (fieldName) {
        fieldConfigMap[fieldName] = mergeFieldConfigs(fieldConfigCandidatesMap[fieldName], typeMergingOptions);
    });
    return fieldConfigMap;
}
function mergeFieldConfigs(candidates, typeMergingOptions) {
    var _a;
    var fieldConfigMerger = (_a = typeMergingOptions === null || typeMergingOptions === void 0 ? void 0 : typeMergingOptions.fieldConfigMerger) !== null && _a !== void 0 ? _a : defaultFieldConfigMerger;
    var finalFieldConfig = fieldConfigMerger(candidates);
    validateFieldConsistency(finalFieldConfig, candidates, typeMergingOptions);
    return finalFieldConfig;
}
function defaultFieldConfigMerger(candidates) {
    var canonicalByField = [];
    var canonicalByType = [];
    candidates.forEach(function (_a) {
        var _b, _c, _d, _e, _f, _g;
        var type = _a.type, fieldName = _a.fieldName, fieldConfig = _a.fieldConfig, transformedSubschema = _a.transformedSubschema;
        if (!isSubschemaConfig(transformedSubschema))
            return;
        if ((_e = (_d = (_c = (_b = transformedSubschema.merge) === null || _b === void 0 ? void 0 : _b[type.name]) === null || _c === void 0 ? void 0 : _c.fields) === null || _d === void 0 ? void 0 : _d[fieldName]) === null || _e === void 0 ? void 0 : _e.canonical) {
            canonicalByField.push(fieldConfig);
        }
        else if ((_g = (_f = transformedSubschema.merge) === null || _f === void 0 ? void 0 : _f[type.name]) === null || _g === void 0 ? void 0 : _g.canonical) {
            canonicalByType.push(fieldConfig);
        }
    });
    if (canonicalByField.length > 1) {
        throw new Error("Multiple canonical definitions for \"" + candidates[0].type.name + "." + candidates[0].fieldName + "\"");
    }
    else if (canonicalByField.length) {
        return canonicalByField[0];
    }
    else if (canonicalByType.length) {
        return canonicalByType[0];
    }
    return candidates[candidates.length - 1].fieldConfig;
}
function inputFieldConfigMapFromTypeCandidates(candidates, typeMergingOptions) {
    var inputFieldConfigCandidatesMap = Object.create(null);
    var fieldInclusionMap = Object.create(null);
    candidates.forEach(function (candidate) {
        var inputFieldMap = candidate.type.getFields();
        Object.keys(inputFieldMap).forEach(function (fieldName) {
            fieldInclusionMap[fieldName] = fieldInclusionMap[fieldName] || 0;
            fieldInclusionMap[fieldName] += 1;
            var inputFieldConfigCandidate = {
                inputFieldConfig: inputFieldToFieldConfig(inputFieldMap[fieldName]),
                fieldName: fieldName,
                type: candidate.type,
                subschema: candidate.subschema,
                transformedSubschema: candidate.transformedSubschema,
            };
            if (fieldName in inputFieldConfigCandidatesMap) {
                inputFieldConfigCandidatesMap[fieldName].push(inputFieldConfigCandidate);
            }
            else {
                inputFieldConfigCandidatesMap[fieldName] = [inputFieldConfigCandidate];
            }
        });
    });
    validateInputObjectConsistency(fieldInclusionMap, candidates, typeMergingOptions);
    var inputFieldConfigMap = Object.create(null);
    Object.keys(inputFieldConfigCandidatesMap).forEach(function (fieldName) {
        var _a;
        var inputFieldConfigMerger = (_a = typeMergingOptions === null || typeMergingOptions === void 0 ? void 0 : typeMergingOptions.inputFieldConfigMerger) !== null && _a !== void 0 ? _a : defaultInputFieldConfigMerger;
        inputFieldConfigMap[fieldName] = inputFieldConfigMerger(inputFieldConfigCandidatesMap[fieldName]);
        validateInputFieldConsistency(inputFieldConfigMap[fieldName], inputFieldConfigCandidatesMap[fieldName], typeMergingOptions);
    });
    return inputFieldConfigMap;
}
function defaultInputFieldConfigMerger(candidates) {
    var canonicalByField = [];
    var canonicalByType = [];
    candidates.forEach(function (_a) {
        var _b, _c, _d, _e, _f, _g;
        var type = _a.type, fieldName = _a.fieldName, inputFieldConfig = _a.inputFieldConfig, transformedSubschema = _a.transformedSubschema;
        if (!isSubschemaConfig(transformedSubschema))
            return;
        if ((_e = (_d = (_c = (_b = transformedSubschema.merge) === null || _b === void 0 ? void 0 : _b[type.name]) === null || _c === void 0 ? void 0 : _c.fields) === null || _d === void 0 ? void 0 : _d[fieldName]) === null || _e === void 0 ? void 0 : _e.canonical) {
            canonicalByField.push(inputFieldConfig);
        }
        else if ((_g = (_f = transformedSubschema.merge) === null || _f === void 0 ? void 0 : _f[type.name]) === null || _g === void 0 ? void 0 : _g.canonical) {
            canonicalByType.push(inputFieldConfig);
        }
    });
    if (canonicalByField.length > 1) {
        throw new Error("Multiple canonical definitions for \"" + candidates[0].type.name + "." + candidates[0].fieldName + "\"");
    }
    else if (canonicalByField.length) {
        return canonicalByField[0];
    }
    else if (canonicalByType.length) {
        return canonicalByType[0];
    }
    return candidates[candidates.length - 1].inputFieldConfig;
}
function canonicalFieldNamesForType(candidates) {
    var canonicalFieldNames = Object.create(null);
    candidates.forEach(function (_a) {
        var _b, _c;
        var type = _a.type, transformedSubschema = _a.transformedSubschema;
        if (isSubschemaConfig(transformedSubschema) &&
            ((_c = (_b = transformedSubschema.merge) === null || _b === void 0 ? void 0 : _b[type.name]) === null || _c === void 0 ? void 0 : _c.fields) &&
            !transformedSubschema.merge[type.name].canonical) {
            Object.entries(transformedSubschema.merge[type.name].fields).forEach(function (_a) {
                var _b = __read(_a, 2), fieldName = _b[0], mergedFieldConfig = _b[1];
                if (mergedFieldConfig.canonical) {
                    canonicalFieldNames[fieldName] = true;
                }
            });
        }
    });
    return Object.keys(canonicalFieldNames);
}

function extractDefinitions(ast) {
    var typeDefinitions = [];
    var directiveDefs = [];
    var schemaDefs = [];
    var schemaExtensions = [];
    var extensionDefs = [];
    ast.definitions.forEach(function (def) {
        switch (def.kind) {
            case Kind.OBJECT_TYPE_DEFINITION:
            case Kind.INTERFACE_TYPE_DEFINITION:
            case Kind.INPUT_OBJECT_TYPE_DEFINITION:
            case Kind.UNION_TYPE_DEFINITION:
            case Kind.ENUM_TYPE_DEFINITION:
            case Kind.SCALAR_TYPE_DEFINITION:
                typeDefinitions.push(def);
                break;
            case Kind.DIRECTIVE_DEFINITION:
                directiveDefs.push(def);
                break;
            case Kind.SCHEMA_DEFINITION:
                schemaDefs.push(def);
                break;
            case Kind.SCHEMA_EXTENSION:
                schemaExtensions.push(def);
                break;
            case Kind.OBJECT_TYPE_EXTENSION:
            case Kind.INTERFACE_TYPE_EXTENSION:
            case Kind.INPUT_OBJECT_TYPE_EXTENSION:
            case Kind.UNION_TYPE_EXTENSION:
            case Kind.ENUM_TYPE_EXTENSION:
            case Kind.SCALAR_TYPE_EXTENSION:
                extensionDefs.push(def);
                break;
        }
    });
    return {
        typeDefinitions: typeDefinitions,
        directiveDefs: directiveDefs,
        schemaDefs: schemaDefs,
        schemaExtensions: schemaExtensions,
        extensionDefs: extensionDefs,
    };
}

function buildTypeCandidates(_a) {
    var subschemas = _a.subschemas, originalSubschemaMap = _a.originalSubschemaMap, types = _a.types, typeDefs = _a.typeDefs, parseOptions = _a.parseOptions, extensions = _a.extensions, directiveMap = _a.directiveMap, schemaDefs = _a.schemaDefs, operationTypeNames = _a.operationTypeNames, mergeDirectives = _a.mergeDirectives;
    var typeCandidates = Object.create(null);
    var schemaDef;
    var schemaExtensions = [];
    var document;
    var extraction;
    if ((typeDefs && !Array.isArray(typeDefs)) || (Array.isArray(typeDefs) && typeDefs.length)) {
        document = buildDocumentFromTypeDefinitions(typeDefs, parseOptions);
        extraction = extractDefinitions(document);
        schemaDef = extraction.schemaDefs[0];
        schemaExtensions = schemaExtensions.concat(extraction.schemaExtensions);
    }
    schemaDefs.schemaDef = schemaDef;
    schemaDefs.schemaExtensions = schemaExtensions;
    setOperationTypeNames(schemaDefs, operationTypeNames);
    subschemas.forEach(function (subschema) {
        var schema = wrapSchema(subschema);
        var operationTypes = {
            query: schema.getQueryType(),
            mutation: schema.getMutationType(),
            subscription: schema.getSubscriptionType(),
        };
        Object.keys(operationTypes).forEach(function (operationType) {
            if (operationTypes[operationType] != null) {
                addTypeCandidate(typeCandidates, operationTypeNames[operationType], {
                    type: operationTypes[operationType],
                    subschema: originalSubschemaMap.get(subschema),
                    transformedSubschema: subschema,
                });
            }
        });
        if (mergeDirectives) {
            schema.getDirectives().forEach(function (directive) {
                directiveMap[directive.name] = directive;
            });
        }
        var originalTypeMap = schema.getTypeMap();
        Object.keys(originalTypeMap).forEach(function (typeName) {
            var 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: type,
                    subschema: originalSubschemaMap.get(subschema),
                    transformedSubschema: subschema,
                });
            }
        });
    });
    if (document !== undefined) {
        extraction.typeDefinitions.forEach(function (def) {
            var type = typeFromAST(def);
            if (type != null) {
                addTypeCandidate(typeCandidates, type.name, { type: type });
            }
        });
        extraction.directiveDefs.forEach(function (def) {
            var directive = typeFromAST(def);
            directiveMap[directive.name] = directive;
        });
        if (extraction.extensionDefs.length > 0) {
            extensions.push(__assign(__assign({}, document), { definitions: extraction.extensionDefs }));
        }
    }
    types.forEach(function (type) { return addTypeCandidate(typeCandidates, type.name, { type: type }); });
    return typeCandidates;
}
function setOperationTypeNames(_a, operationTypeNames) {
    var schemaDef = _a.schemaDef, schemaExtensions = _a.schemaExtensions;
    var allNodes = schemaExtensions.slice();
    if (schemaDef != null) {
        allNodes.unshift(schemaDef);
    }
    allNodes.forEach(function (node) {
        if (node.operationTypes != null) {
            node.operationTypes.forEach(function (operationType) {
                operationTypeNames[operationType.operation] = operationType.type.name.value;
            });
        }
    });
}
function addTypeCandidate(typeCandidates, name, typeCandidate) {
    if (!(name in typeCandidates)) {
        typeCandidates[name] = [];
    }
    typeCandidates[name].push(typeCandidate);
}
function buildTypes(_a) {
    var typeCandidates = _a.typeCandidates, directives = _a.directives, stitchingInfo = _a.stitchingInfo, operationTypeNames = _a.operationTypeNames, onTypeConflict = _a.onTypeConflict, mergeTypes = _a.mergeTypes, typeMergingOptions = _a.typeMergingOptions;
    var typeMap = Object.create(null);
    Object.keys(typeCandidates).forEach(function (typeName) {
        if (typeName === operationTypeNames.query ||
            typeName === operationTypeNames.mutation ||
            typeName === operationTypeNames.subscription ||
            (mergeTypes === true && !typeCandidates[typeName].some(function (candidate) { return 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 {
            var candidateSelector = onTypeConflict != null
                ? onTypeConflictToCandidateSelector(onTypeConflict)
                : function (cands) { return cands[cands.length - 1]; };
            typeMap[typeName] = candidateSelector(typeCandidates[typeName]).type;
        }
    });
    return rewireTypes(typeMap, directives);
}
function onTypeConflictToCandidateSelector(onTypeConflict) {
    return function (cands) {
        return cands.reduce(function (prev, next) {
            var type = onTypeConflict(prev.type, next.type, {
                left: {
                    subschema: prev.subschema,
                    transformedSubschema: prev.transformedSubschema,
                },
                right: {
                    subschema: prev.subschema,
                    transformedSubschema: prev.transformedSubschema,
                },
            });
            if (prev.type === type) {
                return prev;
            }
            else if (next.type === type) {
                return next;
            }
            return {
                schemaName: 'unknown',
                type: type,
            };
        });
    };
}

function createMergedTypeResolver(mergedTypeResolverOptions) {
    var fieldName = mergedTypeResolverOptions.fieldName, argsFromKeys = mergedTypeResolverOptions.argsFromKeys, valuesFromResults = mergedTypeResolverOptions.valuesFromResults, args = mergedTypeResolverOptions.args;
    if (argsFromKeys != null) {
        return function (originalResult, context, info, subschema, selectionSet, key) {
            var _a;
            return batchDelegateToSchema({
                schema: subschema,
                operation: 'query',
                fieldName: fieldName,
                returnType: new GraphQLList(getNamedType((_a = info.schema.getType(originalResult.__typename)) !== null && _a !== void 0 ? _a : info.returnType)),
                key: key,
                argsFromKeys: argsFromKeys,
                valuesFromResults: valuesFromResults,
                selectionSet: selectionSet,
                context: context,
                info: info,
                skipTypeMerging: true,
            });
        };
    }
    if (args != null) {
        return function (originalResult, context, info, subschema, selectionSet) {
            var _a;
            return delegateToSchema({
                schema: subschema,
                operation: 'query',
                fieldName: fieldName,
                returnType: getNamedType((_a = info.schema.getType(originalResult.__typename)) !== null && _a !== void 0 ? _a : info.returnType),
                args: args(originalResult),
                selectionSet: selectionSet,
                context: context,
                info: info,
                skipTypeMerging: true,
            });
        };
    }
    return undefined;
}

function createStitchingInfo(subschemaMap, typeCandidates, mergeTypes) {
    var mergedTypes = createMergedTypes(typeCandidates, mergeTypes);
    var selectionSetsByField = Object.create(null);
    Object.entries(mergedTypes).forEach(function (_a) {
        var _b = __read(_a, 2), typeName = _b[0], mergedTypeInfo = _b[1];
        if (mergedTypeInfo.selectionSets == null && mergedTypeInfo.fieldSelectionSets == null) {
            return;
        }
        selectionSetsByField[typeName] = Object.create(null);
        mergedTypeInfo.selectionSets.forEach(function (selectionSet, subschemaConfig) {
            var schema = subschemaConfig.transformedSchema;
            var type = schema.getType(typeName);
            var fields = type.getFields();
            Object.keys(fields).forEach(function (fieldName) {
                var field = fields[fieldName];
                var 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 }', { noLocation: true }).selections[0]],
                    };
                }
                selectionSetsByField[typeName][fieldName].selections = selectionSetsByField[typeName][fieldName].selections.concat(selectionSet.selections);
            });
        });
        mergedTypeInfo.fieldSelectionSets.forEach(function (selectionSetFieldMap) {
            Object.keys(selectionSetFieldMap).forEach(function (fieldName) {
                if (selectionSetsByField[typeName][fieldName] == null) {
                    selectionSetsByField[typeName][fieldName] = {
                        kind: Kind.SELECTION_SET,
                        selections: [parseSelectionSet('{ __typename }', { noLocation: true }).selections[0]],
                    };
                }
                selectionSetsByField[typeName][fieldName].selections = selectionSetsByField[typeName][fieldName].selections.concat(selectionSetFieldMap[fieldName].selections);
            });
        });
    });
    return {
        subschemaMap: subschemaMap,
        selectionSetsByType: undefined,
        selectionSetsByField: selectionSetsByField,
        dynamicSelectionSetsByField: undefined,
        mergedTypes: mergedTypes,
    };
}
function createMergedTypes(typeCandidates, mergeTypes) {
    var mergedTypes = Object.create(null);
    Object.keys(typeCandidates).forEach(function (typeName) {
        if (typeCandidates[typeName].length > 1 &&
            (isObjectType(typeCandidates[typeName][0].type) || isInterfaceType(typeCandidates[typeName][0].type))) {
            var typeCandidatesWithMergedTypeConfig = typeCandidates[typeName].filter(function (typeCandidate) {
                return typeCandidate.transformedSubschema != null &&
                    typeCandidate.transformedSubschema.merge != null &&
                    typeName in typeCandidate.transformedSubschema.merge;
            });
            if (mergeTypes === true ||
                (typeof mergeTypes === 'function' && mergeTypes(typeCandidates[typeName], typeName)) ||
                (Array.isArray(mergeTypes) && mergeTypes.includes(typeName)) ||
                typeCandidatesWithMergedTypeConfig.length) {
                var targetSubschemas_1 = [];
                var typeMaps_1 = new Map();
                var supportedBySubschemas_1 = Object.create({});
                var selectionSets_1 = new Map();
                var fieldSelectionSets_1 = new Map();
                var resolvers_1 = new Map();
                typeCandidates[typeName].forEach(function (typeCandidate) {
                    var _a, _b;
                    var subschema = typeCandidate.transformedSubschema;
                    if (subschema == null) {
                        return;
                    }
                    typeMaps_1.set(subschema, subschema.transformedSchema.getTypeMap());
                    var 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) {
                        var selectionSet_1 = parseSelectionSet(mergedTypeConfig.selectionSet, { noLocation: true });
                        selectionSets_1.set(subschema, selectionSet_1);
                    }
                    if (mergedTypeConfig.fields) {
                        var parsedFieldSelectionSets_1 = Object.create(null);
                        Object.keys(mergedTypeConfig.fields).forEach(function (fieldName) {
                            if (mergedTypeConfig.fields[fieldName].selectionSet) {
                                var rawFieldSelectionSet = mergedTypeConfig.fields[fieldName].selectionSet;
                                parsedFieldSelectionSets_1[fieldName] = parseSelectionSet(rawFieldSelectionSet, { noLocation: true });
                            }
                        });
                        fieldSelectionSets_1.set(subschema, parsedFieldSelectionSets_1);
                    }
                    var resolver = (_b = mergedTypeConfig.resolve) !== null && _b !== void 0 ? _b : createMergedTypeResolver(mergedTypeConfig);
                    if (resolver == null) {
                        return;
                    }
                    var keyFn = mergedTypeConfig.key;
                    resolvers_1.set(subschema, keyFn
                        ? function (originalResult, context, info, subschema, selectionSet) {
                            var key = keyFn(originalResult);
                            return resolver(originalResult, context, info, subschema, selectionSet, key);
                        }
                        : resolver);
                    targetSubschemas_1.push(subschema);
                    var type = subschema.transformedSchema.getType(typeName);
                    var fieldMap = type.getFields();
                    var selectionSet = selectionSets_1.get(subschema);
                    Object.keys(fieldMap).forEach(function (fieldName) {
                        var field = fieldMap[fieldName];
                        var fieldType = getNamedType(field.type);
                        if (selectionSet && isLeafType(fieldType) && selectionSetContainsTopLevelField(selectionSet, fieldName)) {
                            return;
                        }
                        if (!(fieldName in supportedBySubschemas_1)) {
                            supportedBySubschemas_1[fieldName] = [];
                        }
                        supportedBySubschemas_1[fieldName].push(subschema);
                    });
                });
                var sourceSubschemas = typeCandidates[typeName]
                    .filter(function (typeCandidate) { return typeCandidate.transformedSubschema != null; })
                    .map(function (typeCandidate) { return typeCandidate.transformedSubschema; });
                var targetSubschemasBySubschema_1 = new Map();
                sourceSubschemas.forEach(function (subschema) {
                    var filteredSubschemas = targetSubschemas_1.filter(function (s) { return s !== subschema; });
                    if (filteredSubschemas.length) {
                        targetSubschemasBySubschema_1.set(subschema, filteredSubschemas);
                    }
                });
                mergedTypes[typeName] = {
                    typeName: typeName,
                    targetSubschemas: targetSubschemasBySubschema_1,
                    typeMaps: typeMaps_1,
                    selectionSets: selectionSets_1,
                    fieldSelectionSets: fieldSelectionSets_1,
                    uniqueFields: Object.create({}),
                    nonUniqueFields: Object.create({}),
                    resolvers: resolvers_1,
                };
                Object.keys(supportedBySubschemas_1).forEach(function (fieldName) {
                    if (supportedBySubschemas_1[fieldName].length === 1) {
                        mergedTypes[typeName].uniqueFields[fieldName] = supportedBySubschemas_1[fieldName][0];
                    }
                    else {
                        mergedTypes[typeName].nonUniqueFields[fieldName] = supportedBySubschemas_1[fieldName];
                    }
                });
            }
        }
    });
    return mergedTypes;
}
function completeStitchingInfo(stitchingInfo, resolvers, schema) {
    var selectionSetsByType = Object.create(null);
    [schema.getQueryType(), schema.getMutationType()].forEach(function (rootType) {
        if (rootType) {
            selectionSetsByType[rootType.name] = parseSelectionSet('{ __typename }', { noLocation: true });
        }
    });
    var selectionSetsByField = stitchingInfo.selectionSetsByField;
    var dynamicSelectionSetsByField = Object.create(null);
    Object.keys(resolvers).forEach(function (typeName) {
        var type = resolvers[typeName];
        if (isScalarType(type)) {
            return;
        }
        Object.keys(type).forEach(function (fieldName) {
            var 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 {
                    var selectionSet = parseSelectionSet(field.selectionSet, { noLocation: true });
                    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);
                }
            }
        });
    });
    Object.keys(selectionSetsByField).forEach(function (typeName) {
        var typeSelectionSets = selectionSetsByField[typeName];
        Object.keys(typeSelectionSets).forEach(function (fieldName) {
            var consolidatedSelections = new Map();
            var selectionSet = typeSelectionSets[fieldName];
            selectionSet.selections.forEach(function (selection) {
                consolidatedSelections.set(print(selection), selection);
            });
            selectionSet.selections = Array.from(consolidatedSelections.values());
        });
    });
    stitchingInfo.selectionSetsByType = selectionSetsByType;
    stitchingInfo.selectionSetsByField = selectionSetsByField;
    stitchingInfo.dynamicSelectionSetsByField = dynamicSelectionSetsByField;
    return stitchingInfo;
}
function addStitchingInfo(stitchedSchema, stitchingInfo) {
    return new GraphQLSchema(__assign(__assign({}, stitchedSchema.toConfig()), { extensions: __assign(__assign({}, stitchedSchema.extensions), { stitchingInfo: stitchingInfo }) }));
}
function selectionSetContainsTopLevelField(selectionSet, fieldName) {
    return selectionSet.selections.some(function (selection) { return selection.kind === Kind.FIELD && selection.name.value === fieldName; });
}

function computedDirectiveTransformer(computedDirectiveName) {
    return function (subschemaConfig) {
        var _a;
        var newSubschemaConfig = cloneSubschemaConfig(subschemaConfig);
        mapSchema(subschemaConfig.schema, (_a = {},
            _a[MapperKind.OBJECT_FIELD] = function (fieldConfig, fieldName, typeName, schema) {
                var _a, _b, _c, _d;
                var mergeTypeConfig = (_a = newSubschemaConfig.merge) === null || _a === void 0 ? void 0 : _a[typeName];
                if (mergeTypeConfig == null) {
                    return undefined;
                }
                var computed = getDirectives(schema, fieldConfig)[computedDirectiveName];
                if (computed == null) {
                    return undefined;
                }
                var selectionSet = computed.fields != null ? "{ " + computed.fields + " }" : computed.selectionSet;
                if (selectionSet == null) {
                    return undefined;
                }
                mergeTypeConfig.fields = (_b = mergeTypeConfig.fields) !== null && _b !== void 0 ? _b : {};
                mergeTypeConfig.fields[fieldName] = (_c = mergeTypeConfig.fields[fieldName]) !== null && _c !== void 0 ? _c : {};
                var mergeFieldConfig = mergeTypeConfig.fields[fieldName];
                mergeFieldConfig.selectionSet = (_d = mergeFieldConfig.selectionSet) !== null && _d !== void 0 ? _d : selectionSet;
                mergeFieldConfig.computed = true;
                return undefined;
            },
            _a));
        return newSubschemaConfig;
    };
}

function isolateComputedFieldsTransformer(subschemaConfig) {
    if (subschemaConfig.merge == null) {
        return [subschemaConfig];
    }
    var baseSchemaTypes = Object.create(null);
    var isolatedSchemaTypes = Object.create(null);
    Object.entries(subschemaConfig.merge).forEach(function (_a) {
        var _b;
        var _c = __read(_a, 2), typeName = _c[0], mergedTypeConfig = _c[1];
        baseSchemaTypes[typeName] = mergedTypeConfig;
        if (mergedTypeConfig.computedFields) {
            mergedTypeConfig.fields = (_b = mergedTypeConfig.fields) !== null && _b !== void 0 ? _b : Object.create(null);
            Object.entries(mergedTypeConfig.computedFields).forEach(function (_a) {
                var _b;
                var _c = __read(_a, 2), fieldName = _c[0], mergedFieldConfig = _c[1];
                console.warn("The \"computedFields\" setting is deprecated. Update your @graphql-tools/stitching-directives package, and/or update static merged type config to \"" + typeName + ".fields." + fieldName + " = { selectionSet: '" + mergedFieldConfig.selectionSet + "', computed: true }\"");
                mergedTypeConfig.fields[fieldName] = __assign(__assign(__assign({}, ((_b = mergedTypeConfig.fields[fieldName]) !== null && _b !== void 0 ? _b : {})), mergedFieldConfig), { computed: true });
            });
            delete mergedTypeConfig.computedFields;
        }
        if (mergedTypeConfig.fields) {
            var baseFields_1 = Object.create(null);
            var isolatedFields_1 = Object.create(null);
            Object.entries(mergedTypeConfig.fields).forEach(function (_a) {
                var _b = __read(_a, 2), fieldName = _b[0], mergedFieldConfig = _b[1];
                if (mergedFieldConfig.computed && mergedFieldConfig.selectionSet) {
                    isolatedFields_1[fieldName] = mergedFieldConfig;
                }
                else if (mergedFieldConfig.computed) {
                    throw new Error("A selectionSet is required for computed field \"" + typeName + "." + fieldName + "\"");
                }
                else {
                    baseFields_1[fieldName] = mergedFieldConfig;
                }
            });
            var isolatedFieldCount = Object.keys(isolatedFields_1).length;
            var objectType = subschemaConfig.schema.getType(typeName);
            if (isolatedFieldCount && isolatedFieldCount !== Object.keys(objectType.getFields()).length) {
                baseSchemaTypes[typeName] = __assign(__assign({}, mergedTypeConfig), { fields: baseFields_1 });
                isolatedSchemaTypes[typeName] = __assign(__assign({}, mergedTypeConfig), { fields: isolatedFields_1, canonical: undefined });
            }
        }
    });
    if (Object.keys(isolatedSchemaTypes).length) {
        return [
            filterBaseSubschema(__assign(__assign({}, subschemaConfig), { merge: baseSchemaTypes }), isolatedSchemaTypes),
            filterIsolatedSubschema(__assign(__assign({}, subschemaConfig), { merge: isolatedSchemaTypes })),
        ];
    }
    return [subschemaConfig];
}
function filterBaseSubschema(subschemaConfig, isolatedSchemaTypes) {
    var _a;
    var schema = subschemaConfig.schema;
    var typesForInterface = {};
    var filteredSchema = pruneSchema(filterSchema({
        schema: schema,
        objectFieldFilter: function (typeName, fieldName) { var _a; return !((_a = isolatedSchemaTypes[typeName]) === null || _a === void 0 ? void 0 : _a.fields[fieldName]); },
        interfaceFieldFilter: function (typeName, fieldName) {
            if (!typesForInterface[typeName]) {
                typesForInterface[typeName] = getImplementingTypes(typeName, schema);
            }
            return !typesForInterface[typeName].some(function (implementingTypeName) { var _a; return (_a = isolatedSchemaTypes[implementingTypeName]) === null || _a === void 0 ? void 0 : _a.fields[fieldName]; });
        },
    }));
    var filteredFields = {};
    Object.keys(filteredSchema.getTypeMap()).forEach(function (typeName) {
        var type = filteredSchema.getType(typeName);
        if (isObjectType(type) || isInterfaceType(type)) {
            filteredFields[typeName] = { __typename: true };
            var fieldMap = type.getFields();
            Object.keys(fieldMap).forEach(function (fieldName) {
                filteredFields[typeName][fieldName] = true;
            });
        }
    });
    var filteredSubschema = __assign(__assign({}, subschemaConfig), { merge: subschemaConfig.merge
            ? __assign({}, subschemaConfig.merge) : undefined, transforms: ((_a = subschemaConfig.transforms) !== null && _a !== void 0 ? _a : []).concat([
            new TransformCompositeFields(function (typeName, fieldName) { var _a; return (((_a = filteredFields[typeName]) === null || _a === void 0 ? void 0 : _a[fieldName]) ? undefined : null); }, function (typeName, fieldName) { var _a; return (((_a = filteredFields[typeName]) === null || _a === void 0 ? void 0 : _a[fieldName]) ? undefined : null); }),
        ]) });
    var remainingTypes = filteredSchema.getTypeMap();
    Object.keys(filteredSubschema.merge).forEach(function (mergeType) {
        if (!remainingTypes[mergeType]) {
            delete filteredSubschema.merge[mergeType];
        }
    });
    if (!Object.keys(filteredSubschema.merge).length) {
        delete filteredSubschema.merge;
    }
    return filteredSubschema;
}
function filterIsolatedSubschema(subschemaConfig) {
    var _a;
    var rootFields = {};
    Object.values(subschemaConfig.merge).forEach(function (mergedTypeConfig) {
        var _a;
        var entryPoints = (_a = mergedTypeConfig.entryPoints) !== null && _a !== void 0 ? _a : [mergedTypeConfig];
        entryPoints.forEach(function (entryPoint) {
            rootFields[entryPoint.fieldName] = true;
        });
    });
    var interfaceFields = {};
    Object.keys(subschemaConfig.merge).forEach(function (typeName) {
        subschemaConfig.schema.getType(typeName).getInterfaces().forEach(function (int) {
            Object.keys(subschemaConfig.schema.getType(int.name).getFields()).forEach(function (intFieldName) {
                if (subschemaConfig.merge[typeName].fields[intFieldName]) {
                    interfaceFields[int.name] = interfaceFields[int.name] || {};
                    interfaceFields[int.name][intFieldName] = true;
                }
            });
        });
    });
    var filteredSchema = pruneSchema(filterSchema({
        schema: subschemaConfig.schema,
        rootFieldFilter: function (operation, fieldName) { return operation === 'Query' && rootFields[fieldName] != null; },
        objectFieldFilter: function (typeName, fieldName) { var _a; return ((_a = subschemaConfig.merge[typeName]) === null || _a === void 0 ? void 0 : _a.fields[fieldName]) != null; },
        interfaceFieldFilter: function (typeName, fieldName) { var _a; return ((_a = interfaceFields[typeName]) === null || _a === void 0 ? void 0 : _a[fieldName]) != null; },
    }));
    var filteredFields = {};
    Object.keys(filteredSchema.getTypeMap()).forEach(function (typeName) {
        var type = filteredSchema.getType(typeName);
        if (isObjectType(type) || isInterfaceType(type)) {
            filteredFields[typeName] = { __typename: true };
            var fieldMap = type.getFields();
            Object.keys(fieldMap).forEach(function (fieldName) {
                filteredFields[typeName][fieldName] = true;
            });
        }
    });
    return __assign(__assign({}, subschemaConfig), { transforms: ((_a = subschemaConfig.transforms) !== null && _a !== void 0 ? _a : []).concat([
            new TransformCompositeFields(function (typeName, fieldName) { var _a; return (((_a = filteredFields[typeName]) === null || _a === void 0 ? void 0 : _a[fieldName]) ? undefined : null); }, function (typeName, fieldName) { var _a; return (((_a = filteredFields[typeName]) === null || _a === void 0 ? void 0 : _a[fieldName]) ? undefined : null); }),
        ]) });
}

function splitMergedTypeEntryPointsTransformer(subschemaConfig) {
    if (!subschemaConfig.merge)
        return [subschemaConfig];
    var maxEntryPoints = Object.values(subschemaConfig.merge).reduce(function (max, mergedTypeConfig) {
        var _a, _b;
        return Math.max(max, (_b = (_a = mergedTypeConfig === null || mergedTypeConfig === void 0 ? void 0 : mergedTypeConfig.entryPoints) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0);
    }, 0);
    if (maxEntryPoints === 0)
        return [subschemaConfig];
    var subschemaPermutations = [];
    var _loop_1 = function (i) {
        var subschemaPermutation = cloneSubschemaConfig(subschemaConfig);
        var mergedTypesCopy = subschemaPermutation.merge;
        if (i > 0) {
            subschemaPermutation.merge = Object.create(null);
        }
        Object.keys(mergedTypesCopy).forEach(function (typeName) {
            var _a, _b, _c;
            var mergedTypeConfig = mergedTypesCopy[typeName];
            var mergedTypeEntryPoint = (_a = mergedTypeConfig === null || mergedTypeConfig === void 0 ? void 0 : mergedTypeConfig.entryPoints) === null || _a === void 0 ? void 0 : _a[i];
            if (mergedTypeEntryPoint) {
                if ((_c = (_b = mergedTypeConfig.selectionSet) !== null && _b !== void 0 ? _b : mergedTypeConfig.fieldName) !== null && _c !== void 0 ? _c : mergedTypeConfig.resolve) {
                    throw new Error("Merged type " + typeName + " may not define entryPoints in addition to selectionSet, fieldName, or resolve");
                }
                Object.assign(mergedTypeConfig, mergedTypeEntryPoint);
                delete mergedTypeConfig.entryPoints;
                if (i > 0) {
                    delete mergedTypeConfig.canonical;
                    if (mergedTypeConfig.fields != null) {
                        Object.values(mergedTypeConfig.fields).forEach(function (mergedFieldConfig) {
                            delete mergedFieldConfig.canonical;
                        });
                    }
                }
                subschemaPermutation.merge[typeName] = mergedTypeConfig;
            }
        });
        subschemaPermutations.push(subschemaPermutation);
    };
    for (var i = 0; i < maxEntryPoints; i += 1) {
        _loop_1(i);
    }
    return subschemaPermutations;
}

var defaultSubschemaConfigTransforms = [computedDirectiveTransformer('computed')];

function stitchSchemas(_a) {
    var _b = _a.subschemas, subschemas = _b === void 0 ? [] : _b, _c = _a.types, types = _c === void 0 ? [] : _c, typeDefs = _a.typeDefs, onTypeConflict = _a.onTypeConflict, mergeDirectives = _a.mergeDirectives, _d = _a.mergeTypes, mergeTypes = _d === void 0 ? true : _d, typeMergingOptions = _a.typeMergingOptions, _e = _a.subschemaConfigTransforms, subschemaConfigTransforms = _e === void 0 ? defaultSubschemaConfigTransforms : _e, _f = _a.resolvers, resolvers = _f === void 0 ? {} : _f, schemaDirectives = _a.schemaDirectives, _g = _a.inheritResolversFromInterfaces, inheritResolversFromInterfaces = _g === void 0 ? false : _g, logger = _a.logger, _h = _a.allowUndefinedInResolve, allowUndefinedInResolve = _h === void 0 ? true : _h, _j = _a.resolverValidationOptions, resolverValidationOptions = _j === void 0 ? {} : _j, directiveResolvers = _a.directiveResolvers, _k = _a.schemaTransforms, schemaTransforms = _k === void 0 ? [] : _k, _l = _a.parseOptions, parseOptions = _l === void 0 ? {} : _l, pruningOptions = _a.pruningOptions, updateResolversInPlace = _a.updateResolversInPlace;
    if (typeof resolverValidationOptions !== 'object') {
        throw new Error('Expected `resolverValidationOptions` to be an object');
    }
    var transformedSubschemas = [];
    var subschemaMap = new Map();
    var originalSubschemaMap = new Map();
    subschemas.forEach(function (subschemaOrSubschemaArray) {
        if (Array.isArray(subschemaOrSubschemaArray)) {
            subschemaOrSubschemaArray.forEach(function (s) {
                transformedSubschemas = transformedSubschemas.concat(applySubschemaConfigTransforms(subschemaConfigTransforms, s, subschemaMap, originalSubschemaMap));
            });
        }
        else {
            transformedSubschemas = transformedSubschemas.concat(applySubschemaConfigTransforms(subschemaConfigTransforms, subschemaOrSubschemaArray, subschemaMap, originalSubschemaMap));
        }
    });
    var extensions = [];
    var directives = [];
    var directiveMap = specifiedDirectives.reduce(function (acc, directive) {
        acc[directive.name] = directive;
        return acc;
    }, Object.create(null));
    var schemaDefs = Object.create(null);
    var operationTypeNames = {
        query: 'Query',
        mutation: 'Mutation',
        subscription: 'Subscription',
    };
    var typeCandidates = buildTypeCandidates({
        subschemas: transformedSubschemas,
        originalSubschemaMap: originalSubschemaMap,
        types: types,
        typeDefs: typeDefs,
        parseOptions: parseOptions,
        extensions: extensions,
        directiveMap: directiveMap,
        schemaDefs: schemaDefs,
        operationTypeNames: operationTypeNames,
        mergeDirectives: mergeDirectives,
    });
    Object.keys(directiveMap).forEach(function (directiveName) {
        directives.push(directiveMap[directiveName]);
    });
    var stitchingInfo = createStitchingInfo(subschemaMap, typeCandidates, mergeTypes);
    var _m = buildTypes({
        typeCandidates: typeCandidates,
        directives: directives,
        stitchingInfo: stitchingInfo,
        operationTypeNames: operationTypeNames,
        onTypeConflict: onTypeConflict,
        mergeTypes: mergeTypes,
        typeMergingOptions: typeMergingOptions,
    }), newTypeMap = _m.typeMap, newDirectives = _m.directives;
    var schema = new GraphQLSchema({
        query: newTypeMap[operationTypeNames.query],
        mutation: newTypeMap[operationTypeNames.mutation],
        subscription: newTypeMap[operationTypeNames.subscription],
        types: Object.keys(newTypeMap).map(function (key) { return newTypeMap[key]; }),
        directives: newDirectives,
        astNode: schemaDefs.schemaDef,
        extensionASTNodes: schemaDefs.schemaExtensions,
        extensions: null,
    });
    extensions.forEach(function (extension) {
        schema = extendSchema(schema, extension, {
            commentDescriptions: true,
        });
    });
    // We allow passing in an array of resolver maps, in which case we merge them
    var resolverMap = Array.isArray(resolvers) ? resolvers.reduce(mergeDeep, {}) : resolvers;
    var finalResolvers = inheritResolversFromInterfaces
        ? extendResolversFromInterfaces(schema, resolverMap)
        : resolverMap;
    stitchingInfo = completeStitchingInfo(stitchingInfo, finalResolvers, schema);
    schema = addResolversToSchema({
        schema: schema,
        defaultFieldResolver: defaultMergedResolver,
        resolvers: finalResolvers,
        resolverValidationOptions: resolverValidationOptions,
        inheritResolversFromInterfaces: false,
        updateResolversInPlace: updateResolversInPlace,
    });
    if (Object.keys(resolverValidationOptions).length > 0) {
        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(function (schemaTransform) {
        schema = schemaTransform(schema);
    });
    if (directiveResolvers != null) {
        schema = attachDirectiveResolvers(schema, directiveResolvers);
    }
    if (schemaDirectives != null) {
        SchemaDirectiveVisitor.visitSchemaDirectives(schema, schemaDirectives);
    }
    if (pruningOptions) {
        schema = pruneSchema(schema, pruningOptions);
    }
    return schema;
}
var subschemaConfigTransformerPresets = [isolateComputedFieldsTransformer, splitMergedTypeEntryPointsTransformer];
function applySubschemaConfigTransforms(subschemaConfigTransforms, subschemaOrSubschemaConfig, subschemaMap, originalSubschemaMap) {
    var subschemaConfig = isSubschemaConfig(subschemaOrSubschemaConfig)
        ? subschemaOrSubschemaConfig
        : { schema: subschemaOrSubschemaConfig };
    var transformedSubschemaConfigs = [subschemaConfig];
    subschemaConfigTransforms.concat(subschemaConfigTransformerPresets).forEach(function (subschemaConfigTransform) {
        var mapped = transformedSubschemaConfigs.map(function (ssConfig) {
            return subschemaConfigTransform(ssConfig);
        });
        transformedSubschemaConfigs = mapped.reduce(function (acc, configOrList) {
            if (Array.isArray(configOrList)) {
                return acc.concat(configOrList);
            }
            acc.push(configOrList);
            return acc;
        }, []);
    });
    var transformedSubschemas = transformedSubschemaConfigs.map(function (ssConfig) { return new Subschema(ssConfig); });
    var baseSubschema = transformedSubschemas[0];
    subschemaMap.set(subschemaOrSubschemaConfig, baseSubschema);
    transformedSubschemas.forEach(function (subschema) { return originalSubschemaMap.set(subschema, subschemaOrSubschemaConfig); });
    return transformedSubschemas;
}

var forwardArgsToSelectionSet = function (selectionSet, mapping) {
    var selectionSetDef = parseSelectionSet(selectionSet, { noLocation: true });
    return function (field) {
        var selections = selectionSetDef.selections.map(function (selectionNode) {
            if (selectionNode.kind === Kind.FIELD) {
                if (!mapping) {
                    return __assign(__assign({}, selectionNode), { arguments: field.arguments.slice() });
                }
                else if (selectionNode.name.value in mapping) {
                    var selectionArgs_1 = mapping[selectionNode.name.value];
                    return __assign(__assign({}, selectionNode), { arguments: field.arguments.filter(function (arg) { return selectionArgs_1.includes(arg.name.value); }) });
                }
            }
            return selectionNode;
        });
        return __assign(__assign({}, selectionSetDef), { selections: selections });
    };
};

export { ValidationLevel, computedDirectiveTransformer, createMergedTypeResolver, defaultSubschemaConfigTransforms, forwardArgsToSelectionSet, isolateComputedFieldsTransformer, splitMergedTypeEntryPointsTransformer, stitchSchemas };
//# sourceMappingURL=index.esm.js.map
