@apollo/federation-internals
Version:
Apollo Federation internal utilities
1,248 lines • 109 kB
JavaScript
"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