@graphql-tools/wrap
Version:
A set of utils for faster development of GraphQL tools
174 lines (173 loc) • 7.31 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.unwrapValue = exports.renameFieldNode = exports.wrapFieldNode = void 0;
const tslib_1 = require("tslib");
const graphql_1 = require("graphql");
const utils_1 = require("@graphql-tools/utils");
const delegate_1 = require("@graphql-tools/delegate");
const generateProxyingResolvers_js_1 = require("../generateProxyingResolvers.js");
const MapFields_js_1 = tslib_1.__importDefault(require("./MapFields.js"));
class HoistField {
constructor(typeName, pathConfig, newFieldName, alias = '__gqtlw__') {
this.typeName = typeName;
this.newFieldName = newFieldName;
const path = pathConfig.map(segment => (typeof segment === 'string' ? segment : segment.fieldName));
this.argFilters = pathConfig.map((segment, index) => {
if (typeof segment === 'string' || segment.argFilter == null) {
return index === pathConfig.length - 1 ? () => true : () => false;
}
return segment.argFilter;
});
const pathToField = path.slice();
const oldFieldName = pathToField.pop();
if (oldFieldName == null) {
throw new Error(`Cannot hoist field to ${newFieldName} on type ${typeName}, no path provided.`);
}
this.oldFieldName = oldFieldName;
this.pathToField = pathToField;
const argLevels = Object.create(null);
this.transformer = new MapFields_js_1.default({
[typeName]: {
[newFieldName]: fieldNode => wrapFieldNode(renameFieldNode(fieldNode, oldFieldName), pathToField, alias, argLevels),
},
}, {
[typeName]: value => unwrapValue(value, alias),
}, errors => (errors != null ? unwrapErrors(errors, alias) : undefined));
this.argLevels = argLevels;
}
transformSchema(originalWrappingSchema, subschemaConfig) {
var _a, _b, _c, _d;
const argsMap = Object.create(null);
const innerType = this.pathToField.reduce((acc, pathSegment, index) => {
const field = acc.getFields()[pathSegment];
for (const arg of field.args) {
if (this.argFilters[index](arg)) {
argsMap[arg.name] = arg;
this.argLevels[arg.name] = index;
}
}
return (0, graphql_1.getNullableType)(field.type);
}, originalWrappingSchema.getType(this.typeName));
let [newSchema, targetFieldConfigMap] = (0, utils_1.removeObjectFields)(originalWrappingSchema, innerType.name, fieldName => fieldName === this.oldFieldName);
const targetField = targetFieldConfigMap[this.oldFieldName];
let resolve;
const hoistingToRootField = this.typeName === ((_a = originalWrappingSchema.getQueryType()) === null || _a === void 0 ? void 0 : _a.name) ||
this.typeName === ((_b = originalWrappingSchema.getMutationType()) === null || _b === void 0 ? void 0 : _b.name);
if (hoistingToRootField) {
const targetSchema = subschemaConfig.schema;
const operation = this.typeName === ((_c = targetSchema.getQueryType()) === null || _c === void 0 ? void 0 : _c.name) ? 'query' : 'mutation';
const createProxyingResolver = (_d = subschemaConfig.createProxyingResolver) !== null && _d !== void 0 ? _d : generateProxyingResolvers_js_1.defaultCreateProxyingResolver;
resolve = createProxyingResolver({
subschemaConfig,
operation: operation,
fieldName: this.newFieldName,
});
}
else {
resolve = delegate_1.defaultMergedResolver;
}
const newTargetField = {
...targetField,
resolve: resolve,
};
const level = this.pathToField.length;
const args = targetField.args;
if (args != null) {
for (const argName in args) {
const argConfig = args[argName];
if (argConfig == null) {
continue;
}
const arg = {
...argConfig,
name: argName,
description: argConfig.description,
defaultValue: argConfig.defaultValue,
extensions: argConfig.extensions,
astNode: argConfig.astNode,
};
if (this.argFilters[level](arg)) {
argsMap[argName] = arg;
this.argLevels[arg.name] = level;
}
}
}
newTargetField.args = argsMap;
newSchema = (0, utils_1.appendObjectFields)(newSchema, this.typeName, {
[this.newFieldName]: newTargetField,
});
return this.transformer.transformSchema(newSchema, subschemaConfig);
}
transformRequest(originalRequest, delegationContext, transformationContext) {
return this.transformer.transformRequest(originalRequest, delegationContext, transformationContext);
}
transformResult(originalResult, delegationContext, transformationContext) {
return this.transformer.transformResult(originalResult, delegationContext, transformationContext);
}
}
exports.default = HoistField;
function wrapFieldNode(fieldNode, path, alias, argLevels) {
return path.reduceRight((acc, fieldName, index) => ({
kind: graphql_1.Kind.FIELD,
alias: {
kind: graphql_1.Kind.NAME,
value: alias,
},
name: {
kind: graphql_1.Kind.NAME,
value: fieldName,
},
selectionSet: {
kind: graphql_1.Kind.SELECTION_SET,
selections: [acc],
},
arguments: fieldNode.arguments != null
? fieldNode.arguments.filter(arg => argLevels[arg.name.value] === index)
: undefined,
}), {
...fieldNode,
arguments: fieldNode.arguments != null
? fieldNode.arguments.filter(arg => argLevels[arg.name.value] === path.length)
: undefined,
});
}
exports.wrapFieldNode = wrapFieldNode;
function renameFieldNode(fieldNode, name) {
return {
...fieldNode,
alias: {
kind: graphql_1.Kind.NAME,
value: fieldNode.alias != null ? fieldNode.alias.value : fieldNode.name.value,
},
name: {
kind: graphql_1.Kind.NAME,
value: name,
},
};
}
exports.renameFieldNode = renameFieldNode;
function unwrapValue(originalValue, alias) {
let newValue = originalValue;
let object = newValue[alias];
while (object != null) {
newValue = object;
object = newValue[alias];
}
delete originalValue[alias];
Object.assign(originalValue, newValue);
return originalValue;
}
exports.unwrapValue = unwrapValue;
function unwrapErrors(errors, alias) {
if (errors === undefined) {
return undefined;
}
return errors.map(error => {
const originalPath = error.path;
if (originalPath == null) {
return error;
}
const newPath = originalPath.filter(pathSegment => pathSegment !== alias);
return (0, utils_1.relocatedError)(error, newPath);
});
}
;