@theguild/federation-composition
Version:
Open Source Composition library for Apollo Federation
169 lines (168 loc) • 6.29 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.enumTypeBuilder = enumTypeBuilder;
const ast_js_1 = require("./ast.js");
const common_js_1 = require("./common.js");
function enumTypeBuilder() {
return {
visitSubgraphState(graph, state, typeName, type) {
const enumTypeState = getOrCreateEnumType(state, typeName);
type.tags.forEach(tag => enumTypeState.tags.add(tag));
if (type.inaccessible) {
enumTypeState.inaccessible = true;
}
if (type.authenticated) {
enumTypeState.authenticated = true;
}
if (type.policies) {
enumTypeState.policies.push(...type.policies);
}
if (type.scopes) {
enumTypeState.scopes.push(...type.scopes);
}
if (type.isDefinition) {
enumTypeState.hasDefinition = true;
}
if (type.description && !enumTypeState.description) {
enumTypeState.description = type.description;
}
if (type.referencedByInputType) {
enumTypeState.referencedByInputType = true;
type.inputTypeReferences.forEach(ref => {
enumTypeState.inputTypeReferences.add(ref);
});
}
if (type.referencedByOutputType) {
enumTypeState.referencedByOutputType = true;
type.outputTypeReferences.forEach(ref => {
enumTypeState.outputTypeReferences.add(ref);
});
}
type.ast.directives.forEach(directive => {
enumTypeState.ast.directives.push(directive);
});
enumTypeState.byGraph.set(graph.id, {
inaccessible: type.inaccessible,
version: graph.version,
});
for (const value of type.values.values()) {
const valueState = getOrCreateEnumValue(enumTypeState, value.name);
value.tags.forEach(tag => valueState.tags.add(tag));
if (value.inaccessible) {
valueState.inaccessible = true;
}
if (value.deprecated && !valueState.deprecated) {
valueState.deprecated = value.deprecated;
}
if (value.description && !valueState.description) {
valueState.description = value.description;
}
value.ast.directives.forEach(directive => {
valueState.ast.directives.push(directive);
});
valueState.byGraph.set(graph.id, {
inaccessible: value.inaccessible,
version: graph.version,
});
}
},
composeSupergraphNode(enumType) {
const mergeMethod = decideOnEnumMergeStrategy(enumType.referencedByInputType, enumType.referencedByOutputType);
const values = mergeMethod === 'intersection'
? intersectionOfEnumValues(enumType)
: Array.from(enumType.values);
return (0, ast_js_1.createEnumTypeNode)({
name: enumType.name,
values: values.map(([_, value]) => ({
name: value.name,
join: {
enumValue: Array.from(value.byGraph.keys()).map(graph => ({
graph: graph.toUpperCase(),
})),
},
tags: Array.from(value.tags),
inaccessible: value.inaccessible,
description: value.description,
deprecated: value.deprecated,
ast: {
directives: (0, common_js_1.convertToConst)(value.ast.directives),
},
})),
tags: Array.from(enumType.tags),
inaccessible: enumType.inaccessible,
authenticated: enumType.authenticated,
policies: enumType.policies,
scopes: enumType.scopes,
description: enumType.description,
join: {
type: Array.from(enumType.byGraph.keys()).map(graphName => ({
graph: graphName.toUpperCase(),
})),
},
ast: {
directives: (0, common_js_1.convertToConst)(enumType.ast.directives),
},
});
},
};
}
function decideOnEnumMergeStrategy(referencedByInputType, referencedByOutputType) {
if (referencedByInputType === referencedByOutputType) {
return 'equal';
}
if (referencedByInputType) {
return 'intersection';
}
if (referencedByOutputType) {
return 'union';
}
return 'equal';
}
function intersectionOfEnumValues(enumType) {
const numberOfGraphs = enumType.byGraph.size;
return Array.from(enumType.values).filter(([_, value]) => value.byGraph.size === numberOfGraphs);
}
function getOrCreateEnumType(state, typeName) {
const existing = state.get(typeName);
if (existing) {
return existing;
}
const def = {
kind: 'enum',
name: typeName,
values: new Map(),
tags: new Set(),
hasDefinition: false,
inaccessible: false,
authenticated: false,
policies: [],
scopes: [],
referencedByInputType: false,
referencedByOutputType: false,
inputTypeReferences: new Set(),
outputTypeReferences: new Set(),
byGraph: new Map(),
ast: {
directives: [],
},
};
state.set(typeName, def);
return def;
}
function getOrCreateEnumValue(enumTypeState, enumValueName) {
const existing = enumTypeState.values.get(enumValueName);
if (existing) {
return existing;
}
const def = {
name: enumValueName,
tags: new Set(),
inaccessible: false,
byGraph: new Map(),
ast: {
directives: [],
},
};
enumTypeState.values.set(enumValueName, def);
return def;
}
;