@graphql-mesh/fusion-composition
Version:
Basic composition utility for Fusion spec
257 lines (256 loc) • 11.7 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.ignoreList = void 0;
exports.createRenameTransform = createRenameTransform;
exports.createRenameTypeTransform = createRenameTypeTransform;
exports.createRenameFieldTransform = createRenameFieldTransform;
const graphql_1 = require("graphql");
const graphql_scalars_1 = require("graphql-scalars");
const utils_1 = require("@graphql-tools/utils");
exports.ignoreList = [
'Int',
'Float',
'String',
'Boolean',
'ID',
'date',
'hostname',
'regex',
'json-pointer',
'relative-json-pointer',
'uri-reference',
'uri-template',
'ObjMap',
'HttpMethod',
...Object.keys(graphql_scalars_1.resolvers),
];
// TODO: For backwards compatibility, remove in the next major
function createRenameTransform(opts) {
const typeRenamers = opts.typeRenamer ? [opts.typeRenamer] : [];
const fieldRenamers = opts.fieldRenamer ? [opts.fieldRenamer] : [];
const argRenamers = opts.argRenamer ? [opts.argRenamer] : [];
if (opts.renames?.length) {
for (const change of opts.renames) {
const { from: { type: fromTypeName, field: fromFieldName, argument: fromArgumentName }, to: { type: toTypeName, field: toFieldName, argument: toArgumentName }, useRegExpForTypes, useRegExpForFields, useRegExpForArguments, } = change;
const includeDefaults = change.includeDefaults === true;
const regExpFlags = change.regExpFlags || undefined;
if (fromTypeName !== toTypeName) {
let replaceTypeNameFn;
if (useRegExpForTypes) {
const typeNameRegExp = new RegExp(fromTypeName, regExpFlags);
replaceTypeNameFn = ({ typeName }) => typeName.replace(typeNameRegExp, toTypeName);
}
else {
replaceTypeNameFn = ({ typeName }) => (typeName === fromTypeName ? toTypeName : typeName);
}
typeRenamers.push(({ typeName, type, subgraphConfig }) => {
if (!includeDefaults && exports.ignoreList.includes(typeName)) {
return typeName;
}
return replaceTypeNameFn({ typeName, type, subgraphConfig });
});
}
if (fromFieldName && toFieldName && fromFieldName !== toFieldName) {
let replaceFieldNameFn;
if (useRegExpForFields) {
const fieldNameRegExp = new RegExp(fromFieldName, regExpFlags);
replaceFieldNameFn = ({ typeName, fieldName }) => typeName === toTypeName ? fieldName.replace(fieldNameRegExp, toFieldName) : fieldName;
}
else {
replaceFieldNameFn = ({ typeName, fieldName }) => typeName === toTypeName && fieldName === fromFieldName ? toFieldName : fieldName;
}
fieldRenamers.push(replaceFieldNameFn);
}
if (fromTypeName &&
(fromTypeName === toTypeName || useRegExpForTypes) &&
toFieldName &&
(fromFieldName === toFieldName || useRegExpForFields) &&
fromArgumentName &&
fromArgumentName !== toArgumentName) {
let replaceArgNameFn;
const fieldNameMatch = (fieldName) => fieldName ===
(useRegExpForFields
? fieldName.replace(new RegExp(fromFieldName, regExpFlags), toFieldName)
: toFieldName);
const typeNameMatch = (typeName) => typeName ===
(useRegExpForTypes
? typeName.replace(new RegExp(fromTypeName, regExpFlags), toTypeName)
: toTypeName);
if (useRegExpForArguments) {
const argNameRegExp = new RegExp(fromArgumentName, regExpFlags);
replaceArgNameFn = ({ typeName, fieldName, argName }) => typeNameMatch(typeName) && fieldNameMatch(fieldName)
? argName.replace(argNameRegExp, toArgumentName)
: argName;
}
else {
replaceArgNameFn = ({ typeName, fieldName, argName }) => typeNameMatch(typeName) && fieldNameMatch(fieldName) && argName === fromArgumentName
? toArgumentName
: argName;
}
argRenamers.push(replaceArgNameFn);
}
}
}
return function renameTransform(schema, subgraphConfig) {
const schemaMapper = {};
const typeRenameMap = new Map();
if (typeRenamers.length) {
schemaMapper[utils_1.MapperKind.TYPE] = type => {
let newTypeName = type.name;
for (const renamer of typeRenamers) {
newTypeName =
renamer({
typeName: newTypeName,
type,
subgraphConfig,
}) || newTypeName;
}
if (newTypeName !== type.name) {
typeRenameMap.set(type.name, newTypeName);
return new (Object.getPrototypeOf(type).constructor)({
...type.toConfig(),
name: newTypeName,
});
}
return type;
};
}
const fieldRenameMap = new Map();
schemaMapper[utils_1.MapperKind.FIELD] = (field, fieldName, typeName, schema) => {
let newFieldName = fieldName;
if (fieldRenamers.length) {
const type = schema.getType(typeName);
for (const renamer of fieldRenamers) {
newFieldName =
renamer({
typeName,
fieldName: newFieldName,
type,
field,
subgraphConfig,
}) || newFieldName;
}
let typeFieldRenameMap = fieldRenameMap.get(typeName);
if (!typeFieldRenameMap) {
typeFieldRenameMap = new Map();
fieldRenameMap.set(typeName, typeFieldRenameMap);
}
typeFieldRenameMap.set(fieldName, newFieldName);
}
const fieldDirectives = (0, utils_1.getDirectiveExtensions)(field, schema);
if (fieldDirectives.resolveTo) {
fieldDirectives.resolveTo = fieldDirectives.resolveTo.map(resolveTo => ({
...resolveTo,
sourceTypeName: (resolveTo.sourceTypeName && typeRenameMap.get(resolveTo.sourceTypeName)) ||
resolveTo.sourceTypeName,
sourceFieldName: (resolveTo.sourceFieldName &&
fieldRenameMap.get(resolveTo.sourceTypeName)?.get(resolveTo.sourceFieldName)) ||
resolveTo.sourceFieldName,
}));
const fieldExtensions = (field.extensions ||= {});
fieldExtensions.directives = fieldDirectives;
}
if (argRenamers.length && 'args' in field && field.args) {
const newArgs = {};
for (const argName in field.args) {
let newArgName = argName;
for (const renamer of argRenamers) {
newArgName =
renamer({
typeName,
fieldName,
argName: newArgName,
subgraphConfig,
}) || newArgName;
}
newArgs[newArgName] = field.args[argName];
}
return [
newFieldName,
{
...field,
args: newArgs,
},
];
}
return [newFieldName, field];
};
return (0, utils_1.mapSchema)(schema, schemaMapper);
};
}
function createRenameTypeTransform(renameFn, kind = utils_1.MapperKind.TYPE) {
return function renameTypeTransform(schema, subgraphConfig) {
const rootTypes = (0, utils_1.getRootTypes)(schema);
const renamedTypeMap = new Map();
return (0, utils_1.mapSchema)(schema, {
[kind]: type => {
if ((0, graphql_1.isSpecifiedScalarType)(type) || rootTypes.has(type)) {
return type;
}
const newName = renameFn({
typeName: type.name,
type,
subgraphConfig,
}) || type.name;
if (type.name === newName) {
return type;
}
renamedTypeMap.set(type.name, newName);
return new (Object.getPrototypeOf(type).constructor)({
...type.toConfig(),
name: newName,
});
},
[utils_1.MapperKind.FIELD](field) {
const fieldDirectives = (0, utils_1.getDirectiveExtensions)(field, schema);
if (fieldDirectives?.resolveTo) {
fieldDirectives.resolveTo = fieldDirectives.resolveTo.map(resolveTo => ({
...resolveTo,
sourceTypeName: renamedTypeMap.get(resolveTo.sourceTypeName) || resolveTo.sourceTypeName,
}));
}
const fieldExtensions = (field.extensions ||= {});
fieldExtensions.directives = fieldDirectives;
return field;
},
});
};
}
function createRenameFieldTransform(renameFn, kind = utils_1.MapperKind.FIELD) {
return function renameFieldTransform(schema, subgraphConfig) {
const fieldRenameMap = new Map();
const mapper = {
[kind]: (field, fieldName, typeName) => {
const type = schema.getType(typeName);
const newFieldName = renameFn({
typeName,
fieldName,
type,
field,
subgraphConfig,
}) || fieldName;
let typeFieldRenameMap = fieldRenameMap.get(typeName);
if (!typeFieldRenameMap) {
typeFieldRenameMap = new Map();
fieldRenameMap.set(typeName, typeFieldRenameMap);
}
typeFieldRenameMap.set(fieldName, newFieldName);
return [newFieldName, resolveToUpdater(field, schema)];
},
};
function resolveToUpdater(field, schema) {
const fieldDirectives = (0, utils_1.getDirectiveExtensions)(field, schema);
if (fieldDirectives?.resolveTo) {
fieldDirectives.resolveTo = fieldDirectives.resolveTo.map(resolveTo => ({
...resolveTo,
sourceFieldName: fieldRenameMap.get(resolveTo.sourceTypeName)?.get(resolveTo.sourceFieldName) ||
resolveTo.sourceFieldName,
}));
}
const fieldExtensions = (field.extensions ||= {});
fieldExtensions.directives = fieldDirectives;
return field;
}
return (0, utils_1.mapSchema)(schema, mapper);
};
}
;