UNPKG

@graphql-mesh/fusion-composition

Version:

Basic composition utility for Fusion spec

112 lines (111 loc) 5.74 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.hoistDirective = void 0; exports.createHoistFieldTransform = createHoistFieldTransform; const graphql_1 = require("graphql"); const utils_1 = require("@graphql-tools/utils"); const utils_js_1 = require("./utils.js"); function assertTypeWithFields(type) { if (!checkTypeWithFields(type)) { throw new utils_js_1.TransformValidationError(`Type ${type.name} is not an object or interface type, so you cannot apply hoisting for this type`); } } function checkTypeWithFields(type) { return (0, graphql_1.isObjectType)(type) || (0, graphql_1.isInterfaceType)(type); } exports.hoistDirective = new graphql_1.GraphQLDirective({ name: 'hoist', locations: [graphql_1.DirectiveLocation.FIELD_DEFINITION], args: { subgraph: { type: graphql_1.GraphQLString, }, pathConfig: { type: new graphql_1.GraphQLScalarType({ name: '_HoistConfig', }), }, }, }); function createHoistFieldTransform(opts) { return function hoistFieldTransform(schema, subgraphConfig) { const mappedSchema = (0, utils_1.mapSchema)(schema, { [utils_1.MapperKind.TYPE](type) { if (opts.mapping) { if (checkTypeWithFields(type)) { let changed = false; const fields = type.getFields(); const typeConfig = type.toConfig(); const newFieldConfigMap = typeConfig.fields; for (const mapping of opts.mapping) { if (type.name === mapping.typeName) { const pathConfig = mapping.pathConfig[0]; let fieldName = typeof pathConfig === 'string' ? pathConfig : pathConfig.fieldName; let field = fields[fieldName]; const pathConfigArr = [...mapping.pathConfig.slice(1)]; let filteredArgs = typeof pathConfig === 'object' ? pathConfig.filterArgs : undefined; const argsConfig = {}; while (pathConfigArr.length > 0) { if (!field) { throw new utils_js_1.TransformValidationError(`Field ${fieldName} not found for the hoisting of ${type.name}, so you cannot apply hoisting`); } for (const arg of field.args) { if (filteredArgs) { if (filteredArgs.includes(arg.name)) { continue; } } else if (mapping.filterArgsInPath) { continue; } argsConfig[arg.name] = arg; } const fieldType = (0, graphql_1.getNamedType)(field.type); assertTypeWithFields(fieldType); const subFields = fieldType.getFields(); const pathPart = pathConfigArr.shift(); filteredArgs = typeof pathPart === 'string' ? [] : pathPart.filterArgs || []; fieldName = typeof pathPart === 'string' ? pathPart : pathPart.fieldName; field = subFields[fieldName]; } changed = true; const existingFieldConfig = newFieldConfigMap[mapping.newFieldName]; newFieldConfigMap[mapping.newFieldName] = { ...(existingFieldConfig || {}), args: argsConfig, type: field.type, extensions: { ...existingFieldConfig?.extensions, directives: { ...existingFieldConfig?.extensions?.directives, hoist: [ { subgraph: subgraphConfig.name, pathConfig: mapping.pathConfig, }, ], }, }, }; } } if (changed) { return new (Object.getPrototypeOf(type).constructor)({ ...typeConfig, fields: newFieldConfigMap, }); } } } return type; }, }); if (mappedSchema.getDirective('hoist') == null) { return new graphql_1.GraphQLSchema({ ...mappedSchema.toConfig(), directives: [...mappedSchema.toConfig().directives, exports.hoistDirective], }); } return mappedSchema; }; }