@apollo/federation-internals
Version: 
Apollo Federation internal utilities
642 lines • 27.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.removeAllCoreFeatures = exports.LINK_VERSIONS = exports.CORE_VERSIONS = exports.findCoreSpecVersion = exports.FeatureUrl = exports.FeatureVersion = exports.FeatureDefinitions = exports.CoreSpecDefinition = exports.isCoreSpecDirectiveApplication = exports.extractCoreFeatureImports = exports.FeatureDefinition = exports.corePurposes = exports.ErrCoreCheckFailed = exports.linkDirectiveDefaultName = exports.linkIdentity = exports.coreIdentity = void 0;
const graphql_1 = require("graphql");
const url_1 = require("url");
const definitions_1 = require("../definitions");
const types_1 = require("../types");
const utils_1 = require("../utils");
const error_1 = require("../error");
const values_1 = require("../values");
const knownCoreFeatures_1 = require("../knownCoreFeatures");
const suggestions_1 = require("../suggestions");
const directiveAndTypeSpecification_1 = require("../directiveAndTypeSpecification");
exports.coreIdentity = 'https://specs.apollo.dev/core';
exports.linkIdentity = 'https://specs.apollo.dev/link';
exports.linkDirectiveDefaultName = 'link';
const ErrCoreCheckFailed = (causes) => (0, error_1.aggregateError)('CheckFailed', 'one or more checks failed', causes);
exports.ErrCoreCheckFailed = ErrCoreCheckFailed;
function buildError(message) {
    return new Error(message);
}
exports.corePurposes = [
    'SECURITY',
    'EXECUTION',
];
function purposesDescription(purpose) {
    switch (purpose) {
        case 'SECURITY': return "`SECURITY` features provide metadata necessary to securely resolve fields.";
        case 'EXECUTION': return "`EXECUTION` features provide metadata necessary for operation execution.";
    }
}
class FeatureDefinition {
    constructor(url, minimumFederationVersion) {
        this.minimumFederationVersion = minimumFederationVersion;
        this._directiveSpecs = new utils_1.MapWithCachedArrays();
        this._typeSpecs = new utils_1.MapWithCachedArrays();
        this.url = typeof url === 'string' ? FeatureUrl.parse(url) : url;
    }
    registerDirective(spec) {
        this._directiveSpecs.set(spec.name, spec);
    }
    registerType(spec) {
        this._typeSpecs.set(spec.name, spec);
    }
    registerSubFeature(subFeature) {
        for (const typeSpec of subFeature.typeSpecs()) {
            this.registerType(typeSpec);
        }
        for (const directiveSpec of subFeature.directiveSpecs()) {
            this.registerDirective(directiveSpec);
        }
    }
    directiveSpecs() {
        return this._directiveSpecs.values();
    }
    directiveSpec(name) {
        return this._directiveSpecs.get(name);
    }
    typeSpecs() {
        return this._typeSpecs.values();
    }
    typeSpec(name) {
        return this._typeSpecs.get(name);
    }
    get identity() {
        return this.url.identity;
    }
    get version() {
        return this.url.version;
    }
    isSpecType(type) {
        const nameInSchema = this.nameInSchema(type.schema());
        return nameInSchema !== undefined && type.name.startsWith(`${nameInSchema}__`);
    }
    isSpecDirective(directive) {
        const nameInSchema = this.nameInSchema(directive.schema());
        return nameInSchema != undefined && (directive.name === nameInSchema || directive.name.startsWith(`${nameInSchema}__`));
    }
    addElementsToSchema(schema) {
        const feature = this.featureInSchema(schema);
        (0, utils_1.assert)(feature, () => `The ${this.url} specification should have been added to the schema before this is called`);
        let errors = [];
        for (const type of this.typeSpecs()) {
            errors = errors.concat(type.checkOrAdd(schema, feature));
        }
        for (const directive of this.directiveSpecs()) {
            errors = errors.concat(directive.checkOrAdd(schema, feature));
        }
        return errors;
    }
    allElementNames() {
        return this.directiveSpecs().map((spec) => `@${spec.name}`)
            .concat(this.typeSpecs().map((spec) => spec.name));
    }
    nameInSchema(schema) {
        const feature = this.featureInSchema(schema);
        return feature === null || feature === void 0 ? void 0 : feature.nameInSchema;
    }
    directiveNameInSchema(schema, directiveName) {
        const feature = this.featureInSchema(schema);
        return feature ? feature.directiveNameInSchema(directiveName) : undefined;
    }
    typeNameInSchema(schema, typeName) {
        const feature = this.featureInSchema(schema);
        return feature ? feature.typeNameInSchema(typeName) : undefined;
    }
    rootDirective(schema) {
        const name = this.nameInSchema(schema);
        return name ? schema.directive(name) : undefined;
    }
    directive(schema, elementName) {
        const name = this.directiveNameInSchema(schema, elementName);
        return name ? schema.directive(name) : undefined;
    }
    type(schema, elementName) {
        const name = this.typeNameInSchema(schema, elementName);
        return name ? schema.type(name) : undefined;
    }
    addRootDirective(schema) {
        return schema.addDirectiveDefinition(this.nameInSchema(schema));
    }
    addDirective(schema, name) {
        return schema.addDirectiveDefinition(this.directiveNameInSchema(schema, name));
    }
    addScalarType(schema, name) {
        return schema.addType(new definitions_1.ScalarType(this.typeNameInSchema(schema, name)));
    }
    addEnumType(schema, name) {
        return schema.addType(new definitions_1.EnumType(this.typeNameInSchema(schema, name)));
    }
    featureInSchema(schema) {
        const features = schema.coreFeatures;
        if (!features) {
            throw buildError(`Schema is not a core schema (add @link first)`);
        }
        return features.getByIdentity(this.identity);
    }
    get defaultCorePurpose() {
        return undefined;
    }
    compositionSpecification(directiveNameInFeature) {
        const spec = this._directiveSpecs.get(directiveNameInFeature);
        return spec === null || spec === void 0 ? void 0 : spec.composition;
    }
    toString() {
        return `${this.identity}/${this.version}`;
    }
}
exports.FeatureDefinition = FeatureDefinition;
function extractCoreFeatureImports(url, directive) {
    const args = directive.arguments();
    if (!('import' in args) || !args.import) {
        return [];
    }
    const importArgValue = args.import;
    const definition = (0, knownCoreFeatures_1.coreFeatureDefinitionIfKnown)(url);
    const knownElements = definition === null || definition === void 0 ? void 0 : definition.allElementNames();
    const errors = [];
    const imports = [];
    importArgLoop: for (const elt of importArgValue) {
        if (typeof elt === 'string') {
            imports.push({ name: elt });
            validateImportedName(elt, knownElements, errors, directive);
            continue;
        }
        if (typeof elt !== 'object') {
            errors.push(error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Invalid sub-value ${(0, values_1.valueToString)(elt)} for @link(import:) argument: values should be either strings or input object values of the form { name: "<importedElement>", as: "<alias>" }.`, { nodes: directive.sourceAST }));
            continue;
        }
        let name;
        for (const [key, value] of Object.entries(elt)) {
            switch (key) {
                case 'name':
                    if (typeof value !== 'string') {
                        errors.push(error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Invalid value for the "name" field for sub-value ${(0, values_1.valueToString)(elt)} of @link(import:) argument: must be a string.`, { nodes: directive.sourceAST }));
                        continue importArgLoop;
                    }
                    name = value;
                    break;
                case 'as':
                    if (typeof value !== 'string') {
                        errors.push(error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Invalid value for the "as" field for sub-value ${(0, values_1.valueToString)(elt)} of @link(import:) argument: must be a string.`, { nodes: directive.sourceAST }));
                        continue importArgLoop;
                    }
                    break;
                default:
                    errors.push(error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Unknown field "${key}" for sub-value ${(0, values_1.valueToString)(elt)} of @link(import:) argument.`, { nodes: directive.sourceAST }));
                    continue importArgLoop;
            }
        }
        if (name) {
            const i = elt;
            imports.push(i);
            if (i.as) {
                if (i.name.charAt(0) === '@' && i.as.charAt(0) !== '@') {
                    errors.push(error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Invalid @link import renaming: directive "${i.name}" imported name should start with a '@' character, but got "${i.as}".`, { nodes: directive.sourceAST }));
                }
                else if (i.name.charAt(0) !== '@' && i.as.charAt(0) === '@') {
                    errors.push(error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Invalid @link import renaming: type "${i.name}" imported name should not start with a '@' character, but got "${i.as}" (or, if @${i.name} is a directive, then it should be referred to with a '@').`, { nodes: directive.sourceAST }));
                }
            }
            validateImportedName(name, knownElements, errors, directive);
        }
        else {
            errors.push(error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Invalid sub-value ${(0, values_1.valueToString)(elt)} for @link(import:) argument: missing mandatory "name" field.`, { nodes: directive.sourceAST }));
        }
    }
    if (errors.length > 0) {
        throw (0, definitions_1.ErrGraphQLValidationFailed)(errors);
    }
    return imports;
}
exports.extractCoreFeatureImports = extractCoreFeatureImports;
function validateImportedName(name, knownElements, errors, directive) {
    if (knownElements && !knownElements.includes(name)) {
        let details = '';
        if (!name.startsWith('@') && knownElements.includes('@' + name)) {
            details = ` Did you mean directive "@${name}"?`;
        }
        else {
            const suggestions = (0, suggestions_1.suggestionList)(name, knownElements);
            if (suggestions) {
                details = (0, suggestions_1.didYouMean)(suggestions);
            }
        }
        errors.push(error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Cannot import unknown element "${name}".${details}`, { nodes: directive.sourceAST }));
    }
}
function isCoreSpecDirectiveApplication(directive) {
    var _a, _b, _c;
    const definition = directive.definition;
    if (!definition) {
        return false;
    }
    const asArg = definition.argument('as');
    if (asArg && !(0, types_1.sameType)(asArg.type, directive.schema().stringType())) {
        return false;
    }
    if (!definition.repeatable || definition.locations.length !== 1 || definition.locations[0] !== graphql_1.DirectiveLocation.SCHEMA) {
        return false;
    }
    const urlArg = (_a = definition.argument('url')) !== null && _a !== void 0 ? _a : definition.argument('feature');
    if (!urlArg || !isValidUrlArgumentType(urlArg.type, directive.schema())) {
        return false;
    }
    const args = directive.arguments();
    try {
        const url = FeatureUrl.parse(args[urlArg.name]);
        if (url.identity === exports.coreIdentity) {
            return directive.name === ((_b = args.as) !== null && _b !== void 0 ? _b : 'core');
        }
        else {
            return url.identity === exports.linkIdentity && directive.name === ((_c = args.as) !== null && _c !== void 0 ? _c : exports.linkDirectiveDefaultName);
        }
    }
    catch (err) {
        return false;
    }
}
exports.isCoreSpecDirectiveApplication = isCoreSpecDirectiveApplication;
function isValidUrlArgumentType(type, schema) {
    return (0, types_1.sameType)(type, schema.stringType())
        || (0, types_1.sameType)(type, new definitions_1.NonNullType(schema.stringType()));
}
const linkPurposeTypeSpec = (0, directiveAndTypeSpecification_1.createEnumTypeSpecification)({
    name: 'Purpose',
    values: exports.corePurposes.map((name) => ({ name, description: purposesDescription(name) }))
});
const linkImportTypeSpec = (0, directiveAndTypeSpecification_1.createScalarTypeSpecification)({ name: 'Import' });
class CoreSpecDefinition extends FeatureDefinition {
    constructor(version, minimumFederationVersion, identity = exports.linkIdentity, name = exports.linkDirectiveDefaultName) {
        super(new FeatureUrl(identity, name, version), minimumFederationVersion);
        this.directiveDefinitionSpec = (0, directiveAndTypeSpecification_1.createDirectiveSpecification)({
            name,
            locations: [graphql_1.DirectiveLocation.SCHEMA],
            repeatable: true,
            args: this.createDefinitionArgumentSpecifications(),
        });
        this.registerDirective(this.directiveDefinitionSpec);
    }
    createDefinitionArgumentSpecifications() {
        const args = [
            { name: this.urlArgName(), type: (schema) => schema.stringType() },
            { name: 'as', type: (schema) => schema.stringType() },
        ];
        if (this.supportPurposes()) {
            args.push({
                name: 'for',
                type: (schema, feature) => {
                    (0, utils_1.assert)(feature, "Shouldn't be added without being attached to a @link spec");
                    return schema.type(feature.typeNameInSchema(linkPurposeTypeSpec.name));
                },
            });
        }
        if (this.supportImport()) {
            args.push({
                name: 'import',
                type: (schema, feature) => {
                    (0, utils_1.assert)(feature, "Shouldn't be added without being attached to a @link spec");
                    return new definitions_1.ListType(schema.type(feature.typeNameInSchema(linkImportTypeSpec.name)));
                }
            });
        }
        return args;
    }
    addElementsToSchema(_) {
        return [];
    }
    addToSchema(schema, alias) {
        const errors = this.addDefinitionsToSchema(schema, alias);
        if (errors.length > 0) {
            return errors;
        }
        const args = { [this.urlArgName()]: this.toString() };
        if (alias) {
            args.as = alias;
        }
        const schemaDef = schema.schemaDefinition;
        const hasDefinition = schemaDef.hasNonExtensionElements();
        const directive = schemaDef.applyDirective(alias !== null && alias !== void 0 ? alias : this.url.name, args, true);
        if (!hasDefinition && schemaDef.hasExtensionElements()) {
            const extension = (0, utils_1.firstOf)(schemaDef.extensions());
            (0, utils_1.assert)(extension, '`hasExtensionElements` should not have been `true`');
            directive.setOfExtension(extension);
        }
        return [];
    }
    addDefinitionsToSchema(schema, as, imports = []) {
        const existingCore = schema.coreFeatures;
        if (existingCore) {
            if (existingCore.coreItself.url.identity === this.identity) {
                return [];
            }
            else {
                return [error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Cannot add feature ${this} to the schema, it already uses ${existingCore.coreItself.url}`)];
            }
        }
        const nameInSchema = as !== null && as !== void 0 ? as : this.url.name;
        const feature = new definitions_1.CoreFeature(this.url, nameInSchema, new definitions_1.Directive(nameInSchema), imports);
        let errors = [];
        errors = errors.concat(linkPurposeTypeSpec.checkOrAdd(schema, feature));
        errors = errors.concat(linkImportTypeSpec.checkOrAdd(schema, feature));
        errors = errors.concat(this.directiveDefinitionSpec.checkOrAdd(schema, feature));
        return errors;
    }
    allElementNames() {
        const names = [`@${this.url.name}`];
        if (this.supportPurposes()) {
            names.push('Purpose');
        }
        if (this.supportImport()) {
            names.push('Import');
        }
        return names;
    }
    supportPurposes() {
        return this.version.strictlyGreaterThan(new FeatureVersion(0, 1));
    }
    supportImport() {
        return this.url.name === exports.linkDirectiveDefaultName;
    }
    extractFeature(schema) {
        const features = schema.coreFeatures;
        if (!features) {
            throw buildError(`Schema is not a core schema (add @core first)`);
        }
        if (!features.coreItself.url.version.equals(this.version)) {
            throw buildError(`Cannot use this version of @core (${this.version}), the schema uses version ${features.coreItself.url.version}`);
        }
        return features.coreItself;
    }
    coreDirective(schema) {
        const feature = this.extractFeature(schema);
        const directive = schema.directive(feature.nameInSchema);
        return directive;
    }
    coreVersion(schema) {
        const feature = this.extractFeature(schema);
        return feature.url.version;
    }
    applyFeatureToSchema(schema, feature, as, purpose, imports) {
        const coreDirective = this.coreDirective(schema);
        const args = {
            [this.urlArgName()]: feature.toString(),
            as,
        };
        if (purpose) {
            if (this.supportPurposes()) {
                args.for = purpose;
            }
            else {
                return [new graphql_1.GraphQLError(`Cannot apply feature ${feature} with purpose since the schema's @core/@link version does not support it.`)];
            }
        }
        if (imports && imports.length > 0) {
            if (this.supportImport()) {
                args.import = imports.map(i => i.as ? i : i.name);
            }
            else {
                return [new graphql_1.GraphQLError(`Cannot apply feature ${feature} with imports since the schema's @core/@link version does not support it.`)];
            }
        }
        schema.schemaDefinition.applyDirective(coreDirective, args);
        return feature.addElementsToSchema(schema);
    }
    extractFeatureUrl(args) {
        return FeatureUrl.parse(args[this.urlArgName()]);
    }
    urlArgName() {
        return this.url.name === 'core' ? 'feature' : 'url';
    }
}
exports.CoreSpecDefinition = CoreSpecDefinition;
class FeatureDefinitions {
    constructor(identity) {
        this.identity = identity;
        this._definitions = [];
    }
    add(definition) {
        if (definition.identity !== this.identity) {
            throw buildError(`Cannot add definition for ${definition} to the versions of definitions for ${this.identity}`);
        }
        if (this._definitions.find(def => definition.version.equals(def.version))) {
            return this;
        }
        this._definitions.push(definition);
        this._definitions.sort((def1, def2) => -def1.version.compareTo(def2.version));
        return this;
    }
    find(requested) {
        return this._definitions.find((def) => def.version.equals(requested));
    }
    versions() {
        return this._definitions.map(def => def.version);
    }
    latest() {
        (0, utils_1.assert)(this._definitions.length > 0, 'Trying to get latest when no definitions exist');
        return this._definitions[0];
    }
    getMinimumRequiredVersion(fedVersion) {
        var _a;
        const def = this._definitions.find(def => def.minimumFederationVersion ? fedVersion.gte(def.minimumFederationVersion) : true);
        (0, utils_1.assert)(def, `No compatible definition exists for federation version ${fedVersion}`);
        const latestMajor = this.latest().version.major;
        if (def.version.major !== latestMajor) {
            return (_a = (0, utils_1.findLast)(this._definitions, def => def.version.major === latestMajor)) !== null && _a !== void 0 ? _a : this.latest();
        }
        return def;
    }
}
exports.FeatureDefinitions = FeatureDefinitions;
class FeatureVersion {
    constructor(major, minor) {
        this.major = major;
        this.minor = minor;
    }
    static parse(input) {
        const match = input.match(this.VERSION_RE);
        if (!match) {
            throw error_1.ERRORS.INVALID_LINK_IDENTIFIER.err(`Expected a version string (of the form v1.2), got ${input}`);
        }
        return new this(+match[1], +match[2]);
    }
    static max(versions) {
        let max;
        for (const version of versions) {
            if (!max || version.gt(max)) {
                max = version;
            }
        }
        return max;
    }
    satisfies(required) {
        const { major, minor } = this;
        const { major: rMajor, minor: rMinor } = required;
        return rMajor == major && (major == 0
            ? rMinor == minor
            : rMinor <= minor);
    }
    get series() {
        const { major } = this;
        return major > 0 ? `${major}.x` : String(this);
    }
    compareTo(other) {
        if (this.major > other.major) {
            return 1;
        }
        if (this.major < other.major) {
            return -1;
        }
        if (this.minor > other.minor) {
            return 1;
        }
        if (this.minor < other.minor) {
            return -1;
        }
        return 0;
    }
    lt(other) {
        return this.compareTo(other) < 0;
    }
    lte(other) {
        return this.compareTo(other) <= 0;
    }
    gt(other) {
        return this.compareTo(other) > 0;
    }
    gte(other) {
        return this.compareTo(other) >= 0;
    }
    strictlyGreaterThan(version) {
        return this.compareTo(version) > 0;
    }
    toString() {
        return `v${this.major}.${this.minor}`;
    }
    equals(other) {
        return this.major === other.major && this.minor === other.minor;
    }
}
exports.FeatureVersion = FeatureVersion;
FeatureVersion.VERSION_RE = /^v(\d+)\.(\d+)$/;
class FeatureUrl {
    constructor(identity, name, version, element) {
        this.identity = identity;
        this.name = name;
        this.version = version;
        this.element = element;
    }
    static maybeParse(input, node) {
        try {
            return FeatureUrl.parse(input, node);
        }
        catch (err) {
            return undefined;
        }
    }
    static parse(input, node) {
        const url = new url_1.URL(input);
        if (!url.pathname || url.pathname === '/') {
            throw error_1.ERRORS.INVALID_LINK_IDENTIFIER.err(`Missing path in feature url '${url}'`, { nodes: node });
        }
        const path = url.pathname.split('/');
        const verStr = path.pop();
        if (!verStr) {
            throw error_1.ERRORS.INVALID_LINK_IDENTIFIER.err(`Missing version component in feature url '${url}'`, { nodes: node });
        }
        const version = FeatureVersion.parse(verStr);
        const name = path[path.length - 1];
        if (!name) {
            throw error_1.ERRORS.INVALID_LINK_IDENTIFIER.err(`Missing feature name component in feature url '${url}'`, { nodes: node });
        }
        const element = url.hash ? url.hash.slice(1) : undefined;
        url.hash = '';
        url.search = '';
        url.password = '';
        url.username = '';
        url.pathname = path.join('/');
        return new FeatureUrl(url.toString(), name, version, element);
    }
    static decode(node) {
        return this.parse(node.value, node);
    }
    satisfies(requested) {
        return requested.identity === this.identity &&
            this.version.satisfies(requested.version);
    }
    equals(other) {
        return this.identity === other.identity &&
            this.version.equals(other.version);
    }
    get url() {
        return this.element ?
            `${this.identity}/${this.version}#${this.element}`
            : `${this.identity}/${this.version}`;
    }
    get isDirective() {
        var _a;
        return (_a = this.element) === null || _a === void 0 ? void 0 : _a.startsWith('@');
    }
    get elementName() {
        var _a;
        return this.isDirective ? (_a = this.element) === null || _a === void 0 ? void 0 : _a.slice(1) : this.element;
    }
    get base() {
        if (!this.element)
            return this;
        return new FeatureUrl(this.identity, this.name, this.version);
    }
    toString() {
        return this.url;
    }
}
exports.FeatureUrl = FeatureUrl;
function findCoreSpecVersion(featureUrl) {
    return featureUrl.name === 'core'
        ? exports.CORE_VERSIONS.find(featureUrl.version)
        : (featureUrl.name === exports.linkDirectiveDefaultName ? exports.LINK_VERSIONS.find(featureUrl.version) : undefined);
}
exports.findCoreSpecVersion = findCoreSpecVersion;
exports.CORE_VERSIONS = new FeatureDefinitions(exports.coreIdentity)
    .add(new CoreSpecDefinition(new FeatureVersion(0, 1), undefined, exports.coreIdentity, 'core'))
    .add(new CoreSpecDefinition(new FeatureVersion(0, 2), new FeatureVersion(2, 0), exports.coreIdentity, 'core'));
exports.LINK_VERSIONS = new FeatureDefinitions(exports.linkIdentity)
    .add(new CoreSpecDefinition(new FeatureVersion(1, 0), new FeatureVersion(2, 0)));
(0, knownCoreFeatures_1.registerKnownFeature)(exports.CORE_VERSIONS);
(0, knownCoreFeatures_1.registerKnownFeature)(exports.LINK_VERSIONS);
function removeAllCoreFeatures(schema) {
    var _a, _b;
    const coreFeatures = [...((_b = (_a = schema.coreFeatures) === null || _a === void 0 ? void 0 : _a.allFeatures()) !== null && _b !== void 0 ? _b : [])];
    const typeReferences = [];
    for (const feature of coreFeatures) {
        const featureDirectiveDefs = schema.directives()
            .filter(d => feature.isFeatureDefinition(d));
        featureDirectiveDefs.forEach(def => def.remove().forEach(application => application.remove()));
        const featureTypes = schema.types()
            .filter(t => feature.isFeatureDefinition(t));
        featureTypes.forEach(type => {
            const references = type.remove();
            if (references.length > 0) {
                typeReferences.push({
                    feature,
                    type,
                    references,
                });
            }
        });
    }
    const errors = [];
    for (const { feature, type, references } of typeReferences) {
        const referencesInSchema = references.filter(r => r.isAttached());
        if (referencesInSchema.length > 0) {
            errors.push(error_1.ERRORS.REFERENCED_INACCESSIBLE.err(`Cannot remove elements of feature ${feature} as feature type ${type}` +
                ` is referenced by elements: ${referencesInSchema.join(', ')}`, { nodes: (0, definitions_1.sourceASTs)(...references) }));
        }
    }
    if (errors.length > 0) {
        throw (0, definitions_1.ErrGraphQLAPISchemaValidationFailed)(errors);
    }
}
exports.removeAllCoreFeatures = removeAllCoreFeatures;
//# sourceMappingURL=coreSpec.js.map