@apollo/federation
Version:
Apollo Federation Utilities
109 lines • 5 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.DirectiveMetadata = void 0;
const graphql_1 = require("graphql");
const utilities_1 = require("../utilities");
const utils_1 = require("./utils");
class DirectiveMetadata {
constructor(subgraphs) {
this.directiveUsagesPerSubgraph = new Map();
for (const subgraph of subgraphs) {
const visitor = this.getTypeVisitor(subgraph.name);
(0, graphql_1.visit)(subgraph.typeDefs, {
ObjectTypeDefinition: visitor,
ObjectTypeExtension: visitor,
InterfaceTypeDefinition: visitor,
InterfaceTypeExtension: visitor,
UnionTypeDefinition: visitor,
UnionTypeExtension: visitor,
});
}
}
getTypeVisitor(subgraphName) {
function collectDirectiveUsages(node, usagesOnNode) {
var _a;
for (const directive of (_a = node.directives) !== null && _a !== void 0 ? _a : []) {
const usages = (0, utilities_1.mapGetOrSet)(usagesOnNode, directive.name.value, []);
usages.push(directive);
}
}
return (node) => {
const directiveUsagesPerType = (0, utilities_1.mapGetOrSet)(this.directiveUsagesPerSubgraph, subgraphName, new Map());
const { directives: usagesOnType, fields: usagesByFieldName } = (0, utilities_1.mapGetOrSet)(directiveUsagesPerType, node.name.value, {
directives: new Map(),
fields: new Map(),
});
collectDirectiveUsages(node, usagesOnType);
if ('fields' in node && node.fields) {
for (const field of node.fields) {
const usagesOnField = (0, utilities_1.mapGetOrSet)(usagesByFieldName, field.name.value, new Map());
collectDirectiveUsages(field, usagesOnField);
}
}
};
}
hasUsages(directiveName) {
for (const directiveUsagesPerType of this.directiveUsagesPerSubgraph.values()) {
for (const { directives, fields } of directiveUsagesPerType.values()) {
const usagesOnType = directives.get(directiveName);
if (usagesOnType && usagesOnType.length > 0)
return true;
for (const directiveUsages of fields.values()) {
const usagesOnField = directiveUsages.get(directiveName);
if (usagesOnField && usagesOnField.length > 0)
return true;
}
}
}
return false;
}
applyMetadataToSupergraphSchema(schema) {
for (const directiveUsagesPerType of this.directiveUsagesPerSubgraph.values()) {
for (const [typeName, { directives, fields },] of directiveUsagesPerType.entries()) {
const namedType = schema.getType(typeName);
if (!namedType)
continue;
const existingMetadata = (0, utils_1.getFederationMetadata)(namedType);
const typeFederationMetadata = {
...existingMetadata,
directiveUsages: mergeDirectiveUsages(existingMetadata === null || existingMetadata === void 0 ? void 0 : existingMetadata.directiveUsages, directives),
};
namedType.extensions = {
...namedType.extensions,
federation: typeFederationMetadata,
};
for (const [fieldName, usagesPerDirective] of fields.entries()) {
if (!('getFields' in namedType))
continue;
const field = namedType.getFields()[fieldName];
if (!field)
continue;
const existingMetadata = (0, utils_1.getFederationMetadata)(field);
const fieldFederationMetadata = {
...existingMetadata,
directiveUsages: mergeDirectiveUsages(existingMetadata === null || existingMetadata === void 0 ? void 0 : existingMetadata.directiveUsages, usagesPerDirective),
};
field.extensions = {
...field.extensions,
federation: fieldFederationMetadata,
};
}
}
}
}
}
exports.DirectiveMetadata = DirectiveMetadata;
function mergeDirectiveUsages(first, second) {
const merged = new Map();
if (first) {
for (const [directiveName, usages] of first.entries()) {
merged.set(directiveName, [...usages]);
}
}
for (const [directiveName, newUsages] of second.entries()) {
const usages = (0, utilities_1.mapGetOrSet)(merged, directiveName, []);
usages.push(...newUsages);
}
return merged;
}
//# sourceMappingURL=DirectiveMetadata.js.map
;