@theguild/federation-composition
Version:
Open Source Composition library for Apollo Federation
49 lines (48 loc) • 2.4 kB
JavaScript
import { GraphQLError } from 'graphql';
import { andList } from '../../../utils/format.js';
import { isRealExtension } from '../../composition/object-type.js';
export function ExternalTypeMismatchRule(context) {
return {
ObjectTypeField(objectTypeState, fieldState) {
if (fieldState.usedAsKey) {
return;
}
const groupByType = new Map();
const graphsWithEqualType = [];
for (const [graphId, field] of fieldState.byGraph) {
const graphVersion = context.subgraphStates.get(graphId).version;
const isExternal = graphVersion === 'v1.0'
? field.external && isRealExtension(objectTypeState.byGraph.get(graphId), graphVersion)
: field.external;
if (!isExternal) {
graphsWithEqualType.push(graphId);
continue;
}
if (field.type === fieldState.type) {
graphsWithEqualType.push(graphId);
continue;
}
const existing = groupByType.get(field.type);
if (existing) {
existing.push(graphId);
}
else {
groupByType.set(field.type, [graphId]);
}
}
if (groupByType.size && graphsWithEqualType.length) {
const groups = Array.from(groupByType.entries()).map(([type, graphs]) => {
const plural = graphs.length > 1 ? 's' : '';
return `type "${type}" in subgraph${plural} ${andList(graphs.map(context.graphIdToName), true, '"')}`;
});
const [first, ...rest] = groups;
const nonExternal = `type "${fieldState.type}" in subgraph${graphsWithEqualType.length > 1 ? 's' : ''} ${andList(graphsWithEqualType.map(context.graphIdToName), true, '"')}`;
context.reportError(new GraphQLError(`Type of field "${objectTypeState.name}.${fieldState.name}" is incompatible across subgraphs (where marked @external): it has ${nonExternal} but ${first}${rest.length ? ` and ${rest.join(' and ')}` : ''}`, {
extensions: {
code: 'EXTERNAL_TYPE_MISMATCH',
},
}));
}
},
};
}