@graphql-tools/delegate
Version:
A set of utils for faster development of GraphQL tools
2,726 lines • 90.8 kB
JavaScript
import { memoize2, memoize1, promiseReduce, collectFields, relocatedError, mergeDeep, pathToArray, getResponseKeyFromInfo, astFromType, getDefinedRootType, createGraphQLError, serializeInputValue, implementsAbstractType, getRootTypeNames, isAsyncIterable, getOperationASTFromRequest } from '@graphql-tools/utils';
export { createDeferred } from '@graphql-tools/utils';
import { GraphQLError, locatedError, isAbstractType, getNullableType, isLeafType, isCompositeType, isListType, responsePathAsArray, Kind, TypeInfo, versionInfo, visit, visitWithTypeInfo, isNullableType, isUnionType, getNamedType, isObjectType, isInterfaceType, typeFromAST, defaultFieldResolver, validate } from 'graphql';
import { handleMaybePromise, isPromise, createDeferredPromise, mapAsyncIterator } from '@whatwg-node/promise-helpers';
import { CRITICAL_ERROR, executorFromSchema } from '@graphql-tools/executor';
export { executorFromSchema as createDefaultExecutor } from '@graphql-tools/executor';
import { getBatchingExecutor } from '@graphql-tools/batch-execute';
import { Repeater } from '@repeaterjs/repeater';
import { dset } from 'dset/merge';
const applySchemaTransforms = memoize2(function applySchemaTransforms2(originalWrappingSchema, subschemaConfig) {
const schemaTransforms = subschemaConfig.transforms;
if (schemaTransforms == null) {
return originalWrappingSchema;
}
return schemaTransforms.reduce(
(schema, transform) => transform.transformSchema?.(schema, subschemaConfig) || schema,
originalWrappingSchema
);
});
function isSubschema(value) {
return Boolean(value.transformedSchema);
}
class Subschema {
name;
schema;
executor;
batch;
batchingOptions;
createProxyingResolver;
transforms;
_transformedSchema;
merge;
constructor(config) {
this.name = config.name;
this.schema = config.schema;
this.executor = config.executor;
this.batch = config.batch;
this.batchingOptions = config.batchingOptions;
this.createProxyingResolver = config.createProxyingResolver;
this.transforms = config.transforms ?? [];
this.merge = config.merge;
}
get transformedSchema() {
if (!this._transformedSchema) {
if (globalThis.process?.env?.["DEBUG"] != null) {
console.warn(
"Transformed schema is not set yet. Returning a dummy one."
);
}
this._transformedSchema = applySchemaTransforms(this.schema, this);
}
return this._transformedSchema;
}
set transformedSchema(value) {
this._transformedSchema = value;
}
}
const prototypePollutingKeys = [
"__proto__",
"constructor",
"prototype"
];
function isPrototypePollutingKey(key) {
return prototypePollutingKeys.includes(key);
}
const leftOverByDelegationPlan = /* @__PURE__ */ new WeakMap();
const PLAN_LEFT_OVER = Symbol("PLAN_LEFT_OVER");
function getPlanLeftOverFromParent(parent) {
if (parent != null && typeof parent === "object") {
return parent[PLAN_LEFT_OVER];
}
return void 0;
}
const UNPATHED_ERRORS_SYMBOL = Symbol.for("subschemaErrors");
const OBJECT_SUBSCHEMA_SYMBOL = Symbol.for("initialSubschema");
const FIELD_SUBSCHEMA_MAP_SYMBOL = Symbol.for("subschemaMap");
function isExternalObject(data) {
return data[UNPATHED_ERRORS_SYMBOL] !== void 0;
}
function annotateExternalObject(object, errors, subschema, subschemaMap) {
Object.defineProperties(object, {
[OBJECT_SUBSCHEMA_SYMBOL]: { value: subschema, writable: true },
[FIELD_SUBSCHEMA_MAP_SYMBOL]: { value: subschemaMap, writable: true },
[UNPATHED_ERRORS_SYMBOL]: { value: errors, writable: true }
});
return object;
}
function getSubschema(object, responseKey) {
return object[FIELD_SUBSCHEMA_MAP_SYMBOL]?.[responseKey] ?? object[OBJECT_SUBSCHEMA_SYMBOL];
}
function getUnpathedErrors(object) {
return object[UNPATHED_ERRORS_SYMBOL];
}
const EMPTY_ARRAY = [];
const EMPTY_OBJECT = /* @__PURE__ */ Object.create(null);
const getActualFieldNodes = memoize1(function(fieldNode) {
return [fieldNode];
});
function mergeFields(mergedTypeInfo, object, sourceSubschema, context, info) {
const delegationMaps = mergedTypeInfo.delegationPlanBuilder(
info.schema,
sourceSubschema,
info.variableValues != null && Object.keys(info.variableValues).length > 0 ? info.variableValues : EMPTY_OBJECT,
info.fragments != null && Object.keys(info.fragments).length > 0 ? info.fragments : EMPTY_OBJECT,
info.fieldNodes?.length ? info.fieldNodes.length === 1 && info.fieldNodes[0] ? getActualFieldNodes(info.fieldNodes[0]) : info.fieldNodes : EMPTY_ARRAY,
context,
info
);
const leftOver = leftOverByDelegationPlan.get(delegationMaps);
if (leftOver) {
object[PLAN_LEFT_OVER] = leftOver;
}
return handleMaybePromise(
() => promiseReduce(
delegationMaps,
(_, delegationMap) => executeDelegationStage(
mergedTypeInfo,
delegationMap,
object,
context,
info
),
void 0
),
() => object
);
}
function handleResolverResult(resolverResult, subschema, selectionSet, object, combinedFieldSubschemaMap, info, path, combinedErrors) {
if (resolverResult instanceof Error || resolverResult == null) {
const schema = subschema.transformedSchema || info.schema;
const type = schema.getType(object.__typename);
const { fields } = collectFields(
schema,
info.fragments,
info.variableValues,
type,
selectionSet
);
const nullResult = {};
for (const [responseKey, fieldNodes] of fields) {
const combinedPath = [...path, responseKey];
if (resolverResult instanceof GraphQLError) {
if (resolverResult.message.includes(
"Cannot return null for non-nullable field"
)) {
nullResult[responseKey] = null;
} else {
nullResult[responseKey] = relocatedError(
resolverResult,
combinedPath
);
}
} else if (resolverResult instanceof Error) {
nullResult[responseKey] = locatedError(
resolverResult,
fieldNodes,
combinedPath
);
} else {
nullResult[responseKey] = null;
}
}
resolverResult = nullResult;
} else {
if (resolverResult[UNPATHED_ERRORS_SYMBOL]) {
combinedErrors.push(...resolverResult[UNPATHED_ERRORS_SYMBOL]);
}
}
const objectSubschema = resolverResult[OBJECT_SUBSCHEMA_SYMBOL];
const fieldSubschemaMap = resolverResult[FIELD_SUBSCHEMA_MAP_SYMBOL];
for (const responseKey in resolverResult) {
if (isPrototypePollutingKey(responseKey)) {
continue;
}
const existingPropValue = object[responseKey];
const sourcePropValue = resolverResult[responseKey];
if (responseKey === "__typename" && existingPropValue !== sourcePropValue && isAbstractType(subschema.transformedSchema.getType(sourcePropValue))) {
continue;
}
if (sourcePropValue != null || existingPropValue == null) {
if (existingPropValue != null && typeof existingPropValue === "object" && !(existingPropValue instanceof Error) && Object.keys(existingPropValue).length > 0) {
if (Array.isArray(existingPropValue) && Array.isArray(sourcePropValue) && existingPropValue.length === sourcePropValue.length) {
object[responseKey] = existingPropValue.map(
(existingElement, index) => sourcePropValue instanceof Error ? existingElement : mergeDeep(
[existingElement, sourcePropValue[index]],
void 0,
true,
true
)
);
} else if (!(sourcePropValue instanceof Error)) {
object[responseKey] = mergeDeep(
[existingPropValue, sourcePropValue],
void 0,
true,
true
);
}
} else {
object[responseKey] = sourcePropValue;
}
}
combinedFieldSubschemaMap[responseKey] = fieldSubschemaMap?.[responseKey] ?? objectSubschema ?? subschema;
}
}
function executeDelegationStage(mergedTypeInfo, delegationMap, object, context, info) {
const combinedErrors = object[UNPATHED_ERRORS_SYMBOL];
const path = pathToArray(info.path);
const combinedFieldSubschemaMap = object[FIELD_SUBSCHEMA_MAP_SYMBOL];
const jobs = [];
for (const [subschema, selectionSet] of delegationMap) {
const schema = subschema.transformedSchema || info.schema;
const type = schema.getType(object.__typename);
const resolver = mergedTypeInfo.resolvers.get(subschema);
if (resolver) {
try {
const resolverResult$ = resolver(
object,
context,
info,
subschema,
selectionSet,
void 0,
type
);
if (isPromise(resolverResult$)) {
jobs.push(
resolverResult$.then(
(resolverResult) => handleResolverResult(
resolverResult,
subschema,
selectionSet,
object,
combinedFieldSubschemaMap,
info,
path,
combinedErrors
),
(error) => handleResolverResult(
error,
subschema,
selectionSet,
object,
combinedFieldSubschemaMap,
info,
path,
combinedErrors
)
)
);
} else {
handleResolverResult(
resolverResult$,
subschema,
selectionSet,
object,
combinedFieldSubschemaMap,
info,
path,
combinedErrors
);
}
} catch (error) {
handleResolverResult(
error,
subschema,
selectionSet,
object,
combinedFieldSubschemaMap,
info,
path,
combinedErrors
);
}
}
}
if (jobs.length) {
if (jobs.length === 1) {
return jobs[0];
}
return Promise.all(jobs);
}
}
function resolveExternalValue(result, unpathedErrors, subschema, context, info, returnType = getReturnType$1(info), skipTypeMerging) {
const type = getNullableType(returnType);
if (result instanceof Error) {
return result;
}
if (result == null) {
return reportUnpathedErrorsViaNull(unpathedErrors);
}
if (isLeafType(type)) {
try {
return type.parseValue(result);
} catch {
return null;
}
} else if (isCompositeType(type)) {
return handleMaybePromise(
() => resolveExternalObject(
type,
result,
unpathedErrors,
subschema,
context,
info,
skipTypeMerging
),
(result2) => {
if (info && isAbstractType(type)) {
if (result2.__typename != null) {
const resolvedType = info.schema.getType(result2.__typename);
if (!resolvedType) {
return null;
}
}
return result2;
}
return result2;
}
);
} else if (isListType(type)) {
if (Array.isArray(result)) {
return resolveExternalList(
type,
result,
unpathedErrors,
subschema,
context,
info,
skipTypeMerging
);
}
return resolveExternalValue(
result,
unpathedErrors,
subschema,
context,
info,
type.ofType,
skipTypeMerging
);
}
}
function resolveExternalObject(type, object, unpathedErrors, subschema, context, info, skipTypeMerging) {
if (!isExternalObject(object)) {
annotateExternalObject(
object,
unpathedErrors,
subschema,
/* @__PURE__ */ Object.create(null)
);
}
if (skipTypeMerging || info == null) {
return object;
}
const stitchingInfo = info.schema.extensions?.["stitchingInfo"];
if (stitchingInfo == null) {
return object;
}
let mergedTypeInfo;
const possibleTypeNames = [object.__typename, type.name];
for (const possibleTypeName of possibleTypeNames) {
if (possibleTypeName != null && stitchingInfo.mergedTypes[possibleTypeName]?.targetSubschemas?.get(
subschema
)?.length) {
mergedTypeInfo = stitchingInfo.mergedTypes[possibleTypeName];
break;
}
}
if (!mergedTypeInfo) {
return object;
}
return mergeFields(
mergedTypeInfo,
object,
subschema,
context,
info
);
}
function resolveExternalList(type, list, unpathedErrors, subschema, context, info, skipTypeMerging) {
return list.map(
(listMember) => resolveExternalValue(
listMember,
unpathedErrors,
subschema,
context,
info,
type.ofType,
skipTypeMerging
)
);
}
const reportedErrors = /* @__PURE__ */ new WeakMap();
function reportUnpathedErrorsViaNull(unpathedErrors) {
if (unpathedErrors.length) {
const unreportedErrors = [];
for (const error of unpathedErrors) {
if (!reportedErrors.has(error)) {
unreportedErrors.push(error);
reportedErrors.set(error, true);
}
}
if (unreportedErrors.length) {
const unreportedError = unreportedErrors[0];
if (unreportedErrors.length === 1 && unreportedError) {
return locatedError(
unreportedError,
void 0,
unreportedError.path
);
}
return new AggregateError(
unreportedErrors.map(
(e) => (
// We cast path as any for GraphQL.js 14 compat
// locatedError path argument must be defined, but it is just forwarded to a constructor that allows a undefined value
// https://github.com/graphql/graphql-js/blob/b4bff0ba9c15c9d7245dd68556e754c41f263289/src/error/locatedError.js#L25
// https://github.com/graphql/graphql-js/blob/b4bff0ba9c15c9d7245dd68556e754c41f263289/src/error/GraphQLError.js#L19
locatedError(e, void 0, unreportedError?.path)
)
),
unreportedErrors.map((error) => error.message).join(", \n")
);
}
}
return null;
}
function getReturnType$1(info) {
if (info == null) {
throw new Error(`Return type cannot be inferred without a source schema.`);
}
return info.returnType;
}
function checkResultAndHandleErrors(result = {
data: null,
errors: []
}, delegationContext) {
const {
context,
info,
fieldName: responseKey = getResponseKey(info),
subschema,
returnType = getReturnType(info),
skipTypeMerging,
onLocatedError
} = delegationContext;
const { data, unpathedErrors } = mergeDataAndErrors(
result.data == null ? void 0 : result.data[responseKey],
result.errors == null ? [] : result.errors,
info != null && info.path ? responsePathAsArray(info.path) : void 0,
onLocatedError
);
return resolveExternalValue(
data,
unpathedErrors,
subschema,
context,
info,
returnType,
skipTypeMerging
);
}
function mergeDataAndErrors(data, errors, path, onLocatedError, index = 1) {
if (data == null) {
if (!errors.length) {
return { data: null, unpathedErrors: [] };
}
if (errors.length === 1 && errors[0]) {
const error = onLocatedError ? onLocatedError(errors[0]) : errors[0];
const newPath = path === void 0 ? error.path : !error.path ? path : path.concat(error.path.slice(1));
return { data: relocatedError(errors[0], newPath), unpathedErrors: [] };
}
const combinedError = new AggregateError(
errors.map(
(e) => (
// We cast path as any for GraphQL.js 14 compat
// locatedError path argument must be defined, but it is just forwarded to a constructor that allows a undefined value
// https://github.com/graphql/graphql-js/blob/b4bff0ba9c15c9d7245dd68556e754c41f263289/src/error/locatedError.js#L25
// https://github.com/graphql/graphql-js/blob/b4bff0ba9c15c9d7245dd68556e754c41f263289/src/error/GraphQLError.js#L19
locatedError(e, void 0, path)
)
),
errors.map((error) => error.message).join(", \n")
);
return { data: combinedError, unpathedErrors: [] };
}
if (!errors.length) {
return { data, unpathedErrors: [] };
}
const unpathedErrors = [];
const errorMap = /* @__PURE__ */ new Map();
for (const error of errors) {
const pathSegment = error.path?.[index];
if (pathSegment != null) {
let pathSegmentErrors = errorMap.get(pathSegment);
if (pathSegmentErrors === void 0) {
pathSegmentErrors = [error];
errorMap.set(pathSegment, pathSegmentErrors);
} else {
pathSegmentErrors.push(error);
}
} else {
unpathedErrors.push(error);
}
}
for (const [pathSegment, pathSegmentErrors] of errorMap) {
if (data[pathSegment] !== void 0) {
const { data: newData, unpathedErrors: newErrors } = mergeDataAndErrors(
data[pathSegment],
pathSegmentErrors,
path,
onLocatedError,
index + 1
);
data[pathSegment] = newData;
unpathedErrors.push(...newErrors);
} else {
unpathedErrors.push(...pathSegmentErrors);
}
}
return { data, unpathedErrors };
}
function getResponseKey(info) {
if (info == null) {
throw new Error(
`Data cannot be extracted from result without an explicit key or source schema.`
);
}
return getResponseKeyFromInfo(info);
}
function getReturnType(info) {
if (info == null) {
throw new Error(`Return type cannot be inferred without a source schema.`);
}
return info.returnType;
}
function getDocumentMetadata(document) {
const operations = [];
const fragments = [];
const fragmentNames = /* @__PURE__ */ new Set();
for (let i = 0; i < document.definitions.length; i++) {
const def = document.definitions[i];
if (def?.kind === Kind.FRAGMENT_DEFINITION) {
fragments.push(def);
fragmentNames.add(def.name.value);
} else if (def?.kind === Kind.OPERATION_DEFINITION) {
operations.push(def);
}
}
return {
operations,
fragments,
fragmentNames
};
}
const getTypeInfo = memoize1(function getTypeInfo2(schema) {
return new TypeInfo(schema);
});
const getTypeInfoWithType = memoize2(function getTypeInfoWithType2(schema, type) {
return versionInfo.major < 16 ? new TypeInfo(schema, void 0, type) : new TypeInfo(schema, type);
});
function updateArgument(argumentNodes, variableDefinitionsMap, variableValues, argName, varName, type, value) {
argumentNodes[argName] = {
kind: Kind.ARGUMENT,
name: {
kind: Kind.NAME,
value: argName
},
value: {
kind: Kind.VARIABLE,
name: {
kind: Kind.NAME,
value: varName
}
}
};
variableDefinitionsMap[varName] = {
kind: Kind.VARIABLE_DEFINITION,
variable: {
kind: Kind.VARIABLE,
name: {
kind: Kind.NAME,
value: varName
}
},
type: astFromType(type)
};
if (value !== void 0) {
variableValues[varName] = value;
return;
}
if (varName in variableValues) {
delete variableValues[varName];
}
}
function createVariableNameGenerator(variableDefinitionMap) {
let varCounter = 0;
return (argName) => {
let varName;
do {
varName = varCounter === 0 ? argName : `_v${varCounter.toString()}_${argName}`;
varCounter++;
} while (varName in variableDefinitionMap);
return varName;
};
}
function finalizeGatewayDocument(targetSchema, fragments, operations, onOverlappingAliases, delegationContext) {
let usedVariables = [];
let usedFragments = [];
const newOperations = [];
let newFragments = [];
const validFragments = [];
const validFragmentsWithType = /* @__PURE__ */ Object.create(null);
for (const fragment of fragments) {
const typeName = fragment.typeCondition.name.value;
const type = targetSchema.getType(typeName);
if (type != null) {
validFragments.push(fragment);
validFragmentsWithType[fragment.name.value] = type;
}
}
let fragmentSet = /* @__PURE__ */ Object.create(null);
for (const operation of operations) {
const type = getDefinedRootType(targetSchema, operation.operation);
const {
selectionSet,
usedFragments: operationUsedFragments,
usedVariables: operationUsedVariables
} = finalizeSelectionSet(
targetSchema,
type,
validFragmentsWithType,
operation.selectionSet,
onOverlappingAliases
);
usedFragments = union(usedFragments, operationUsedFragments);
const {
usedVariables: collectedUsedVariables,
newFragments: collectedNewFragments,
fragmentSet: collectedFragmentSet
} = collectFragmentVariables(
targetSchema,
fragmentSet,
validFragments,
validFragmentsWithType,
usedFragments,
onOverlappingAliases
);
const operationOrFragmentVariables = union(
operationUsedVariables,
collectedUsedVariables
);
usedVariables = union(usedVariables, operationOrFragmentVariables);
newFragments = collectedNewFragments;
fragmentSet = collectedFragmentSet;
const variableDefinitions = (operation.variableDefinitions ?? []).filter(
(variable) => operationOrFragmentVariables.indexOf(variable.variable.name.value) !== -1
);
if (operation.operation === "subscription") {
selectionSet.selections = selectionSet.selections.filter(
(selection) => selection.kind !== Kind.FIELD || selection.name.value !== "__typename"
);
}
if (selectionSet.selections.length === 1 && selectionSet.selections[0] && selectionSet.selections[0].kind === Kind.FIELD && selectionSet.selections[0].name.value === "__typename") {
continue;
}
newOperations.push({
kind: Kind.OPERATION_DEFINITION,
operation: operation.operation,
name: operation.name,
directives: operation.directives,
variableDefinitions,
selectionSet
});
}
if (!newOperations.length) {
throw createGraphQLError(
"Failed to create a gateway request. The request must contain at least one operation.",
{
extensions: {
[CRITICAL_ERROR]: true
}
}
);
}
let newDocument = {
kind: Kind.DOCUMENT,
definitions: [...newOperations, ...newFragments]
};
const stitchingInfo = delegationContext.info?.schema?.extensions?.["stitchingInfo"];
if (stitchingInfo != null) {
const typeInfo = getTypeInfo(targetSchema);
newDocument = visit(
newDocument,
visitWithTypeInfo(typeInfo, {
[Kind.FIELD](fieldNode) {
const parentType = typeInfo.getParentType();
if (parentType) {
const parentTypeName = parentType.name;
const typeConfig = stitchingInfo?.mergedTypes?.[parentTypeName];
if (typeConfig) {
const providedSelectionsByField = typeConfig?.providedSelectionsByField?.get(
delegationContext.subschema
);
if (providedSelectionsByField) {
const providedSelection = providedSelectionsByField[fieldNode.name.value];
if (providedSelection) {
return {
...fieldNode,
selectionSet: {
kind: Kind.SELECTION_SET,
selections: [
...providedSelection.selections,
...fieldNode.selectionSet?.selections ?? []
]
}
};
}
}
}
}
return fieldNode;
}
})
);
}
return {
usedVariables,
newDocument
};
}
function finalizeGatewayRequest(originalRequest, delegationContext, onOverlappingAliases) {
let { document, variables } = originalRequest;
let { operations, fragments } = getDocumentMetadata(document);
const { targetSchema, args } = delegationContext;
if (args) {
const requestWithNewVariables = addVariablesToRootFields(
targetSchema,
operations,
args
);
operations = requestWithNewVariables.newOperations;
variables = Object.assign(
{},
variables ?? {},
requestWithNewVariables.newVariables
);
}
const { usedVariables, newDocument } = finalizeGatewayDocument(
targetSchema,
fragments,
operations,
onOverlappingAliases,
delegationContext
);
const newVariables = {};
if (variables != null) {
for (const variableName of usedVariables) {
const variableValue = variables[variableName];
if (variableValue !== void 0) {
newVariables[variableName] = variableValue;
}
}
}
return {
...originalRequest,
document: newDocument,
variables: newVariables
};
}
function isTypeNameField(selection) {
return selection.kind === Kind.FIELD && !selection.alias && selection.name.value === "__typename";
}
function filterTypenameFields(selections) {
let hasTypeNameField = false;
const filteredSelections = selections.filter((selection) => {
if (isTypeNameField(selection)) {
hasTypeNameField = true;
return false;
}
return true;
});
return {
hasTypeNameField,
selections: filteredSelections
};
}
function addVariablesToRootFields(targetSchema, operations, args) {
const newVariables = /* @__PURE__ */ Object.create(null);
const newOperations = operations.map((operation) => {
const variableDefinitionMap = (operation.variableDefinitions ?? []).reduce(
(prev, def) => ({
...prev,
[def.variable.name.value]: def
}),
{}
);
const type = getDefinedRootType(targetSchema, operation.operation);
const newSelections = [];
for (const selection of operation.selectionSet.selections) {
if (selection.kind === Kind.FIELD) {
const argumentNodes = selection.arguments ?? [];
const argumentNodeMap = argumentNodes.reduce(
(prev, argument) => ({
...prev,
[argument.name.value]: argument
}),
{}
);
const targetField = type.getFields()[selection.name.value];
if (targetField != null) {
updateArguments(
targetField,
argumentNodeMap,
variableDefinitionMap,
newVariables,
args
);
}
newSelections.push({
...selection,
arguments: Object.values(argumentNodeMap)
});
} else {
newSelections.push(selection);
}
}
const newSelectionSet = {
kind: Kind.SELECTION_SET,
selections: newSelections
};
return {
...operation,
variableDefinitions: Object.values(variableDefinitionMap),
selectionSet: newSelectionSet
};
});
return {
newOperations,
newVariables
};
}
function updateArguments(targetField, argumentNodeMap, variableDefinitionMap, variableValues, newArgs) {
const generateVariableName = createVariableNameGenerator(
variableDefinitionMap
);
for (const argument of targetField.args) {
const argName = argument.name;
const argType = argument.type;
if (argName in newArgs) {
updateArgument(
argumentNodeMap,
variableDefinitionMap,
variableValues,
argName,
generateVariableName(argName),
argType,
serializeInputValue(argType, newArgs[argName])
);
}
}
}
function collectFragmentVariables(targetSchema, fragmentSet, validFragments, validFragmentsWithType, usedFragments, onOverlappingAliases) {
let remainingFragments = usedFragments.slice();
let usedVariables = [];
const newFragments = [];
while (remainingFragments.length !== 0) {
const nextFragmentName = remainingFragments.pop();
const fragment = validFragments.find(
(fr) => fr.name.value === nextFragmentName
);
if (fragment != null) {
const name = nextFragmentName;
const typeName = fragment.typeCondition.name.value;
const type = targetSchema.getType(typeName);
if (type == null) {
throw new Error(
`Fragment reference type "${typeName}", but the type is not contained within the target schema.`
);
}
const {
selectionSet,
usedFragments: fragmentUsedFragments,
usedVariables: fragmentUsedVariables
} = finalizeSelectionSet(
targetSchema,
type,
validFragmentsWithType,
fragment.selectionSet,
onOverlappingAliases
);
remainingFragments = union(remainingFragments, fragmentUsedFragments);
usedVariables = union(usedVariables, fragmentUsedVariables);
if (name && !(name in fragmentSet)) {
fragmentSet[name] = true;
newFragments.push({
kind: Kind.FRAGMENT_DEFINITION,
name: {
kind: Kind.NAME,
value: name
},
typeCondition: fragment.typeCondition,
selectionSet
});
}
}
}
return {
usedVariables,
newFragments,
fragmentSet
};
}
const filteredSelectionSetVisitorKeys = {
SelectionSet: ["selections"],
Field: ["selectionSet"],
InlineFragment: ["selectionSet"],
FragmentDefinition: ["selectionSet"]
};
const variablesVisitorKeys = {
SelectionSet: ["selections"],
Field: ["arguments", "directives", "selectionSet"],
Argument: ["value"],
InlineFragment: ["directives", "selectionSet"],
FragmentSpread: ["directives"],
FragmentDefinition: ["selectionSet"],
ObjectValue: ["fields"],
ObjectField: ["name", "value"],
Directive: ["arguments"],
ListValue: ["values"]
};
function finalizeSelectionSet(schema, type, validFragments, selectionSet, onOverlappingAliases) {
const usedFragments = [];
const usedVariables = [];
const typeInfo = getTypeInfoWithType(schema, type);
const seenNonNullableMap = /* @__PURE__ */ new WeakMap();
const seenNullableMap = /* @__PURE__ */ new WeakMap();
const filteredSelectionSet = visit(
selectionSet,
visitWithTypeInfo(typeInfo, {
[Kind.FIELD]: {
enter: (node) => {
const parentType = typeInfo.getParentType();
if (isObjectType(parentType) || isInterfaceType(parentType)) {
const field = typeInfo.getFieldDef();
if (!field) {
return null;
}
const args = field.args != null ? field.args : [];
const argsMap = /* @__PURE__ */ Object.create(null);
for (const arg of args) {
argsMap[arg.name] = arg;
}
if (node.arguments != null) {
const newArgs = [];
for (const arg of node.arguments) {
if (arg.name.value in argsMap) {
newArgs.push(arg);
}
}
if (newArgs.length !== node.arguments.length) {
return {
...node,
arguments: newArgs
};
}
}
}
if (isUnionType(parentType) && typeInfo.getType() == null) {
const possibleTypeNames = [];
const fieldName = node.name.value;
for (const memberType of parentType.getTypes()) {
const memberFields = memberType.getFields();
const possibleField = memberFields[fieldName];
if (possibleField != null) {
const namedType = getNamedType(possibleField.type);
if (node.selectionSet?.selections?.length && isLeafType(namedType)) {
continue;
}
if (!node.selectionSet?.selections?.length && isCompositeType(namedType)) {
continue;
}
possibleTypeNames.push(memberType.name);
}
}
if (possibleTypeNames.length > 0) {
return possibleTypeNames.map((possibleTypeName) => ({
kind: Kind.INLINE_FRAGMENT,
typeCondition: {
kind: Kind.NAMED_TYPE,
name: {
kind: Kind.NAME,
value: possibleTypeName
}
},
selectionSet: {
kind: Kind.SELECTION_SET,
selections: [node]
}
}));
}
}
return void 0;
},
leave: (node) => {
const type2 = typeInfo.getType();
if (type2 == null) {
return null;
}
const namedType = getNamedType(type2);
if (schema.getType(namedType.name) == null) {
return null;
}
if (isObjectType(namedType) || isInterfaceType(namedType)) {
const selections = node.selectionSet != null ? node.selectionSet.selections : null;
if (selections == null || selections.length === 0) {
return null;
}
}
return void 0;
}
},
[Kind.FRAGMENT_SPREAD]: {
enter: (node) => {
if (!(node.name.value in validFragments)) {
return null;
}
const parentType = typeInfo.getParentType();
const innerType = validFragments[node.name.value];
if (!implementsAbstractType(schema, parentType, innerType)) {
return null;
}
usedFragments.push(node.name.value);
return void 0;
}
},
[Kind.SELECTION_SET]: {
enter: (node, _key, _parent, _path) => {
const parentType = typeInfo.getParentType();
const { hasTypeNameField, selections } = filterTypenameFields(
node.selections
);
if (hasTypeNameField || parentType != null && isAbstractType(parentType)) {
selections.unshift({
kind: Kind.FIELD,
name: {
kind: Kind.NAME,
value: "__typename"
}
});
}
return {
...node,
selections
};
}
},
[Kind.INLINE_FRAGMENT]: {
enter: (node) => {
if (node.typeCondition != null) {
const parentType = typeInfo.getParentType();
const innerType = schema.getType(node.typeCondition.name.value);
if (isUnionType(parentType) && parentType.getTypes().some((t) => t.name === innerType?.name)) {
return node;
}
if (!implementsAbstractType(schema, parentType, innerType)) {
return null;
}
}
return void 0;
},
leave: (selection, _key, parent) => {
if (!selection.selectionSet?.selections?.length) {
return null;
}
if (Array.isArray(parent)) {
const selectionTypeName = selection.typeCondition?.name.value;
if (selectionTypeName) {
const selectionType = schema.getType(selectionTypeName);
if (selectionType && "getFields" in selectionType) {
const selectionTypeFields = selectionType.getFields();
let seenNonNullable = seenNonNullableMap.get(parent);
if (!seenNonNullable) {
seenNonNullable = /* @__PURE__ */ new Set();
seenNonNullableMap.set(parent, seenNonNullable);
}
let seenNullable = seenNullableMap.get(parent);
if (!seenNullable) {
seenNullable = /* @__PURE__ */ new Set();
seenNullableMap.set(parent, seenNullable);
}
selection = {
...selection,
selectionSet: {
...selection.selectionSet,
selections: selection.selectionSet.selections.map(
(subSelection) => {
if (subSelection.kind === Kind.FIELD) {
const fieldName = subSelection.name.value;
if (!subSelection.alias) {
const field = selectionTypeFields[fieldName];
if (field) {
let currentNullable;
if (isNullableType(field.type)) {
seenNullable.add(fieldName);
currentNullable = true;
} else {
seenNonNullable.add(fieldName);
currentNullable = false;
}
if (seenNullable.has(fieldName) && seenNonNullable.has(fieldName)) {
onOverlappingAliases();
return {
...subSelection,
alias: {
kind: Kind.NAME,
value: currentNullable ? `_nullable_${fieldName}` : `_nonNullable_${fieldName}`
}
};
}
}
}
}
return subSelection;
}
)
}
};
}
}
}
const { selections } = filterTypenameFields(
selection.selectionSet.selections
);
if (selections.length === 0) {
return null;
}
return {
...selection,
selectionSet: {
...selection.selectionSet,
selections
},
// @defer is not available for the communication between the gw and subgraph
directives: selection.directives?.filter?.(
(directive) => directive.name.value !== "defer"
)
};
}
}
}),
// visitorKeys argument usage a la https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-graphql/src/batching/merge-queries.js
// empty keys cannot be removed only because of typescript errors
// will hopefully be fixed in future version of graphql-js to be optional
filteredSelectionSetVisitorKeys
);
visit(
filteredSelectionSet,
{
[Kind.VARIABLE]: (variableNode) => {
usedVariables.push(variableNode.name.value);
}
},
// visitorKeys argument usage a la https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-graphql/src/batching/merge-queries.js
// empty keys cannot be removed only because of typescript errors
// will hopefully be fixed in future version of graphql-js to be optional
variablesVisitorKeys
);
return {
selectionSet: filteredSelectionSet,
usedFragments,
usedVariables
};
}
function union(...arrays) {
const cache = /* @__PURE__ */ Object.create(null);
const result = [];
for (const array of arrays) {
for (const item of array) {
if (!(item in cache)) {
cache[item] = true;
result.push(item);
}
}
}
return result;
}
function prepareGatewayDocument(originalDocument, transformedSchema, returnType, infoSchema) {
const wrappedConcreteTypesDocument = wrapConcreteTypes(
returnType,
transformedSchema,
originalDocument
);
if (infoSchema == null) {
return wrappedConcreteTypesDocument;
}
const visitedSelections = /* @__PURE__ */ new WeakSet();
const {
possibleTypesMap,
reversePossibleTypesMap: reversePossibleTypesMap2,
interfaceExtensionsMap,
fieldNodesByType,
fieldNodesByField,
dynamicSelectionSetsByField
} = getSchemaMetaData(infoSchema, transformedSchema);
const { operations, fragments, fragmentNames } = getDocumentMetadata(
wrappedConcreteTypesDocument
);
const { expandedFragments, fragmentReplacements } = getExpandedFragments(
fragments,
fragmentNames,
possibleTypesMap
);
const typeInfo = getTypeInfo(transformedSchema);
const expandedDocument = {
kind: Kind.DOCUMENT,
definitions: [...operations, ...fragments, ...expandedFragments]
};
const visitorKeyMap = {
Document: ["definitions"],
OperationDefinition: ["selectionSet"],
SelectionSet: ["selections"],
Field: ["selectionSet"],
InlineFragment: ["selectionSet"],
FragmentDefinition: ["selectionSet"]
};
return visit(
expandedDocument,
visitWithTypeInfo(typeInfo, {
[Kind.SELECTION_SET]: (node) => visitSelectionSet(
node,
fragmentReplacements,
transformedSchema,
typeInfo,
possibleTypesMap,
reversePossibleTypesMap2,
interfaceExtensionsMap,
fieldNodesByType,
fieldNodesByField,
dynamicSelectionSetsByField,
infoSchema,
visitedSelections
)
}),
// visitorKeys argument usage a la https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-graphql/src/batching/merge-queries.js
// empty keys cannot be removed only because of typescript errors
// will hopefully be fixed in future version of graphql-js to be optional
visitorKeyMap
);
}
const getExtraPossibleTypesFn = memoize2(function getExtraPossibleTypes(transformedSchema, infoSchema) {
const extraPossiblesTypesMap = /* @__PURE__ */ new Map();
return function getExtraPossibleTypes2(typeName) {
let extraTypesForSubschema = extraPossiblesTypesMap.get(typeName);
if (!extraTypesForSubschema) {
extraTypesForSubschema = /* @__PURE__ */ new Set();
const gatewayType = infoSchema.getType(typeName);
const subschemaType = transformedSchema.getType(typeName);
if (isAbstractType(gatewayType) && isAbstractType(subschemaType)) {
const possibleTypes = infoSchema.getPossibleTypes(gatewayType);
const possibleTypesInSubschema = transformedSchema.getPossibleTypes(subschemaType);
for (const possibleType of possibleTypes) {
const possibleTypeInSubschema = transformedSchema.getType(
possibleType.name
);
if (!possibleTypeInSubschema) {
continue;
}
if (possibleTypeInSubschema && possibleTypesInSubschema.some((t) => t.name === possibleType.name)) {
continue;
}
extraTypesForSubschema.add(possibleType.name);
}
}
extraPossiblesTypesMap.set(typeName, extraTypesForSubschema);
}
return extraTypesForSubschema;
};
});
function visitSelectionSet(node, fragmentReplacements, transformedSchema, typeInfo, possibleTypesMap, reversePossibleTypesMap2, interfaceExtensionsMap, fieldNodesByType, fieldNodesByField, dynamicSelectionSetsByField, infoSchema, visitedSelections) {
const newSelections = /* @__PURE__ */ new Set();
const maybeType = typeInfo.getParentType();
if (maybeType != null) {
const parentType = getNamedType(maybeType);
const parentTypeName = parentType.name;
const fieldNodes = fieldNodesByType[parentTypeName];
if (fieldNodes) {
for (const fieldNode of fieldNodes) {
newSelections.add(fieldNode);
}
}
const interfaceExtensions = interfaceExtensionsMap[parentType.name];
const interfaceExtensionFields = [];
for (const selection of node.selections) {
if (selection.kind === Kind.INLINE_FRAGMENT) {
if (selection.typeCondition != null) {
if (!visitedSelections.has(selection)) {
visitedSelections.add(selection);
const typeName = selection.typeCondition.name.value;
const getExtraPossibleTypes2 = getExtraPossibleTypesFn(
transformedSchema,
infoSchema
);
const extraPossibleTypes = getExtraPossibleTypes2(typeName);
for (const extraPossibleTypeName of extraPossibleTypes) {
newSelections.add({
...selection,
typeCondition: {
kind: Kind.NAMED_TYPE,
name: {
kind: Kind.NAME,
value: extraPossibleTypeName
}
}
});
}
const typeInSubschema = transformedSchema.getType(typeName);
if (isObjectType(typeInSubschema) || isInterfaceType(typeInSubschema)) {
const fieldMap = typeInSubschema.getFields();
for (const subSelection of selection.selectionSet.selections) {
if (subSelection.kind === Kind.FIELD) {
const fieldName = subSelection.name.value;
const field = fieldMap[fieldName];
if (!field) {
newSelections.add(subSelection);
}
}
}
} else if (!typeInSubschema) {
for (const subSelection of selection.selectionSet.selections) {
newSelections.add(subSelection);
}
}
}
const possibleTypes = possibleTypesMap[selection.typeCondition.name.value];
if (possibleTypes == null) {
const fieldNodesForTypeName = fieldNodesByField[parentTypeName]?.["__typename"];
if (fieldNodesForTypeName) {
for (const fieldNode of fieldNodesForTypeName) {
newSelections.add(fieldNode);
}
}
newSelections.add(selection);
continue;
}
for (const possibleTypeName of possibleTypes) {
const maybePossibleType = transformedSchema.getType(possibleTypeName);
if (maybePossibleType != null && implementsAbstractType(
transformedSchema,
parentType,
maybePossibleType
)) {
newSelections.add(
generateInlineFragment(
possibleTypeName,
selection.selectionSet
)
);
}
}
if (possibleTypes.length === 0) {
newSelections.add(selection);
}
} else {
newSelections.add(selection);
}
} else if (selection.kind === Kind.FRAGMENT_SPREAD) {
const fragmentName = selection.name.value;
if (!fragmentReplacements[fragmentName]) {
newSelections.add(selection);
continue;
}
for (const replacement of fragmentReplacements[fragmentName]) {
const typeName = replacement.typeName;
const maybeReplacementType = transformedSchema.getType(typeName);
if (maybeReplacementType != null && implementsAbstractType(transformedSchema, parentType, maybeType)) {
newSelections.add({
kind: Kind.FRAGMENT_SPREAD,
name: {
kind: Kind.NAME,
value: replacement.fragmentName
}
});
}
}
} else {
const fieldName = selection.name.value;
if (isAbstractType(parentType)) {
const fieldNodesForTypeName = fieldNodesByField[parentTypeName]?.["__typename"];
if (fieldNodesForTypeName) {
for (const fieldNode of fieldNodesForTypeName) {
newSelections.add(fieldNode);
}
}
}
const fieldNodesMapForType = fieldNodesByField[parentTypeName];
if (fieldNodesMapForType) {
addDependenciesNestedly(
selection,
/* @__PURE__ */ new Set(),
fieldNodesMapForType,
newSelections
);
}
const dynamicSelectionSets = dynamicSelectionSetsByField[parentTypeName]?.[fieldName];
if (dynamicSelectionSets != null) {
for (const selectionSetFn of dynamicSelectionSets) {
const selectionSet = selectionSetFn(selection);
if (selectionSet != null) {
for (const selection2 of selectionSet.selections) {
newSelections.add(selection2);
}
}
}
}
if (interfaceExtensions?.[fieldName]) {
interfaceExtensionFields.push(selection);
} else {
newSelections.add(selection);
}
}
}
if (reversePossibleTypesMap2[parentType.name]) {
newSelections.add({
kind: Kind.FIELD,
name: {
kind: Kind.NAME,
value: "__typename"
}
});
}
if (interfaceExtensionFields.length) {
const possibleTypes = possibleTypesMap[parentType.name];
if (possibleTypes != null) {
for (const possibleType of possibleTypes) {
newSelections.add(
generateInlineFragment(possibleType, {
kind: Kind.SELECTION_SET,
selections: interfaceExtensionFields
})
);
}
}
}
return {
...node,
selections: Array.from(newSelections)
};
}
return node;
}
function addDependenciesNestedly(fieldNode, seenFieldNames, fieldNodesByField, newSelections) {
if (seenFieldNames.has(fieldNode.name.value)) {
return;
}
seenFieldNames.add(fieldNode.name.value);
const fieldNodes = fieldNodesByField[fieldNode.name.value];
if (fieldNodes != null) {
for (const nestedFieldNode of fieldNodes) {
newSelections.add(nestedFieldNode);
addDependenciesNestedly(
nestedFieldNode,
seenFieldNames,
fieldNodesByField,
newSelections
);
}
}
}
function generateInlineFragment(typeName, selectionSet) {
return {
kind: Kind.INLINE_FRAGMENT,
typeCondition: {
kind: Kind.NAMED_TYPE,
name: {
kind: Kind.NAME,
value: typeName
}
},
selectionSet
};
}
const getSchemaMetaData = memoize2(
(sourceSchema, targetSchema) => {
const typeMap = sourceSchema.getTypeMap();
const targetTypeMap = targetSchema.getTypeMap();
const possibleTypesMap = /* @__PURE__ */ Object.create(null);
const interfaceExtensionsMap = /* @__PURE__ */ Object.create(null);
for (const typeName in typeMap) {
const type = typeMap[typeName];
if (isAbstractType(type)) {
const targetType = targetTypeMap[typeName];
if (isInterfaceType(type) && isInterfaceType(targetType)) {
const targetTypeFields = targetType.getFields();
const sourceTypeFields = type.getFields();
const extensionFields = /* @__PURE__ */ Object.create(null);
let isExtensionFieldsEmpty = true;
for (const fieldName in sourceTypeFields) {
if (!targetTypeFields[fieldName]) {
extensionFields[fieldName] = true;
isExtensionFieldsEmpty = false;
}
}
if (!isExtensionFieldsEmpty) {
interfaceExtensionsMap[typeName] = extensionFields;
}
}
if (interfaceExtensionsMap[typeName] || !isAbstractType(targetType)) {
const implementations = sourceSchema.getPossibleTypes(type);
possibleTypesMap[typeName] = [];
for (const impl of implementations) {
if (targetTypeMap[impl.name]) {
possibleTypesMap[typeName].push(impl.name);
}
}
}
}
}
const stitchingInfo = sourceSchema.extensions?.["stitchingInfo"];
return {
possibleTypesMap,
reversePossibleTypesMap: reversePossibleTypesMap(possibleTypesMap),
interfaceExtensionsMap,
fieldNodesByType: stitchingInfo?.fieldNodesByType ?? {},
fieldNodesByField: stitchingInfo?.fieldNodesByField ?? {},
dynamicSelectionSetsByField: stitchingInfo?.dynamicSelectionSetsByField ?? {}
};
}
);
function reversePossibleTypesMap(possibleTypesMap) {
const result = /* @__PURE__ */ Object.create(null);
for (const typeName in possibleTypesMap) {
const toTypeNames = possibleTypesMap[typeName];
if (toTypeNames) {
for (const toTypeName of toTypeNames) {
if (!result[toTypeName]) {
result[toTypeName] = [];
}
result[toTypeName].push(typeName);
}
}
}
return result;
}
function getExpandedFragments(fragments, fragmentNames, possibleTypesMap) {
let fragmentCounter = 0;
function generateFragmentName(typeName) {
let fragmentName;
do {
fragmentName = `_${typeName}_Fragment${fragmentCounter.toString()}`;
fragmentCounter++;
} while (fragmentNames.has(fragmentName));
return fragmentName;
}
const expandedFragments = [];
const fragmentReplacements = /* @__PURE__ */ Object.create(null);
for (const fragment of fragments) {
const possibleTypes = possibleTypesMap[fragment.typeCondition.name.value];
if (possibleTypes != null) {
const fragmentName = fragment.name.value;
fragmentReplacements[fragmentName] = [];
for (const possibleTypeName of possibleTypes) {
const name = generateFragmentName(possibleTypeName);
fragmentNames.add(name);
expandedFragments.push({
kind: Kind.FRAGMENT_DEFINITION,
name: {
kind: Kind.NAME,
value: name
},
typeCondition: {
kind: Kind.NAMED_TYPE,
name: {
kind: Kind.NAME,
value: possibleTypeName
}
},
selectionSet: fragment.selectionSet
});
fragmentReplacements[fragmentName].push({
fragmentName: name,
typeName: possibleTypeName
});
}
}
}
return {
expandedFragments,
fragmentReplacements
};
}
function wrapConcreteTypes(returnType, targetSchema, document) {
const namedType = getNamedType(returnType);
if (isLeafType(namedType)) {
return document;
}
let possibleTypes = isAbstractType(
namedType
) ? targetSchema.getPossibleTypes(namedType) : [namedType];
if (possibleTypes.length === 0) {
possibleTypes = [namedType];
}
const rootTypeNames = getRootTypeNames(targetSchema);
const typeInfo = getTypeInfo(targetSchema);
const visitorKeys = {
Document: ["definitions"],
OperationDefinition: ["selectionSet"],
SelectionSet: ["selections"],
InlineFragment: ["selectionSet"],
FragmentDefinition: ["selectionSet"]
};
return visit(
document,
visitWithTypeInfo(typeInfo, {
[Kind.FRAGMENT_DEFINITION]: (node) => {
const typeName = node.typeCondition.name.value;
if (!rootTypeNames.has(typeName)) {
return false;
}
return void 0;
},
[Kind.FIELD]: (node) => {
const fieldType = typeInfo.getType();
if (fieldType) {
const fieldNamedType = getNamedType(fieldType);
if (isAbstractType(fieldNamedType) && fieldNamedType.name !== namedType.name && possibleTypes.length > 0) {
return {
...node,
selectionSet: {
kind: Kind.SELECTION_SET,
selections: possibleTypes.map((possibleType) => ({
kind: Kind.INLINE_FRAGMENT,
typeCondition: {
kind: Kind.NAMED_TYPE,
name: {
kind: Kind.NAME,
value: possibleType.name
}
},
selectionSet: node.selectionSet
}))
}
};
}
}
return void 0;
}
}),
// visitorKeys argument usage a la https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-graphql/src/batching/merge-queries.js
// empty keys cannot be removed only because of typescript errors
// will hopefully be fixed in future version of graphql-js to be optional
visitorKeys
);
}
class Transformer {
transformations = [];
delegationContext;
hasOverlappingAliases = false;
constructor(context) {
this.delegationContext = context;
const transforms = context.transforms;
const delegationTransforms = transforms.slice().reverse();
for (const transform of delegationTransforms) {
this.addTransform(transform);
}
}
addTransform(transform, context = {}) {
this.transformations.push({ transform, context });
}
transformRequest(originalRequest) {
let request = {
...originalRequest,
document: prepareGatewayDocument(
originalRequest.document,
this.delegationContext.transformedSchema,
this.delegationContext.returnType,
this.delegationContext.info?.schema
)
};
for (const transformation of this.transformations) {
if (transformation.transform.transformRequest) {
request = transformation.transform.transformRequest(
request,
this.delegationContext,
transformation.context
);
}
}
return finalizeGatewayRequest(request, this.delegationContext, () => {
this.hasOverlappingAliases = true;
});
}
transformResult(originalResult) {
let result = originalResult;
for (let i = this.transformations.length - 1; i >= 0; i--) {
const transformation = this.transformations[i];
if (transformation?.transform.transformResult) {
result = transformation.transform.transformResult(
result,
this.delegationContext,
transformation.context
);
}
}
if (this.hasOverlappingAliases) {
result = removeOverlappingAliases(result);
}
return checkResultAndHandleErrors(result, this.delegationContext);
}
}
function removeOverlappingAliases(result) {
if (result != null) {
if (Array.isArray(result)) {
return result.map(removeOverlappingAliases);
} else if (typeof result === "object") {
const newResult = {};
for (const key in result) {
if (key.startsWith("_nullable_") || key.startsWith("_nonNullable_")) {
const newKey = key.replace(/^_nullable_/, "").replace(/^_nonNullable_/, "");
newResult[newKey] = removeOverlappingAliases(result[key]);
} else {
newResult[key] = removeOverlappingAliases(result[key]);
}
}
return newResult;
}
}
return result;
}
function getDelegatingOperation(parentType, schema) {
if (parentType === schema.getMutationType()) {
return "mutation";
} else if (parentType === schema.getSubscriptionType()) {
return "subscription";
}
return "query";
}
function createRequest({
sourceSchema,
sourceParentType,
sourceFieldName,
fragments,
variableDefinitions,
variableValues,
targetRootValue,
targetOperationName,
targetOperation,
targetFieldName,
selectionSet,
fieldNodes,
context,
info
}) {
let newSelectionSet;
const argumentNodeMap = /* @__PURE__ */ Object.create(null);
if (selectionSet != null) {
newSelectionSet = selectionSet;
} else {
const selections = [];
for (const fieldNode2 of fieldNodes || []) {
if (fieldNode2.selectionSet) {
for (const selection of fieldNode2.selectionSet.selections) {
selections.push(selection);
}
}
}
newSelectionSet = selections.length ? {
kind: Kind.SELECTION_SET,
selections
} : void 0;
const args = fieldNodes?.[0]?.arguments;
if (args) {
for (const argNode of args) {
argumentNodeMap[argNode.name.value] = argNode;
}
}
}
const newVariables = /* @__PURE__ */ Object.create(null);
const variableDefinitionMap = /* @__PURE__ */ Object.create(null);
if (sourceSchema != null && variableDefinitions != null) {
for (const def of variableDefinitions) {
const varName = def.variable.name.value;
variableDefinitionMap[varName] = def;
const varType = typeFromAST(
sourceSchema,
def.type
);
const serializedValue = serializeInputValue(
varType,
variableValues?.[varName]
);
if (serializedValue !== void 0) {
newVariables[varName] = serializedValue;
}
}
}
if (sourceParentType != null && sourceFieldName != null) {
updateArgumentsWithDefaults(
sourceParentType,
sourceFieldName,
argumentNodeMap,
variableDefinitionMap,
newVariables
);
}
const fieldNode = fieldNodes?.[0];
const rootFieldName = targetFieldName ?? fieldNode?.name.value;
if (rootFieldName === void 0) {
throw new Error(
`Either "targetFieldName" or a non empty "fieldNodes" array must be provided.`
);
}
const rootfieldNode = {
kind: Kind.FIELD,
arguments: Object.values(argumentNodeMap),
name: {
kind: Kind.NAME,
value: rootFieldName
},
selectionSet: newSelectionSet,
directives: fieldNode?.directives
};
const operationName = targetOperationName ? {
kind: Kind.NAME,
value: targetOperationName
} : void 0;
const operationDefinition = {
kind: Kind.OPERATION_DEFINITION,
name: operationName,
operation: targetOperation,
variableDefinitions: Object.values(variableDefinitionMap),
selectionSet: {
kind: Kind.SELECTION_SET,
selections: [rootfieldNode]
}
};
const definitions = [operationDefinition];
if (fragments != null) {
for (const fragmentName in fragments) {
const fragment = fragments[fragmentName];
if (fragment) {
definitions.push(fragment);
}
}
}
const document = {
kind: Kind.DOCUMENT,
definitions
};
return {
document,
variables: newVariables,
rootValue: targetRootValue,
operationName: targetOperationName,
context,
info,
operationType: targetOperation
};
}
function updateArgumentsWithDefaults(sourceParentType, sourceFieldName, argumentNodeMap, variableDefinitionMap, variableValues) {
const generateVariableName = createVariableNameGenerator(
variableDefinitionMap
);
const sourceField = sourceParentType.getFields()[sourceFieldName];
if (!sourceField) {
throw new Error(
`Field "${sourceFieldName}" was not found in type "${sourceParentType}".`
);
}
for (const argument of sourceField.args) {
const argName = argument.name;
const sourceArgType = argument.type;
if (argumentNodeMap[argName] === void 0) {
const defaultValue = argument.defaultValue;
if (defaultValue !== void 0) {
updateArgument(
argumentNodeMap,
variableDefinitionMap,
variableValues,
argName,
generateVariableName(argName),
sourceArgType,
serializeInputValue(sourceArgType, defaultValue)
);
}
}
}
}
function defaultMergedResolver(parent, args, context, info) {
if (!parent) {
return null;
}
const responseKey = getResponseKeyFromInfo(info);
if (!isExternalObject(parent)) {
return defaultFieldResolver(parent, args, context, info);
}
if (!Object.prototype.hasOwnProperty.call(parent, responseKey)) {
const leftOver = getPlanLeftOverFromParent(parent);
if (leftOver) {
let missingFieldNodes = leftOver.missingFieldsParentMap.get(parent);
if (!missingFieldNodes) {
missingFieldNodes = [];
leftOver.missingFieldsParentMap.set(parent, missingFieldNodes);
}
missingFieldNodes.push(
...info.fieldNodes.filter(
(fieldNode) => leftOver.unproxiableFieldNodes.some(
(unproxiableFieldNode) => unproxiableFieldNode === fieldNode
)
)
);
let missingDeferredFields = leftOver.missingFieldsParentDeferredMap.get(parent);
if (!missingDeferredFields) {
missingDeferredFields = /* @__PURE__ */ new Map();
leftOver.missingFieldsParentDeferredMap.set(
parent,
missingDeferredFields
);
}
const deferred = createDeferredPromise();
missingDeferredFields.set(responseKey, deferred);
const stitchingInfo = info.schema.extensions?.["stitchingInfo"];
const parentTypeName = parent?.__typename || info.parentType.name;
const fieldNodesByType = stitchingInfo?.fieldNodesByField?.[parentTypeName]?.[info.fieldName];
if (fieldNodesByType?.every((fieldNode) => {
const responseKey2 = fieldNode.alias?.value ?? fieldNode.name.value;
if (Object.prototype.hasOwnProperty.call(parent, responseKey2)) {
return true;
}
return false;
})) {
handleResult(parent, responseKey, context, info);
}
return deferred.promise;
}
return void 0;
}
return handleResult(parent, responseKey, context, info);
}
function handleResult(parent, responseKey, context, info) {
const subschema = getSubschema(parent, responseKey);
const data = parent[responseKey];
const unpathedErrors = getUnpathedErrors(parent);
const resolvedData$ = resolveExternalValue(
data,
unpathedErrors,
subschema,
context,
info
);
const leftOver = getPlanLeftOverFromParent(parent);
if (leftOver) {
return handleMaybePromise(
() => resolvedData$,
(resolvedData) => {
parent[responseKey] = resolvedData;
handleLeftOver(parent, context, info, leftOver);
return resolvedData;
}
);
}
return resolvedData$;
}
function handleLeftOver(parent, context, info, leftOver) {
const stitchingInfo = info.schema.extensions?.["stitchingInfo"];
if (stitchingInfo) {
for (const possibleSubschema of leftOver.nonProxiableSubschemas) {
const parentTypeName = info.parentType.name;
const selectionSets = /* @__PURE__ */ new Set();
const mainSelectionSet = stitchingInfo.mergedTypes[parentTypeName]?.selectionSets.get(
possibleSubschema
);
if (mainSelectionSet) {
selectionSets.add(mainSelectionSet);
}
for (const fieldNode of leftOver.unproxiableFieldNodes) {
const fieldName = fieldNode.name.value;
const fieldSelectionSet = stitchingInfo.mergedTypes[parentTypeName]?.fieldSelectionSets.get(
possibleSubschema
)?.[fieldName];
if (fieldSelectionSet) {
selectionSets.add(fieldSelectionSet);
}
}
if (selectionSets.size) {
const selectionSet = {
kind: Kind.SELECTION_SET,
selections: Array.from(selectionSets).flatMap(
(selectionSet2) => selectionSet2.selections
)
};
handleMaybePromise(
() => flattenPromise(parent),
(flattenedParent) => {
handleFlattenedParent(
flattenedParent,
parent,
possibleSubschema,
selectionSet,
leftOver,
stitchingInfo,
parentTypeName,
context,
info
);
}
);
}
}
}
}
function handleFlattenedParent(flattenedParent, leftOverParent, possibleSubschema, selectionSet, leftOver, stitchingInfo, parentTypeName, context, info) {
if (parentSatisfiedSelectionSet(flattenedParent, selectionSet)) {
const missingFieldNodes = leftOver.missingFieldsParentMap.get(leftOverParent);
if (missingFieldNodes) {
const resolver = stitchingInfo.mergedTypes[parentTypeName]?.resolvers.get(
possibleSubschema
);
if (resolver) {
Object.assign(leftOverParent, flattenedParent);
const selectionSet2 = {
kind: Kind.SELECTION_SET,
selections: missingFieldNodes
};
handleMaybePromise(
() => resolver(
leftOverParent,
context,
info,
possibleSubschema,
selectionSet2,
info.parentType,
info.parentType
),
(resolverResult) => {
handleDeferredResolverResult(
resolverResult,
possibleSubschema,
selectionSet2,
leftOverParent,
leftOver,
context,
info
);
},
(error) => handleDeferredResolverFailure(leftOver, leftOverParent, error)
);
}
}
} else {
for (const selectionNode of selectionSet.selections) {
if (selectionNode.kind === Kind.FIELD && selectionNode.selectionSet?.selections?.length) {
const responseKey = selectionNode.alias?.value ?? selectionNode.name.value;
const nestedParent = flattenedParent[responseKey];
const nestedSelectionSet = selectionNode.selectionSet;
if (nestedParent != null) {
if (!parentSatisfiedSelectionSet(nestedParent, nestedSelectionSet)) {
async function handleNestedParentItem(nestedParentItem, fieldNode) {
const nestedTypeName = nestedParentItem["__typename"];
const sourceSubschema = getSubschema(
flattenedParent,
responseKey
);
if (sourceSubschema && nestedTypeName) {
const delegationPlan = stitchingInfo.mergedTypes[nestedTypeName]?.delegationPlanBuilder(
info.schema,
sourceSubschema,
info.variableValues != null && Object.keys(info.variableValues).length > 0 ? info.variableValues : EMPTY_OBJECT,
info.fragments != null && Object.keys(info.fragments).length > 0 ? info.fragments : EMPTY_OBJECT,
getActualFieldNodes(fieldNode),
context,
info
);
if (delegationPlan?.length) {
for (const delegationMap of delegationPlan) {
for (const [subschema, selectionSet2] of delegationMap) {
const resolver = stitchingInfo.mergedTypes[nestedTypeName]?.resolvers.get(subschema);
if (resolver) {
const res = await resolver(
nestedParentItem,
context,
info,
subschema,
selectionSet2,
info.parentType,
info.parentType
);
if (res) {
handleResolverResult(
res,
subschema,
selectionSet2,
nestedParentItem,
nestedParentItem[FIELD_SUBSCHEMA_MAP_SYMBOL] ||= /* @__PURE__ */ new Map(),
info,
responsePathAsArray(info.path),
nestedParentItem[UNPATHED_ERRORS_SYMBOL] ||= []
);
}
}
}
}
}
if (parentSatisfiedSelectionSet(nestedParent, nestedSelectionSet)) {
handleFlattenedParent(
flattenedParent,
leftOverParent,
possibleSubschema,
selectionSet,
leftOver,
stitchingInfo,
parentTypeName,
context,
info
);
}
}
}
if (Array.isArray(nestedParent)) {
nestedParent.forEach(
(nestedParentItem) => handleNestedParentItem(nestedParentItem, selectionNode)
);
} else {
handleNestedParentItem(nestedParent, selectionNode);
}
}
}
}
}
}
}
function handleDeferredResolverResult(resolverResult, possibleSubschema, selectionSet, leftOverParent, leftOver, context, info) {
handleResolverResult(
resolverResult,
possibleSubschema,
selectionSet,
leftOverParent,
leftOverParent[FIELD_SUBSCHEMA_MAP_SYMBOL],
info,
responsePathAsArray(info.path),
leftOverParent[UNPATHED_ERRORS_SYMBOL]
);
const deferredFields = leftOver.missingFieldsParentDeferredMap.get(leftOverParent);
if (deferredFields) {
for (const [responseKey, deferred] of deferredFields) {
if (Object.prototype.hasOwnProperty.call(resolverResult, responseKey)) {
deferred.resolve(
handleResult(leftOverParent, responseKey, context, info)
);
}
}
leftOver.missingFieldsParentDeferredMap.delete(leftOverParent);
}
}
function handleDeferredResolverFailure(leftOver, leftOverParent, error) {
const deferredFields = leftOver.missingFieldsParentDeferredMap.get(leftOverParent);
if (deferredFields) {
for (const [_responseKey, deferred] of deferredFields) {
deferred.reject(error);
}
leftOver.missingFieldsParentDeferredMap.delete(leftOverParent);
}
}
function parentSatisfiedSelectionSet(parent, selectionSet) {
if (Array.isArray(parent)) {
const subschemas2 = /* @__PURE__ */ new Set();
for (const item of parent) {
const satisfied = parentSatisfiedSelectionSet(item, selectionSet);
if (satisfied === void 0) {
return void 0;
}
for (const subschema of satisfied) {
subschemas2.add(subschema);
}
}
return subschemas2;
}
if (parent === null) {
return /* @__PURE__ */ new Set();
}
if (parent === void 0) {
return void 0;
}
const subschemas = /* @__PURE__ */ new Set();
for (const selection of selectionSet.selections) {
if (selection.kind === Kind.FIELD) {
const responseKey = selection.alias?.value ?? selection.name.value;
if (parent[responseKey] === void 0) {
return void 0;
}
if (isExternalObject(parent)) {
const subschema = getSubschema(parent, responseKey);
if (subschema) {
subschemas.add(subschema);
}
}
if (parent[responseKey] === null) {
continue;
}
if (selection.selectionSet != null) {
const satisfied = parentSatisfiedSelectionSet(
parent[responseKey],
selection.selectionSet
);
if (satisfied === void 0) {
return void 0;
}
for (const subschema of satisfied) {
subschemas.add(subschema);
}
}
} else if (selection.kind === Kind.INLINE_FRAGMENT) {
const inlineSatisfied = parentSatisfiedSelectionSet(
parent,
selection.selectionSet
);
if (inlineSatisfied === void 0) {
return void 0;
}
for (const subschema of inlineSatisfied) {
subschemas.add(subschema);
}
}
}
return subschemas;
}
function flattenPromise(data) {
if (isPromise(data)) {
return data.then(flattenPromise);
}
if (Array.isArray(data)) {
return Promise.all(data.map(flattenPromise));
}
if (data != null && typeof data === "object") {
const jobs = [];
const newData = {};
for (const key in data) {
const keyResult = flattenPromise(data[key]);
if (isPromise(keyResult)) {
jobs.push(
keyResult.then((resolvedKeyResult) => {
newData[key] = resolvedKeyResult;
})
);
} else {
newData[key] = keyResult;
}
}
if (OBJECT_SUBSCHEMA_SYMBOL in data) {
newData[OBJECT_SUBSCHEMA_SYMBOL] = data[OBJECT_SUBSCHEMA_SYMBOL];
}
if (FIELD_SUBSCHEMA_MAP_SYMBOL in data) {
newData[FIELD_SUBSCHEMA_MAP_SYMBOL] = data[FIELD_SUBSCHEMA_MAP_SYMBOL];
}
if (UNPATHED_ERRORS_SYMBOL in data) {
newData[UNPATHED_ERRORS_SYMBOL] = data[UNPATHED_ERRORS_SYMBOL];
}
if (jobs.length) {
return Promise.all(jobs).then(() => newData);
}
return newData;
}
return data;
}
function isSubschemaConfig(value) {
return Boolean(value?.schema);
}
function cloneSubschemaConfig(subschemaConfig) {
const newSubschemaConfig = {
...subschemaConfig,
transforms: subschemaConfig.transforms != null ? [...subschemaConfig.transforms] : void 0
};
if (newSubschemaConfig.merge != null) {
newSubschemaConfig.merge = { ...subschemaConfig.merge };
for (const typeName in newSubschemaConfig.merge) {
const mergedTypeConfig = newSubschemaConfig.merge[typeName] = {
...subschemaConfig.merge?.[typeName] ?? {}
};
if (mergedTypeConfig.entryPoints != null) {
mergedTypeConfig.entryPoints = mergedTypeConfig.entryPoints.map(
(entryPoint) => ({
...entryPoint
})
);
}
if (mergedTypeConfig.fields != null) {
const fields = mergedTypeConfig.fields = {
...mergedTypeConfig.fields
};
for (const fieldName in fields) {
fields[fieldName] = { ...fields[fieldName] };
}
}
}
}
return newSubschemaConfig;
}
function delegateToSchema(options) {
const {
info,
schema,
rootValue = schema.rootValue ?? info.rootValue,
operationName = info.operation.name?.value,
operation = getDelegatingOperation(info.parentType, info.schema),
fieldName = info.fieldName,
selectionSet,
fieldNodes = info.fieldNodes,
context
} = options;
const request = createRequest({
sourceSchema: info.schema,
sourceParentType: info.parentType,
sourceFieldName: info.fieldName,
fragments: info.fragments,
variableDefinitions: info.operation.variableDefinitions,
variableValues: info.variableValues,
targetRootValue: rootValue,
targetOperationName: operationName,
targetOperation: operation,
targetFieldName: fieldName,
selectionSet,
fieldNodes,
context,
info
});
return delegateRequest({
...options,
request
});
}
function getDelegationReturnType(targetSchema, operation, fieldName) {
const rootType = getDefinedRootType(targetSchema, operation);
const rootFieldType = rootType.getFields()[fieldName];
if (!rootFieldType) {
throw new Error(
`Unable to find field '${fieldName}' in type '${rootType}'.`
);
}
return rootFieldType.type;
}
function delegateRequest(options) {
const delegationContext = getDelegationContext(options);
const transformer = new Transformer(delegationContext);
const processedRequest = transformer.transformRequest(options.request);
if (options.validateRequest) {
validateRequest(delegationContext, processedRequest.document);
}
return handleMaybePromise(
() => getExecutor(delegationContext)(processedRequest),
function handleExecutorResult(executorResult) {
if (isAsyncIterable(executorResult)) {
if (delegationContext.operation === "query" && isListType(delegationContext.returnType)) {
return new Repeater(async (push, stop) => {
const pushed = /* @__PURE__ */ new WeakSet();
let stopped = false;
stop.finally(() => {
stopped = true;
});
try {
for await (const result of executorResult) {
if (stopped) {
break;
}
if (result.incremental) {
const data = {};
for (const incrementalRes of result.incremental) {
if (incrementalRes.items?.length) {
for (const item of incrementalRes.items) {
dset(
data,
(incrementalRes.path || []).slice(0, -1),
item
);
}
await push(await transformer.transformResult({ data }));
}
}
if (result.hasNext === false) {
break;
} else {
continue;
}
}
const transformedResult = await transformer.transformResult(result);
if (Array.isArray(transformedResult)) {
for (const individualResult$ of transformedResult) {
if (stopped) {
break;
}
const individualResult = await individualResult$;
if (!pushed.has(individualResult)) {
pushed.add(individualResult);
await push(individualResult);
}
}
} else {
await push(await transformedResult);
}
}
stop();
} catch (error) {
stop(error);
}
});
}
return mapAsyncIterator(
executorResult,
(result) => transformer.transformResult(result)
);
}
return transformer.transformResult(executorResult);
}
);
}
function getDelegationContext({
request,
schema,
fieldName,
returnType,
args,
info,
transforms = [],
transformedSchema,
skipTypeMerging = false,
onLocatedError
}) {
const operationDefinition = getOperationASTFromRequest(request);
let targetFieldName;
if (fieldName == null) {
targetFieldName = operationDefinition.selectionSet.selections[0].name.value;
} else {
targetFieldName = fieldName;
}
const stitchingInfo = info?.schema.extensions?.["stitchingInfo"];
const subschemaOrSubschemaConfig = stitchingInfo?.subschemaMap.get(schema) ?? schema;
const operation = operationDefinition.operation;
if (isSubschemaConfig(subschemaOrSubschemaConfig)) {
const targetSchema = subschemaOrSubschemaConfig.schema;
return {
subschema: schema,
subschemaConfig: subschemaOrSubschemaConfig,
targetSchema,
operation,
fieldName: targetFieldName,
args,
context: request.context,
info,
returnType: returnType ?? info?.returnType ?? getDelegationReturnType(targetSchema, operation, targetFieldName),
transforms: subschemaOrSubschemaConfig.transforms != null ? subschemaOrSubschemaConfig.transforms.concat(transforms) : transforms,
transformedSchema: transformedSchema ?? (subschemaOrSubschemaConfig instanceof Subschema ? subschemaOrSubschemaConfig.transformedSchema : applySchemaTransforms(targetSchema, subschemaOrSubschemaConfig)),
skipTypeMerging,
onLocatedError
};
}
return {
subschema: schema,
subschemaConfig: void 0,
targetSchema: subschemaOrSubschemaConfig,
operation,
fieldName: targetFieldName,
args,
context: request.context,
info,
returnType: returnType ?? info?.returnType ?? getDelegationReturnType(
subschemaOrSubschemaConfig,
operation,
targetFieldName
),
transforms,
transformedSchema: transformedSchema ?? subschemaOrSubschemaConfig,
skipTypeMerging
};
}
function validateRequest(delegationContext, document) {
const errors = validate(delegationContext.targetSchema, document);
if (errors.length > 0) {
if (errors.length > 1) {
const combinedError = new AggregateError(
errors,
errors.map((error2) => error2.message).join(", \n")
);
throw combinedError;
}
const error = errors[0];
if (error) {
throw error.originalError || error;
}
}
}
const GLOBAL_CONTEXT = {};
function getExecutor(delegationContext) {
const { subschemaConfig, targetSchema, context } = delegationContext;
let executor = subschemaConfig?.executor || executorFromSchema(targetSchema);
if (subschemaConfig?.batch) {
const batchingOptions = subschemaConfig?.batchingOptions;
executor = getBatchingExecutor(
context ?? GLOBAL_CONTEXT,
executor,
batchingOptions?.dataLoaderOptions,
batchingOptions?.extensionsReducer
);
}
return executor;
}
function extractUnavailableFieldsFromSelectionSet(schema, fieldType, fieldSelectionSet, shouldAdd, fragments = {}) {
if (isLeafType(fieldType)) {
return [];
}
if (isUnionType(fieldType)) {
const unavailableSelections2 = [];
for (const type of fieldType.getTypes()) {
const fieldSelectionExcluded = {
...fieldSelectionSet,
selections: fieldSelectionSet.selections.filter(
(selection) => selection.kind === Kind.INLINE_FRAGMENT ? selection.typeCondition ? selection.typeCondition.name.value === type.name : false : true
)
};
unavailableSelections2.push(
...extractUnavailableFieldsFromSelectionSet(
schema,
type,
fieldSelectionExcluded,
shouldAdd,
fragments
)
);
}
return unavailableSelections2;
}
const subFields = fieldType.getFields();
const unavailableSelections = [];
for (const selection of fieldSelectionSet.selections) {
if (selection.kind === Kind.FIELD) {
if (selection.name.value === "__typename") {
continue;
}
const fieldName = selection.name.value;
const selectionField = subFields[fieldName];
if (!selectionField) {
if (shouldAdd(fieldType, selection)) {
unavailableSelections.push(selection);
}
} else {
const unavailableSubFields = extractUnavailableFields(
schema,
selectionField,
selection,
shouldAdd,
fragments
);
if (unavailableSubFields.length) {
unavailableSelections.push({
...selection,
selectionSet: {
kind: Kind.SELECTION_SET,
selections: unavailableSubFields
}
});
}
}
} else if (selection.kind === Kind.INLINE_FRAGMENT) {
const subFieldName = selection.typeCondition?.name.value || fieldType.name;
const subFieldType = selection.typeCondition && schema.getType(subFieldName) || fieldType;
if (subFieldName === fieldType.name || (isObjectType(subFieldType) || isInterfaceType(subFieldType)) && isAbstractType(fieldType) && schema.isSubType(fieldType, subFieldType)) {
const unavailableFields = extractUnavailableFieldsFromSelectionSet(
schema,
subFieldType,
selection.selectionSet,
shouldAdd,
fragments
);
if (unavailableFields.length) {
unavailableSelections.push({
...selection,
selectionSet: {
kind: Kind.SELECTION_SET,
selections: unavailableFields
}
});
}
} else if (isObjectType(subFieldType) || isInterfaceType(subFieldType)) {
for (const subSelection of selection.selectionSet.selections) {
if (subSelection.kind === Kind.FIELD && subSelection.name.value === "__typename") {
continue;
}
if (shouldAdd(subFieldType, subSelection)) {
unavailableSelections.push(subSelection);
}
}
}
} else if (selection.kind === Kind.FRAGMENT_SPREAD) {
const fragment = fragments[selection.name.value];
if (fragment) {
const fragmentUnavailableFields = extractUnavailableFieldsFromSelectionSet(
schema,
fieldType,
{
kind: Kind.SELECTION_SET,
selections: [
{
kind: Kind.INLINE_FRAGMENT,
typeCondition: {
kind: Kind.NAMED_TYPE,
name: {
kind: Kind.NAME,
value: fragment.typeCondition.name.value
}
},
selectionSet: fragment.selectionSet
}
]
},
shouldAdd,
fragments
);
if (fragmentUnavailableFields.length) {
unavailableSelections.push(...fragmentUnavailableFields);
}
}
}
}
return unavailableSelections;
}
function extractUnavailableFields(schema, field, fieldNode, shouldAdd, fragments = {}) {
if (fieldNode.selectionSet) {
const fieldType = getNamedType(field.type);
return extractUnavailableFieldsFromSelectionSet(
schema,
fieldType,
fieldNode.selectionSet,
shouldAdd,
fragments
);
}
return [];
}
function fieldExistsInSelectionSet(node, path) {
let currentNode = node;
const isArrayOfSelectionNodes = (node2) => Array.isArray(node2);
for (const [segment, fieldName] of path) {
if (!currentNode) {
return false;
}
if (isArrayOfSelectionNodes(currentNode) && fieldName) {
currentNode = currentNode.find((selectionNode) => {
return selectionNode.name?.value === fieldName;
});
} else {
currentNode = currentNode[segment];
}
}
return !!currentNode;
}
function getPathWithFieldNames(node, path) {
const pathWithFieldNames = [];
let currentNode = node;
const isArrayOfSelectionNodes = (node2) => Array.isArray(node2);
for (const segment of path) {
currentNode = currentNode[segment];
if (!isArrayOfSelectionNodes(currentNode) && currentNode.kind === Kind.FIELD) {
pathWithFieldNames.push([segment, currentNode.name.value]);
} else {
pathWithFieldNames.push([segment]);
}
}
return pathWithFieldNames;
}
function subtractSelectionSets(selectionSetA, selectionSetB) {
return visit(selectionSetA, {
[Kind.FIELD]: {
enter(node, _key, _parent, path) {
if (!node.selectionSet) {
const pathWithFieldNames = getPathWithFieldNames(selectionSetA, path);
const fieldExists = fieldExistsInSelectionSet(
selectionSetB,
pathWithFieldNames
);
if (fieldExists) {
return null;
}
}
return void 0;
}
},
[Kind.SELECTION_SET]: {
leave(node) {
if (node.selections.length === 0) {
return null;
}
return void 0;
}
},
[Kind.INLINE_FRAGMENT]: {
leave(node) {
if (node.selectionSet?.selections.length === 0) {
return null;
}
return void 0;
}
}
});
}
export { EMPTY_ARRAY, EMPTY_OBJECT, FIELD_SUBSCHEMA_MAP_SYMBOL, OBJECT_SUBSCHEMA_SYMBOL, PLAN_LEFT_OVER, Subschema, Transformer, UNPATHED_ERRORS_SYMBOL, annotateExternalObject, applySchemaTransforms, cloneSubschemaConfig, createRequest, defaultMergedResolver, delegateRequest, delegateToSchema, extractUnavailableFields, extractUnavailableFieldsFromSelectionSet, getActualFieldNodes, getDelegatingOperation, getPlanLeftOverFromParent, getSubschema, getTypeInfo, getTypeInfoWithType, getUnpathedErrors, handleResolverResult, isExternalObject, isPrototypePollutingKey, isSubschema, isSubschemaConfig, leftOverByDelegationPlan, mergeFields, resolveExternalValue, subtractSelectionSets };