UNPKG

@theguild/federation-composition

Version:
109 lines (108 loc) 4.39 kB
import { Kind, specifiedDirectives as specifiedDirectivesArray, visit, } from 'graphql'; export const federationScalars = new Set([ '_FieldSet', 'link__Import', 'join__FieldSet', 'join__DirectiveArguments', 'policy__Policy', 'requiresScopes__Scope', ]); export const federationEnums = new Set(['core__Purpose', 'join__Graph', 'link__Purpose']); export const federationDirectives = new Set([ 'link', 'core', 'tag', 'join__graph', 'join__type', 'join__owner', 'join__implements', 'join__unionMember', 'join__directive', 'join__enumValue', 'join__field', 'inaccessible', 'authenticated', 'policy', 'requiresScopes', ]); const specifiedDirectives = new Set(specifiedDirectivesArray.map(d => d.name)); function getAdditionalDirectivesToStrip(documentNode) { const schemaDefinitionNode = documentNode.definitions.find((node) => node.kind === Kind.SCHEMA_DEFINITION); if (!schemaDefinitionNode?.directives?.length) { return null; } const additionalDirectivesToStrip = new Set(); for (const directive of schemaDefinitionNode.directives) { if (directive.name.value !== 'link') { continue; } const asArg = directive.arguments?.find(arg => arg.name.value === 'as'); if (asArg?.value.kind === Kind.STRING) { additionalDirectivesToStrip.add(asArg.value.value); } } return additionalDirectivesToStrip; } const federationInaccessibleDirectiveUrlPrefix = 'https://specs.apollo.dev/inaccessible'; function getInaccessibleDirectiveName(documentNode) { const schemaDefinitionNode = documentNode.definitions.find((node) => node.kind === Kind.SCHEMA_DEFINITION); if (schemaDefinitionNode?.directives?.length) { for (const directive of schemaDefinitionNode.directives) { if (directive.name.value !== 'link') { continue; } const urlArg = directive.arguments?.find(arg => arg.name.value === 'url'); const asArg = directive.arguments?.find(arg => arg.name.value === 'as'); if (urlArg?.value.kind === Kind.STRING && urlArg.value.value.startsWith(federationInaccessibleDirectiveUrlPrefix)) { if (asArg?.value.kind === Kind.STRING) { return asArg.value.value; } break; } } } return 'inaccessible'; } export function transformSupergraphToPublicSchema(documentNode) { const additionalFederationDirectives = getAdditionalDirectivesToStrip(documentNode); const inaccessibleDirectiveName = getInaccessibleDirectiveName(documentNode); function removeFederationOrSpecifiedDirectives(node) { if (federationDirectives.has(node.name.value) || additionalFederationDirectives?.has(node.name.value) || (node.kind === Kind.DIRECTIVE_DEFINITION && specifiedDirectives.has(node.name.value))) { return null; } } function hasInaccessibleDirective(node) { return node.directives?.some(d => d.name.value === inaccessibleDirectiveName); } function removeInaccessibleNode(node) { if (hasInaccessibleDirective(node)) { return null; } } return visit(documentNode, { [Kind.DIRECTIVE_DEFINITION]: removeFederationOrSpecifiedDirectives, [Kind.DIRECTIVE]: removeFederationOrSpecifiedDirectives, [Kind.SCHEMA_EXTENSION]: () => null, [Kind.SCHEMA_DEFINITION]: () => null, [Kind.SCALAR_TYPE_DEFINITION](node) { if (federationScalars.has(node.name.value) || hasInaccessibleDirective(node)) { return null; } }, [Kind.ENUM_TYPE_DEFINITION](node) { if (federationEnums.has(node.name.value) || hasInaccessibleDirective(node)) { return null; } }, [Kind.ENUM_VALUE_DEFINITION]: removeInaccessibleNode, [Kind.OBJECT_TYPE_DEFINITION]: removeInaccessibleNode, [Kind.FIELD_DEFINITION]: removeInaccessibleNode, [Kind.INTERFACE_TYPE_DEFINITION]: removeInaccessibleNode, [Kind.UNION_TYPE_DEFINITION]: removeInaccessibleNode, [Kind.INPUT_OBJECT_TYPE_DEFINITION]: removeInaccessibleNode, [Kind.INPUT_VALUE_DEFINITION]: removeInaccessibleNode, }); }