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