@graphql-tools/stitching-directives 3.0.0-alpha-be1b2ebd.0 → 3.0.0-alpha-20230517123108-df347e95

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. package/README.md +0 -2
  2. package/cjs/defaultStitchingDirectiveOptions.js +10 -0
  3. package/cjs/extractVariables.js +52 -0
  4. package/cjs/federationToStitchingSDL.js +114 -0
  5. package/cjs/getSourcePaths.js +25 -0
  6. package/cjs/index.js +6 -0
  7. package/cjs/package.json +1 -0
  8. package/cjs/parseMergeArgsExpr.js +69 -0
  9. package/cjs/pathsFromSelectionSet.js +31 -0
  10. package/cjs/preparseMergeArgsExpr.js +31 -0
  11. package/cjs/properties.js +70 -0
  12. package/cjs/stitchingDirectives.js +78 -0
  13. package/cjs/stitchingDirectivesTransformer.js +423 -0
  14. package/cjs/stitchingDirectivesValidator.js +120 -0
  15. package/cjs/types.js +0 -0
  16. package/esm/defaultStitchingDirectiveOptions.js +7 -0
  17. package/esm/extractVariables.js +48 -0
  18. package/esm/federationToStitchingSDL.js +110 -0
  19. package/esm/getSourcePaths.js +21 -0
  20. package/esm/index.js +3 -0
  21. package/esm/parseMergeArgsExpr.js +65 -0
  22. package/esm/pathsFromSelectionSet.js +27 -0
  23. package/esm/preparseMergeArgsExpr.js +27 -0
  24. package/esm/properties.js +63 -0
  25. package/esm/stitchingDirectives.js +74 -0
  26. package/esm/stitchingDirectivesTransformer.js +419 -0
  27. package/esm/stitchingDirectivesValidator.js +116 -0
  28. package/esm/types.js +0 -0
  29. package/package.json +40 -15
  30. package/typings/defaultStitchingDirectiveOptions.d.cts +2 -0
  31. package/{defaultStitchingDirectiveOptions.d.ts → typings/defaultStitchingDirectiveOptions.d.ts} +1 -1
  32. package/typings/extractVariables.d.cts +7 -0
  33. package/{extractVariables.d.ts → typings/extractVariables.d.ts} +1 -1
  34. package/typings/federationToStitchingSDL.d.cts +2 -0
  35. package/{federationToStitchingSDL.d.ts → typings/federationToStitchingSDL.d.ts} +1 -1
  36. package/typings/getSourcePaths.d.cts +3 -0
  37. package/{getSourcePaths.d.ts → typings/getSourcePaths.d.ts} +1 -1
  38. package/typings/index.d.cts +3 -0
  39. package/typings/index.d.ts +3 -0
  40. package/typings/parseMergeArgsExpr.d.cts +3 -0
  41. package/{parseMergeArgsExpr.d.ts → typings/parseMergeArgsExpr.d.ts} +1 -1
  42. package/typings/pathsFromSelectionSet.d.ts +2 -0
  43. package/typings/preparseMergeArgsExpr.d.ts +6 -0
  44. package/typings/properties.d.cts +5 -0
  45. package/{properties.d.ts → typings/properties.d.ts} +1 -1
  46. package/typings/stitchingDirectives.d.cts +19 -0
  47. package/{stitchingDirectives.d.ts → typings/stitchingDirectives.d.ts} +1 -1
  48. package/typings/stitchingDirectivesTransformer.d.cts +3 -0
  49. package/{stitchingDirectivesTransformer.d.ts → typings/stitchingDirectivesTransformer.d.ts} +1 -1
  50. package/typings/stitchingDirectivesValidator.d.cts +3 -0
  51. package/{stitchingDirectivesValidator.d.ts → typings/stitchingDirectivesValidator.d.ts} +1 -1
  52. package/typings/types.d.cts +35 -0
  53. package/{types.d.ts → typings/types.d.ts} +3 -3
  54. package/index.d.ts +0 -3
  55. package/index.js +0 -972
  56. package/index.mjs +0 -967
  57. /package/{pathsFromSelectionSet.d.ts → typings/pathsFromSelectionSet.d.cts} +0 -0
  58. /package/{preparseMergeArgsExpr.d.ts → typings/preparseMergeArgsExpr.d.cts} +0 -0
package/index.mjs DELETED
@@ -1,967 +0,0 @@
1
- import { visit, Kind, TypeNameMetaFieldDef, parseValue, valueFromASTUntyped, getNullableType, isListType, isNamedType, isInterfaceType, isUnionType, isObjectType, isAbstractType, getNamedType, print, GraphQLDirective, GraphQLNonNull, GraphQLString, GraphQLList, parse } from 'graphql';
2
- import { mapSchema, MapperKind, getDirective, parseSelectionSet, getImplementingTypes, isSome, mergeDeep } from '@graphql-tools/utils';
3
- import { cloneSubschemaConfig } from '@graphql-tools/delegate';
4
-
5
- const defaultStitchingDirectiveOptions = {
6
- keyDirectiveName: 'key',
7
- computedDirectiveName: 'computed',
8
- canonicalDirectiveName: 'canonical',
9
- mergeDirectiveName: 'merge',
10
- pathToDirectivesInExtensions: ['directives'],
11
- };
12
-
13
- function extractVariables(inputValue) {
14
- const path = [];
15
- const variablePaths = Object.create(null);
16
- const keyPathVisitor = {
17
- enter: (_node, key) => {
18
- if (typeof key === 'number') {
19
- path.push(key);
20
- }
21
- },
22
- leave: (_node, key) => {
23
- if (typeof key === 'number') {
24
- path.pop();
25
- }
26
- },
27
- };
28
- const fieldPathVisitor = {
29
- enter: (node) => {
30
- path.push(node.name.value);
31
- },
32
- leave: () => {
33
- path.pop();
34
- },
35
- };
36
- const variableVisitor = {
37
- enter: (node, key) => {
38
- if (typeof key === 'number') {
39
- variablePaths[node.name.value] = path.concat([key]);
40
- }
41
- else {
42
- variablePaths[node.name.value] = path.slice();
43
- }
44
- return {
45
- kind: Kind.NULL,
46
- };
47
- },
48
- };
49
- const newInputValue = visit(inputValue, {
50
- [Kind.OBJECT]: keyPathVisitor,
51
- [Kind.LIST]: keyPathVisitor,
52
- [Kind.OBJECT_FIELD]: fieldPathVisitor,
53
- [Kind.VARIABLE]: variableVisitor,
54
- });
55
- return {
56
- inputValue: newInputValue,
57
- variablePaths,
58
- };
59
- }
60
-
61
- const KEY_DELIMITER = '__dot__';
62
- const EXPANSION_PREFIX = '__exp';
63
- function preparseMergeArgsExpr(mergeArgsExpr) {
64
- const variableRegex = /\$[_A-Za-z][_A-Za-z0-9.]*/g;
65
- const dotRegex = /\./g;
66
- mergeArgsExpr = mergeArgsExpr.replace(variableRegex, variable => variable.replace(dotRegex, KEY_DELIMITER));
67
- const segments = mergeArgsExpr.split('[[');
68
- const expansionExpressions = Object.create(null);
69
- if (segments.length === 1) {
70
- return { mergeArgsExpr: mergeArgsExpr, expansionExpressions };
71
- }
72
- let finalSegments = [segments[0]];
73
- for (let i = 1; i < segments.length; i++) {
74
- const additionalSegments = segments[i].split(']]');
75
- if (additionalSegments.length !== 2) {
76
- throw new Error(`Each opening "[[" must be matched by a closing "]]" without nesting.`);
77
- }
78
- finalSegments = finalSegments.concat(additionalSegments);
79
- }
80
- let finalMergeArgsExpr = finalSegments[0];
81
- for (let i = 1; i < finalSegments.length - 1; i += 2) {
82
- const variableName = `${EXPANSION_PREFIX}${(i - 1) / 2 + 1}`;
83
- expansionExpressions[variableName] = finalSegments[i];
84
- finalMergeArgsExpr += `\$${variableName}${finalSegments[i + 1]}`;
85
- }
86
- return { mergeArgsExpr: finalMergeArgsExpr, expansionExpressions };
87
- }
88
-
89
- function addProperty(object, path, value) {
90
- const initialSegment = path[0];
91
- if (path.length === 1) {
92
- object[initialSegment] = value;
93
- return;
94
- }
95
- let field = object[initialSegment];
96
- if (field != null) {
97
- addProperty(field, path.slice(1), value);
98
- return;
99
- }
100
- if (typeof path[1] === 'string') {
101
- field = Object.create(null);
102
- }
103
- else {
104
- field = [];
105
- }
106
- addProperty(field, path.slice(1), value);
107
- object[initialSegment] = field;
108
- }
109
- function getProperty(object, path) {
110
- if (!path.length || object == null) {
111
- return object;
112
- }
113
- const newPath = path.slice();
114
- const key = newPath.shift();
115
- if (key == null) {
116
- return;
117
- }
118
- const prop = object[key];
119
- return getProperty(prop, newPath);
120
- }
121
- function getProperties(object, propertyTree) {
122
- if (object == null) {
123
- return object;
124
- }
125
- const newObject = Object.create(null);
126
- for (const key in propertyTree) {
127
- const subKey = propertyTree[key];
128
- if (subKey == null) {
129
- newObject[key] = object[key];
130
- continue;
131
- }
132
- const prop = object[key];
133
- newObject[key] = deepMap(prop, function deepMapFn(item) {
134
- return getProperties(item, subKey);
135
- });
136
- }
137
- return newObject;
138
- }
139
- function propertyTreeFromPaths(paths) {
140
- const propertyTree = Object.create(null);
141
- for (const path of paths) {
142
- addProperty(propertyTree, path, null);
143
- }
144
- return propertyTree;
145
- }
146
- function deepMap(arrayOrItem, fn) {
147
- if (Array.isArray(arrayOrItem)) {
148
- return arrayOrItem.map(nestedArrayOrItem => deepMap(nestedArrayOrItem, fn));
149
- }
150
- return fn(arrayOrItem);
151
- }
152
-
153
- function pathsFromSelectionSet(selectionSet, path = []) {
154
- var _a;
155
- const paths = [];
156
- for (const selection of selectionSet.selections) {
157
- const additions = (_a = pathsFromSelection(selection, path)) !== null && _a !== void 0 ? _a : [];
158
- for (const addition of additions) {
159
- paths.push(addition);
160
- }
161
- }
162
- return paths;
163
- }
164
- function pathsFromSelection(selection, path) {
165
- var _a, _b;
166
- if (selection.kind === Kind.FIELD) {
167
- const responseKey = (_b = (_a = selection.alias) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : selection.name.value;
168
- if (selection.selectionSet) {
169
- return pathsFromSelectionSet(selection.selectionSet, path.concat([responseKey]));
170
- }
171
- else {
172
- return [path.concat([responseKey])];
173
- }
174
- }
175
- else if (selection.kind === Kind.INLINE_FRAGMENT) {
176
- return pathsFromSelectionSet(selection.selectionSet, path);
177
- }
178
- }
179
-
180
- function getSourcePaths(mappingInstructions, selectionSet) {
181
- const sourcePaths = [];
182
- for (const mappingInstruction of mappingInstructions) {
183
- const { sourcePath } = mappingInstruction;
184
- if (sourcePath.length) {
185
- sourcePaths.push(sourcePath);
186
- continue;
187
- }
188
- if (selectionSet == null) {
189
- continue;
190
- }
191
- const paths = pathsFromSelectionSet(selectionSet);
192
- for (const path of paths) {
193
- sourcePaths.push(path);
194
- }
195
- sourcePaths.push([TypeNameMetaFieldDef.name]);
196
- }
197
- return sourcePaths;
198
- }
199
-
200
- function parseMergeArgsExpr(mergeArgsExpr, selectionSet) {
201
- const { mergeArgsExpr: newMergeArgsExpr, expansionExpressions } = preparseMergeArgsExpr(mergeArgsExpr);
202
- const inputValue = parseValue(`{ ${newMergeArgsExpr} }`, { noLocation: true });
203
- const { inputValue: newInputValue, variablePaths } = extractVariables(inputValue);
204
- if (!Object.keys(expansionExpressions).length) {
205
- if (!Object.keys(variablePaths).length) {
206
- throw new Error('Merge arguments must declare a key.');
207
- }
208
- const mappingInstructions = getMappingInstructions(variablePaths);
209
- const usedProperties = propertyTreeFromPaths(getSourcePaths(mappingInstructions, selectionSet));
210
- return { args: valueFromASTUntyped(newInputValue), usedProperties, mappingInstructions };
211
- }
212
- const expansionRegEx = new RegExp(`^${EXPANSION_PREFIX}[0-9]+$`);
213
- for (const variableName in variablePaths) {
214
- if (!variableName.match(expansionRegEx)) {
215
- throw new Error('Expansions cannot be mixed with single key declarations.');
216
- }
217
- }
218
- const expansions = [];
219
- const sourcePaths = [];
220
- for (const variableName in expansionExpressions) {
221
- const str = expansionExpressions[variableName];
222
- const valuePath = variablePaths[variableName];
223
- const { inputValue: expansionInputValue, variablePaths: expansionVariablePaths } = extractVariables(parseValue(`${str}`, { noLocation: true }));
224
- if (!Object.keys(expansionVariablePaths).length) {
225
- throw new Error('Merge arguments must declare a key.');
226
- }
227
- const mappingInstructions = getMappingInstructions(expansionVariablePaths);
228
- const value = valueFromASTUntyped(expansionInputValue);
229
- sourcePaths.push(...getSourcePaths(mappingInstructions, selectionSet));
230
- assertNotWithinList(valuePath);
231
- expansions.push({
232
- valuePath,
233
- value,
234
- mappingInstructions,
235
- });
236
- }
237
- const usedProperties = propertyTreeFromPaths(sourcePaths);
238
- return { args: valueFromASTUntyped(newInputValue), usedProperties, expansions };
239
- }
240
- function getMappingInstructions(variablePaths) {
241
- const mappingInstructions = [];
242
- for (const keyPath in variablePaths) {
243
- const valuePath = variablePaths[keyPath];
244
- const splitKeyPath = keyPath.split(KEY_DELIMITER).slice(1);
245
- assertNotWithinList(valuePath);
246
- mappingInstructions.push({
247
- destinationPath: valuePath,
248
- sourcePath: splitKeyPath,
249
- });
250
- }
251
- return mappingInstructions;
252
- }
253
- function assertNotWithinList(path) {
254
- for (const pathSegment of path) {
255
- if (typeof pathSegment === 'number') {
256
- throw new Error('Insertions cannot be made into a list.');
257
- }
258
- }
259
- }
260
-
261
- const dottedNameRegEx = /^[_A-Za-z][_0-9A-Za-z]*(.[_A-Za-z][_0-9A-Za-z]*)*$/;
262
- function stitchingDirectivesValidator(options = {}) {
263
- const { keyDirectiveName, computedDirectiveName, mergeDirectiveName, pathToDirectivesInExtensions } = {
264
- ...defaultStitchingDirectiveOptions,
265
- ...options,
266
- };
267
- return (schema) => {
268
- var _a;
269
- const queryTypeName = (_a = schema.getQueryType()) === null || _a === void 0 ? void 0 : _a.name;
270
- mapSchema(schema, {
271
- [MapperKind.OBJECT_TYPE]: type => {
272
- var _a;
273
- const keyDirective = (_a = getDirective(schema, type, keyDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
274
- if (keyDirective != null) {
275
- parseSelectionSet(keyDirective['selectionSet']);
276
- }
277
- return undefined;
278
- },
279
- [MapperKind.OBJECT_FIELD]: (fieldConfig, _fieldName, typeName) => {
280
- var _a, _b, _c;
281
- const computedDirective = (_a = getDirective(schema, fieldConfig, computedDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
282
- if (computedDirective != null) {
283
- parseSelectionSet(computedDirective['selectionSet']);
284
- }
285
- const mergeDirective = (_b = getDirective(schema, fieldConfig, mergeDirectiveName, pathToDirectivesInExtensions)) === null || _b === void 0 ? void 0 : _b[0];
286
- if (mergeDirective != null) {
287
- if (typeName !== queryTypeName) {
288
- throw new Error('@merge directive may be used only for root fields of the root Query type.');
289
- }
290
- let returnType = getNullableType(fieldConfig.type);
291
- if (isListType(returnType)) {
292
- returnType = getNullableType(returnType.ofType);
293
- }
294
- if (!isNamedType(returnType)) {
295
- throw new Error('@merge directive must be used on a field that returns an object or a list of objects.');
296
- }
297
- const mergeArgsExpr = mergeDirective['argsExpr'];
298
- if (mergeArgsExpr != null) {
299
- parseMergeArgsExpr(mergeArgsExpr);
300
- }
301
- const args = Object.keys((_c = fieldConfig.args) !== null && _c !== void 0 ? _c : {});
302
- const keyArg = mergeDirective['keyArg'];
303
- if (keyArg == null) {
304
- if (!mergeArgsExpr && args.length !== 1) {
305
- throw new Error('Cannot use @merge directive without `keyArg` argument if resolver takes more than one argument.');
306
- }
307
- }
308
- else if (!keyArg.match(dottedNameRegEx)) {
309
- throw new Error('`keyArg` argument for @merge directive must be a set of valid GraphQL SDL names separated by periods.');
310
- // TODO: ideally we should check that the arg exists for the resolver
311
- }
312
- const keyField = mergeDirective['keyField'];
313
- if (keyField != null && !keyField.match(dottedNameRegEx)) {
314
- throw new Error('`keyField` argument for @merge directive must be a set of valid GraphQL SDL names separated by periods.');
315
- // TODO: ideally we should check that it is part of the key
316
- }
317
- const key = mergeDirective['key'];
318
- if (key != null) {
319
- if (keyField != null) {
320
- throw new Error('Cannot use @merge directive with both `keyField` and `key` arguments.');
321
- }
322
- for (const keyDef of key) {
323
- let [aliasOrKeyPath, keyPath] = keyDef.split(':');
324
- let aliasPath;
325
- if (keyPath == null) {
326
- keyPath = aliasPath = aliasOrKeyPath;
327
- }
328
- else {
329
- aliasPath = aliasOrKeyPath;
330
- }
331
- if (keyPath != null && !keyPath.match(dottedNameRegEx)) {
332
- throw new Error('Each partial key within the `key` argument for @merge directive must be a set of valid GraphQL SDL names separated by periods.');
333
- // TODO: ideally we should check that it is part of the key
334
- }
335
- if (aliasPath != null && !aliasOrKeyPath.match(dottedNameRegEx)) {
336
- throw new Error('Each alias within the `key` argument for @merge directive must be a set of valid GraphQL SDL names separated by periods.');
337
- // TODO: ideally we should check that the arg exists within the resolver
338
- }
339
- }
340
- }
341
- const additionalArgs = mergeDirective['additionalArgs'];
342
- if (additionalArgs != null) {
343
- parseValue(`{ ${additionalArgs} }`, { noLocation: true });
344
- }
345
- if (mergeArgsExpr != null && (keyArg != null || additionalArgs != null)) {
346
- throw new Error('Cannot use @merge directive with both `argsExpr` argument and any additional argument.');
347
- }
348
- if (!isInterfaceType(returnType) && !isUnionType(returnType) && !isObjectType(returnType)) {
349
- throw new Error('@merge directive may be used only with resolver that return an object, interface, or union.');
350
- }
351
- const typeNames = mergeDirective['types'];
352
- if (typeNames != null) {
353
- if (!isAbstractType(returnType)) {
354
- throw new Error('Types argument can only be used with a field that returns an abstract type.');
355
- }
356
- const implementingTypes = isInterfaceType(returnType)
357
- ? getImplementingTypes(returnType.name, schema).map(typeName => schema.getType(typeName))
358
- : returnType.getTypes();
359
- const implementingTypeNames = implementingTypes.map(type => type === null || type === void 0 ? void 0 : type.name).filter(isSome);
360
- for (const typeName of typeNames) {
361
- if (!implementingTypeNames.includes(typeName)) {
362
- throw new Error(`Types argument can only include only type names that implement the field return type's abstract type.`);
363
- }
364
- }
365
- }
366
- }
367
- return undefined;
368
- },
369
- });
370
- return schema;
371
- };
372
- }
373
-
374
- function stitchingDirectivesTransformer(options = {}) {
375
- const { keyDirectiveName, computedDirectiveName, mergeDirectiveName, canonicalDirectiveName, pathToDirectivesInExtensions, } = {
376
- ...defaultStitchingDirectiveOptions,
377
- ...options,
378
- };
379
- return (subschemaConfig) => {
380
- var _a, _b, _c, _d, _e, _f, _g, _h;
381
- const newSubschemaConfig = cloneSubschemaConfig(subschemaConfig);
382
- const selectionSetsByType = Object.create(null);
383
- const computedFieldSelectionSets = Object.create(null);
384
- const mergedTypesResolversInfo = Object.create(null);
385
- const canonicalTypesInfo = Object.create(null);
386
- const schema = subschemaConfig.schema;
387
- // gateway should also run validation
388
- stitchingDirectivesValidator(options)(schema);
389
- function setCanonicalDefinition(typeName, fieldName) {
390
- var _a;
391
- canonicalTypesInfo[typeName] = canonicalTypesInfo[typeName] || Object.create(null);
392
- if (fieldName) {
393
- const fields = (_a = canonicalTypesInfo[typeName].fields) !== null && _a !== void 0 ? _a : Object.create(null);
394
- canonicalTypesInfo[typeName].fields = fields;
395
- fields[fieldName] = true;
396
- }
397
- else {
398
- canonicalTypesInfo[typeName].canonical = true;
399
- }
400
- }
401
- mapSchema(schema, {
402
- [MapperKind.OBJECT_TYPE]: type => {
403
- var _a, _b;
404
- const keyDirective = (_a = getDirective(schema, type, keyDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
405
- if (keyDirective != null) {
406
- const selectionSet = parseSelectionSet(keyDirective['selectionSet'], { noLocation: true });
407
- selectionSetsByType[type.name] = selectionSet;
408
- }
409
- const canonicalDirective = (_b = getDirective(schema, type, canonicalDirectiveName, pathToDirectivesInExtensions)) === null || _b === void 0 ? void 0 : _b[0];
410
- if (canonicalDirective != null) {
411
- setCanonicalDefinition(type.name);
412
- }
413
- return undefined;
414
- },
415
- [MapperKind.OBJECT_FIELD]: (fieldConfig, fieldName, typeName) => {
416
- var _a, _b, _c;
417
- const computedDirective = (_a = getDirective(schema, fieldConfig, computedDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
418
- if (computedDirective != null) {
419
- const selectionSet = parseSelectionSet(computedDirective['selectionSet'], { noLocation: true });
420
- if (!computedFieldSelectionSets[typeName]) {
421
- computedFieldSelectionSets[typeName] = Object.create(null);
422
- }
423
- computedFieldSelectionSets[typeName][fieldName] = selectionSet;
424
- }
425
- const mergeDirective = (_b = getDirective(schema, fieldConfig, mergeDirectiveName, pathToDirectivesInExtensions)) === null || _b === void 0 ? void 0 : _b[0];
426
- if ((mergeDirective === null || mergeDirective === void 0 ? void 0 : mergeDirective['keyField']) != null) {
427
- const mergeDirectiveKeyField = mergeDirective['keyField'];
428
- const selectionSet = parseSelectionSet(`{ ${mergeDirectiveKeyField}}`, { noLocation: true });
429
- const typeNames = mergeDirective['types'];
430
- const returnType = getNamedType(fieldConfig.type);
431
- forEachConcreteType(schema, returnType, typeNames, typeName => {
432
- if (typeNames == null || typeNames.includes(typeName)) {
433
- const existingSelectionSet = selectionSetsByType[typeName];
434
- selectionSetsByType[typeName] = existingSelectionSet
435
- ? mergeSelectionSets(existingSelectionSet, selectionSet)
436
- : selectionSet;
437
- }
438
- });
439
- }
440
- const canonicalDirective = (_c = getDirective(schema, fieldConfig, canonicalDirectiveName, pathToDirectivesInExtensions)) === null || _c === void 0 ? void 0 : _c[0];
441
- if (canonicalDirective != null) {
442
- setCanonicalDefinition(typeName, fieldName);
443
- }
444
- return undefined;
445
- },
446
- [MapperKind.INTERFACE_TYPE]: type => {
447
- var _a;
448
- const canonicalDirective = (_a = getDirective(schema, type, canonicalDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
449
- if (canonicalDirective) {
450
- setCanonicalDefinition(type.name);
451
- }
452
- return undefined;
453
- },
454
- [MapperKind.INTERFACE_FIELD]: (fieldConfig, fieldName, typeName) => {
455
- var _a;
456
- const canonicalDirective = (_a = getDirective(schema, fieldConfig, canonicalDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
457
- if (canonicalDirective) {
458
- setCanonicalDefinition(typeName, fieldName);
459
- }
460
- return undefined;
461
- },
462
- [MapperKind.INPUT_OBJECT_TYPE]: type => {
463
- var _a;
464
- const canonicalDirective = (_a = getDirective(schema, type, canonicalDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
465
- if (canonicalDirective) {
466
- setCanonicalDefinition(type.name);
467
- }
468
- return undefined;
469
- },
470
- [MapperKind.INPUT_OBJECT_FIELD]: (inputFieldConfig, fieldName, typeName) => {
471
- var _a;
472
- const canonicalDirective = (_a = getDirective(schema, inputFieldConfig, canonicalDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
473
- if (canonicalDirective != null) {
474
- setCanonicalDefinition(typeName, fieldName);
475
- }
476
- return undefined;
477
- },
478
- [MapperKind.UNION_TYPE]: type => {
479
- var _a;
480
- const canonicalDirective = (_a = getDirective(schema, type, canonicalDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
481
- if (canonicalDirective != null) {
482
- setCanonicalDefinition(type.name);
483
- }
484
- return undefined;
485
- },
486
- [MapperKind.ENUM_TYPE]: type => {
487
- var _a;
488
- const canonicalDirective = (_a = getDirective(schema, type, canonicalDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
489
- if (canonicalDirective != null) {
490
- setCanonicalDefinition(type.name);
491
- }
492
- return undefined;
493
- },
494
- [MapperKind.SCALAR_TYPE]: type => {
495
- var _a;
496
- const canonicalDirective = (_a = getDirective(schema, type, canonicalDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
497
- if (canonicalDirective != null) {
498
- setCanonicalDefinition(type.name);
499
- }
500
- return undefined;
501
- },
502
- });
503
- if (subschemaConfig.merge) {
504
- for (const typeName in subschemaConfig.merge) {
505
- const mergedTypeConfig = subschemaConfig.merge[typeName];
506
- if (mergedTypeConfig.selectionSet) {
507
- const selectionSet = parseSelectionSet(mergedTypeConfig.selectionSet, { noLocation: true });
508
- if (selectionSet) {
509
- if (selectionSetsByType[typeName]) {
510
- selectionSetsByType[typeName] = mergeSelectionSets(selectionSetsByType[typeName], selectionSet);
511
- }
512
- else {
513
- selectionSetsByType[typeName] = selectionSet;
514
- }
515
- }
516
- }
517
- if (mergedTypeConfig.fields) {
518
- for (const fieldName in mergedTypeConfig.fields) {
519
- const fieldConfig = mergedTypeConfig.fields[fieldName];
520
- if (!fieldConfig.selectionSet)
521
- continue;
522
- const selectionSet = parseSelectionSet(fieldConfig.selectionSet, { noLocation: true });
523
- if (selectionSet) {
524
- if ((_a = computedFieldSelectionSets[typeName]) === null || _a === void 0 ? void 0 : _a[fieldName]) {
525
- computedFieldSelectionSets[typeName][fieldName] = mergeSelectionSets(computedFieldSelectionSets[typeName][fieldName], selectionSet);
526
- }
527
- else {
528
- if (computedFieldSelectionSets[typeName] == null) {
529
- computedFieldSelectionSets[typeName] = Object.create(null);
530
- }
531
- computedFieldSelectionSets[typeName][fieldName] = selectionSet;
532
- }
533
- }
534
- }
535
- }
536
- }
537
- }
538
- const allSelectionSetsByType = Object.create(null);
539
- for (const typeName in selectionSetsByType) {
540
- allSelectionSetsByType[typeName] = allSelectionSetsByType[typeName] || [];
541
- const selectionSet = selectionSetsByType[typeName];
542
- allSelectionSetsByType[typeName].push(selectionSet);
543
- }
544
- for (const typeName in computedFieldSelectionSets) {
545
- const selectionSets = computedFieldSelectionSets[typeName];
546
- for (const i in selectionSets) {
547
- allSelectionSetsByType[typeName] = allSelectionSetsByType[typeName] || [];
548
- const selectionSet = selectionSets[i];
549
- allSelectionSetsByType[typeName].push(selectionSet);
550
- }
551
- }
552
- mapSchema(schema, {
553
- [MapperKind.OBJECT_FIELD]: function objectFieldMapper(fieldConfig, fieldName) {
554
- var _a, _b;
555
- const mergeDirective = (_a = getDirective(schema, fieldConfig, mergeDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
556
- if (mergeDirective != null) {
557
- const returnType = getNullableType(fieldConfig.type);
558
- const returnsList = isListType(returnType);
559
- const namedType = getNamedType(returnType);
560
- let mergeArgsExpr = mergeDirective['argsExpr'];
561
- if (mergeArgsExpr == null) {
562
- const key = mergeDirective['key'];
563
- const keyField = mergeDirective['keyField'];
564
- const keyExpr = key != null ? buildKeyExpr(key) : keyField != null ? `$key.${keyField}` : '$key';
565
- const keyArg = mergeDirective['keyArg'];
566
- const argNames = keyArg == null ? [Object.keys((_b = fieldConfig.args) !== null && _b !== void 0 ? _b : {})[0]] : keyArg.split('.');
567
- const lastArgName = argNames.pop();
568
- mergeArgsExpr = returnsList ? `${lastArgName}: [[${keyExpr}]]` : `${lastArgName}: ${keyExpr}`;
569
- for (const argName of argNames.reverse()) {
570
- mergeArgsExpr = `${argName}: { ${mergeArgsExpr} }`;
571
- }
572
- }
573
- const typeNames = mergeDirective['types'];
574
- forEachConcreteTypeName(namedType, schema, typeNames, function generateResolveInfo(typeName) {
575
- const parsedMergeArgsExpr = parseMergeArgsExpr(mergeArgsExpr, allSelectionSetsByType[typeName] == null
576
- ? undefined
577
- : mergeSelectionSets(...allSelectionSetsByType[typeName]));
578
- const additionalArgs = mergeDirective['additionalArgs'];
579
- if (additionalArgs != null) {
580
- parsedMergeArgsExpr.args = mergeDeep([
581
- parsedMergeArgsExpr.args,
582
- valueFromASTUntyped(parseValue(`{ ${additionalArgs} }`, { noLocation: true })),
583
- ]);
584
- }
585
- mergedTypesResolversInfo[typeName] = {
586
- fieldName,
587
- returnsList,
588
- ...parsedMergeArgsExpr,
589
- };
590
- });
591
- }
592
- return undefined;
593
- },
594
- });
595
- for (const typeName in selectionSetsByType) {
596
- const selectionSet = selectionSetsByType[typeName];
597
- const mergeConfig = (_b = newSubschemaConfig.merge) !== null && _b !== void 0 ? _b : Object.create(null);
598
- newSubschemaConfig.merge = mergeConfig;
599
- if (mergeConfig[typeName] == null) {
600
- newSubschemaConfig.merge[typeName] = Object.create(null);
601
- }
602
- const mergeTypeConfig = mergeConfig[typeName];
603
- mergeTypeConfig.selectionSet = print(selectionSet);
604
- }
605
- for (const typeName in computedFieldSelectionSets) {
606
- const selectionSets = computedFieldSelectionSets[typeName];
607
- const mergeConfig = (_c = newSubschemaConfig.merge) !== null && _c !== void 0 ? _c : Object.create(null);
608
- newSubschemaConfig.merge = mergeConfig;
609
- if (mergeConfig[typeName] == null) {
610
- mergeConfig[typeName] = Object.create(null);
611
- }
612
- const mergeTypeConfig = newSubschemaConfig.merge[typeName];
613
- const mergeTypeConfigFields = (_d = mergeTypeConfig.fields) !== null && _d !== void 0 ? _d : Object.create(null);
614
- mergeTypeConfig.fields = mergeTypeConfigFields;
615
- for (const fieldName in selectionSets) {
616
- const selectionSet = selectionSets[fieldName];
617
- const fieldConfig = (_e = mergeTypeConfigFields[fieldName]) !== null && _e !== void 0 ? _e : Object.create(null);
618
- mergeTypeConfigFields[fieldName] = fieldConfig;
619
- fieldConfig.selectionSet = print(selectionSet);
620
- fieldConfig.computed = true;
621
- }
622
- }
623
- for (const typeName in mergedTypesResolversInfo) {
624
- const mergedTypeResolverInfo = mergedTypesResolversInfo[typeName];
625
- const mergeConfig = (_f = newSubschemaConfig.merge) !== null && _f !== void 0 ? _f : Object.create(null);
626
- newSubschemaConfig.merge = mergeConfig;
627
- if (newSubschemaConfig.merge[typeName] == null) {
628
- newSubschemaConfig.merge[typeName] = Object.create(null);
629
- }
630
- const mergeTypeConfig = newSubschemaConfig.merge[typeName];
631
- mergeTypeConfig.fieldName = mergedTypeResolverInfo.fieldName;
632
- if (mergedTypeResolverInfo.returnsList) {
633
- mergeTypeConfig.key = generateKeyFn(mergedTypeResolverInfo);
634
- mergeTypeConfig.argsFromKeys = generateArgsFromKeysFn(mergedTypeResolverInfo);
635
- }
636
- else {
637
- mergeTypeConfig.args = generateArgsFn(mergedTypeResolverInfo);
638
- }
639
- }
640
- for (const typeName in canonicalTypesInfo) {
641
- const canonicalTypeInfo = canonicalTypesInfo[typeName];
642
- const mergeConfig = (_g = newSubschemaConfig.merge) !== null && _g !== void 0 ? _g : Object.create(null);
643
- newSubschemaConfig.merge = mergeConfig;
644
- if (newSubschemaConfig.merge[typeName] == null) {
645
- newSubschemaConfig.merge[typeName] = Object.create(null);
646
- }
647
- const mergeTypeConfig = newSubschemaConfig.merge[typeName];
648
- if (canonicalTypeInfo.canonical) {
649
- mergeTypeConfig.canonical = true;
650
- }
651
- if (canonicalTypeInfo.fields) {
652
- const mergeTypeConfigFields = (_h = mergeTypeConfig.fields) !== null && _h !== void 0 ? _h : Object.create(null);
653
- mergeTypeConfig.fields = mergeTypeConfigFields;
654
- for (const fieldName in canonicalTypeInfo.fields) {
655
- if (mergeTypeConfigFields[fieldName] == null) {
656
- mergeTypeConfigFields[fieldName] = Object.create(null);
657
- }
658
- mergeTypeConfigFields[fieldName].canonical = true;
659
- }
660
- }
661
- }
662
- return newSubschemaConfig;
663
- };
664
- }
665
- function forEachConcreteType(schema, type, typeNames, fn) {
666
- if (isInterfaceType(type)) {
667
- for (const typeName of getImplementingTypes(type.name, schema)) {
668
- if (typeNames == null || typeNames.includes(typeName)) {
669
- fn(typeName);
670
- }
671
- }
672
- }
673
- else if (isUnionType(type)) {
674
- for (const { name: typeName } of type.getTypes()) {
675
- if (typeNames == null || typeNames.includes(typeName)) {
676
- fn(typeName);
677
- }
678
- }
679
- }
680
- else if (isObjectType(type)) {
681
- fn(type.name);
682
- }
683
- }
684
- function generateKeyFn(mergedTypeResolverInfo) {
685
- return function keyFn(originalResult) {
686
- return getProperties(originalResult, mergedTypeResolverInfo.usedProperties);
687
- };
688
- }
689
- function generateArgsFromKeysFn(mergedTypeResolverInfo) {
690
- const { expansions, args } = mergedTypeResolverInfo;
691
- return function generateArgsFromKeys(keys) {
692
- const newArgs = mergeDeep([{}, args]);
693
- if (expansions) {
694
- for (const expansion of expansions) {
695
- const mappingInstructions = expansion.mappingInstructions;
696
- const expanded = [];
697
- for (const key of keys) {
698
- let newValue = mergeDeep([{}, expansion.valuePath]);
699
- for (const { destinationPath, sourcePath } of mappingInstructions) {
700
- if (destinationPath.length) {
701
- addProperty(newValue, destinationPath, getProperty(key, sourcePath));
702
- }
703
- else {
704
- newValue = getProperty(key, sourcePath);
705
- }
706
- }
707
- expanded.push(newValue);
708
- }
709
- addProperty(newArgs, expansion.valuePath, expanded);
710
- }
711
- }
712
- return newArgs;
713
- };
714
- }
715
- function generateArgsFn(mergedTypeResolverInfo) {
716
- const { mappingInstructions, args, usedProperties } = mergedTypeResolverInfo;
717
- return function generateArgs(originalResult) {
718
- const newArgs = mergeDeep([{}, args]);
719
- const filteredResult = getProperties(originalResult, usedProperties);
720
- if (mappingInstructions) {
721
- for (const mappingInstruction of mappingInstructions) {
722
- const { destinationPath, sourcePath } = mappingInstruction;
723
- addProperty(newArgs, destinationPath, getProperty(filteredResult, sourcePath));
724
- }
725
- }
726
- return newArgs;
727
- };
728
- }
729
- function buildKeyExpr(key) {
730
- let mergedObject = {};
731
- for (const keyDef of key) {
732
- let [aliasOrKeyPath, keyPath] = keyDef.split(':');
733
- let aliasPath;
734
- if (keyPath == null) {
735
- keyPath = aliasPath = aliasOrKeyPath;
736
- }
737
- else {
738
- aliasPath = aliasOrKeyPath;
739
- }
740
- const aliasParts = aliasPath.split('.');
741
- const lastAliasPart = aliasParts.pop();
742
- if (lastAliasPart == null) {
743
- throw new Error(`Key "${key}" is invalid, no path provided.`);
744
- }
745
- let object = { [lastAliasPart]: `$key.${keyPath}` };
746
- for (const aliasPart of aliasParts.reverse()) {
747
- object = { [aliasPart]: object };
748
- }
749
- mergedObject = mergeDeep([mergedObject, object]);
750
- }
751
- return JSON.stringify(mergedObject).replace(/"/g, '');
752
- }
753
- function mergeSelectionSets(...selectionSets) {
754
- const normalizedSelections = Object.create(null);
755
- for (const selectionSet of selectionSets) {
756
- for (const selection of selectionSet.selections) {
757
- const normalizedSelection = print(selection);
758
- normalizedSelections[normalizedSelection] = selection;
759
- }
760
- }
761
- const newSelectionSet = {
762
- kind: Kind.SELECTION_SET,
763
- selections: Object.values(normalizedSelections),
764
- };
765
- return newSelectionSet;
766
- }
767
- function forEachConcreteTypeName(returnType, schema, typeNames, fn) {
768
- if (isInterfaceType(returnType)) {
769
- for (const typeName of getImplementingTypes(returnType.name, schema)) {
770
- if (typeNames == null || typeNames.includes(typeName)) {
771
- fn(typeName);
772
- }
773
- }
774
- }
775
- else if (isUnionType(returnType)) {
776
- for (const type of returnType.getTypes()) {
777
- if (typeNames == null || typeNames.includes(type.name)) {
778
- fn(type.name);
779
- }
780
- }
781
- }
782
- else if (isObjectType(returnType) && (typeNames == null || typeNames.includes(returnType.name))) {
783
- fn(returnType.name);
784
- }
785
- }
786
-
787
- function stitchingDirectives(options = {}) {
788
- const finalOptions = {
789
- ...defaultStitchingDirectiveOptions,
790
- ...options,
791
- };
792
- const { keyDirectiveName, computedDirectiveName, mergeDirectiveName, canonicalDirectiveName } = finalOptions;
793
- const keyDirectiveTypeDefs = /* GraphQL */ `directive @${keyDirectiveName}(selectionSet: String!) on OBJECT`;
794
- const computedDirectiveTypeDefs = /* GraphQL */ `directive @${computedDirectiveName}(selectionSet: String!) on FIELD_DEFINITION`;
795
- const mergeDirectiveTypeDefs = /* GraphQL */ `directive @${mergeDirectiveName}(argsExpr: String, keyArg: String, keyField: String, key: [String!], additionalArgs: String) on FIELD_DEFINITION`;
796
- const canonicalDirectiveTypeDefs = /* GraphQL */ `directive @${canonicalDirectiveName} on OBJECT | INTERFACE | INPUT_OBJECT | UNION | ENUM | SCALAR | FIELD_DEFINITION | INPUT_FIELD_DEFINITION`;
797
- const keyDirective = new GraphQLDirective({
798
- name: keyDirectiveName,
799
- locations: ['OBJECT'],
800
- args: {
801
- selectionSet: { type: new GraphQLNonNull(GraphQLString) },
802
- },
803
- });
804
- const computedDirective = new GraphQLDirective({
805
- name: computedDirectiveName,
806
- locations: ['FIELD_DEFINITION'],
807
- args: {
808
- selectionSet: { type: new GraphQLNonNull(GraphQLString) },
809
- },
810
- });
811
- const mergeDirective = new GraphQLDirective({
812
- name: mergeDirectiveName,
813
- locations: ['FIELD_DEFINITION'],
814
- args: {
815
- argsExpr: { type: GraphQLString },
816
- keyArg: { type: GraphQLString },
817
- keyField: { type: GraphQLString },
818
- key: { type: new GraphQLList(new GraphQLNonNull(GraphQLString)) },
819
- additionalArgs: { type: GraphQLString },
820
- },
821
- });
822
- const canonicalDirective = new GraphQLDirective({
823
- name: canonicalDirectiveName,
824
- locations: [
825
- 'OBJECT',
826
- 'INTERFACE',
827
- 'INPUT_OBJECT',
828
- 'UNION',
829
- 'ENUM',
830
- 'SCALAR',
831
- 'FIELD_DEFINITION',
832
- 'INPUT_FIELD_DEFINITION',
833
- ],
834
- });
835
- const allStitchingDirectivesTypeDefs = [
836
- keyDirectiveTypeDefs,
837
- computedDirectiveTypeDefs,
838
- mergeDirectiveTypeDefs,
839
- canonicalDirectiveTypeDefs,
840
- ].join('\n');
841
- return {
842
- keyDirectiveTypeDefs,
843
- computedDirectiveTypeDefs,
844
- mergeDirectiveTypeDefs,
845
- canonicalDirectiveTypeDefs,
846
- stitchingDirectivesTypeDefs: allStitchingDirectivesTypeDefs,
847
- allStitchingDirectivesTypeDefs,
848
- keyDirective,
849
- computedDirective,
850
- mergeDirective,
851
- canonicalDirective,
852
- allStitchingDirectives: [keyDirective, computedDirective, mergeDirective, canonicalDirective],
853
- stitchingDirectivesValidator: stitchingDirectivesValidator(finalOptions),
854
- stitchingDirectivesTransformer: stitchingDirectivesTransformer(finalOptions),
855
- };
856
- }
857
-
858
- // Taken from https://github.com/gmac/federation-to-stitching-sdl/blob/main/index.js
859
- const extensionKind = /Extension$/;
860
- const entityKinds = [
861
- Kind.OBJECT_TYPE_DEFINITION,
862
- Kind.OBJECT_TYPE_EXTENSION,
863
- Kind.INTERFACE_TYPE_DEFINITION,
864
- Kind.INTERFACE_TYPE_EXTENSION,
865
- ];
866
- function isEntityKind(def) {
867
- return entityKinds.includes(def.kind);
868
- }
869
- function getQueryTypeDef(definitions) {
870
- var _a;
871
- const schemaDef = definitions.find(def => def.kind === Kind.SCHEMA_DEFINITION);
872
- const typeName = schemaDef
873
- ? (_a = schemaDef.operationTypes.find(({ operation }) => operation === 'query')) === null || _a === void 0 ? void 0 : _a.type.name.value
874
- : 'Query';
875
- return definitions.find(def => def.kind === Kind.OBJECT_TYPE_DEFINITION && def.name.value === typeName);
876
- }
877
- // Federation services are actually fairly complex,
878
- // as the `buildFederatedSchema` helper does a fair amount
879
- // of hidden work to setup the Federation schema specification:
880
- // https://www.apollographql.com/docs/federation/federation-spec/#federation-schema-specification
881
- function federationToStitchingSDL(federationSDL, stitchingConfig = stitchingDirectives()) {
882
- const doc = parse(federationSDL);
883
- const entityTypes = [];
884
- const baseTypeNames = doc.definitions.reduce((memo, typeDef) => {
885
- if (!extensionKind.test(typeDef.kind) && 'name' in typeDef && typeDef.name) {
886
- memo[typeDef.name.value] = true;
887
- }
888
- return memo;
889
- }, {});
890
- doc.definitions.forEach(typeDef => {
891
- var _a, _b, _c;
892
- // Un-extend all types (remove "extends" keywords)...
893
- // extended types are invalid GraphQL without a local base type to extend from.
894
- // Stitching merges flat types in lieu of hierarchical extensions.
895
- if (extensionKind.test(typeDef.kind) && 'name' in typeDef && typeDef.name && !baseTypeNames[typeDef.name.value]) {
896
- typeDef.kind = typeDef.kind.replace(extensionKind, 'Definition');
897
- }
898
- if (!isEntityKind(typeDef))
899
- return;
900
- // Find object definitions with "@key" directives;
901
- // these are federated entities that get turned into merged types.
902
- const keyDirs = [];
903
- const otherDirs = [];
904
- (_a = typeDef.directives) === null || _a === void 0 ? void 0 : _a.forEach(dir => {
905
- if (dir.name.value === 'key') {
906
- keyDirs.push(dir);
907
- }
908
- else {
909
- otherDirs.push(dir);
910
- }
911
- });
912
- if (!keyDirs.length)
913
- return;
914
- // Setup stitching MergedTypeConfig for all federated entities:
915
- const selectionSet = `{ ${keyDirs.map((dir) => dir.arguments[0].value.value).join(' ')} }`;
916
- const keyFields = parse(selectionSet).definitions[0].selectionSet.selections.map((sel) => sel.name.value);
917
- const keyDir = keyDirs[0];
918
- keyDir.name.value = stitchingConfig.keyDirective.name;
919
- keyDir.arguments[0].name.value = 'selectionSet';
920
- keyDir.arguments[0].value.value = selectionSet;
921
- typeDef.directives = [keyDir, ...otherDirs];
922
- // Remove non-key "@external" fields from the type...
923
- // the stitching query planner expects services to only publish their own fields.
924
- // This makes "@provides" moot because the query planner can automate the logic.
925
- typeDef.fields = (_b = typeDef.fields) === null || _b === void 0 ? void 0 : _b.filter(fieldDef => {
926
- var _a;
927
- return (keyFields.includes(fieldDef.name.value) || !((_a = fieldDef.directives) === null || _a === void 0 ? void 0 : _a.find(dir => dir.name.value === 'external')));
928
- });
929
- // Discard remaining "@external" directives and any "@provides" directives
930
- (_c = typeDef.fields) === null || _c === void 0 ? void 0 : _c.forEach((fieldDef) => {
931
- fieldDef.directives = fieldDef.directives.filter((dir) => !/^(external|provides)$/.test(dir.name.value));
932
- fieldDef.directives.forEach((dir) => {
933
- if (dir.name.value === 'requires') {
934
- dir.name.value = stitchingConfig.computedDirective.name;
935
- dir.arguments[0].name.value = 'selectionSet';
936
- dir.arguments[0].value.value = `{ ${dir.arguments[0].value.value} }`;
937
- }
938
- });
939
- });
940
- if (typeDef.kind === Kind.OBJECT_TYPE_DEFINITION || typeDef.kind === Kind.OBJECT_TYPE_EXTENSION) {
941
- entityTypes.push(typeDef.name.value);
942
- }
943
- });
944
- // Federation service SDLs are incomplete because they omit the federation spec itself...
945
- // (https://www.apollographql.com/docs/federation/federation-spec/#federation-schema-specification)
946
- // To make federation SDLs into valid and parsable GraphQL schemas,
947
- // we must fill in the missing details from the specification.
948
- if (entityTypes.length) {
949
- const queryDef = getQueryTypeDef(doc.definitions);
950
- const entitiesSchema = parse(/* GraphQL */ `
951
- scalar _Any
952
- union _Entity = ${entityTypes.filter((v, i, a) => a.indexOf(v) === i).join(' | ')}
953
- type Query { _entities(representations: [_Any!]!): [_Entity]! @${stitchingConfig.mergeDirective.name} }
954
- `).definitions;
955
- doc.definitions.push(entitiesSchema[0]);
956
- doc.definitions.push(entitiesSchema[1]);
957
- if (queryDef) {
958
- queryDef.fields.push(entitiesSchema[2].fields[0]);
959
- }
960
- else {
961
- doc.definitions.push(entitiesSchema[2]);
962
- }
963
- }
964
- return [stitchingConfig.stitchingDirectivesTypeDefs, print(doc)].join('\n');
965
- }
966
-
967
- export { federationToStitchingSDL, stitchingDirectives };