UNPKG

@theguild/federation-composition

Version:
49 lines (48 loc) 2.4 kB
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', }, })); } }, }; }