@graphql-mesh/fusion-composition
Version:
Basic composition utility for Fusion spec
112 lines (111 loc) • 5.74 kB
JavaScript
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;
};
}
;