@theguild/federation-composition
Version:
Open Source Composition library for Apollo Federation
409 lines (408 loc) • 20.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isFederationVersion = isFederationVersion;
exports.createSpecSchema = createSpecSchema;
exports.getLatestFederationVersion = getLatestFederationVersion;
exports.isFederationLink = isFederationLink;
exports.detectFederationVersion = detectFederationVersion;
const graphql_1 = require("graphql");
const printer_js_1 = require("../graphql/printer.js");
const inaccessible_js_1 = require("./inaccessible.js");
const link_js_1 = require("./link.js");
const tag_js_1 = require("./tag.js");
function isFederationVersion(version) {
return version in federationSpecFactory;
}
function createSpecSchema(version, imports) {
if (!isFederationVersion(version)) {
throw new graphql_1.GraphQLError(`Invalid version ${version} for the federation feature in directive on schema`, {
extensions: {
code: "UNKNOWN_FEDERATION_LINK_VERSION",
},
});
}
if (version !== "v1.0") {
const spec = federationSpecFactory[version]("", imports);
const namespacedSpec = federationSpecFactory[version]("federation__");
return {
directives: spec.directives.concat(namespacedSpec.directives),
types: spec.types.concat(namespacedSpec.types),
};
}
const spec = federationSpecFactory[version]("");
return {
directives: spec.directives.concat([tag_js_1.directive, inaccessible_js_1.directive]),
types: spec.types,
};
}
const federationSpecFactory = {
"v1.0": (prefix) => createTypeDefinitions(`
directive (
fields: _FieldSet!
resolvable: Boolean = true
) repeatable on OBJECT | INTERFACE
directive (fields: _FieldSet!) on FIELD_DEFINITION
directive (fields: _FieldSet!) on FIELD_DEFINITION
directive on OBJECT | FIELD_DEFINITION
directive on OBJECT | INTERFACE
# is not supported in v1 but somehow it's supported by Apollo Composition
directive (from: String!) on FIELD_DEFINITION
scalar _FieldSet
`, prefix),
"v2.0": (prefix, imports) => createTypeDefinitions(`
directive (
fields: FieldSet!
resolvable: Boolean = true
) repeatable on OBJECT | INTERFACE
directive (fields: FieldSet!) on FIELD_DEFINITION
directive (fields: FieldSet!) on FIELD_DEFINITION
directive on OBJECT | FIELD_DEFINITION
directive on FIELD_DEFINITION | OBJECT
directive on OBJECT | INTERFACE
directive (from: String!) on FIELD_DEFINITION
directive on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ENUM | ENUM_VALUE | SCALAR | INPUT_OBJECT | INPUT_FIELD_DEFINITION | ARGUMENT_DEFINITION
directive (
name: String!
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
scalar FieldSet
`, prefix, imports),
"v2.1": (prefix, imports) => createTypeDefinitions(`
directive (name: String!) repeatable on SCHEMA
directive on OBJECT | INTERFACE
directive on OBJECT | FIELD_DEFINITION
directive (
fields: FieldSet!
resolvable: Boolean = true
) repeatable on OBJECT | INTERFACE
directive on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ENUM | ENUM_VALUE | SCALAR | INPUT_OBJECT | INPUT_FIELD_DEFINITION | ARGUMENT_DEFINITION
directive (from: String!) on FIELD_DEFINITION
directive (fields: FieldSet!) on FIELD_DEFINITION
directive (fields: FieldSet!) on FIELD_DEFINITION
directive on FIELD_DEFINITION | OBJECT
directive (
name: String!
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
scalar FieldSet
`, prefix, imports),
"v2.2": (prefix, imports) => createTypeDefinitions(`
directive (name: String!) repeatable on SCHEMA
directive on OBJECT | INTERFACE
directive on OBJECT | FIELD_DEFINITION
directive (
fields: FieldSet!
resolvable: Boolean = true
) repeatable on OBJECT | INTERFACE
directive on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ENUM | ENUM_VALUE | SCALAR | INPUT_OBJECT | INPUT_FIELD_DEFINITION | ARGUMENT_DEFINITION
directive (from: String!) on FIELD_DEFINITION
directive (fields: FieldSet!) on FIELD_DEFINITION
directive (fields: FieldSet!) on FIELD_DEFINITION
directive repeatable on FIELD_DEFINITION | OBJECT
directive (
name: String!
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
scalar FieldSet
`, prefix, imports),
"v2.3": (prefix, imports) => createTypeDefinitions(`
directive (name: String!) repeatable on SCHEMA
directive on OBJECT | INTERFACE
directive on OBJECT | FIELD_DEFINITION
directive (
fields: FieldSet!
resolvable: Boolean = true
) repeatable on OBJECT | INTERFACE
directive on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ENUM | ENUM_VALUE | SCALAR | INPUT_OBJECT | INPUT_FIELD_DEFINITION | ARGUMENT_DEFINITION
directive on OBJECT
directive (from: String!) on FIELD_DEFINITION
directive (fields: FieldSet!) on FIELD_DEFINITION
directive (fields: FieldSet!) on FIELD_DEFINITION
directive repeatable on FIELD_DEFINITION | OBJECT
directive (
name: String!
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
scalar FieldSet
`, prefix, imports),
"v2.4": (prefix, imports) => createTypeDefinitions(`
directive (name: String!) repeatable on SCHEMA
directive on OBJECT | INTERFACE
directive on OBJECT | FIELD_DEFINITION
directive (
fields: FieldSet!
resolvable: Boolean = true
) repeatable on OBJECT | INTERFACE
directive on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ENUM | ENUM_VALUE | SCALAR | INPUT_OBJECT | INPUT_FIELD_DEFINITION | ARGUMENT_DEFINITION
directive on OBJECT
directive (from: String!) on FIELD_DEFINITION
directive (fields: FieldSet!) on FIELD_DEFINITION
directive (fields: FieldSet!) on FIELD_DEFINITION
directive repeatable on FIELD_DEFINITION | OBJECT
directive (
name: String!
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
scalar FieldSet
`, prefix, imports),
"v2.5": (prefix, imports) => createTypeDefinitions(`
directive on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM
directive (
scopes: [[Scope!]!]!
) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM
directive (name: String!) repeatable on SCHEMA
directive on OBJECT | INTERFACE
directive on OBJECT | FIELD_DEFINITION
directive (
fields: FieldSet!
resolvable: Boolean = true
) repeatable on OBJECT | INTERFACE
directive on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ENUM | ENUM_VALUE | SCALAR | INPUT_OBJECT | INPUT_FIELD_DEFINITION | ARGUMENT_DEFINITION
directive on OBJECT
directive (from: String!) on FIELD_DEFINITION
directive (fields: FieldSet!) on FIELD_DEFINITION
directive (fields: FieldSet!) on FIELD_DEFINITION
directive repeatable on FIELD_DEFINITION | OBJECT
directive (
name: String!
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
scalar FieldSet
scalar Scope
`, prefix, imports),
"v2.6": (prefix, imports) => createTypeDefinitions(`
directive (
policies: [[federation__Policy!]!]!
) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM
directive on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM
directive (
scopes: [[federation__Scope!]!]!
) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM
directive (name: String!) repeatable on SCHEMA
directive on OBJECT | INTERFACE
directive on OBJECT | FIELD_DEFINITION
directive (
fields: FieldSet!
resolvable: Boolean = true
) repeatable on OBJECT | INTERFACE
directive on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ENUM | ENUM_VALUE | SCALAR | INPUT_OBJECT | INPUT_FIELD_DEFINITION | ARGUMENT_DEFINITION
directive on OBJECT
directive (from: String!) on FIELD_DEFINITION
directive (fields: FieldSet!) on FIELD_DEFINITION
directive (fields: FieldSet!) on FIELD_DEFINITION
directive repeatable on FIELD_DEFINITION | OBJECT
directive (
name: String!
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
scalar FieldSet
scalar federation__Policy
scalar federation__Scope
`, prefix, imports),
"v2.7": (prefix, imports) => createTypeDefinitions(`
directive (
policies: [[federation__Policy!]!]!
) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM
directive on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM
directive (
scopes: [[federation__Scope!]!]!
) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM
directive (name: String!) repeatable on SCHEMA
directive on OBJECT | INTERFACE
directive on OBJECT | FIELD_DEFINITION
directive (
fields: FieldSet!
resolvable: Boolean = true
) repeatable on OBJECT | INTERFACE
directive on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ENUM | ENUM_VALUE | SCALAR | INPUT_OBJECT | INPUT_FIELD_DEFINITION | ARGUMENT_DEFINITION
directive on OBJECT
directive (from: String!, label: String) on FIELD_DEFINITION
directive (fields: FieldSet!) on FIELD_DEFINITION
directive (fields: FieldSet!) on FIELD_DEFINITION
directive repeatable on FIELD_DEFINITION | OBJECT
directive (
name: String!
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
scalar FieldSet
scalar federation__Policy
scalar federation__Scope
`, prefix, imports),
"v2.8": (prefix, imports) => createTypeDefinitions(`
directive (
policies: [[federation__Policy!]!]!
) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM
directive on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM
directive (
scopes: [[federation__Scope!]!]!
) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM
directive (name: String!) repeatable on SCHEMA
directive on OBJECT | INTERFACE
directive on OBJECT | FIELD_DEFINITION
directive (
fields: FieldSet!
resolvable: Boolean = true
) repeatable on OBJECT | INTERFACE
directive on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ENUM | ENUM_VALUE | SCALAR | INPUT_OBJECT | INPUT_FIELD_DEFINITION | ARGUMENT_DEFINITION
directive on OBJECT
directive (from: String!, label: String) on FIELD_DEFINITION
directive (fields: FieldSet!) on FIELD_DEFINITION
directive (fields: FieldSet!) on FIELD_DEFINITION
directive repeatable on FIELD_DEFINITION | OBJECT
directive (
name: String!
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
directive (
weight: Int!
) on ARGUMENT_DEFINITION | ENUM | FIELD_DEFINITION | INPUT_FIELD_DEFINITION | OBJECT | SCALAR
directive (
assumedSize: Int
slicingArguments: [String!]
sizedFields: [String!]
requireOneSlicingArgument: Boolean = true
) on FIELD_DEFINITION
directive (
name: String!
) repeatable on INTERFACE | OBJECT | UNION
directive (
field: federation__ContextFieldValue
) on ARGUMENT_DEFINITION
scalar FieldSet
scalar federation__Policy
scalar federation__Scope
scalar federation__ContextFieldValue
`, prefix, imports),
"v2.9": (prefix, imports) => createTypeDefinitions(`
directive (
policies: [[federation__Policy!]!]!
) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM
directive on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM
directive (
scopes: [[federation__Scope!]!]!
) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM
directive (name: String!) repeatable on SCHEMA
directive on OBJECT | INTERFACE
directive on OBJECT | FIELD_DEFINITION
directive (
fields: FieldSet!
resolvable: Boolean = true
) repeatable on OBJECT | INTERFACE
directive on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ENUM | ENUM_VALUE | SCALAR | INPUT_OBJECT | INPUT_FIELD_DEFINITION | ARGUMENT_DEFINITION
directive on OBJECT
directive (from: String!, label: String) on FIELD_DEFINITION
directive (fields: FieldSet!) on FIELD_DEFINITION
directive (fields: FieldSet!) on FIELD_DEFINITION
directive repeatable on FIELD_DEFINITION | OBJECT
directive (
name: String!
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
directive (
weight: Int!
) on ARGUMENT_DEFINITION | ENUM | FIELD_DEFINITION | INPUT_FIELD_DEFINITION | OBJECT | SCALAR
directive (
assumedSize: Int
slicingArguments: [String!]
sizedFields: [String!]
requireOneSlicingArgument: Boolean = true
) on FIELD_DEFINITION
directive (
name: String!
) repeatable on INTERFACE | OBJECT | UNION
directive (
field: federation__ContextFieldValue
) on ARGUMENT_DEFINITION
scalar FieldSet
scalar federation__Policy
scalar federation__Scope
scalar federation__ContextFieldValue
`, prefix, imports),
};
function getLatestFederationVersion() {
return Object.keys(federationSpecFactory).sort().pop();
}
function createTypeDefinitions(doc, prefix, imports) {
const shouldFilter = !!imports;
const toInclude = new Set(imports?.map((i) => i.name.replace(/^@/, "")));
const docAST = (0, graphql_1.parse)(doc, {
noLocation: true,
});
if (!imports?.length ||
toInclude.has("key") ||
toInclude.has("requires") ||
toInclude.has("provides")) {
toInclude.add("FieldSet");
toInclude.add("federation__FieldSet");
}
if (toInclude.has("requiresScopes")) {
toInclude.add("federation__Scope");
}
if (toInclude.has("policy")) {
toInclude.add("federation__Policy");
}
const directives = [];
const types = [];
for (const node of docAST.definitions) {
if (isDirectiveDefinitionNode(node)) {
directives.push(applyPrefix(node, prefix));
}
else {
types.push(applyPrefix(node, prefix));
}
}
return {
directives: directives.filter((d) => !graphql_1.specifiedDirectives.some((sd) => sd.name === d.name.value) &&
(!shouldFilter || toInclude.has(d.name.value))),
types: types.filter((t) => toInclude.has(t.name.value)),
};
}
function isDirectiveDefinitionNode(node) {
return node.kind === graphql_1.Kind.DIRECTIVE_DEFINITION;
}
function applyPrefix(node, prefix) {
if (prefix.length === 0) {
return node;
}
node.name.value = `${prefix}${node.name.value}`;
if (isDirectiveDefinitionNode(node)) {
node.arguments?.forEach((arg) => {
const nameNode = resolveNamedType(arg.type);
if (!graphql_1.specifiedScalarTypes.some((t) => t.name === nameNode.value)) {
nameNode.value = `${prefix}${nameNode.value}`;
}
});
}
return node;
}
function resolveNamedType(node) {
if (node.kind === graphql_1.Kind.LIST_TYPE) {
return resolveNamedType(node.type);
}
if (node.kind === graphql_1.Kind.NON_NULL_TYPE) {
return resolveNamedType(node.type);
}
return node.name;
}
function isFederationLink(link) {
return link.identity === "https://specs.apollo.dev/federation";
}
function detectFederationVersion(typeDefs) {
for (const definition of typeDefs.definitions) {
if (definition.kind === graphql_1.Kind.SCHEMA_EXTENSION ||
definition.kind === graphql_1.Kind.SCHEMA_DEFINITION) {
const links = definition.directives?.filter((directive) => directive.name.value === "link");
if (links?.length) {
const parsedLinks = links.map((l) => {
const url = l.arguments?.find((a) => a.name.value === "url");
const importArg = l.arguments?.find((a) => a.name.value === "import");
if (!url) {
throw new Error("Invalid @link directive");
}
return (0, link_js_1.parseLink)(url.value.value, importArg ? (0, printer_js_1.print)(importArg.value) : "[]");
});
const fedLink = parsedLinks.find((l) => l.identity === "https://specs.apollo.dev/federation");
if (fedLink?.version) {
if (!isFederationVersion(fedLink.version)) {
throw new Error(`Unsupported federation version: ${fedLink.version}`);
}
return {
version: fedLink.version,
imports: fedLink.imports,
};
}
}
}
}
return { version: "v1.0", imports: [] };
}