UNPKG

74.5 kBJavaScriptView Raw
1import { cloneSchema, serializeInputValue, updateArgument, collectFields, relocatedError, mergeDeep, getResponseKeyFromInfo, implementsAbstractType, mapAsyncIterator } from '@graphql-tools/utils';
2import { Kind, typeFromAST, GraphQLError, responsePathAsArray, getNamedType, getNullableType, isLeafType, isCompositeType, isListType, isAbstractType, locatedError, defaultFieldResolver, TypeInfo, visit, visitWithTypeInfo, print, isInterfaceType, isObjectType, TypeNameMetaFieldDef, getOperationAST, subscribe, validate, execute } from 'graphql';
3import AggregateError from '@ardatan/aggregate-error';
4import isPromise from 'is-promise';
5import { getBatchingExecutor } from '@graphql-tools/batch-execute';
6
7function applySchemaTransforms(originalWrappingSchema, subschemaConfig, transformedSchema) {
8 const schemaTransforms = subschemaConfig.transforms;
9 if (schemaTransforms == null) {
10 return originalWrappingSchema;
11 }
12 return schemaTransforms.reduce((schema, transform) => transform.transformSchema != null
13 ? transform.transformSchema(cloneSchema(schema), subschemaConfig, transformedSchema)
14 : schema, originalWrappingSchema);
15}
16
17function isSubschema(value) {
18 return Boolean(value.transformedSchema);
19}
20class Subschema {
21 constructor(config) {
22 var _a;
23 this.schema = config.schema;
24 this.rootValue = config.rootValue;
25 this.executor = config.executor;
26 this.subscriber = config.subscriber;
27 this.batch = config.batch;
28 this.batchingOptions = config.batchingOptions;
29 this.createProxyingResolver = config.createProxyingResolver;
30 this.transforms = (_a = config.transforms) !== null && _a !== void 0 ? _a : [];
31 this.transformedSchema = applySchemaTransforms(this.schema, config);
32 this.merge = config.merge;
33 }
34}
35
36function getDelegatingOperation(parentType, schema) {
37 if (parentType === schema.getMutationType()) {
38 return 'mutation';
39 }
40 else if (parentType === schema.getSubscriptionType()) {
41 return 'subscription';
42 }
43 return 'query';
44}
45function createRequestFromInfo({ info, operationName, operation = getDelegatingOperation(info.parentType, info.schema), fieldName = info.fieldName, selectionSet, fieldNodes = info.fieldNodes, }) {
46 return createRequest({
47 sourceSchema: info.schema,
48 sourceParentType: info.parentType,
49 sourceFieldName: info.fieldName,
50 fragments: info.fragments,
51 variableDefinitions: info.operation.variableDefinitions,
52 variableValues: info.variableValues,
53 targetOperationName: operationName,
54 targetOperation: operation,
55 targetFieldName: fieldName,
56 selectionSet,
57 fieldNodes,
58 });
59}
60function createRequest({ sourceSchema, sourceParentType, sourceFieldName, fragments, variableDefinitions, variableValues, targetOperationName, targetOperation, targetFieldName, selectionSet, fieldNodes, }) {
61 var _a;
62 let newSelectionSet;
63 let argumentNodeMap;
64 if (selectionSet != null) {
65 newSelectionSet = selectionSet;
66 argumentNodeMap = Object.create(null);
67 }
68 else {
69 const selections = fieldNodes.reduce((acc, fieldNode) => (fieldNode.selectionSet != null ? acc.concat(fieldNode.selectionSet.selections) : acc), []);
70 newSelectionSet = selections.length
71 ? {
72 kind: Kind.SELECTION_SET,
73 selections,
74 }
75 : undefined;
76 argumentNodeMap = {};
77 const args = (_a = fieldNodes[0]) === null || _a === void 0 ? void 0 : _a.arguments;
78 if (args) {
79 argumentNodeMap = args.reduce((prev, curr) => ({
80 ...prev,
81 [curr.name.value]: curr,
82 }), argumentNodeMap);
83 }
84 }
85 const newVariables = Object.create(null);
86 const variableDefinitionMap = Object.create(null);
87 if (sourceSchema != null && variableDefinitions != null) {
88 variableDefinitions.forEach(def => {
89 const varName = def.variable.name.value;
90 variableDefinitionMap[varName] = def;
91 const varType = typeFromAST(sourceSchema, def.type);
92 const serializedValue = serializeInputValue(varType, variableValues[varName]);
93 if (serializedValue !== undefined) {
94 newVariables[varName] = serializedValue;
95 }
96 });
97 }
98 if (sourceParentType != null) {
99 updateArgumentsWithDefaults(sourceParentType, sourceFieldName, argumentNodeMap, variableDefinitionMap, newVariables);
100 }
101 const rootfieldNode = {
102 kind: Kind.FIELD,
103 arguments: Object.keys(argumentNodeMap).map(argName => argumentNodeMap[argName]),
104 name: {
105 kind: Kind.NAME,
106 value: targetFieldName || fieldNodes[0].name.value,
107 },
108 selectionSet: newSelectionSet,
109 };
110 const operationName = targetOperationName
111 ? {
112 kind: Kind.NAME,
113 value: targetOperationName,
114 }
115 : undefined;
116 const operationDefinition = {
117 kind: Kind.OPERATION_DEFINITION,
118 name: operationName,
119 operation: targetOperation,
120 variableDefinitions: Object.keys(variableDefinitionMap).map(varName => variableDefinitionMap[varName]),
121 selectionSet: {
122 kind: Kind.SELECTION_SET,
123 selections: [rootfieldNode],
124 },
125 };
126 let definitions = [operationDefinition];
127 if (fragments != null) {
128 definitions = definitions.concat(Object.keys(fragments).map(fragmentName => fragments[fragmentName]));
129 }
130 const document = {
131 kind: Kind.DOCUMENT,
132 definitions,
133 };
134 return {
135 document,
136 variables: newVariables,
137 };
138}
139function updateArgumentsWithDefaults(sourceParentType, sourceFieldName, argumentNodeMap, variableDefinitionMap, variableValues) {
140 const sourceField = sourceParentType.getFields()[sourceFieldName];
141 sourceField.args.forEach((argument) => {
142 const argName = argument.name;
143 const sourceArgType = argument.type;
144 if (argumentNodeMap[argName] === undefined) {
145 const defaultValue = argument.defaultValue;
146 if (defaultValue !== undefined) {
147 updateArgument(argName, sourceArgType, argumentNodeMap, variableDefinitionMap, variableValues, serializeInputValue(sourceArgType, defaultValue));
148 }
149 }
150 });
151}
152
153const UNPATHED_ERRORS_SYMBOL = Symbol('subschemaErrors');
154const OBJECT_SUBSCHEMA_SYMBOL = Symbol('initialSubschema');
155const FIELD_SUBSCHEMA_MAP_SYMBOL = Symbol('subschemaMap');
156
157function isExternalObject(data) {
158 return data[UNPATHED_ERRORS_SYMBOL] !== undefined;
159}
160function annotateExternalObject(object, errors, subschema) {
161 Object.defineProperties(object, {
162 [OBJECT_SUBSCHEMA_SYMBOL]: { value: subschema },
163 [FIELD_SUBSCHEMA_MAP_SYMBOL]: { value: Object.create(null) },
164 [UNPATHED_ERRORS_SYMBOL]: { value: errors },
165 });
166 return object;
167}
168function getSubschema(object, responseKey) {
169 var _a;
170 return (_a = object[FIELD_SUBSCHEMA_MAP_SYMBOL][responseKey]) !== null && _a !== void 0 ? _a : object[OBJECT_SUBSCHEMA_SYMBOL];
171}
172function getUnpathedErrors(object) {
173 return object[UNPATHED_ERRORS_SYMBOL];
174}
175function mergeExternalObjects(schema, path, typeName, target, sources, selectionSets) {
176 var _a;
177 const results = [];
178 let errors = [];
179 sources.forEach((source, index) => {
180 if (source instanceof GraphQLError || source === null) {
181 const selectionSet = selectionSets[index];
182 const fieldNodes = collectFields({
183 schema,
184 variableValues: {},
185 fragments: {},
186 }, schema.getType(typeName), selectionSet, Object.create(null), Object.create(null));
187 const nullResult = {};
188 Object.keys(fieldNodes).forEach(responseKey => {
189 nullResult[responseKey] =
190 source instanceof GraphQLError ? relocatedError(source, path.concat([responseKey])) : null;
191 });
192 results.push(nullResult);
193 }
194 else {
195 errors = errors.concat(source[UNPATHED_ERRORS_SYMBOL]);
196 results.push(source);
197 }
198 });
199 const combinedResult = results.reduce(mergeDeep, target);
200 const newFieldSubschemaMap = (_a = target[FIELD_SUBSCHEMA_MAP_SYMBOL]) !== null && _a !== void 0 ? _a : Object.create(null);
201 results.forEach((source) => {
202 const objectSubschema = source[OBJECT_SUBSCHEMA_SYMBOL];
203 const fieldSubschemaMap = source[FIELD_SUBSCHEMA_MAP_SYMBOL];
204 if (fieldSubschemaMap === undefined) {
205 Object.keys(source).forEach(responseKey => {
206 newFieldSubschemaMap[responseKey] = objectSubschema;
207 });
208 }
209 else {
210 Object.keys(source).forEach(responseKey => {
211 var _a;
212 newFieldSubschemaMap[responseKey] = (_a = fieldSubschemaMap[responseKey]) !== null && _a !== void 0 ? _a : objectSubschema;
213 });
214 }
215 });
216 combinedResult[FIELD_SUBSCHEMA_MAP_SYMBOL] = newFieldSubschemaMap;
217 combinedResult[OBJECT_SUBSCHEMA_SYMBOL] = target[OBJECT_SUBSCHEMA_SYMBOL];
218 combinedResult[UNPATHED_ERRORS_SYMBOL] = target[UNPATHED_ERRORS_SYMBOL].concat(errors);
219 return combinedResult;
220}
221
222function isSubschemaConfig(value) {
223 return Boolean(value === null || value === void 0 ? void 0 : value.schema);
224}
225function cloneSubschemaConfig(subschemaConfig) {
226 const newSubschemaConfig = {
227 ...subschemaConfig,
228 transforms: subschemaConfig.transforms != null ? [...subschemaConfig.transforms] : undefined,
229 };
230 if (newSubschemaConfig.merge != null) {
231 newSubschemaConfig.merge = { ...subschemaConfig.merge };
232 Object.keys(newSubschemaConfig.merge).forEach(typeName => {
233 newSubschemaConfig.merge[typeName] = { ...subschemaConfig.merge[typeName] };
234 const fields = newSubschemaConfig.merge[typeName].fields;
235 if (fields != null) {
236 Object.keys(fields).forEach(fieldName => {
237 fields[fieldName] = { ...fields[fieldName] };
238 });
239 }
240 const computedFields = newSubschemaConfig.merge[typeName].computedFields;
241 if (computedFields != null) {
242 Object.keys(computedFields).forEach(fieldName => {
243 computedFields[fieldName] = { ...computedFields[fieldName] };
244 });
245 }
246 });
247 }
248 return newSubschemaConfig;
249}
250
251function memoizeInfoAnd2Objects(fn) {
252 let cache1;
253 function memoized(a1, a2, a3) {
254 if (!cache1) {
255 cache1 = new WeakMap();
256 const cache2 = new WeakMap();
257 cache1.set(a1.fieldNodes, cache2);
258 const cache3 = new WeakMap();
259 cache2.set(a2, cache3);
260 const newValue = fn(a1, a2, a3);
261 cache3.set(a3, newValue);
262 return newValue;
263 }
264 let cache2 = cache1.get(a1.fieldNodes);
265 if (!cache2) {
266 cache2 = new WeakMap();
267 cache1.set(a1.fieldNodes, cache2);
268 const cache3 = new WeakMap();
269 cache2.set(a2, cache3);
270 const newValue = fn(a1, a2, a3);
271 cache3.set(a3, newValue);
272 return newValue;
273 }
274 let cache3 = cache2.get(a2);
275 if (!cache3) {
276 cache3 = new WeakMap();
277 cache2.set(a2, cache3);
278 const newValue = fn(a1, a2, a3);
279 cache3.set(a3, newValue);
280 return newValue;
281 }
282 const cachedValue = cache3.get(a3);
283 if (cachedValue === undefined) {
284 const newValue = fn(a1, a2, a3);
285 cache3.set(a3, newValue);
286 return newValue;
287 }
288 return cachedValue;
289 }
290 return memoized;
291}
292function memoize4(fn) {
293 let cache1;
294 function memoized(a1, a2, a3, a4) {
295 if (!cache1) {
296 cache1 = new WeakMap();
297 const cache2 = new WeakMap();
298 cache1.set(a1, cache2);
299 const cache3 = new WeakMap();
300 cache2.set(a2, cache3);
301 const cache4 = new WeakMap();
302 cache3.set(a3, cache4);
303 const newValue = fn(a1, a2, a3, a4);
304 cache4.set(a4, newValue);
305 return newValue;
306 }
307 let cache2 = cache1.get(a1);
308 if (!cache2) {
309 cache2 = new WeakMap();
310 cache1.set(a1, cache2);
311 const cache3 = new WeakMap();
312 cache2.set(a2, cache3);
313 const cache4 = new WeakMap();
314 cache3.set(a3, cache4);
315 const newValue = fn(a1, a2, a3, a4);
316 cache4.set(a4, newValue);
317 return newValue;
318 }
319 let cache3 = cache2.get(a2);
320 if (!cache3) {
321 cache3 = new WeakMap();
322 cache2.set(a2, cache3);
323 const cache4 = new WeakMap();
324 cache3.set(a3, cache4);
325 const newValue = fn(a1, a2, a3, a4);
326 cache4.set(a4, newValue);
327 return newValue;
328 }
329 const cache4 = cache3.get(a3);
330 if (!cache4) {
331 const cache4 = new WeakMap();
332 cache3.set(a3, cache4);
333 const newValue = fn(a1, a2, a3, a4);
334 cache4.set(a4, newValue);
335 return newValue;
336 }
337 const cachedValue = cache4.get(a4);
338 if (cachedValue === undefined) {
339 const newValue = fn(a1, a2, a3, a4);
340 cache4.set(a4, newValue);
341 return newValue;
342 }
343 return cachedValue;
344 }
345 return memoized;
346}
347function memoize3(fn) {
348 let cache1;
349 function memoized(a1, a2, a3) {
350 if (!cache1) {
351 cache1 = new WeakMap();
352 const cache2 = new WeakMap();
353 cache1.set(a1, cache2);
354 const cache3 = new WeakMap();
355 cache2.set(a2, cache3);
356 const newValue = fn(a1, a2, a3);
357 cache3.set(a3, newValue);
358 return newValue;
359 }
360 let cache2 = cache1.get(a1);
361 if (!cache2) {
362 cache2 = new WeakMap();
363 cache1.set(a1, cache2);
364 const cache3 = new WeakMap();
365 cache2.set(a2, cache3);
366 const newValue = fn(a1, a2, a3);
367 cache3.set(a3, newValue);
368 return newValue;
369 }
370 let cache3 = cache2.get(a2);
371 if (!cache3) {
372 cache3 = new WeakMap();
373 cache2.set(a2, cache3);
374 const newValue = fn(a1, a2, a3);
375 cache3.set(a3, newValue);
376 return newValue;
377 }
378 const cachedValue = cache3.get(a3);
379 if (cachedValue === undefined) {
380 const newValue = fn(a1, a2, a3);
381 cache3.set(a3, newValue);
382 return newValue;
383 }
384 return cachedValue;
385 }
386 return memoized;
387}
388function memoize2(fn) {
389 let cache1;
390 function memoized(a1, a2) {
391 if (!cache1) {
392 cache1 = new WeakMap();
393 const cache2 = new WeakMap();
394 cache1.set(a1, cache2);
395 const newValue = fn(a1, a2);
396 cache2.set(a2, newValue);
397 return newValue;
398 }
399 let cache2 = cache1.get(a1);
400 if (!cache2) {
401 cache2 = new WeakMap();
402 cache1.set(a1, cache2);
403 const newValue = fn(a1, a2);
404 cache2.set(a2, newValue);
405 return newValue;
406 }
407 const cachedValue = cache2.get(a2);
408 if (cachedValue === undefined) {
409 const newValue = fn(a1, a2);
410 cache2.set(a2, newValue);
411 return newValue;
412 }
413 return cachedValue;
414 }
415 return memoized;
416}
417
418function collectSubFields(info, typeName) {
419 let subFieldNodes = Object.create(null);
420 const visitedFragmentNames = Object.create(null);
421 const type = info.schema.getType(typeName);
422 const partialExecutionContext = {
423 schema: info.schema,
424 variableValues: info.variableValues,
425 fragments: info.fragments,
426 };
427 info.fieldNodes.forEach(fieldNode => {
428 subFieldNodes = collectFields(partialExecutionContext, type, fieldNode.selectionSet, subFieldNodes, visitedFragmentNames);
429 });
430 const stitchingInfo = info.schema.extensions.stitchingInfo;
431 const selectionSetsByField = stitchingInfo.selectionSetsByField;
432 Object.keys(subFieldNodes).forEach(responseName => {
433 var _a;
434 const fieldName = subFieldNodes[responseName][0].name.value;
435 const fieldSelectionSet = (_a = selectionSetsByField === null || selectionSetsByField === void 0 ? void 0 : selectionSetsByField[typeName]) === null || _a === void 0 ? void 0 : _a[fieldName];
436 if (fieldSelectionSet != null) {
437 subFieldNodes = collectFields(partialExecutionContext, type, fieldSelectionSet, subFieldNodes, visitedFragmentNames);
438 }
439 });
440 return subFieldNodes;
441}
442const getFieldsNotInSubschema = memoizeInfoAnd2Objects(function (info, subschema, mergedTypeInfo) {
443 const typeMap = isSubschemaConfig(subschema) ? mergedTypeInfo.typeMaps.get(subschema) : subschema.getTypeMap();
444 const typeName = mergedTypeInfo.typeName;
445 const fields = typeMap[typeName].getFields();
446 const subFieldNodes = collectSubFields(info, typeName);
447 let fieldsNotInSchema = [];
448 Object.keys(subFieldNodes).forEach(responseName => {
449 const fieldName = subFieldNodes[responseName][0].name.value;
450 if (!(fieldName in fields)) {
451 fieldsNotInSchema = fieldsNotInSchema.concat(subFieldNodes[responseName]);
452 }
453 });
454 return fieldsNotInSchema;
455});
456
457const sortSubschemasByProxiability = memoize4(function (mergedTypeInfo, sourceSubschemaOrSourceSubschemas, targetSubschemas, fieldNodes) {
458 // 1. calculate if possible to delegate to given subschema
459 const proxiableSubschemas = [];
460 const nonProxiableSubschemas = [];
461 targetSubschemas.forEach(t => {
462 const selectionSet = mergedTypeInfo.selectionSets.get(t);
463 const fieldSelectionSets = mergedTypeInfo.fieldSelectionSets.get(t);
464 if (selectionSet != null &&
465 !subschemaTypesContainSelectionSet(mergedTypeInfo, sourceSubschemaOrSourceSubschemas, selectionSet)) {
466 nonProxiableSubschemas.push(t);
467 }
468 else {
469 if (fieldSelectionSets == null ||
470 fieldNodes.every(fieldNode => {
471 const fieldName = fieldNode.name.value;
472 const fieldSelectionSet = fieldSelectionSets[fieldName];
473 return (fieldSelectionSet == null ||
474 subschemaTypesContainSelectionSet(mergedTypeInfo, sourceSubschemaOrSourceSubschemas, fieldSelectionSet));
475 })) {
476 proxiableSubschemas.push(t);
477 }
478 else {
479 nonProxiableSubschemas.push(t);
480 }
481 }
482 });
483 return {
484 proxiableSubschemas,
485 nonProxiableSubschemas,
486 };
487});
488const buildDelegationPlan = memoize3(function (mergedTypeInfo, fieldNodes, proxiableSubschemas) {
489 const { uniqueFields, nonUniqueFields } = mergedTypeInfo;
490 const unproxiableFieldNodes = [];
491 // 2. for each selection:
492 const delegationMap = new Map();
493 fieldNodes.forEach(fieldNode => {
494 if (fieldNode.name.value === '__typename') {
495 return;
496 }
497 // 2a. use uniqueFields map to assign fields to subschema if one of possible subschemas
498 const uniqueSubschema = uniqueFields[fieldNode.name.value];
499 if (uniqueSubschema != null) {
500 if (!proxiableSubschemas.includes(uniqueSubschema)) {
501 unproxiableFieldNodes.push(fieldNode);
502 return;
503 }
504 const existingSubschema = delegationMap.get(uniqueSubschema);
505 if (existingSubschema != null) {
506 existingSubschema.push(fieldNode);
507 }
508 else {
509 delegationMap.set(uniqueSubschema, [fieldNode]);
510 }
511 return;
512 }
513 // 2b. use nonUniqueFields to assign to a possible subschema,
514 // preferring one of the subschemas already targets of delegation
515 let nonUniqueSubschemas = nonUniqueFields[fieldNode.name.value];
516 if (nonUniqueSubschemas == null) {
517 unproxiableFieldNodes.push(fieldNode);
518 return;
519 }
520 nonUniqueSubschemas = nonUniqueSubschemas.filter(s => proxiableSubschemas.includes(s));
521 if (nonUniqueSubschemas == null) {
522 unproxiableFieldNodes.push(fieldNode);
523 return;
524 }
525 const subschemas = Array.from(delegationMap.keys());
526 const existingSubschema = nonUniqueSubschemas.find(s => subschemas.includes(s));
527 if (existingSubschema != null) {
528 delegationMap.get(existingSubschema).push(fieldNode);
529 }
530 else {
531 delegationMap.set(nonUniqueSubschemas[0], [fieldNode]);
532 }
533 });
534 const finalDelegationMap = new Map();
535 delegationMap.forEach((selections, subschema) => {
536 finalDelegationMap.set(subschema, {
537 kind: Kind.SELECTION_SET,
538 selections,
539 });
540 });
541 return {
542 delegationMap: finalDelegationMap,
543 unproxiableFieldNodes,
544 };
545});
546const combineSubschemas = memoize2(function (subschemaOrSubschemas, additionalSubschemas) {
547 return Array.isArray(subschemaOrSubschemas)
548 ? subschemaOrSubschemas.concat(additionalSubschemas)
549 : [subschemaOrSubschemas].concat(additionalSubschemas);
550});
551function mergeFields(mergedTypeInfo, typeName, object, fieldNodes, sourceSubschemaOrSourceSubschemas, targetSubschemas, context, info) {
552 if (!fieldNodes.length) {
553 return object;
554 }
555 const { proxiableSubschemas, nonProxiableSubschemas } = sortSubschemasByProxiability(mergedTypeInfo, sourceSubschemaOrSourceSubschemas, targetSubschemas, fieldNodes);
556 const { delegationMap, unproxiableFieldNodes } = buildDelegationPlan(mergedTypeInfo, fieldNodes, proxiableSubschemas);
557 if (!delegationMap.size) {
558 return object;
559 }
560 let containsPromises = false;
561 const resultMap = new Map();
562 delegationMap.forEach((selectionSet, s) => {
563 const resolver = mergedTypeInfo.resolvers.get(s);
564 let maybePromise = resolver(object, context, info, s, selectionSet);
565 if (isPromise(maybePromise)) {
566 containsPromises = true;
567 maybePromise = maybePromise.then(undefined, error => error);
568 }
569 resultMap.set(maybePromise, selectionSet);
570 });
571 return containsPromises
572 ? Promise.all(resultMap.keys()).then(results => mergeFields(mergedTypeInfo, typeName, mergeExternalObjects(info.schema, responsePathAsArray(info.path), object.__typename, object, results, Array.from(resultMap.values())), unproxiableFieldNodes, combineSubschemas(sourceSubschemaOrSourceSubschemas, proxiableSubschemas), nonProxiableSubschemas, context, info))
573 : mergeFields(mergedTypeInfo, typeName, mergeExternalObjects(info.schema, responsePathAsArray(info.path), object.__typename, object, Array.from(resultMap.keys()), Array.from(resultMap.values())), unproxiableFieldNodes, combineSubschemas(sourceSubschemaOrSourceSubschemas, proxiableSubschemas), nonProxiableSubschemas, context, info);
574}
575const subschemaTypesContainSelectionSet = memoize3(function (mergedTypeInfo, sourceSubschemaOrSourceSubschemas, selectionSet) {
576 if (Array.isArray(sourceSubschemaOrSourceSubschemas)) {
577 return typesContainSelectionSet(sourceSubschemaOrSourceSubschemas.map(sourceSubschema => sourceSubschema.transformedSchema.getType(mergedTypeInfo.typeName)), selectionSet);
578 }
579 return typesContainSelectionSet([sourceSubschemaOrSourceSubschemas.transformedSchema.getType(mergedTypeInfo.typeName)], selectionSet);
580});
581function typesContainSelectionSet(types, selectionSet) {
582 const fieldMaps = types.map(type => type.getFields());
583 for (const selection of selectionSet.selections) {
584 if (selection.kind === Kind.FIELD) {
585 const fields = fieldMaps.map(fieldMap => fieldMap[selection.name.value]).filter(field => field != null);
586 if (!fields.length) {
587 return false;
588 }
589 if (selection.selectionSet != null) {
590 return typesContainSelectionSet(fields.map(field => getNamedType(field.type)), selection.selectionSet);
591 }
592 }
593 else if (selection.kind === Kind.INLINE_FRAGMENT && selection.typeCondition.name.value === types[0].name) {
594 return typesContainSelectionSet(types, selection.selectionSet);
595 }
596 }
597 return true;
598}
599
600function resolveExternalValue(result, unpathedErrors, subschema, context, info, returnType = info.returnType, skipTypeMerging) {
601 const type = getNullableType(returnType);
602 if (result instanceof Error) {
603 return result;
604 }
605 if (result == null) {
606 return reportUnpathedErrorsViaNull(unpathedErrors);
607 }
608 if (isLeafType(type)) {
609 return type.parseValue(result);
610 }
611 else if (isCompositeType(type)) {
612 return resolveExternalObject(type, result, unpathedErrors, subschema, context, info, skipTypeMerging);
613 }
614 else if (isListType(type)) {
615 return resolveExternalList(type, result, unpathedErrors, subschema, context, info, skipTypeMerging);
616 }
617}
618function resolveExternalObject(type, object, unpathedErrors, subschema, context, info, skipTypeMerging) {
619 var _a;
620 const stitchingInfo = (_a = info === null || info === void 0 ? void 0 : info.schema.extensions) === null || _a === void 0 ? void 0 : _a.stitchingInfo;
621 annotateExternalObject(object, unpathedErrors, subschema);
622 if (skipTypeMerging || !stitchingInfo) {
623 return object;
624 }
625 let typeName;
626 if (isAbstractType(type)) {
627 const resolvedType = info.schema.getTypeMap()[object.__typename];
628 if (resolvedType == null) {
629 throw new Error(`Unable to resolve type '${object.__typename}'. Did you forget to include a transform that renames types? Did you delegate to the original subschema rather that the subschema config object containing the transform?`);
630 }
631 typeName = resolvedType.name;
632 }
633 else {
634 typeName = type.name;
635 }
636 const mergedTypeInfo = stitchingInfo.mergedTypes[typeName];
637 let targetSubschemas;
638 // Within the stitching context, delegation to a stitched GraphQLSchema or SubschemaConfig
639 // will be redirected to the appropriate Subschema object, from which merge targets can be queried.
640 if (mergedTypeInfo != null) {
641 targetSubschemas = mergedTypeInfo.targetSubschemas.get(subschema);
642 }
643 // If there are no merge targets from the subschema, return.
644 if (!targetSubschemas) {
645 return object;
646 }
647 const fieldNodes = getFieldsNotInSubschema(info, subschema, mergedTypeInfo);
648 return mergeFields(mergedTypeInfo, typeName, object, fieldNodes, subschema, targetSubschemas, context, info);
649}
650function resolveExternalList(type, list, unpathedErrors, subschema, context, info, skipTypeMerging) {
651 return list.map(listMember => resolveExternalListMember(getNullableType(type.ofType), listMember, unpathedErrors, subschema, context, info, skipTypeMerging));
652}
653function resolveExternalListMember(type, listMember, unpathedErrors, subschema, context, info, skipTypeMerging) {
654 if (listMember instanceof Error) {
655 return listMember;
656 }
657 if (listMember == null) {
658 return reportUnpathedErrorsViaNull(unpathedErrors);
659 }
660 if (isLeafType(type)) {
661 return type.parseValue(listMember);
662 }
663 else if (isCompositeType(type)) {
664 return resolveExternalObject(type, listMember, unpathedErrors, subschema, context, info, skipTypeMerging);
665 }
666 else if (isListType(type)) {
667 return resolveExternalList(type, listMember, unpathedErrors, subschema, context, info, skipTypeMerging);
668 }
669}
670const reportedErrors = new Map();
671function reportUnpathedErrorsViaNull(unpathedErrors) {
672 if (unpathedErrors.length) {
673 const unreportedErrors = [];
674 unpathedErrors.forEach(error => {
675 if (!reportedErrors.has(error)) {
676 unreportedErrors.push(error);
677 reportedErrors.set(error, true);
678 }
679 });
680 if (unreportedErrors.length) {
681 if (unreportedErrors.length === 1) {
682 return unreportedErrors[0];
683 }
684 const combinedError = new AggregateError(unreportedErrors);
685 return locatedError(combinedError, undefined, unreportedErrors[0].path);
686 }
687 }
688 return null;
689}
690
691/**
692 * Resolver that knows how to:
693 * a) handle aliases for proxied schemas
694 * b) handle errors from proxied schemas
695 * c) handle external to internal enum coversion
696 */
697function defaultMergedResolver(parent, args, context, info) {
698 if (!parent) {
699 return null;
700 }
701 const responseKey = getResponseKeyFromInfo(info);
702 // check to see if parent is not a proxied result, i.e. if parent resolver was manually overwritten
703 // See https://github.com/apollographql/graphql-tools/issues/967
704 if (!isExternalObject(parent)) {
705 return defaultFieldResolver(parent, args, context, info);
706 }
707 const data = parent[responseKey];
708 const unpathedErrors = getUnpathedErrors(parent);
709 const subschema = getSubschema(parent, responseKey);
710 return resolveExternalValue(data, unpathedErrors, subschema, context, info);
711}
712
713class VisitSelectionSets {
714 constructor(visitor) {
715 this.visitor = visitor;
716 }
717 transformRequest(originalRequest, delegationContext, _transformationContext) {
718 const document = visitSelectionSets(originalRequest, delegationContext.info.schema, delegationContext.returnType, this.visitor);
719 return {
720 ...originalRequest,
721 document,
722 };
723 }
724}
725function visitSelectionSets(request, schema, initialType, visitor) {
726 const { document, variables } = request;
727 const operations = [];
728 const fragments = Object.create(null);
729 document.definitions.forEach(def => {
730 if (def.kind === Kind.OPERATION_DEFINITION) {
731 operations.push(def);
732 }
733 else if (def.kind === Kind.FRAGMENT_DEFINITION) {
734 fragments[def.name.value] = def;
735 }
736 });
737 const partialExecutionContext = {
738 schema,
739 variableValues: variables,
740 fragments,
741 };
742 const typeInfo = new TypeInfo(schema, undefined, initialType);
743 const newDefinitions = operations.map(operation => {
744 const type = operation.operation === 'query'
745 ? schema.getQueryType()
746 : operation.operation === 'mutation'
747 ? schema.getMutationType()
748 : schema.getSubscriptionType();
749 const fields = collectFields(partialExecutionContext, type, operation.selectionSet, Object.create(null), Object.create(null));
750 const newSelections = [];
751 Object.keys(fields).forEach(responseKey => {
752 const fieldNodes = fields[responseKey];
753 fieldNodes.forEach(fieldNode => {
754 const selectionSet = fieldNode.selectionSet;
755 if (selectionSet == null) {
756 newSelections.push(fieldNode);
757 return;
758 }
759 const newSelectionSet = visit(selectionSet, visitWithTypeInfo(typeInfo, {
760 [Kind.SELECTION_SET]: node => visitor(node, typeInfo),
761 }));
762 if (newSelectionSet === selectionSet) {
763 newSelections.push(fieldNode);
764 return;
765 }
766 newSelections.push({
767 ...fieldNode,
768 selectionSet: newSelectionSet,
769 });
770 });
771 });
772 return {
773 ...operation,
774 selectionSet: {
775 kind: Kind.SELECTION_SET,
776 selections: newSelections,
777 },
778 };
779 });
780 Object.values(fragments).forEach(fragment => {
781 newDefinitions.push(visit(fragment, visitWithTypeInfo(typeInfo, {
782 [Kind.SELECTION_SET]: node => visitor(node, typeInfo),
783 })));
784 });
785 return {
786 ...document,
787 definitions: newDefinitions,
788 };
789}
790
791class AddSelectionSets {
792 constructor(selectionSetsByType, selectionSetsByField, dynamicSelectionSetsByField) {
793 this.transformer = new VisitSelectionSets((node, typeInfo) => visitSelectionSet(node, typeInfo, selectionSetsByType, selectionSetsByField, dynamicSelectionSetsByField));
794 }
795 transformRequest(originalRequest, delegationContext, transformationContext) {
796 return this.transformer.transformRequest(originalRequest, delegationContext, transformationContext);
797 }
798}
799function visitSelectionSet(node, typeInfo, selectionSetsByType, selectionSetsByField, dynamicSelectionSetsByField) {
800 const parentType = typeInfo.getParentType();
801 const newSelections = new Map();
802 if (parentType != null) {
803 const parentTypeName = parentType.name;
804 addSelectionsToMap(newSelections, node);
805 if (parentTypeName in selectionSetsByType) {
806 const selectionSet = selectionSetsByType[parentTypeName];
807 addSelectionsToMap(newSelections, selectionSet);
808 }
809 if (parentTypeName in selectionSetsByField) {
810 node.selections.forEach(selection => {
811 if (selection.kind === Kind.FIELD) {
812 const name = selection.name.value;
813 const selectionSet = selectionSetsByField[parentTypeName][name];
814 if (selectionSet != null) {
815 addSelectionsToMap(newSelections, selectionSet);
816 }
817 }
818 });
819 }
820 if (parentTypeName in dynamicSelectionSetsByField) {
821 node.selections.forEach(selection => {
822 if (selection.kind === Kind.FIELD) {
823 const name = selection.name.value;
824 const dynamicSelectionSets = dynamicSelectionSetsByField[parentTypeName][name];
825 if (dynamicSelectionSets != null) {
826 dynamicSelectionSets.forEach(selectionSetFn => {
827 const selectionSet = selectionSetFn(selection);
828 if (selectionSet != null) {
829 addSelectionsToMap(newSelections, selectionSet);
830 }
831 });
832 }
833 }
834 });
835 }
836 return {
837 ...node,
838 selections: Array.from(newSelections.values()),
839 };
840 }
841}
842const addSelectionsToMap = memoize2(function (map, selectionSet) {
843 selectionSet.selections.forEach(selection => {
844 map.set(print(selection), selection);
845 });
846});
847
848class ExpandAbstractTypes {
849 transformRequest(originalRequest, delegationContext, _transformationContext) {
850 const targetSchema = delegationContext.targetSchema;
851 const { possibleTypesMap, interfaceExtensionsMap } = extractPossibleTypes(delegationContext.info.schema, targetSchema);
852 const reversePossibleTypesMap = flipMapping(possibleTypesMap);
853 const document = expandAbstractTypes(targetSchema, possibleTypesMap, reversePossibleTypesMap, interfaceExtensionsMap, originalRequest.document);
854 return {
855 ...originalRequest,
856 document,
857 };
858 }
859}
860function extractPossibleTypes(sourceSchema, targetSchema) {
861 const typeMap = sourceSchema.getTypeMap();
862 const possibleTypesMap = Object.create(null);
863 const interfaceExtensionsMap = Object.create(null);
864 Object.keys(typeMap).forEach(typeName => {
865 const type = typeMap[typeName];
866 if (isAbstractType(type)) {
867 const targetType = targetSchema.getType(typeName);
868 if (isInterfaceType(type) && isInterfaceType(targetType)) {
869 const targetTypeFields = targetType.getFields();
870 const extensionFields = Object.create(null);
871 Object.keys(type.getFields()).forEach((fieldName) => {
872 if (!targetTypeFields[fieldName]) {
873 extensionFields[fieldName] = true;
874 }
875 });
876 if (Object.keys(extensionFields).length) {
877 interfaceExtensionsMap[typeName] = extensionFields;
878 }
879 }
880 if (!isAbstractType(targetType) || typeName in interfaceExtensionsMap) {
881 const implementations = sourceSchema.getPossibleTypes(type);
882 possibleTypesMap[typeName] = implementations
883 .filter(impl => targetSchema.getType(impl.name))
884 .map(impl => impl.name);
885 }
886 }
887 });
888 return { possibleTypesMap, interfaceExtensionsMap };
889}
890function flipMapping(mapping) {
891 const result = Object.create(null);
892 Object.keys(mapping).forEach(typeName => {
893 const toTypeNames = mapping[typeName];
894 toTypeNames.forEach(toTypeName => {
895 if (!(toTypeName in result)) {
896 result[toTypeName] = [];
897 }
898 result[toTypeName].push(typeName);
899 });
900 });
901 return result;
902}
903function expandAbstractTypes(targetSchema, possibleTypesMap, reversePossibleTypesMap, interfaceExtensionsMap, document) {
904 const operations = document.definitions.filter(def => def.kind === Kind.OPERATION_DEFINITION);
905 const fragments = document.definitions.filter(def => def.kind === Kind.FRAGMENT_DEFINITION);
906 const existingFragmentNames = fragments.map(fragment => fragment.name.value);
907 let fragmentCounter = 0;
908 const generateFragmentName = (typeName) => {
909 let fragmentName;
910 do {
911 fragmentName = `_${typeName}_Fragment${fragmentCounter.toString()}`;
912 fragmentCounter++;
913 } while (existingFragmentNames.indexOf(fragmentName) !== -1);
914 return fragmentName;
915 };
916 const generateInlineFragment = (typeName, selectionSet) => {
917 return {
918 kind: Kind.INLINE_FRAGMENT,
919 typeCondition: {
920 kind: Kind.NAMED_TYPE,
921 name: {
922 kind: Kind.NAME,
923 value: typeName,
924 },
925 },
926 selectionSet,
927 };
928 };
929 const newFragments = [];
930 const fragmentReplacements = Object.create(null);
931 fragments.forEach((fragment) => {
932 newFragments.push(fragment);
933 const possibleTypes = possibleTypesMap[fragment.typeCondition.name.value];
934 if (possibleTypes != null) {
935 fragmentReplacements[fragment.name.value] = [];
936 possibleTypes.forEach(possibleTypeName => {
937 const name = generateFragmentName(possibleTypeName);
938 existingFragmentNames.push(name);
939 const newFragment = {
940 kind: Kind.FRAGMENT_DEFINITION,
941 name: {
942 kind: Kind.NAME,
943 value: name,
944 },
945 typeCondition: {
946 kind: Kind.NAMED_TYPE,
947 name: {
948 kind: Kind.NAME,
949 value: possibleTypeName,
950 },
951 },
952 selectionSet: fragment.selectionSet,
953 };
954 newFragments.push(newFragment);
955 fragmentReplacements[fragment.name.value].push({
956 fragmentName: name,
957 typeName: possibleTypeName,
958 });
959 });
960 }
961 });
962 const newDocument = {
963 ...document,
964 definitions: [...operations, ...newFragments],
965 };
966 const typeInfo = new TypeInfo(targetSchema);
967 return visit(newDocument, visitWithTypeInfo(typeInfo, {
968 [Kind.SELECTION_SET](node) {
969 let newSelections = node.selections;
970 const addedSelections = [];
971 const maybeType = typeInfo.getParentType();
972 if (maybeType != null) {
973 const parentType = getNamedType(maybeType);
974 const interfaceExtension = interfaceExtensionsMap[parentType.name];
975 const interfaceExtensionFields = [];
976 node.selections.forEach((selection) => {
977 if (selection.kind === Kind.INLINE_FRAGMENT) {
978 if (selection.typeCondition != null) {
979 const possibleTypes = possibleTypesMap[selection.typeCondition.name.value];
980 if (possibleTypes != null) {
981 possibleTypes.forEach(possibleType => {
982 const maybePossibleType = targetSchema.getType(possibleType);
983 if (maybePossibleType != null &&
984 implementsAbstractType(targetSchema, parentType, maybePossibleType)) {
985 addedSelections.push(generateInlineFragment(possibleType, selection.selectionSet));
986 }
987 });
988 }
989 }
990 }
991 else if (selection.kind === Kind.FRAGMENT_SPREAD) {
992 const fragmentName = selection.name.value;
993 if (fragmentName in fragmentReplacements) {
994 fragmentReplacements[fragmentName].forEach(replacement => {
995 const typeName = replacement.typeName;
996 const maybeReplacementType = targetSchema.getType(typeName);
997 if (maybeReplacementType != null && implementsAbstractType(targetSchema, parentType, maybeType)) {
998 addedSelections.push({
999 kind: Kind.FRAGMENT_SPREAD,
1000 name: {
1001 kind: Kind.NAME,
1002 value: replacement.fragmentName,
1003 },
1004 });
1005 }
1006 });
1007 }
1008 }
1009 else if (interfaceExtension != null &&
1010 interfaceExtension[selection.name.value] &&
1011 selection.kind === Kind.FIELD) {
1012 interfaceExtensionFields.push(selection);
1013 }
1014 });
1015 if (parentType.name in reversePossibleTypesMap) {
1016 addedSelections.push({
1017 kind: Kind.FIELD,
1018 name: {
1019 kind: Kind.NAME,
1020 value: '__typename',
1021 },
1022 });
1023 }
1024 if (interfaceExtensionFields.length) {
1025 const possibleTypes = possibleTypesMap[parentType.name];
1026 if (possibleTypes != null) {
1027 possibleTypes.forEach(possibleType => {
1028 addedSelections.push(generateInlineFragment(possibleType, {
1029 kind: Kind.SELECTION_SET,
1030 selections: interfaceExtensionFields,
1031 }));
1032 });
1033 newSelections = newSelections.filter((selection) => !(selection.kind === Kind.FIELD && interfaceExtension[selection.name.value]));
1034 }
1035 }
1036 }
1037 if (addedSelections.length) {
1038 return {
1039 ...node,
1040 selections: newSelections.concat(addedSelections),
1041 };
1042 }
1043 },
1044 }));
1045}
1046
1047// For motivation, see https://github.com/ardatan/graphql-tools/issues/751
1048class WrapConcreteTypes {
1049 transformRequest(originalRequest, delegationContext, _transformationContext) {
1050 const document = wrapConcreteTypes(delegationContext.returnType, delegationContext.targetSchema, originalRequest.document);
1051 return {
1052 ...originalRequest,
1053 document,
1054 };
1055 }
1056}
1057function wrapConcreteTypes(returnType, targetSchema, document) {
1058 var _a, _b, _c;
1059 const namedType = getNamedType(returnType);
1060 if (!isObjectType(namedType)) {
1061 return document;
1062 }
1063 const queryTypeName = (_a = targetSchema.getQueryType()) === null || _a === void 0 ? void 0 : _a.name;
1064 const mutationTypeName = (_b = targetSchema.getMutationType()) === null || _b === void 0 ? void 0 : _b.name;
1065 const subscriptionTypeName = (_c = targetSchema.getSubscriptionType()) === null || _c === void 0 ? void 0 : _c.name;
1066 const typeInfo = new TypeInfo(targetSchema);
1067 const newDocument = visit(document, visitWithTypeInfo(typeInfo, {
1068 [Kind.FRAGMENT_DEFINITION]: (node) => {
1069 const typeName = node.typeCondition.name.value;
1070 if (typeName !== queryTypeName && typeName !== mutationTypeName && typeName !== subscriptionTypeName) {
1071 return false;
1072 }
1073 },
1074 [Kind.FIELD]: (node) => {
1075 if (isAbstractType(getNamedType(typeInfo.getType()))) {
1076 return {
1077 ...node,
1078 selectionSet: {
1079 kind: Kind.SELECTION_SET,
1080 selections: [
1081 {
1082 kind: Kind.INLINE_FRAGMENT,
1083 typeCondition: {
1084 kind: Kind.NAMED_TYPE,
1085 name: {
1086 kind: Kind.NAME,
1087 value: namedType.name,
1088 },
1089 },
1090 selectionSet: node.selectionSet,
1091 },
1092 ],
1093 },
1094 };
1095 }
1096 },
1097 }),
1098 // visitorKeys argument usage a la https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-graphql/src/batching/merge-queries.js
1099 // empty keys cannot be removed only because of typescript errors
1100 // will hopefully be fixed in future version of graphql-js to be optional
1101 {
1102 Name: [],
1103 Document: ['definitions'],
1104 OperationDefinition: ['selectionSet'],
1105 VariableDefinition: [],
1106 Variable: [],
1107 SelectionSet: ['selections'],
1108 Field: [],
1109 Argument: [],
1110 FragmentSpread: [],
1111 InlineFragment: ['selectionSet'],
1112 FragmentDefinition: ['selectionSet'],
1113 IntValue: [],
1114 FloatValue: [],
1115 StringValue: [],
1116 BooleanValue: [],
1117 NullValue: [],
1118 EnumValue: [],
1119 ListValue: [],
1120 ObjectValue: [],
1121 ObjectField: [],
1122 Directive: [],
1123 NamedType: [],
1124 ListType: [],
1125 NonNullType: [],
1126 SchemaDefinition: [],
1127 OperationTypeDefinition: [],
1128 ScalarTypeDefinition: [],
1129 ObjectTypeDefinition: [],
1130 FieldDefinition: [],
1131 InputValueDefinition: [],
1132 InterfaceTypeDefinition: [],
1133 UnionTypeDefinition: [],
1134 EnumTypeDefinition: [],
1135 EnumValueDefinition: [],
1136 InputObjectTypeDefinition: [],
1137 DirectiveDefinition: [],
1138 SchemaExtension: [],
1139 ScalarTypeExtension: [],
1140 ObjectTypeExtension: [],
1141 InterfaceTypeExtension: [],
1142 UnionTypeExtension: [],
1143 EnumTypeExtension: [],
1144 InputObjectTypeExtension: [],
1145 });
1146 return newDocument;
1147}
1148
1149class FilterToSchema {
1150 transformRequest(originalRequest, delegationContext, _transformationContext) {
1151 return {
1152 ...originalRequest,
1153 ...filterToSchema(delegationContext.targetSchema, originalRequest.document, originalRequest.variables),
1154 };
1155 }
1156}
1157function filterToSchema(targetSchema, document, variables) {
1158 const operations = document.definitions.filter(def => def.kind === Kind.OPERATION_DEFINITION);
1159 const fragments = document.definitions.filter(def => def.kind === Kind.FRAGMENT_DEFINITION);
1160 let usedVariables = [];
1161 let usedFragments = [];
1162 const newOperations = [];
1163 let newFragments = [];
1164 const validFragments = fragments.filter((fragment) => {
1165 const typeName = fragment.typeCondition.name.value;
1166 return Boolean(targetSchema.getType(typeName));
1167 });
1168 const validFragmentsWithType = validFragments.reduce((prev, fragment) => ({
1169 ...prev,
1170 [fragment.name.value]: targetSchema.getType(fragment.typeCondition.name.value),
1171 }), {});
1172 let fragmentSet = Object.create(null);
1173 operations.forEach((operation) => {
1174 let type;
1175 if (operation.operation === 'subscription') {
1176 type = targetSchema.getSubscriptionType();
1177 }
1178 else if (operation.operation === 'mutation') {
1179 type = targetSchema.getMutationType();
1180 }
1181 else {
1182 type = targetSchema.getQueryType();
1183 }
1184 const { selectionSet, usedFragments: operationUsedFragments, usedVariables: operationUsedVariables, } = filterSelectionSet(targetSchema, type, validFragmentsWithType, operation.selectionSet);
1185 usedFragments = union(usedFragments, operationUsedFragments);
1186 const { usedVariables: collectedUsedVariables, newFragments: collectedNewFragments, fragmentSet: collectedFragmentSet, } = collectFragmentVariables(targetSchema, fragmentSet, validFragments, validFragmentsWithType, usedFragments);
1187 const operationOrFragmentVariables = union(operationUsedVariables, collectedUsedVariables);
1188 usedVariables = union(usedVariables, operationOrFragmentVariables);
1189 newFragments = collectedNewFragments;
1190 fragmentSet = collectedFragmentSet;
1191 const variableDefinitions = operation.variableDefinitions.filter((variable) => operationOrFragmentVariables.indexOf(variable.variable.name.value) !== -1);
1192 newOperations.push({
1193 kind: Kind.OPERATION_DEFINITION,
1194 operation: operation.operation,
1195 name: operation.name,
1196 directives: operation.directives,
1197 variableDefinitions,
1198 selectionSet,
1199 });
1200 });
1201 const newVariables = usedVariables.reduce((acc, variableName) => {
1202 const variableValue = variables[variableName];
1203 if (variableValue !== undefined) {
1204 acc[variableName] = variableValue;
1205 }
1206 return acc;
1207 }, {});
1208 return {
1209 document: {
1210 kind: Kind.DOCUMENT,
1211 definitions: [...newOperations, ...newFragments],
1212 },
1213 variables: newVariables,
1214 };
1215}
1216function collectFragmentVariables(targetSchema, fragmentSet, validFragments, validFragmentsWithType, usedFragments) {
1217 let remainingFragments = usedFragments.slice();
1218 let usedVariables = [];
1219 const newFragments = [];
1220 while (remainingFragments.length !== 0) {
1221 const nextFragmentName = remainingFragments.pop();
1222 const fragment = validFragments.find(fr => fr.name.value === nextFragmentName);
1223 if (fragment != null) {
1224 const name = nextFragmentName;
1225 const typeName = fragment.typeCondition.name.value;
1226 const type = targetSchema.getType(typeName);
1227 const { selectionSet, usedFragments: fragmentUsedFragments, usedVariables: fragmentUsedVariables, } = filterSelectionSet(targetSchema, type, validFragmentsWithType, fragment.selectionSet);
1228 remainingFragments = union(remainingFragments, fragmentUsedFragments);
1229 usedVariables = union(usedVariables, fragmentUsedVariables);
1230 if (!(name in fragmentSet)) {
1231 fragmentSet[name] = true;
1232 newFragments.push({
1233 kind: Kind.FRAGMENT_DEFINITION,
1234 name: {
1235 kind: Kind.NAME,
1236 value: name,
1237 },
1238 typeCondition: fragment.typeCondition,
1239 selectionSet,
1240 });
1241 }
1242 }
1243 }
1244 return {
1245 usedVariables,
1246 newFragments,
1247 fragmentSet,
1248 };
1249}
1250function filterSelectionSet(schema, type, validFragments, selectionSet) {
1251 const usedFragments = [];
1252 const usedVariables = [];
1253 const typeInfo = new TypeInfo(schema, undefined, type);
1254 const filteredSelectionSet = visit(selectionSet, visitWithTypeInfo(typeInfo, {
1255 [Kind.FIELD]: {
1256 enter(node) {
1257 const parentType = typeInfo.getParentType();
1258 if (isObjectType(parentType) || isInterfaceType(parentType)) {
1259 const fields = parentType.getFields();
1260 const field = node.name.value === '__typename' ? TypeNameMetaFieldDef : fields[node.name.value];
1261 if (!field) {
1262 return null;
1263 }
1264 const argNames = (field.args != null ? field.args : []).map(arg => arg.name);
1265 if (node.arguments != null) {
1266 const args = node.arguments.filter((arg) => argNames.indexOf(arg.name.value) !== -1);
1267 if (args.length !== node.arguments.length) {
1268 return {
1269 ...node,
1270 arguments: args,
1271 };
1272 }
1273 }
1274 }
1275 },
1276 leave(node) {
1277 const resolvedType = getNamedType(typeInfo.getType());
1278 if (isObjectType(resolvedType) || isInterfaceType(resolvedType)) {
1279 const selections = node.selectionSet != null ? node.selectionSet.selections : null;
1280 if (selections == null || selections.length === 0) {
1281 // need to remove any added variables. Is there a better way to do this?
1282 visit(node, {
1283 [Kind.VARIABLE](variableNode) {
1284 const index = usedVariables.indexOf(variableNode.name.value);
1285 if (index !== -1) {
1286 usedVariables.splice(index, 1);
1287 }
1288 },
1289 });
1290 return null;
1291 }
1292 }
1293 },
1294 },
1295 [Kind.FRAGMENT_SPREAD](node) {
1296 if (node.name.value in validFragments) {
1297 const parentType = typeInfo.getParentType();
1298 const innerType = validFragments[node.name.value];
1299 if (!implementsAbstractType(schema, parentType, innerType)) {
1300 return null;
1301 }
1302 usedFragments.push(node.name.value);
1303 return;
1304 }
1305 return null;
1306 },
1307 [Kind.INLINE_FRAGMENT]: {
1308 enter(node) {
1309 if (node.typeCondition != null) {
1310 const parentType = typeInfo.getParentType();
1311 const innerType = schema.getType(node.typeCondition.name.value);
1312 if (!implementsAbstractType(schema, parentType, innerType)) {
1313 return null;
1314 }
1315 }
1316 },
1317 },
1318 [Kind.VARIABLE](node) {
1319 usedVariables.push(node.name.value);
1320 },
1321 }));
1322 return {
1323 selectionSet: filteredSelectionSet,
1324 usedFragments,
1325 usedVariables,
1326 };
1327}
1328function union(...arrays) {
1329 const cache = Object.create(null);
1330 const result = [];
1331 arrays.forEach(array => {
1332 array.forEach(item => {
1333 if (!(item in cache)) {
1334 cache[item] = true;
1335 result.push(item);
1336 }
1337 });
1338 });
1339 return result;
1340}
1341
1342class AddTypenameToAbstract {
1343 transformRequest(originalRequest, delegationContext, _transformationContext) {
1344 const document = addTypenameToAbstract(delegationContext.targetSchema, originalRequest.document);
1345 return {
1346 ...originalRequest,
1347 document,
1348 };
1349 }
1350}
1351function addTypenameToAbstract(targetSchema, document) {
1352 const typeInfo = new TypeInfo(targetSchema);
1353 return visit(document, visitWithTypeInfo(typeInfo, {
1354 [Kind.SELECTION_SET](node) {
1355 const parentType = typeInfo.getParentType();
1356 let selections = node.selections;
1357 if (parentType != null && isAbstractType(parentType)) {
1358 selections = selections.concat({
1359 kind: Kind.FIELD,
1360 name: {
1361 kind: Kind.NAME,
1362 value: '__typename',
1363 },
1364 });
1365 }
1366 if (selections !== node.selections) {
1367 return {
1368 ...node,
1369 selections,
1370 };
1371 }
1372 },
1373 }));
1374}
1375
1376class CheckResultAndHandleErrors {
1377 transformResult(originalResult, delegationContext, _transformationContext) {
1378 return checkResultAndHandleErrors(originalResult, delegationContext.context != null ? delegationContext.context : {}, delegationContext.info, delegationContext.fieldName, delegationContext.subschema, delegationContext.returnType, delegationContext.skipTypeMerging, delegationContext.onLocatedError);
1379 }
1380}
1381function checkResultAndHandleErrors(result, context, info, responseKey = getResponseKeyFromInfo(info), subschema, returnType = info.returnType, skipTypeMerging, onLocatedError) {
1382 const { data, unpathedErrors } = mergeDataAndErrors(result.data == null ? undefined : result.data[responseKey], result.errors == null ? [] : result.errors, info ? responsePathAsArray(info.path) : undefined, onLocatedError);
1383 return resolveExternalValue(data, unpathedErrors, subschema, context, info, returnType, skipTypeMerging);
1384}
1385function mergeDataAndErrors(data, errors, path, onLocatedError, index = 1) {
1386 if (data == null) {
1387 if (!errors.length) {
1388 return { data: null, unpathedErrors: [] };
1389 }
1390 if (errors.length === 1) {
1391 const error = onLocatedError ? onLocatedError(errors[0]) : errors[0];
1392 const newPath = path === undefined ? error.path : error.path === undefined ? path : path.concat(error.path.slice(1));
1393 return { data: relocatedError(errors[0], newPath), unpathedErrors: [] };
1394 }
1395 const newError = locatedError(new AggregateError(errors), undefined, path);
1396 return { data: newError, unpathedErrors: [] };
1397 }
1398 if (!errors.length) {
1399 return { data, unpathedErrors: [] };
1400 }
1401 let unpathedErrors = [];
1402 const errorMap = Object.create(null);
1403 errors.forEach(error => {
1404 var _a;
1405 const pathSegment = (_a = error.path) === null || _a === void 0 ? void 0 : _a[index];
1406 if (pathSegment != null) {
1407 const pathSegmentErrors = errorMap[pathSegment];
1408 if (pathSegmentErrors === undefined) {
1409 errorMap[pathSegment] = [error];
1410 }
1411 else {
1412 pathSegmentErrors.push(error);
1413 }
1414 }
1415 else {
1416 unpathedErrors.push(error);
1417 }
1418 });
1419 Object.keys(errorMap).forEach(pathSegment => {
1420 if (data[pathSegment] !== undefined) {
1421 const { data: newData, unpathedErrors: newErrors } = mergeDataAndErrors(data[pathSegment], errorMap[pathSegment], path, onLocatedError, index + 1);
1422 data[pathSegment] = newData;
1423 unpathedErrors = unpathedErrors.concat(newErrors);
1424 }
1425 else {
1426 unpathedErrors = unpathedErrors.concat(errorMap[pathSegment]);
1427 }
1428 });
1429 return { data, unpathedErrors };
1430}
1431
1432class AddArgumentsAsVariables {
1433 constructor(args) {
1434 this.args = Object.entries(args).reduce((prev, [key, val]) => ({
1435 ...prev,
1436 [key]: val,
1437 }), {});
1438 }
1439 transformRequest(originalRequest, delegationContext, _transformationContext) {
1440 const { document, variables } = addVariablesToRootField(delegationContext.targetSchema, originalRequest, this.args);
1441 return {
1442 ...originalRequest,
1443 document,
1444 variables,
1445 };
1446 }
1447}
1448function addVariablesToRootField(targetSchema, originalRequest, args) {
1449 const document = originalRequest.document;
1450 const variableValues = originalRequest.variables;
1451 const operations = document.definitions.filter(def => def.kind === Kind.OPERATION_DEFINITION);
1452 const fragments = document.definitions.filter(def => def.kind === Kind.FRAGMENT_DEFINITION);
1453 const newOperations = operations.map((operation) => {
1454 const variableDefinitionMap = operation.variableDefinitions.reduce((prev, def) => ({
1455 ...prev,
1456 [def.variable.name.value]: def,
1457 }), {});
1458 let type;
1459 if (operation.operation === 'subscription') {
1460 type = targetSchema.getSubscriptionType();
1461 }
1462 else if (operation.operation === 'mutation') {
1463 type = targetSchema.getMutationType();
1464 }
1465 else {
1466 type = targetSchema.getQueryType();
1467 }
1468 const newSelectionSet = [];
1469 operation.selectionSet.selections.forEach((selection) => {
1470 var _a;
1471 if (selection.kind === Kind.FIELD) {
1472 const argumentNodes = (_a = selection.arguments) !== null && _a !== void 0 ? _a : [];
1473 const argumentNodeMap = argumentNodes.reduce((prev, argument) => ({
1474 ...prev,
1475 [argument.name.value]: argument,
1476 }), {});
1477 const targetField = type.getFields()[selection.name.value];
1478 // excludes __typename
1479 if (targetField != null) {
1480 updateArguments(targetField, argumentNodeMap, variableDefinitionMap, variableValues, args);
1481 }
1482 newSelectionSet.push({
1483 ...selection,
1484 arguments: Object.keys(argumentNodeMap).map(argName => argumentNodeMap[argName]),
1485 });
1486 }
1487 else {
1488 newSelectionSet.push(selection);
1489 }
1490 });
1491 return {
1492 ...operation,
1493 variableDefinitions: Object.keys(variableDefinitionMap).map(varName => variableDefinitionMap[varName]),
1494 selectionSet: {
1495 kind: Kind.SELECTION_SET,
1496 selections: newSelectionSet,
1497 },
1498 };
1499 });
1500 return {
1501 document: {
1502 ...document,
1503 definitions: [...newOperations, ...fragments],
1504 },
1505 variables: variableValues,
1506 };
1507}
1508function updateArguments(targetField, argumentNodeMap, variableDefinitionMap, variableValues, newArgs) {
1509 targetField.args.forEach((argument) => {
1510 const argName = argument.name;
1511 const argType = argument.type;
1512 if (argName in newArgs) {
1513 updateArgument(argName, argType, argumentNodeMap, variableDefinitionMap, variableValues, serializeInputValue(argType, newArgs[argName]));
1514 }
1515 });
1516}
1517
1518function defaultDelegationBinding(delegationContext) {
1519 var _a;
1520 let delegationTransforms = [new CheckResultAndHandleErrors()];
1521 const info = delegationContext.info;
1522 const stitchingInfo = (_a = info === null || info === void 0 ? void 0 : info.schema.extensions) === null || _a === void 0 ? void 0 : _a.stitchingInfo;
1523 if (stitchingInfo != null) {
1524 delegationTransforms = delegationTransforms.concat([
1525 new ExpandAbstractTypes(),
1526 new AddSelectionSets({}, stitchingInfo.selectionSetsByField, stitchingInfo.dynamicSelectionSetsByField),
1527 new WrapConcreteTypes(),
1528 ]);
1529 }
1530 else if (info != null) {
1531 delegationTransforms = delegationTransforms.concat([new WrapConcreteTypes(), new ExpandAbstractTypes()]);
1532 }
1533 else {
1534 delegationTransforms.push(new WrapConcreteTypes());
1535 }
1536 const transforms = delegationContext.transforms;
1537 if (transforms != null) {
1538 delegationTransforms = delegationTransforms.concat(transforms.slice().reverse());
1539 }
1540 const args = delegationContext.args;
1541 if (args != null) {
1542 delegationTransforms.push(new AddArgumentsAsVariables(args));
1543 }
1544 delegationTransforms = delegationTransforms.concat([new FilterToSchema(), new AddTypenameToAbstract()]);
1545 return delegationTransforms;
1546}
1547
1548class Transformer {
1549 constructor(context, binding = defaultDelegationBinding) {
1550 this.transformations = [];
1551 this.delegationContext = context;
1552 const delegationTransforms = binding(this.delegationContext);
1553 delegationTransforms.forEach(transform => this.addTransform(transform, {}));
1554 }
1555 addTransform(transform, context = {}) {
1556 this.transformations.push({ transform, context });
1557 }
1558 transformRequest(originalRequest) {
1559 return this.transformations.reduce((request, transformation) => transformation.transform.transformRequest != null
1560 ? transformation.transform.transformRequest(request, this.delegationContext, transformation.context)
1561 : request, originalRequest);
1562 }
1563 transformResult(originalResult) {
1564 return this.transformations.reduceRight((result, transformation) => transformation.transform.transformResult != null
1565 ? transformation.transform.transformResult(result, this.delegationContext, transformation.context)
1566 : result, originalResult);
1567 }
1568}
1569
1570function delegateToSchema(options) {
1571 const { info, operationName, operation = getDelegatingOperation(info.parentType, info.schema), fieldName = info.fieldName, returnType = info.returnType, selectionSet, fieldNodes, } = options;
1572 const request = createRequestFromInfo({
1573 info,
1574 operation,
1575 fieldName,
1576 selectionSet,
1577 fieldNodes,
1578 operationName,
1579 });
1580 return delegateRequest({
1581 ...options,
1582 request,
1583 operation,
1584 fieldName,
1585 returnType,
1586 });
1587}
1588function getDelegationReturnType(targetSchema, operation, fieldName) {
1589 let rootType;
1590 if (operation === 'query') {
1591 rootType = targetSchema.getQueryType();
1592 }
1593 else if (operation === 'mutation') {
1594 rootType = targetSchema.getMutationType();
1595 }
1596 else {
1597 rootType = targetSchema.getSubscriptionType();
1598 }
1599 return rootType.getFields()[fieldName].type;
1600}
1601function delegateRequest({ request, schema: subschemaOrSubschemaConfig, rootValue, info, operation, fieldName, args, returnType, onLocatedError, context, transforms = [], transformedSchema, skipValidation, skipTypeMerging, binding, }) {
1602 var _a, _b, _c;
1603 let operationDefinition;
1604 let targetOperation;
1605 let targetFieldName;
1606 if (operation == null) {
1607 operationDefinition = getOperationAST(request.document, undefined);
1608 targetOperation = operationDefinition.operation;
1609 }
1610 else {
1611 targetOperation = operation;
1612 }
1613 if (fieldName == null) {
1614 operationDefinition = operationDefinition !== null && operationDefinition !== void 0 ? operationDefinition : getOperationAST(request.document, undefined);
1615 targetFieldName = operationDefinition.selectionSet.selections[0].name.value;
1616 }
1617 else {
1618 targetFieldName = fieldName;
1619 }
1620 const { targetSchema, targetRootValue, subschemaConfig, allTransforms } = collectTargetParameters(subschemaOrSubschemaConfig, rootValue, info, transforms);
1621 const delegationContext = {
1622 subschema: subschemaOrSubschemaConfig,
1623 targetSchema,
1624 operation: targetOperation,
1625 fieldName: targetFieldName,
1626 args,
1627 context,
1628 info,
1629 returnType: (_a = returnType !== null && returnType !== void 0 ? returnType : info === null || info === void 0 ? void 0 : info.returnType) !== null && _a !== void 0 ? _a : getDelegationReturnType(targetSchema, targetOperation, targetFieldName),
1630 onLocatedError,
1631 transforms: allTransforms,
1632 transformedSchema: (_c = transformedSchema !== null && transformedSchema !== void 0 ? transformedSchema : (_b = subschemaConfig) === null || _b === void 0 ? void 0 : _b.transformedSchema) !== null && _c !== void 0 ? _c : targetSchema,
1633 skipTypeMerging,
1634 };
1635 const transformer = new Transformer(delegationContext, binding);
1636 const processedRequest = transformer.transformRequest(request);
1637 if (!skipValidation) {
1638 validateRequest(targetSchema, processedRequest.document);
1639 }
1640 if (targetOperation === 'query' || targetOperation === 'mutation') {
1641 let executor = (subschemaConfig === null || subschemaConfig === void 0 ? void 0 : subschemaConfig.executor) || createDefaultExecutor(targetSchema, (subschemaConfig === null || subschemaConfig === void 0 ? void 0 : subschemaConfig.rootValue) || targetRootValue);
1642 if (subschemaConfig === null || subschemaConfig === void 0 ? void 0 : subschemaConfig.batch) {
1643 const batchingOptions = subschemaConfig === null || subschemaConfig === void 0 ? void 0 : subschemaConfig.batchingOptions;
1644 executor = getBatchingExecutor(context, executor, batchingOptions === null || batchingOptions === void 0 ? void 0 : batchingOptions.dataLoaderOptions, batchingOptions === null || batchingOptions === void 0 ? void 0 : batchingOptions.extensionsReducer);
1645 }
1646 const executionResult = executor({
1647 ...processedRequest,
1648 context,
1649 info,
1650 });
1651 if (isPromise(executionResult)) {
1652 return executionResult.then(originalResult => {
1653 return transformer.transformResult(originalResult);
1654 });
1655 }
1656 return transformer.transformResult(executionResult);
1657 }
1658 const subscriber = (subschemaConfig === null || subschemaConfig === void 0 ? void 0 : subschemaConfig.subscriber) || createDefaultSubscriber(targetSchema, (subschemaConfig === null || subschemaConfig === void 0 ? void 0 : subschemaConfig.rootValue) || targetRootValue);
1659 return subscriber({
1660 ...processedRequest,
1661 context,
1662 info,
1663 }).then((subscriptionResult) => {
1664 if (Symbol.asyncIterator in subscriptionResult) {
1665 // "subscribe" to the subscription result and map the result through the transforms
1666 return mapAsyncIterator(subscriptionResult, originalResult => ({
1667 [targetFieldName]: transformer.transformResult(originalResult),
1668 }));
1669 }
1670 return transformer.transformResult(subscriptionResult);
1671 });
1672}
1673const emptyObject = {};
1674function collectTargetParameters(subschema, rootValue, info, transforms = []) {
1675 var _a, _b, _c, _d, _e;
1676 const stitchingInfo = (_a = info === null || info === void 0 ? void 0 : info.schema.extensions) === null || _a === void 0 ? void 0 : _a.stitchingInfo;
1677 const subschemaOrSubschemaConfig = (_b = stitchingInfo === null || stitchingInfo === void 0 ? void 0 : stitchingInfo.subschemaMap.get(subschema)) !== null && _b !== void 0 ? _b : subschema;
1678 if (isSubschemaConfig(subschemaOrSubschemaConfig)) {
1679 return {
1680 targetSchema: subschemaOrSubschemaConfig.schema,
1681 targetRootValue: (_d = (_c = rootValue !== null && rootValue !== void 0 ? rootValue : subschemaOrSubschemaConfig === null || subschemaOrSubschemaConfig === void 0 ? void 0 : subschemaOrSubschemaConfig.rootValue) !== null && _c !== void 0 ? _c : info === null || info === void 0 ? void 0 : info.rootValue) !== null && _d !== void 0 ? _d : emptyObject,
1682 subschemaConfig: subschemaOrSubschemaConfig,
1683 allTransforms: subschemaOrSubschemaConfig.transforms != null
1684 ? subschemaOrSubschemaConfig.transforms.concat(transforms)
1685 : transforms,
1686 };
1687 }
1688 return {
1689 targetSchema: subschemaOrSubschemaConfig,
1690 targetRootValue: (_e = rootValue !== null && rootValue !== void 0 ? rootValue : info === null || info === void 0 ? void 0 : info.rootValue) !== null && _e !== void 0 ? _e : emptyObject,
1691 allTransforms: transforms,
1692 };
1693}
1694function validateRequest(targetSchema, document) {
1695 const errors = validate(targetSchema, document);
1696 if (errors.length > 0) {
1697 if (errors.length > 1) {
1698 const combinedError = new AggregateError(errors);
1699 throw combinedError;
1700 }
1701 const error = errors[0];
1702 throw error.originalError || error;
1703 }
1704}
1705const createDefaultExecutor = memoize2(function (schema, rootValue) {
1706 return (({ document, context, variables, info }) => execute({
1707 schema,
1708 document,
1709 contextValue: context,
1710 variableValues: variables,
1711 rootValue: rootValue !== null && rootValue !== void 0 ? rootValue : info === null || info === void 0 ? void 0 : info.rootValue,
1712 }));
1713});
1714function createDefaultSubscriber(schema, rootValue) {
1715 return ({ document, context, variables, info }) => subscribe({
1716 schema,
1717 document,
1718 contextValue: context,
1719 variableValues: variables,
1720 rootValue: rootValue !== null && rootValue !== void 0 ? rootValue : info === null || info === void 0 ? void 0 : info.rootValue,
1721 });
1722}
1723
1724export { AddArgumentsAsVariables, AddSelectionSets, AddTypenameToAbstract, CheckResultAndHandleErrors, ExpandAbstractTypes, FilterToSchema, Subschema, VisitSelectionSets, annotateExternalObject, applySchemaTransforms, checkResultAndHandleErrors, cloneSubschemaConfig, createRequest, createRequestFromInfo, defaultDelegationBinding, defaultMergedResolver, delegateRequest, delegateToSchema, getDelegatingOperation, getSubschema, getUnpathedErrors, isExternalObject, isSubschema, isSubschemaConfig, mergeExternalObjects, resolveExternalValue };
1725//# sourceMappingURL=index.esm.js.map