UNPKG

@theguild/federation-composition

Version:
300 lines (299 loc) 12.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.interfaceTypeBuilder = interfaceTypeBuilder; const ast_js_1 = require("./ast.js"); const common_js_1 = require("./common.js"); function interfaceTypeBuilder() { return { visitSubgraphState(graph, state, typeName, type) { const interfaceTypeState = getOrCreateInterfaceType(state, typeName); type.tags.forEach(tag => interfaceTypeState.tags.add(tag)); if (type.inaccessible) { interfaceTypeState.inaccessible = true; } if (type.authenticated) { interfaceTypeState.authenticated = true; } if (type.policies) { interfaceTypeState.policies.push(...type.policies); } if (type.scopes) { interfaceTypeState.scopes.push(...type.scopes); } if (type.isDefinition) { interfaceTypeState.hasDefinition = true; } if (type.isInterfaceObject) { interfaceTypeState.hasInterfaceObject = true; } if (type.description && !interfaceTypeState.description) { interfaceTypeState.description = type.description; } type.ast.directives.forEach(directive => { interfaceTypeState.ast.directives.push(directive); }); type.interfaces.forEach(interfaceName => interfaceTypeState.interfaces.add(interfaceName)); type.implementedBy.forEach(objectTypeName => interfaceTypeState.implementedBy.add(objectTypeName)); if (type.keys.length) { interfaceTypeState.isEntity = true; } interfaceTypeState.byGraph.set(graph.id, { extension: type.extension, keys: type.keys, interfaces: type.interfaces, implementedBy: type.implementedBy, isInterfaceObject: type.isInterfaceObject, version: graph.version, }); for (const field of type.fields.values()) { const fieldState = getOrCreateInterfaceField(interfaceTypeState, field.name, field.type); field.tags.forEach(tag => fieldState.tags.add(tag)); if (!field.type.endsWith('!') && fieldState.type.endsWith('!')) { fieldState.type = field.type; } if (field.isLeaf) { fieldState.isLeaf = true; } if (field.inaccessible) { fieldState.inaccessible = true; } if (field.authenticated) { fieldState.authenticated = true; } if (field.policies) { fieldState.policies.push(...field.policies); } if (field.scopes) { fieldState.scopes.push(...field.scopes); } if (field.deprecated && !fieldState.deprecated) { fieldState.deprecated = field.deprecated; } if (field.description && !fieldState.description) { fieldState.description = field.description; } field.ast.directives.forEach(directive => { fieldState.ast.directives.push(directive); }); const usedAsKey = type.fieldsUsedAsKeys.has(field.name); if (usedAsKey) { fieldState.usedAsKey = true; } fieldState.byGraph.set(graph.id, { type: field.type, override: field.override, provides: field.provides, requires: field.requires, version: graph.version, external: field.external, shareable: field.shareable, usedAsKey, }); for (const arg of field.args.values()) { const argState = getOrCreateArg(fieldState, arg.name, arg.type, arg.kind); arg.tags.forEach(tag => argState.tags.add(tag)); if (arg.type.endsWith('!')) { argState.type = arg.type; } if (arg.deprecated && !argState.deprecated) { argState.deprecated = arg.deprecated; } if (arg.description && !argState.description) { argState.description = arg.description; } if (typeof arg.defaultValue !== 'undefined') { argState.defaultValue = arg.defaultValue; } arg.ast.directives.forEach(directive => { argState.ast.directives.push(directive); }); argState.kind = arg.kind; argState.byGraph.set(graph.id, { type: arg.type, kind: arg.kind, defaultValue: arg.defaultValue, version: graph.version, }); } } }, composeSupergraphNode(interfaceType, graphs) { return (0, ast_js_1.createInterfaceTypeNode)({ name: interfaceType.name, fields: Array.from(interfaceType.fields.values()).map(field => { let nonEmptyJoinField = false; const joinFields = []; if (field.byGraph.size !== interfaceType.byGraph.size) { for (const [graphId, meta] of field.byGraph.entries()) { if (meta.type !== field.type || meta.override || meta.provides || meta.requires || meta.external) { nonEmptyJoinField = true; } joinFields.push({ graph: graphId, type: meta.type === field.type ? undefined : meta.type, override: meta.override ?? undefined, provides: meta.provides ?? undefined, requires: meta.requires ?? undefined, external: meta.external, }); } } return { name: field.name, type: field.type, inaccessible: field.inaccessible, authenticated: field.authenticated, policies: field.policies, scopes: field.scopes, tags: Array.from(field.tags), deprecated: field.deprecated, description: field.description, ast: { directives: (0, common_js_1.convertToConst)(field.ast.directives), }, arguments: Array.from(field.args.values()) .filter(arg => { if (arg.byGraph.size !== field.byGraph.size) { return false; } return true; }) .map(arg => { return { name: arg.name, type: arg.type, kind: arg.kind, tags: Array.from(arg.tags), defaultValue: arg.defaultValue, deprecated: arg.deprecated, description: arg.description, ast: { directives: (0, common_js_1.convertToConst)(arg.ast.directives), }, }; }), join: { field: joinFields, }, }; }), tags: Array.from(interfaceType.tags), inaccessible: interfaceType.inaccessible, authenticated: interfaceType.authenticated, policies: interfaceType.policies, scopes: interfaceType.scopes, description: interfaceType.description, interfaces: Array.from(interfaceType.interfaces), ast: { directives: (0, common_js_1.convertToConst)(interfaceType.ast.directives), }, join: { type: Array.from(interfaceType.byGraph) .map(([graphId, meta]) => { if (meta.keys.length && graphs.get(graphId).version !== 'v1.0') { return meta.keys.map(key => ({ graph: graphId, key: key.fields, extension: meta.extension, isInterfaceObject: meta.isInterfaceObject, resolvable: key.resolvable, })); } return [ { graph: graphId, }, ]; }) .flat(1), implements: interfaceType.interfaces.size > 0 ? Array.from(interfaceType.byGraph.entries()) .map(([graphId, meta]) => { if (meta.interfaces.size) { return Array.from(meta.interfaces).map(iface => ({ graph: graphId, interface: iface, })); } return []; }) .flat(1) : [], }, }); }, }; } function getOrCreateInterfaceType(state, typeName) { const existing = state.get(typeName); if (existing) { return existing; } const def = { kind: 'interface', name: typeName, tags: new Set(), inaccessible: false, authenticated: false, policies: [], scopes: [], hasDefinition: false, hasInterfaceObject: false, isEntity: false, byGraph: new Map(), fields: new Map(), interfaces: new Set(), implementedBy: new Set(), ast: { directives: [], }, }; state.set(typeName, def); return def; } function getOrCreateInterfaceField(interfaceTypeState, fieldName, fieldType) { const existing = interfaceTypeState.fields.get(fieldName); if (existing) { return existing; } const def = { name: fieldName, type: fieldType, isLeaf: false, usedAsKey: false, tags: new Set(), inaccessible: false, authenticated: false, policies: [], scopes: [], byGraph: new Map(), args: new Map(), ast: { directives: [], }, }; interfaceTypeState.fields.set(fieldName, def); return def; } function getOrCreateArg(fieldState, argName, argType, argKind) { const existing = fieldState.args.get(argName); if (existing) { return existing; } const def = { name: argName, type: argType, kind: argKind, tags: new Set(), byGraph: new Map(), ast: { directives: [], }, }; fieldState.args.set(argName, def); return def; }