UNPKG

@apollo/federation-internals

Version:
1,248 lines 109 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CoreFeature = exports.defaultSchemaBlueprint = exports.SchemaBlueprint = exports.NamedSchemaElementWithType = exports.NamedSchemaElement = exports.SchemaElement = exports.Extension = exports.sourceASTs = exports.DirectiveTargetElement = exports.isLeafType = exports.typeFromAST = exports.typeToAST = exports.isTypeSystemDirectiveLocation = exports.typeSystemDirectiveLocations = exports.isExecutableDirectiveLocation = exports.executableDirectiveLocations = exports.isConditionalDirective = exports.supertypes = exports.runtimeTypesIntersects = exports.possibleRuntimeTypes = exports.isCompositeType = exports.isAbstractType = exports.isNullableType = exports.baseType = exports.filterTypesOfKind = exports.isTypeOfKind = exports.isInputType = exports.isOutputType = exports.isInputObjectType = exports.isUnionType = exports.isEnumType = exports.isInterfaceType = exports.isObjectType = exports.isIDType = exports.isBooleanType = exports.isFloatType = exports.isStringType = exports.isIntType = exports.isCustomScalarType = exports.isScalarType = exports.isNonNullType = exports.isListType = exports.isWrapperType = exports.isNamedType = exports.isSchemaRootType = exports.defaultRootName = exports.allSchemaRootKinds = exports.typenameFieldName = exports.ErrGraphQLAPISchemaValidationFailed = exports.ErrGraphQLValidationFailed = void 0; exports.isFieldDefinition = exports.copyDirectiveDefinitionToSchema = exports.newNamedType = exports.variableDefinitionFromAST = exports.variableDefinitionsFromAST = exports.VariableDefinitions = exports.VariableDefinition = exports.isVariable = exports.VariableCollector = exports.Variable = exports.directiveApplicationsSubstraction = exports.isDirectiveApplicationsSubset = exports.sameDirectiveApplications = exports.sameDirectiveApplication = exports.directivesToDirectiveNodes = exports.directivesToString = exports.Directive = exports.DirectiveDefinition = exports.EnumValue = exports.ArgumentDefinition = exports.InputFieldDefinition = exports.FieldDefinition = exports.NonNullType = exports.ListType = exports.InputObjectType = exports.EnumType = exports.UnionType = exports.UnionMember = exports.InterfaceType = exports.ObjectType = exports.InterfaceImplementation = exports.ScalarType = exports.SchemaDefinition = exports.RootType = exports.Schema = exports.CoreFeatures = void 0; const graphql_1 = require("graphql"); const coreSpec_1 = require("./specs/coreSpec"); const utils_1 = require("./utils"); const values_1 = require("./values"); const inaccessibleSpec_1 = require("./specs/inaccessibleSpec"); const print_1 = require("./print"); const types_1 = require("./types"); const introspection_1 = require("./introspection"); const validate_1 = require("graphql/validation/validate"); const specifiedRules_1 = require("graphql/validation/specifiedRules"); const validate_2 = require("./validate"); const directiveAndTypeSpecification_1 = require("./directiveAndTypeSpecification"); const suggestions_1 = require("./suggestions"); const error_1 = require("./error"); const knownCoreFeatures_1 = require("./knownCoreFeatures"); const validationErrorCode = 'GraphQLValidationFailed'; const DEFAULT_VALIDATION_ERROR_MESSAGE = 'The schema is not a valid GraphQL schema.'; const EMPTY_SET = new Set(); const ErrGraphQLValidationFailed = (causes, message = DEFAULT_VALIDATION_ERROR_MESSAGE) => (0, error_1.aggregateError)(validationErrorCode, message, causes); exports.ErrGraphQLValidationFailed = ErrGraphQLValidationFailed; const apiSchemaValidationErrorCode = 'GraphQLAPISchemaValidationFailed'; const ErrGraphQLAPISchemaValidationFailed = (causes) => (0, error_1.aggregateError)(apiSchemaValidationErrorCode, 'The supergraph schema failed to produce a valid API schema', causes); exports.ErrGraphQLAPISchemaValidationFailed = ErrGraphQLAPISchemaValidationFailed; exports.typenameFieldName = '__typename'; exports.allSchemaRootKinds = ['query', 'mutation', 'subscription']; function defaultRootName(rootKind) { return rootKind.charAt(0).toUpperCase() + rootKind.slice(1); } exports.defaultRootName = defaultRootName; function checkDefaultSchemaRoot(type) { if (type.kind !== 'ObjectType') { return undefined; } switch (type.name) { case 'Query': return 'query'; case 'Mutation': return 'mutation'; case 'Subscription': return 'subscription'; default: return undefined; } } function isSchemaRootType(type) { return isObjectType(type) && type.isRootType(); } exports.isSchemaRootType = isSchemaRootType; function isNamedType(type) { return type instanceof BaseNamedType; } exports.isNamedType = isNamedType; function isWrapperType(type) { return isListType(type) || isNonNullType(type); } exports.isWrapperType = isWrapperType; function isListType(type) { return type.kind == 'ListType'; } exports.isListType = isListType; function isNonNullType(type) { return type.kind == 'NonNullType'; } exports.isNonNullType = isNonNullType; function isScalarType(type) { return type.kind == 'ScalarType'; } exports.isScalarType = isScalarType; function isCustomScalarType(type) { return isScalarType(type) && !graphQLBuiltInTypes.includes(type.name); } exports.isCustomScalarType = isCustomScalarType; function isIntType(type) { return type === type.schema().intType(); } exports.isIntType = isIntType; function isStringType(type) { return type === type.schema().stringType(); } exports.isStringType = isStringType; function isFloatType(type) { return type === type.schema().floatType(); } exports.isFloatType = isFloatType; function isBooleanType(type) { return type === type.schema().booleanType(); } exports.isBooleanType = isBooleanType; function isIDType(type) { return type === type.schema().idType(); } exports.isIDType = isIDType; function isObjectType(type) { return type.kind == 'ObjectType'; } exports.isObjectType = isObjectType; function isInterfaceType(type) { return type.kind == 'InterfaceType'; } exports.isInterfaceType = isInterfaceType; function isEnumType(type) { return type.kind == 'EnumType'; } exports.isEnumType = isEnumType; function isUnionType(type) { return type.kind == 'UnionType'; } exports.isUnionType = isUnionType; function isInputObjectType(type) { return type.kind == 'InputObjectType'; } exports.isInputObjectType = isInputObjectType; function isOutputType(type) { switch (baseType(type).kind) { case 'ScalarType': case 'ObjectType': case 'UnionType': case 'EnumType': case 'InterfaceType': return true; default: return false; } } exports.isOutputType = isOutputType; function isInputType(type) { switch (baseType(type).kind) { case 'ScalarType': case 'EnumType': case 'InputObjectType': return true; default: return false; } } exports.isInputType = isInputType; function isTypeOfKind(type, kind) { return type.kind === kind; } exports.isTypeOfKind = isTypeOfKind; function filterTypesOfKind(types, kind) { return types.reduce((acc, type) => { if (isTypeOfKind(type, kind)) { acc.push(type); } return acc; }, []); } exports.filterTypesOfKind = filterTypesOfKind; function baseType(type) { return isWrapperType(type) ? type.baseType() : type; } exports.baseType = baseType; function isNullableType(type) { return !isNonNullType(type); } exports.isNullableType = isNullableType; function isAbstractType(type) { return isInterfaceType(type) || isUnionType(type); } exports.isAbstractType = isAbstractType; function isCompositeType(type) { return isObjectType(type) || isInterfaceType(type) || isUnionType(type); } exports.isCompositeType = isCompositeType; function possibleRuntimeTypes(type) { switch (type.kind) { case 'InterfaceType': return type.possibleRuntimeTypes(); case 'UnionType': return type.types(); case 'ObjectType': return [type]; } } exports.possibleRuntimeTypes = possibleRuntimeTypes; function runtimeTypesIntersects(t1, t2) { if (t1 === t2) { return true; } const rt1 = possibleRuntimeTypes(t1); const rt2 = possibleRuntimeTypes(t2); for (const obj1 of rt1) { if (rt2.some(obj2 => obj1.name === obj2.name)) { return true; } } return false; } exports.runtimeTypesIntersects = runtimeTypesIntersects; function supertypes(type) { switch (type.kind) { case 'InterfaceType': return type.interfaces(); case 'UnionType': return []; case 'ObjectType': return type.interfaces().concat(type.unionsWhereMember()); } } exports.supertypes = supertypes; function isConditionalDirective(directive) { return ['include', 'skip'].includes(directive.name); } exports.isConditionalDirective = isConditionalDirective; exports.executableDirectiveLocations = [ graphql_1.DirectiveLocation.QUERY, graphql_1.DirectiveLocation.MUTATION, graphql_1.DirectiveLocation.SUBSCRIPTION, graphql_1.DirectiveLocation.FIELD, graphql_1.DirectiveLocation.FRAGMENT_DEFINITION, graphql_1.DirectiveLocation.FRAGMENT_SPREAD, graphql_1.DirectiveLocation.INLINE_FRAGMENT, graphql_1.DirectiveLocation.VARIABLE_DEFINITION, ]; const executableDirectiveLocationsSet = new Set(exports.executableDirectiveLocations); function isExecutableDirectiveLocation(loc) { return executableDirectiveLocationsSet.has(loc); } exports.isExecutableDirectiveLocation = isExecutableDirectiveLocation; exports.typeSystemDirectiveLocations = [ graphql_1.DirectiveLocation.SCHEMA, graphql_1.DirectiveLocation.SCALAR, graphql_1.DirectiveLocation.OBJECT, graphql_1.DirectiveLocation.FIELD_DEFINITION, graphql_1.DirectiveLocation.ARGUMENT_DEFINITION, graphql_1.DirectiveLocation.INTERFACE, graphql_1.DirectiveLocation.UNION, graphql_1.DirectiveLocation.ENUM, graphql_1.DirectiveLocation.ENUM_VALUE, graphql_1.DirectiveLocation.INPUT_OBJECT, graphql_1.DirectiveLocation.INPUT_FIELD_DEFINITION, ]; const typeSystemDirectiveLocationsSet = new Set(exports.typeSystemDirectiveLocations); function isTypeSystemDirectiveLocation(loc) { return typeSystemDirectiveLocationsSet.has(loc); } exports.isTypeSystemDirectiveLocation = isTypeSystemDirectiveLocation; function typeToAST(type) { switch (type.kind) { case 'ListType': return { kind: graphql_1.Kind.LIST_TYPE, type: typeToAST(type.ofType) }; case 'NonNullType': return { kind: graphql_1.Kind.NON_NULL_TYPE, type: typeToAST(type.ofType) }; default: return { kind: graphql_1.Kind.NAMED_TYPE, name: { kind: graphql_1.Kind.NAME, value: type.name } }; } } exports.typeToAST = typeToAST; function typeFromAST(schema, node) { switch (node.kind) { case graphql_1.Kind.LIST_TYPE: return new ListType(typeFromAST(schema, node.type)); case graphql_1.Kind.NON_NULL_TYPE: return new NonNullType(typeFromAST(schema, node.type)); default: const type = schema.type(node.name.value); if (!type) { throw error_1.ERRORS.INVALID_GRAPHQL.err(`Unknown type "${node.name.value}"`, { nodes: node }); } return type; } } exports.typeFromAST = typeFromAST; function isLeafType(type) { return isScalarType(type) || isEnumType(type); } exports.isLeafType = isLeafType; class DirectiveTargetElement { constructor(_schema, directives = []) { this._schema = _schema; this.appliedDirectives = directives.map((d) => this.attachDirective(d)); } schema() { return this._schema; } attachDirective(directive) { const toAdd = directive.isAttached() ? new Directive(directive.name, directive.arguments()) : directive; Element.prototype['setParent'].call(toAdd, this); return toAdd; } appliedDirectivesOf(nameOrDefinition) { const directiveName = typeof nameOrDefinition === 'string' ? nameOrDefinition : nameOrDefinition.name; return this.appliedDirectives.filter(d => d.name == directiveName); } hasAppliedDirective(nameOrDefinition) { const directiveName = typeof nameOrDefinition === 'string' ? nameOrDefinition : nameOrDefinition.name; return this.appliedDirectives.some(d => d.name == directiveName); } appliedDirectivesToDirectiveNodes() { return directivesToDirectiveNodes(this.appliedDirectives); } appliedDirectivesToString() { return directivesToString(this.appliedDirectives); } collectVariablesInAppliedDirectives(collector) { for (const applied of this.appliedDirectives) { collector.collectInArguments(applied.arguments()); } } } exports.DirectiveTargetElement = DirectiveTargetElement; function sourceASTs(...elts) { return elts.map(elt => elt === null || elt === void 0 ? void 0 : elt.sourceAST).filter((elt) => elt !== undefined); } exports.sourceASTs = sourceASTs; class Element { schema() { const schema = this.schemaInternal(); (0, utils_1.assert)(schema, 'requested schema does not exist. Probably because the element is unattached'); return schema; } schemaInternal() { if (!this._parent) { return undefined; } else if (this._parent instanceof Schema) { return this._parent; } else if (this._parent instanceof SchemaElement) { return this._parent.schemaInternal(); } else if (this._parent instanceof DirectiveTargetElement) { return this._parent.schema(); } (0, utils_1.assert)(false, 'unreachable code. parent is of unknown type'); } get parent() { (0, utils_1.assert)(this._parent, 'trying to access non-existent parent'); return this._parent; } isAttached() { return !!this._parent; } setParent(parent) { (0, utils_1.assert)(!this._parent, "Cannot set parent of an already attached element"); this._parent = parent; this.onAttached(); } onAttached() { } checkUpdate() { (0, utils_1.assert)(this.isAttached(), () => `Cannot modify detached element ${this}`); } } class Extension { get extendedElement() { return this._extendedElement; } setExtendedElement(element) { (0, utils_1.assert)(!this._extendedElement, "Cannot attached already attached extension"); this._extendedElement = element; } } exports.Extension = Extension; class SchemaElement extends Element { addUnappliedDirective({ nameOrDef, args, extension, directive }) { const toAdd = { nameOrDef, args: args !== null && args !== void 0 ? args : {}, extension, directive, }; if (this._unappliedDirectives) { this._unappliedDirectives.push(toAdd); } else { this._unappliedDirectives = [toAdd]; } } processUnappliedDirectives() { var _a; for (const { nameOrDef, args, extension, directive } of (_a = this._unappliedDirectives) !== null && _a !== void 0 ? _a : []) { const d = this.applyDirective(nameOrDef, args); d.setOfExtension(extension); d.sourceAST = directive; } this._unappliedDirectives = undefined; } get appliedDirectives() { var _a; return (_a = this._appliedDirectives) !== null && _a !== void 0 ? _a : []; } appliedDirectivesOf(nameOrDefinition) { const directiveName = typeof nameOrDefinition === 'string' ? nameOrDefinition : nameOrDefinition.name; return this.appliedDirectives.filter(d => d.name == directiveName); } hasAppliedDirective(nameOrDefinition) { return (typeof nameOrDefinition === 'string' ? this.appliedDirectivesOf(nameOrDefinition) : this.appliedDirectivesOf(nameOrDefinition)).length !== 0; } applyDirective(nameOrDef, args, asFirstDirective = false) { var _a; let toAdd; if (typeof nameOrDef === 'string') { this.checkUpdate(); toAdd = new Directive(nameOrDef, args !== null && args !== void 0 ? args : Object.create(null)); const def = (_a = this.schema().directive(nameOrDef)) !== null && _a !== void 0 ? _a : this.schema().blueprint.onMissingDirectiveDefinition(this.schema(), toAdd); if (!def) { throw this.schema().blueprint.onGraphQLJSValidationError(this.schema(), error_1.ERRORS.INVALID_GRAPHQL.err(`Unknown directive "@${nameOrDef}".`)); } if (Array.isArray(def)) { throw (0, exports.ErrGraphQLValidationFailed)(def); } } else { this.checkUpdate(nameOrDef); toAdd = new Directive(nameOrDef.name, args !== null && args !== void 0 ? args : Object.create(null)); } Element.prototype['setParent'].call(toAdd, this); if (this._appliedDirectives) { if (asFirstDirective) { this._appliedDirectives.unshift(toAdd); } else { this._appliedDirectives.push(toAdd); } } else { this._appliedDirectives = [toAdd]; } DirectiveDefinition.prototype['addReferencer'].call(toAdd.definition, toAdd); this.onModification(); return toAdd; } removeAppliedDirectives() { if (!this._appliedDirectives) { return; } const applied = this._appliedDirectives.concat(); applied.forEach(d => d.remove()); } onModification() { const schema = this.schemaInternal(); if (schema) { Schema.prototype['onModification'].call(schema); } } isElementBuiltIn() { return false; } removeTypeReferenceInternal(type) { this.removeTypeReference(type); } checkRemoval() { (0, utils_1.assert)(!this.isElementBuiltIn() || Schema.prototype['canModifyBuiltIn'].call(this.schema()), () => `Cannot modify built-in ${this}`); } checkUpdate(addedElement) { super.checkUpdate(); if (!Schema.prototype['canModifyBuiltIn'].call(this.schema())) { let thisElement = this; while (thisElement && thisElement instanceof SchemaElement) { (0, utils_1.assert)(!thisElement.isElementBuiltIn(), () => `Cannot modify built-in (or part of built-in) ${this}`); thisElement = thisElement.parent; } } if (addedElement && addedElement.isAttached()) { const thatSchema = addedElement.schema(); (0, utils_1.assert)(!thatSchema || thatSchema === this.schema(), () => `Cannot add element ${addedElement} to ${this} as it is attached to another schema`); } } } exports.SchemaElement = SchemaElement; class NamedSchemaElement extends SchemaElement { constructor(name) { super(); this._name = name; } get name() { return this._name; } } exports.NamedSchemaElement = NamedSchemaElement; class BaseNamedType extends NamedSchemaElement { constructor(name, isBuiltIn = false) { super(name); this.isBuiltIn = isBuiltIn; this.preserveEmptyDefinition = false; } addReferencer(referencer) { var _a; (_a = this._referencers) !== null && _a !== void 0 ? _a : (this._referencers = new Set()); this._referencers.add(referencer); } removeReferencer(referencer) { var _a; (_a = this._referencers) === null || _a === void 0 ? void 0 : _a.delete(referencer); } get coordinate() { return this.name; } *allChildElements() { } extensions() { var _a; return (_a = this._extensions) !== null && _a !== void 0 ? _a : []; } hasExtension(extension) { var _a, _b; return (_b = (_a = this._extensions) === null || _a === void 0 ? void 0 : _a.includes(extension)) !== null && _b !== void 0 ? _b : false; } newExtension() { return this.addExtension(new Extension()); } addExtension(extension) { this.checkUpdate(); if (this.hasExtension(extension)) { return extension; } (0, utils_1.assert)(!extension.extendedElement, () => `Cannot add extension to type ${this}: it is already added to another type`); if (this._extensions) { this._extensions.push(extension); } else { this._extensions = [extension]; } Extension.prototype['setExtendedElement'].call(extension, this); this.onModification(); return extension; } removeExtensions() { if (!this._extensions) { return; } this._extensions = undefined; for (const directive of this.appliedDirectives) { directive.removeOfExtension(); } this.removeInnerElementsExtensions(); } isIntrospectionType() { return (0, introspection_1.isIntrospectionName)(this.name); } hasExtensionElements() { return !!this._extensions; } hasNonExtensionElements() { return this.preserveEmptyDefinition || this.appliedDirectives.some(d => d.ofExtension() === undefined) || this.hasNonExtensionInnerElements(); } isElementBuiltIn() { return this.isBuiltIn; } rename(newName) { this.checkUpdate(); const oldName = this._name; this._name = newName; Schema.prototype['renameTypeInternal'].call(this._parent, oldName, newName); this.onModification(); } remove() { var _a; if (!this._parent) { return []; } this.checkRemoval(); this.onModification(); this.sourceAST = undefined; this.removeAppliedDirectives(); this.removeInnerElements(); const toReturn = []; (_a = this._referencers) === null || _a === void 0 ? void 0 : _a.forEach(r => { SchemaElement.prototype['removeTypeReferenceInternal'].call(r, this); toReturn.push(r); }); this._referencers = undefined; Schema.prototype['removeTypeInternal'].call(this._parent, this); this._parent = undefined; return toReturn; } removeRecursive() { this.remove().forEach(ref => this.removeReferenceRecursive(ref)); } referencers() { var _a; return (_a = this._referencers) !== null && _a !== void 0 ? _a : EMPTY_SET; } isReferenced() { return !!this._referencers; } toString() { return this.name; } } class NamedSchemaElementWithType extends NamedSchemaElement { get type() { return this._type; } set type(type) { if (type) { this.checkUpdate(type); } else { this.checkRemoval(); } if (this._type) { removeReferenceToType(this, this._type); } this._type = type; if (type) { addReferenceToType(this, type); } } removeTypeReference(type) { (0, utils_1.assert)(this._type && baseType(this._type) === type, () => `Cannot remove reference to type ${type} on ${this} as its type is ${this._type}`); this._type = undefined; } } exports.NamedSchemaElementWithType = NamedSchemaElementWithType; class BaseExtensionMember extends Element { ofExtension() { return this._extension; } removeOfExtension() { this._extension = undefined; } setOfExtension(extension) { var _a; this.checkUpdate(); (0, utils_1.assert)(!extension || ((_a = this._parent) === null || _a === void 0 ? void 0 : _a.hasExtension(extension)), () => `Cannot set object as part of the provided extension: it is not an extension of parent ${this.parent}`); this._extension = extension; } remove() { this.removeInner(); Schema.prototype['onModification'].call(this.schema()); this._extension = undefined; this._parent = undefined; } } class SchemaBlueprint { onMissingDirectiveDefinition(_schema, _directive) { return undefined; } onDirectiveDefinitionAndSchemaParsed(_) { return []; } ignoreParsedField(_type, _fieldName) { return false; } onConstructed(_) { } onAddedCoreFeature(_schema, _feature) { } onInvalidation(_) { } onValidation(_schema) { return []; } validationRules() { return specifiedRules_1.specifiedSDLRules; } onGraphQLJSValidationError(schema, error) { var _a; const matcher = /^Unknown directive "@(?<directive>[_A-Za-z][_0-9A-Za-z]*)"\.$/.exec(error.message); const name = (_a = matcher === null || matcher === void 0 ? void 0 : matcher.groups) === null || _a === void 0 ? void 0 : _a.directive; if (!name) { return error; } const allDefinedDirectiveNames = schema.allDirectives().map((d) => d.name); const suggestions = (0, suggestions_1.suggestionList)(name, allDefinedDirectiveNames); if (suggestions.length === 0) { return this.onUnknownDirectiveValidationError(schema, name, error); } else { return (0, error_1.withModifiedErrorMessage)(error, `${error.message}${(0, suggestions_1.didYouMean)(suggestions.map((s) => '@' + s))}`); } } onUnknownDirectiveValidationError(_schema, _unknownDirectiveName, error) { return error; } applyDirectivesAfterParsing() { return false; } } exports.SchemaBlueprint = SchemaBlueprint; exports.defaultSchemaBlueprint = new SchemaBlueprint(); class CoreFeature { constructor(url, nameInSchema, directive, imports, purpose) { this.url = url; this.nameInSchema = nameInSchema; this.directive = directive; this.imports = imports; this.purpose = purpose; } isFeatureDefinition(element) { const importName = element.kind === 'DirectiveDefinition' ? '@' + element.name : element.name; return element.name.startsWith(this.nameInSchema + '__') || (element.kind === 'DirectiveDefinition' && element.name === this.nameInSchema) || !!this.imports.find((i) => { var _a; return importName === ((_a = i.as) !== null && _a !== void 0 ? _a : i.name); }); } directiveNameInSchema(name) { return CoreFeature.directiveNameInSchemaForCoreArguments(this.url, this.nameInSchema, this.imports, name); } static directiveNameInSchemaForCoreArguments(specUrl, specNameInSchema, imports, directiveNameInSpec) { var _a, _b; const elementImport = imports.find((i) => i.name.charAt(0) === '@' && i.name.slice(1) === directiveNameInSpec); return elementImport ? ((_b = (_a = elementImport.as) === null || _a === void 0 ? void 0 : _a.slice(1)) !== null && _b !== void 0 ? _b : directiveNameInSpec) : (directiveNameInSpec === specUrl.name ? specNameInSchema : specNameInSchema + '__' + directiveNameInSpec); } typeNameInSchema(name) { var _a; const elementImport = this.imports.find((i) => i.name === name); return elementImport ? ((_a = elementImport.as) !== null && _a !== void 0 ? _a : name) : this.nameInSchema + '__' + name; } minimumFederationVersion() { var _a; return (_a = (0, knownCoreFeatures_1.coreFeatureDefinitionIfKnown)(this.url)) === null || _a === void 0 ? void 0 : _a.minimumFederationVersion; } } exports.CoreFeature = CoreFeature; class CoreFeatures { constructor(coreItself) { this.coreItself = coreItself; this.byAlias = new Map(); this.byIdentity = new Map(); this.add(coreItself); const coreDef = (0, coreSpec_1.findCoreSpecVersion)(coreItself.url); if (!coreDef) { throw error_1.ERRORS.UNKNOWN_LINK_VERSION.err(`Schema uses unknown version ${coreItself.url.version} of the ${coreItself.url.name} spec`); } this.coreDefinition = coreDef; } getByIdentity(identity) { return this.byIdentity.get(identity); } allFeatures() { return this.byIdentity.values(); } removeFeature(featureIdentity) { const feature = this.byIdentity.get(featureIdentity); if (feature) { this.byIdentity.delete(featureIdentity); this.byAlias.delete(feature.nameInSchema); } } maybeAddFeature(directive) { var _a, _b; if (((_a = directive.definition) === null || _a === void 0 ? void 0 : _a.name) !== this.coreItself.nameInSchema) { return undefined; } const typedDirective = directive; const args = typedDirective.arguments(); const url = this.coreDefinition.extractFeatureUrl(args); const existing = this.byIdentity.get(url.identity); if (existing) { throw error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Duplicate inclusion of feature ${url.identity}`); } const imports = (0, coreSpec_1.extractCoreFeatureImports)(url, typedDirective); const feature = new CoreFeature(url, (_b = args.as) !== null && _b !== void 0 ? _b : url.name, directive, imports, args.for); this.add(feature); directive.schema().blueprint.onAddedCoreFeature(directive.schema(), feature); return feature; } add(feature) { this.byAlias.set(feature.nameInSchema, feature); this.byIdentity.set(feature.url.identity, feature); } sourceFeature(element) { const isDirective = element instanceof DirectiveDefinition || element instanceof Directive; const splitted = element.name.split('__'); if (splitted.length > 1) { const feature = this.byAlias.get(splitted[0]); return feature ? { feature, nameInFeature: splitted.slice(1).join('__'), isImported: false, } : undefined; } else { const importName = isDirective ? '@' + element.name : element.name; const allFeatures = [this.coreItself, ...this.byIdentity.values()]; for (const feature of allFeatures) { for (const { as, name } of feature.imports) { if ((as !== null && as !== void 0 ? as : name) === importName) { return { feature, nameInFeature: isDirective ? name.slice(1) : name, isImported: true, }; } } } const directFeature = this.byAlias.get(element.name); if (directFeature && isDirective) { return { feature: directFeature, nameInFeature: element.name, isImported: false, }; } return undefined; } } } exports.CoreFeatures = CoreFeatures; const graphQLBuiltInTypes = ['Int', 'Float', 'String', 'Boolean', 'ID']; const graphQLBuiltInTypesSpecifications = graphQLBuiltInTypes.map((name) => (0, directiveAndTypeSpecification_1.createScalarTypeSpecification)({ name })); const graphQLBuiltInDirectivesSpecifications = [ (0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ name: 'include', locations: [graphql_1.DirectiveLocation.FIELD, graphql_1.DirectiveLocation.FRAGMENT_SPREAD, graphql_1.DirectiveLocation.INLINE_FRAGMENT], args: [{ name: 'if', type: (schema) => new NonNullType(schema.booleanType()) }], }), (0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ name: 'skip', locations: [graphql_1.DirectiveLocation.FIELD, graphql_1.DirectiveLocation.FRAGMENT_SPREAD, graphql_1.DirectiveLocation.INLINE_FRAGMENT], args: [{ name: 'if', type: (schema) => new NonNullType(schema.booleanType()) }], }), (0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ name: 'deprecated', locations: [graphql_1.DirectiveLocation.FIELD_DEFINITION, graphql_1.DirectiveLocation.ENUM_VALUE, graphql_1.DirectiveLocation.ARGUMENT_DEFINITION, graphql_1.DirectiveLocation.INPUT_FIELD_DEFINITION], args: [{ name: 'reason', type: (schema) => schema.stringType(), defaultValue: 'No longer supported' }], }), (0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ name: 'specifiedBy', locations: [graphql_1.DirectiveLocation.SCALAR], args: [{ name: 'url', type: (schema) => new NonNullType(schema.stringType()) }], }), (0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ name: 'defer', locations: [graphql_1.DirectiveLocation.FRAGMENT_SPREAD, graphql_1.DirectiveLocation.INLINE_FRAGMENT], args: [ { name: 'label', type: (schema) => schema.stringType() }, { name: 'if', type: (schema) => new NonNullType(schema.booleanType()), defaultValue: true }, ], }), (0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ name: 'stream', locations: [graphql_1.DirectiveLocation.FIELD], args: [ { name: 'label', type: (schema) => schema.stringType() }, { name: 'initialCount', type: (schema) => schema.intType(), defaultValue: 0 }, { name: 'if', type: (schema) => new NonNullType(schema.booleanType()), defaultValue: true }, ], }), ]; const coordinateRegexp = /^@?[_A-Za-z][_0-9A-Za-z]*(\.[_A-Za-z][_0-9A-Za-z]*)?(\([_A-Za-z][_0-9A-Za-z]*:\))?$/; class Schema { constructor(blueprint = exports.defaultSchemaBlueprint, config = {}) { this.blueprint = blueprint; this.config = config; this._builtInTypes = new utils_1.MapWithCachedArrays(); this._types = new utils_1.MapWithCachedArrays(); this._builtInDirectives = new utils_1.MapWithCachedArrays(); this._directives = new utils_1.MapWithCachedArrays(); this.isConstructed = false; this.isValidated = false; this._schemaDefinition = new SchemaDefinition(); Element.prototype['setParent'].call(this._schemaDefinition, this); graphQLBuiltInTypesSpecifications.forEach((spec) => spec.checkOrAdd(this, undefined, true)); graphQLBuiltInDirectivesSpecifications.forEach((spec) => spec.checkOrAdd(this, undefined, true)); blueprint.onConstructed(this); this.isConstructed = true; } canModifyBuiltIn() { return !this.isConstructed; } runWithBuiltInModificationAllowed(fct) { const wasConstructed = this.isConstructed; this.isConstructed = false; fct(); this.isConstructed = wasConstructed; } renameTypeInternal(oldName, newName) { this._types.set(newName, this._types.get(oldName)); this._types.delete(oldName); } removeTypeInternal(type) { this._types.delete(type.name); } removeDirectiveInternal(definition) { this._directives.delete(definition.name); } markAsCoreSchema(coreItself) { this._coreFeatures = new CoreFeatures(coreItself); } unmarkAsCoreSchema() { this._coreFeatures = undefined; } onModification() { if (this.isConstructed) { this.invalidate(); this.cachedDocument = undefined; this.apiSchema = undefined; } } isCoreSchema() { return this.coreFeatures !== undefined; } get coreFeatures() { return this._coreFeatures; } toAST() { var _a; if (!this.cachedDocument) { const ast = (0, graphql_1.parse)((0, print_1.printSchema)(this), { noLocation: true }); const shouldCache = (_a = this.config.cacheAST) !== null && _a !== void 0 ? _a : false; if (!shouldCache) { return ast; } this.cachedDocument = ast; } return this.cachedDocument; } toAPISchema() { if (!this.apiSchema) { this.validate(); const apiSchema = this.clone(undefined, false); for (const toRemoveIfCustom of ['defer', 'stream']) { const directive = apiSchema.directive(toRemoveIfCustom); if (directive && !directive.isBuiltIn) { directive.removeRecursive(); } } (0, inaccessibleSpec_1.removeInaccessibleElements)(apiSchema); (0, coreSpec_1.removeAllCoreFeatures)(apiSchema); (0, utils_1.assert)(!apiSchema.isCoreSchema(), "The API schema shouldn't be a core schema"); apiSchema.validate(); this.apiSchema = apiSchema; } return this.apiSchema; } emptyASTDefinitionsForExtensionsWithoutDefinition() { const nodes = []; if (this.schemaDefinition.hasExtensionElements() && !this.schemaDefinition.hasNonExtensionElements()) { const node = { kind: graphql_1.Kind.SCHEMA_DEFINITION, operationTypes: [] }; nodes.push(node); } for (const type of this.types()) { if (type.hasExtensionElements() && !type.hasNonExtensionElements()) { const node = { kind: type.astDefinitionKind, name: { kind: graphql_1.Kind.NAME, value: type.name }, }; nodes.push(node); } } return nodes; } toGraphQLJSSchema(config) { var _a, _b; const includeDefer = (_a = config === null || config === void 0 ? void 0 : config.includeDefer) !== null && _a !== void 0 ? _a : false; const includeStream = (_b = config === null || config === void 0 ? void 0 : config.includeStream) !== null && _b !== void 0 ? _b : false; let ast = this.toAST(); const additionalNodes = this.emptyASTDefinitionsForExtensionsWithoutDefinition(); if (includeDefer) { additionalNodes.push(this.deferDirective().toAST()); } if (includeStream) { additionalNodes.push(this.streamDirective().toAST()); } if (additionalNodes.length > 0) { ast = { kind: graphql_1.Kind.DOCUMENT, definitions: ast.definitions.concat(additionalNodes), }; } const graphQLSchema = (0, graphql_1.buildASTSchema)(ast); if (additionalNodes.length > 0) { for (const node of additionalNodes) { switch (node.kind) { case graphql_1.Kind.SCHEMA_DEFINITION: graphQLSchema.astNode = undefined; break; case graphql_1.Kind.SCALAR_TYPE_DEFINITION: case graphql_1.Kind.OBJECT_TYPE_DEFINITION: case graphql_1.Kind.INTERFACE_TYPE_DEFINITION: case graphql_1.Kind.ENUM_TYPE_DEFINITION: case graphql_1.Kind.UNION_TYPE_DEFINITION: case graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION: const type = graphQLSchema.getType(node.name.value); if (type) { type.astNode = undefined; } } } } return graphQLSchema; } get schemaDefinition() { return this._schemaDefinition; } types() { return this._types.values(); } interfaceTypes() { return filterTypesOfKind(this.types(), 'InterfaceType'); } objectTypes() { return filterTypesOfKind(this.types(), 'ObjectType'); } unionTypes() { return filterTypesOfKind(this.types(), 'UnionType'); } scalarTypes() { return filterTypesOfKind(this.types(), 'ScalarType'); } inputTypes() { return filterTypesOfKind(this.types(), 'InputObjectType'); } enumTypes() { return filterTypesOfKind(this.types(), 'EnumType'); } builtInTypes(includeShadowed = false) { const allBuiltIns = this._builtInTypes.values(); return includeShadowed ? allBuiltIns : allBuiltIns.filter(t => !this.isShadowedBuiltInType(t)); } isShadowedBuiltInType(type) { return type.isBuiltIn && this._types.has(type.name); } allTypes() { return this.builtInTypes().concat(this.types()); } type(name) { const type = this._types.get(name); return type ? type : this._builtInTypes.get(name); } typeOfKind(name, kind) { const type = this.type(name); return type && type.kind === kind ? type : undefined; } intType() { return this._builtInTypes.get('Int'); } floatType() { return this._builtInTypes.get('Float'); } stringType() { return this._builtInTypes.get('String'); } booleanType() { return this._builtInTypes.get('Boolean'); } idType() { return this._builtInTypes.get('ID'); } builtInScalarTypes() { return [ this.intType(), this.floatType(), this.stringType(), this.booleanType(), this.idType(), ]; } addType(type) { const existing = this.type(type.name); if (existing) { (0, utils_1.assert)(existing.isBuiltIn, () => `Type ${type} already exists in this schema`); } if (type.isAttached()) { (0, utils_1.assert)(type.parent == this, () => `Cannot add type ${type} to this schema; it is already attached to another schema`); return type; } if (type.isBuiltIn) { (0, utils_1.assert)(!this.isConstructed, `Cannot add built-in ${type} to this schema (built-ins can only be added at schema construction time)`); this._builtInTypes.set(type.name, type); } else { this._types.set(type.name, type); } Element.prototype['setParent'].call(type, this); const defaultSchemaRoot = checkDefaultSchemaRoot(type); if (defaultSchemaRoot && !this.schemaDefinition.root(defaultSchemaRoot)) { this.schemaDefinition.setRoot(defaultSchemaRoot, type); } this.onModification(); return type; } directives() { return this._directives.values(); } builtInDirectives(includeShadowed = false) { return includeShadowed ? this._builtInDirectives.values() : this._builtInDirectives.values().filter(d => !this.isShadowedBuiltInDirective(d)); } allDirectives() { return this.builtInDirectives().concat(this.directives()); } isShadowedBuiltInDirective(directive) { return directive.isBuiltIn && this._directives.has(directive.name); } directive(name) { const directive = this._directives.get(name); return directive ? directive : this.builtInDirective(name); } builtInDirective(name) { return this._builtInDirectives.get(name); } *allNamedSchemaElement() { for (const type of this.types()) { yield type; yield* type.allChildElements(); } for (const directive of this.directives()) { yield directive; yield* directive.arguments(); } } *allSchemaElement() { yield this._schemaDefinition; yield* this.allNamedSchemaElement(); } addDirectiveDefinition(directiveOrName) { const definition = typeof directiveOrName === 'string' ? new DirectiveDefinition(directiveOrName) : directiveOrName; const existing = this.directive(definition.name); (0, utils_1.assert)(!existing || existing.isBuiltIn, () => `Directive ${definition} already exists in this schema`); if (definition.isAttached()) { (0, utils_1.assert)(definition.parent == this, () => `Cannot add directive ${definition} to this schema; it is already attached to another schema`); return definition; } if (definition.isBuiltIn) { (0, utils_1.assert)(!this.isConstructed, () => `Cannot add built-in ${definition} to this schema (built-ins can only be added at schema construction time)`); this._builtInDirectives.set(definition.name, definition); } else { this._directives.set(definition.name, definition); } Element.prototype['setParent'].call(definition, this); this.onModification(); return definition; } invalidate() { if (this.isValidated) { this.blueprint.onInvalidation(this); } this.isValidated = false; } assumeValid() { this.runWithBuiltInModificationAllowed(() => { (0, introspection_1.addIntrospectionFields)(this); }); this.isValidated = true; } validate() { if (this.isValidated) { return; } this.runWithBuiltInModificationAllowed(() => { (0, introspection_1.addIntrospectionFields)(this); }); let errors = (0, validate_1.validateSDL)(this.toAST(), undefined, this.blueprint.validationRules()).map((e) => this.blueprint.onGraphQLJSValidationError(this, e)); errors = errors.concat((0, validate_2.validateSchema)(this)); if (errors.length === 0) { this.runWithBuiltInModificationAllowed(() => { errors = this.blueprint.onValidation(this); }); } if (errors.length > 0) { throw (0, exports.ErrGraphQLValidationFailed)(errors); } this.isValidated = true; } clone(builtIns, cloneJoinDirectives = true) { const cloned = new Schema(builtIns !== null && builtIns !== void 0 ? builtIns : this.blueprint); copy(this, cloned, cloneJoinDirectives); if (this.isValidated) { cloned.assumeValid(); } return cloned; } getBuiltInDirective(name) { const directive = this.directive(name); (0, utils_1.assert)(directive, `The provided schema has not be built with the ${name} directive built-in`); return directive; } includeDirective() { return this.getBuiltInDirective('include'); } skipDirective() { return this.getBuiltInDirective('skip'); } deprecatedDirective() { return this.getBuiltInDirective('deprecated'); } specifiedByDirective() { return this.getBuiltInDirective('specifiedBy'); } deferDirective() { return this.getBuiltInDirective('defer'); } streamDirective() { return this.getBuiltInDirective('stream'); } elementByCoordinate(coordinate) { if (!coordinate.match(coordinateRegexp)) { throw error_1.ERRORS.INVALID_GRAPHQL.err(`Invalid argument "${coordinate}: it is not a syntactically valid graphQL coordinate."`); } const argStartIdx = coordinate.indexOf('('); const start = argStartIdx < 0 ? coordinate : coordinate.slice(0, argStartIdx); const argName = argStartIdx < 0 ? undefined : coordinate.slice(argStartIdx + 1, coordinate.length - 2); const splittedStart = start.split('.'); const typeOrDirectiveName = splittedStart[0]; const fieldOrEnumName = splittedStart[1]; const isDirective = typeOrDirectiveName.startsWith('@'); if (isDirective) { if (fieldOrEnumName) { throw error_1.ERRORS.INVALID_GRAPHQL.err(`Invalid argument "${coordinate}: it is not a syntactically valid graphQL coordinate."`); } const directive = this.directive(typeOrDirectiveName.slice(1)); return argName ? directive === null || directive === void 0 ? void 0 : directive.argument(argName) : directive; } else { const type = this.type(typeOrDirectiveName); if (!type || !fieldOrEnumName) { return type; } switch (type.kind) { case 'ObjectType': case 'InterfaceType': const field = type.field(fieldOrEnumName); return argName ? field === null || field === void 0 ? void 0 : field.argument(argName) : field; case 'InputObjectType': if (argName) { throw error_1.ERRORS.INVALID_GRAPHQL.err(`Invalid argument "${coordinate}: it is not a syntactically valid graphQL coordinate."`); } return type.field(fieldOrEnumName); case 'EnumType': if (argName) { throw error_1.ERRORS.INVALID_GRAPHQL.err(`Invalid argument "${coordinate}: it is not a syntactically valid graphQL coordinate."`); } return type.value(fieldOrEnumName); default: throw error_1.ERRORS.INVALID_GRAPHQL.err(`Invalid argument "${coordinate}: it is not a syntactically valid graphQL coordinate."`); } } } } exports.Schema = Schema; class RootType extends BaseExtensionMember { constructor(rootKind, type) { super(); this.rootKind = ro