@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
@@ -0,0 +1,423 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stitchingDirectivesTransformer = void 0;
4
+ const graphql_1 = require("graphql");
5
+ const delegate_1 = require("@graphql-tools/delegate");
6
+ const utils_1 = require("@graphql-tools/utils");
7
+ const defaultStitchingDirectiveOptions_js_1 = require("./defaultStitchingDirectiveOptions.js");
8
+ const parseMergeArgsExpr_js_1 = require("./parseMergeArgsExpr.js");
9
+ const properties_js_1 = require("./properties.js");
10
+ const stitchingDirectivesValidator_js_1 = require("./stitchingDirectivesValidator.js");
11
+ function stitchingDirectivesTransformer(options = {}) {
12
+ const { keyDirectiveName, computedDirectiveName, mergeDirectiveName, canonicalDirectiveName, pathToDirectivesInExtensions, } = {
13
+ ...defaultStitchingDirectiveOptions_js_1.defaultStitchingDirectiveOptions,
14
+ ...options,
15
+ };
16
+ return (subschemaConfig) => {
17
+ var _a, _b, _c, _d, _e, _f, _g, _h;
18
+ const newSubschemaConfig = (0, delegate_1.cloneSubschemaConfig)(subschemaConfig);
19
+ const selectionSetsByType = Object.create(null);
20
+ const computedFieldSelectionSets = Object.create(null);
21
+ const mergedTypesResolversInfo = Object.create(null);
22
+ const canonicalTypesInfo = Object.create(null);
23
+ const schema = subschemaConfig.schema;
24
+ // gateway should also run validation
25
+ (0, stitchingDirectivesValidator_js_1.stitchingDirectivesValidator)(options)(schema);
26
+ function setCanonicalDefinition(typeName, fieldName) {
27
+ var _a;
28
+ canonicalTypesInfo[typeName] = canonicalTypesInfo[typeName] || Object.create(null);
29
+ if (fieldName) {
30
+ const fields = (_a = canonicalTypesInfo[typeName].fields) !== null && _a !== void 0 ? _a : Object.create(null);
31
+ canonicalTypesInfo[typeName].fields = fields;
32
+ fields[fieldName] = true;
33
+ }
34
+ else {
35
+ canonicalTypesInfo[typeName].canonical = true;
36
+ }
37
+ }
38
+ (0, utils_1.mapSchema)(schema, {
39
+ [utils_1.MapperKind.OBJECT_TYPE]: type => {
40
+ var _a, _b;
41
+ const keyDirective = (_a = (0, utils_1.getDirective)(schema, type, keyDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
42
+ if (keyDirective != null) {
43
+ const selectionSet = (0, utils_1.parseSelectionSet)(keyDirective['selectionSet'], { noLocation: true });
44
+ selectionSetsByType[type.name] = selectionSet;
45
+ }
46
+ const canonicalDirective = (_b = (0, utils_1.getDirective)(schema, type, canonicalDirectiveName, pathToDirectivesInExtensions)) === null || _b === void 0 ? void 0 : _b[0];
47
+ if (canonicalDirective != null) {
48
+ setCanonicalDefinition(type.name);
49
+ }
50
+ return undefined;
51
+ },
52
+ [utils_1.MapperKind.OBJECT_FIELD]: (fieldConfig, fieldName, typeName) => {
53
+ var _a, _b, _c;
54
+ const computedDirective = (_a = (0, utils_1.getDirective)(schema, fieldConfig, computedDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
55
+ if (computedDirective != null) {
56
+ const selectionSet = (0, utils_1.parseSelectionSet)(computedDirective['selectionSet'], { noLocation: true });
57
+ if (!computedFieldSelectionSets[typeName]) {
58
+ computedFieldSelectionSets[typeName] = Object.create(null);
59
+ }
60
+ computedFieldSelectionSets[typeName][fieldName] = selectionSet;
61
+ }
62
+ const mergeDirective = (_b = (0, utils_1.getDirective)(schema, fieldConfig, mergeDirectiveName, pathToDirectivesInExtensions)) === null || _b === void 0 ? void 0 : _b[0];
63
+ if ((mergeDirective === null || mergeDirective === void 0 ? void 0 : mergeDirective['keyField']) != null) {
64
+ const mergeDirectiveKeyField = mergeDirective['keyField'];
65
+ const selectionSet = (0, utils_1.parseSelectionSet)(`{ ${mergeDirectiveKeyField}}`, { noLocation: true });
66
+ const typeNames = mergeDirective['types'];
67
+ const returnType = (0, graphql_1.getNamedType)(fieldConfig.type);
68
+ forEachConcreteType(schema, returnType, typeNames, typeName => {
69
+ if (typeNames == null || typeNames.includes(typeName)) {
70
+ const existingSelectionSet = selectionSetsByType[typeName];
71
+ selectionSetsByType[typeName] = existingSelectionSet
72
+ ? mergeSelectionSets(existingSelectionSet, selectionSet)
73
+ : selectionSet;
74
+ }
75
+ });
76
+ }
77
+ const canonicalDirective = (_c = (0, utils_1.getDirective)(schema, fieldConfig, canonicalDirectiveName, pathToDirectivesInExtensions)) === null || _c === void 0 ? void 0 : _c[0];
78
+ if (canonicalDirective != null) {
79
+ setCanonicalDefinition(typeName, fieldName);
80
+ }
81
+ return undefined;
82
+ },
83
+ [utils_1.MapperKind.INTERFACE_TYPE]: type => {
84
+ var _a;
85
+ const canonicalDirective = (_a = (0, utils_1.getDirective)(schema, type, canonicalDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
86
+ if (canonicalDirective) {
87
+ setCanonicalDefinition(type.name);
88
+ }
89
+ return undefined;
90
+ },
91
+ [utils_1.MapperKind.INTERFACE_FIELD]: (fieldConfig, fieldName, typeName) => {
92
+ var _a;
93
+ const canonicalDirective = (_a = (0, utils_1.getDirective)(schema, fieldConfig, canonicalDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
94
+ if (canonicalDirective) {
95
+ setCanonicalDefinition(typeName, fieldName);
96
+ }
97
+ return undefined;
98
+ },
99
+ [utils_1.MapperKind.INPUT_OBJECT_TYPE]: type => {
100
+ var _a;
101
+ const canonicalDirective = (_a = (0, utils_1.getDirective)(schema, type, canonicalDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
102
+ if (canonicalDirective) {
103
+ setCanonicalDefinition(type.name);
104
+ }
105
+ return undefined;
106
+ },
107
+ [utils_1.MapperKind.INPUT_OBJECT_FIELD]: (inputFieldConfig, fieldName, typeName) => {
108
+ var _a;
109
+ const canonicalDirective = (_a = (0, utils_1.getDirective)(schema, inputFieldConfig, canonicalDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
110
+ if (canonicalDirective != null) {
111
+ setCanonicalDefinition(typeName, fieldName);
112
+ }
113
+ return undefined;
114
+ },
115
+ [utils_1.MapperKind.UNION_TYPE]: type => {
116
+ var _a;
117
+ const canonicalDirective = (_a = (0, utils_1.getDirective)(schema, type, canonicalDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
118
+ if (canonicalDirective != null) {
119
+ setCanonicalDefinition(type.name);
120
+ }
121
+ return undefined;
122
+ },
123
+ [utils_1.MapperKind.ENUM_TYPE]: type => {
124
+ var _a;
125
+ const canonicalDirective = (_a = (0, utils_1.getDirective)(schema, type, canonicalDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
126
+ if (canonicalDirective != null) {
127
+ setCanonicalDefinition(type.name);
128
+ }
129
+ return undefined;
130
+ },
131
+ [utils_1.MapperKind.SCALAR_TYPE]: type => {
132
+ var _a;
133
+ const canonicalDirective = (_a = (0, utils_1.getDirective)(schema, type, canonicalDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
134
+ if (canonicalDirective != null) {
135
+ setCanonicalDefinition(type.name);
136
+ }
137
+ return undefined;
138
+ },
139
+ });
140
+ if (subschemaConfig.merge) {
141
+ for (const typeName in subschemaConfig.merge) {
142
+ const mergedTypeConfig = subschemaConfig.merge[typeName];
143
+ if (mergedTypeConfig.selectionSet) {
144
+ const selectionSet = (0, utils_1.parseSelectionSet)(mergedTypeConfig.selectionSet, { noLocation: true });
145
+ if (selectionSet) {
146
+ if (selectionSetsByType[typeName]) {
147
+ selectionSetsByType[typeName] = mergeSelectionSets(selectionSetsByType[typeName], selectionSet);
148
+ }
149
+ else {
150
+ selectionSetsByType[typeName] = selectionSet;
151
+ }
152
+ }
153
+ }
154
+ if (mergedTypeConfig.fields) {
155
+ for (const fieldName in mergedTypeConfig.fields) {
156
+ const fieldConfig = mergedTypeConfig.fields[fieldName];
157
+ if (!fieldConfig.selectionSet)
158
+ continue;
159
+ const selectionSet = (0, utils_1.parseSelectionSet)(fieldConfig.selectionSet, { noLocation: true });
160
+ if (selectionSet) {
161
+ if ((_a = computedFieldSelectionSets[typeName]) === null || _a === void 0 ? void 0 : _a[fieldName]) {
162
+ computedFieldSelectionSets[typeName][fieldName] = mergeSelectionSets(computedFieldSelectionSets[typeName][fieldName], selectionSet);
163
+ }
164
+ else {
165
+ if (computedFieldSelectionSets[typeName] == null) {
166
+ computedFieldSelectionSets[typeName] = Object.create(null);
167
+ }
168
+ computedFieldSelectionSets[typeName][fieldName] = selectionSet;
169
+ }
170
+ }
171
+ }
172
+ }
173
+ }
174
+ }
175
+ const allSelectionSetsByType = Object.create(null);
176
+ for (const typeName in selectionSetsByType) {
177
+ allSelectionSetsByType[typeName] = allSelectionSetsByType[typeName] || [];
178
+ const selectionSet = selectionSetsByType[typeName];
179
+ allSelectionSetsByType[typeName].push(selectionSet);
180
+ }
181
+ for (const typeName in computedFieldSelectionSets) {
182
+ const selectionSets = computedFieldSelectionSets[typeName];
183
+ for (const i in selectionSets) {
184
+ allSelectionSetsByType[typeName] = allSelectionSetsByType[typeName] || [];
185
+ const selectionSet = selectionSets[i];
186
+ allSelectionSetsByType[typeName].push(selectionSet);
187
+ }
188
+ }
189
+ (0, utils_1.mapSchema)(schema, {
190
+ [utils_1.MapperKind.OBJECT_FIELD]: function objectFieldMapper(fieldConfig, fieldName) {
191
+ var _a, _b;
192
+ const mergeDirective = (_a = (0, utils_1.getDirective)(schema, fieldConfig, mergeDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
193
+ if (mergeDirective != null) {
194
+ const returnType = (0, graphql_1.getNullableType)(fieldConfig.type);
195
+ const returnsList = (0, graphql_1.isListType)(returnType);
196
+ const namedType = (0, graphql_1.getNamedType)(returnType);
197
+ let mergeArgsExpr = mergeDirective['argsExpr'];
198
+ if (mergeArgsExpr == null) {
199
+ const key = mergeDirective['key'];
200
+ const keyField = mergeDirective['keyField'];
201
+ const keyExpr = key != null ? buildKeyExpr(key) : keyField != null ? `$key.${keyField}` : '$key';
202
+ const keyArg = mergeDirective['keyArg'];
203
+ const argNames = keyArg == null ? [Object.keys((_b = fieldConfig.args) !== null && _b !== void 0 ? _b : {})[0]] : keyArg.split('.');
204
+ const lastArgName = argNames.pop();
205
+ mergeArgsExpr = returnsList ? `${lastArgName}: [[${keyExpr}]]` : `${lastArgName}: ${keyExpr}`;
206
+ for (const argName of argNames.reverse()) {
207
+ mergeArgsExpr = `${argName}: { ${mergeArgsExpr} }`;
208
+ }
209
+ }
210
+ const typeNames = mergeDirective['types'];
211
+ forEachConcreteTypeName(namedType, schema, typeNames, function generateResolveInfo(typeName) {
212
+ const parsedMergeArgsExpr = (0, parseMergeArgsExpr_js_1.parseMergeArgsExpr)(mergeArgsExpr, allSelectionSetsByType[typeName] == null
213
+ ? undefined
214
+ : mergeSelectionSets(...allSelectionSetsByType[typeName]));
215
+ const additionalArgs = mergeDirective['additionalArgs'];
216
+ if (additionalArgs != null) {
217
+ parsedMergeArgsExpr.args = (0, utils_1.mergeDeep)([
218
+ parsedMergeArgsExpr.args,
219
+ (0, graphql_1.valueFromASTUntyped)((0, graphql_1.parseValue)(`{ ${additionalArgs} }`, { noLocation: true })),
220
+ ]);
221
+ }
222
+ mergedTypesResolversInfo[typeName] = {
223
+ fieldName,
224
+ returnsList,
225
+ ...parsedMergeArgsExpr,
226
+ };
227
+ });
228
+ }
229
+ return undefined;
230
+ },
231
+ });
232
+ for (const typeName in selectionSetsByType) {
233
+ const selectionSet = selectionSetsByType[typeName];
234
+ const mergeConfig = (_b = newSubschemaConfig.merge) !== null && _b !== void 0 ? _b : Object.create(null);
235
+ newSubschemaConfig.merge = mergeConfig;
236
+ if (mergeConfig[typeName] == null) {
237
+ newSubschemaConfig.merge[typeName] = Object.create(null);
238
+ }
239
+ const mergeTypeConfig = mergeConfig[typeName];
240
+ mergeTypeConfig.selectionSet = (0, graphql_1.print)(selectionSet);
241
+ }
242
+ for (const typeName in computedFieldSelectionSets) {
243
+ const selectionSets = computedFieldSelectionSets[typeName];
244
+ const mergeConfig = (_c = newSubschemaConfig.merge) !== null && _c !== void 0 ? _c : Object.create(null);
245
+ newSubschemaConfig.merge = mergeConfig;
246
+ if (mergeConfig[typeName] == null) {
247
+ mergeConfig[typeName] = Object.create(null);
248
+ }
249
+ const mergeTypeConfig = newSubschemaConfig.merge[typeName];
250
+ const mergeTypeConfigFields = (_d = mergeTypeConfig.fields) !== null && _d !== void 0 ? _d : Object.create(null);
251
+ mergeTypeConfig.fields = mergeTypeConfigFields;
252
+ for (const fieldName in selectionSets) {
253
+ const selectionSet = selectionSets[fieldName];
254
+ const fieldConfig = (_e = mergeTypeConfigFields[fieldName]) !== null && _e !== void 0 ? _e : Object.create(null);
255
+ mergeTypeConfigFields[fieldName] = fieldConfig;
256
+ fieldConfig.selectionSet = (0, graphql_1.print)(selectionSet);
257
+ fieldConfig.computed = true;
258
+ }
259
+ }
260
+ for (const typeName in mergedTypesResolversInfo) {
261
+ const mergedTypeResolverInfo = mergedTypesResolversInfo[typeName];
262
+ const mergeConfig = (_f = newSubschemaConfig.merge) !== null && _f !== void 0 ? _f : Object.create(null);
263
+ newSubschemaConfig.merge = mergeConfig;
264
+ if (newSubschemaConfig.merge[typeName] == null) {
265
+ newSubschemaConfig.merge[typeName] = Object.create(null);
266
+ }
267
+ const mergeTypeConfig = newSubschemaConfig.merge[typeName];
268
+ mergeTypeConfig.fieldName = mergedTypeResolverInfo.fieldName;
269
+ if (mergedTypeResolverInfo.returnsList) {
270
+ mergeTypeConfig.key = generateKeyFn(mergedTypeResolverInfo);
271
+ mergeTypeConfig.argsFromKeys = generateArgsFromKeysFn(mergedTypeResolverInfo);
272
+ }
273
+ else {
274
+ mergeTypeConfig.args = generateArgsFn(mergedTypeResolverInfo);
275
+ }
276
+ }
277
+ for (const typeName in canonicalTypesInfo) {
278
+ const canonicalTypeInfo = canonicalTypesInfo[typeName];
279
+ const mergeConfig = (_g = newSubschemaConfig.merge) !== null && _g !== void 0 ? _g : Object.create(null);
280
+ newSubschemaConfig.merge = mergeConfig;
281
+ if (newSubschemaConfig.merge[typeName] == null) {
282
+ newSubschemaConfig.merge[typeName] = Object.create(null);
283
+ }
284
+ const mergeTypeConfig = newSubschemaConfig.merge[typeName];
285
+ if (canonicalTypeInfo.canonical) {
286
+ mergeTypeConfig.canonical = true;
287
+ }
288
+ if (canonicalTypeInfo.fields) {
289
+ const mergeTypeConfigFields = (_h = mergeTypeConfig.fields) !== null && _h !== void 0 ? _h : Object.create(null);
290
+ mergeTypeConfig.fields = mergeTypeConfigFields;
291
+ for (const fieldName in canonicalTypeInfo.fields) {
292
+ if (mergeTypeConfigFields[fieldName] == null) {
293
+ mergeTypeConfigFields[fieldName] = Object.create(null);
294
+ }
295
+ mergeTypeConfigFields[fieldName].canonical = true;
296
+ }
297
+ }
298
+ }
299
+ return newSubschemaConfig;
300
+ };
301
+ }
302
+ exports.stitchingDirectivesTransformer = stitchingDirectivesTransformer;
303
+ function forEachConcreteType(schema, type, typeNames, fn) {
304
+ if ((0, graphql_1.isInterfaceType)(type)) {
305
+ for (const typeName of (0, utils_1.getImplementingTypes)(type.name, schema)) {
306
+ if (typeNames == null || typeNames.includes(typeName)) {
307
+ fn(typeName);
308
+ }
309
+ }
310
+ }
311
+ else if ((0, graphql_1.isUnionType)(type)) {
312
+ for (const { name: typeName } of type.getTypes()) {
313
+ if (typeNames == null || typeNames.includes(typeName)) {
314
+ fn(typeName);
315
+ }
316
+ }
317
+ }
318
+ else if ((0, graphql_1.isObjectType)(type)) {
319
+ fn(type.name);
320
+ }
321
+ }
322
+ function generateKeyFn(mergedTypeResolverInfo) {
323
+ return function keyFn(originalResult) {
324
+ return (0, properties_js_1.getProperties)(originalResult, mergedTypeResolverInfo.usedProperties);
325
+ };
326
+ }
327
+ function generateArgsFromKeysFn(mergedTypeResolverInfo) {
328
+ const { expansions, args } = mergedTypeResolverInfo;
329
+ return function generateArgsFromKeys(keys) {
330
+ const newArgs = (0, utils_1.mergeDeep)([{}, args]);
331
+ if (expansions) {
332
+ for (const expansion of expansions) {
333
+ const mappingInstructions = expansion.mappingInstructions;
334
+ const expanded = [];
335
+ for (const key of keys) {
336
+ let newValue = (0, utils_1.mergeDeep)([{}, expansion.valuePath]);
337
+ for (const { destinationPath, sourcePath } of mappingInstructions) {
338
+ if (destinationPath.length) {
339
+ (0, properties_js_1.addProperty)(newValue, destinationPath, (0, properties_js_1.getProperty)(key, sourcePath));
340
+ }
341
+ else {
342
+ newValue = (0, properties_js_1.getProperty)(key, sourcePath);
343
+ }
344
+ }
345
+ expanded.push(newValue);
346
+ }
347
+ (0, properties_js_1.addProperty)(newArgs, expansion.valuePath, expanded);
348
+ }
349
+ }
350
+ return newArgs;
351
+ };
352
+ }
353
+ function generateArgsFn(mergedTypeResolverInfo) {
354
+ const { mappingInstructions, args, usedProperties } = mergedTypeResolverInfo;
355
+ return function generateArgs(originalResult) {
356
+ const newArgs = (0, utils_1.mergeDeep)([{}, args]);
357
+ const filteredResult = (0, properties_js_1.getProperties)(originalResult, usedProperties);
358
+ if (mappingInstructions) {
359
+ for (const mappingInstruction of mappingInstructions) {
360
+ const { destinationPath, sourcePath } = mappingInstruction;
361
+ (0, properties_js_1.addProperty)(newArgs, destinationPath, (0, properties_js_1.getProperty)(filteredResult, sourcePath));
362
+ }
363
+ }
364
+ return newArgs;
365
+ };
366
+ }
367
+ function buildKeyExpr(key) {
368
+ let mergedObject = {};
369
+ for (const keyDef of key) {
370
+ let [aliasOrKeyPath, keyPath] = keyDef.split(':');
371
+ let aliasPath;
372
+ if (keyPath == null) {
373
+ keyPath = aliasPath = aliasOrKeyPath;
374
+ }
375
+ else {
376
+ aliasPath = aliasOrKeyPath;
377
+ }
378
+ const aliasParts = aliasPath.split('.');
379
+ const lastAliasPart = aliasParts.pop();
380
+ if (lastAliasPart == null) {
381
+ throw new Error(`Key "${key}" is invalid, no path provided.`);
382
+ }
383
+ let object = { [lastAliasPart]: `$key.${keyPath}` };
384
+ for (const aliasPart of aliasParts.reverse()) {
385
+ object = { [aliasPart]: object };
386
+ }
387
+ mergedObject = (0, utils_1.mergeDeep)([mergedObject, object]);
388
+ }
389
+ return JSON.stringify(mergedObject).replace(/"/g, '');
390
+ }
391
+ function mergeSelectionSets(...selectionSets) {
392
+ const normalizedSelections = Object.create(null);
393
+ for (const selectionSet of selectionSets) {
394
+ for (const selection of selectionSet.selections) {
395
+ const normalizedSelection = (0, graphql_1.print)(selection);
396
+ normalizedSelections[normalizedSelection] = selection;
397
+ }
398
+ }
399
+ const newSelectionSet = {
400
+ kind: graphql_1.Kind.SELECTION_SET,
401
+ selections: Object.values(normalizedSelections),
402
+ };
403
+ return newSelectionSet;
404
+ }
405
+ function forEachConcreteTypeName(returnType, schema, typeNames, fn) {
406
+ if ((0, graphql_1.isInterfaceType)(returnType)) {
407
+ for (const typeName of (0, utils_1.getImplementingTypes)(returnType.name, schema)) {
408
+ if (typeNames == null || typeNames.includes(typeName)) {
409
+ fn(typeName);
410
+ }
411
+ }
412
+ }
413
+ else if ((0, graphql_1.isUnionType)(returnType)) {
414
+ for (const type of returnType.getTypes()) {
415
+ if (typeNames == null || typeNames.includes(type.name)) {
416
+ fn(type.name);
417
+ }
418
+ }
419
+ }
420
+ else if ((0, graphql_1.isObjectType)(returnType) && (typeNames == null || typeNames.includes(returnType.name))) {
421
+ fn(returnType.name);
422
+ }
423
+ }
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stitchingDirectivesValidator = void 0;
4
+ const graphql_1 = require("graphql");
5
+ const utils_1 = require("@graphql-tools/utils");
6
+ const defaultStitchingDirectiveOptions_js_1 = require("./defaultStitchingDirectiveOptions.js");
7
+ const parseMergeArgsExpr_js_1 = require("./parseMergeArgsExpr.js");
8
+ const dottedNameRegEx = /^[_A-Za-z][_0-9A-Za-z]*(.[_A-Za-z][_0-9A-Za-z]*)*$/;
9
+ function stitchingDirectivesValidator(options = {}) {
10
+ const { keyDirectiveName, computedDirectiveName, mergeDirectiveName, pathToDirectivesInExtensions } = {
11
+ ...defaultStitchingDirectiveOptions_js_1.defaultStitchingDirectiveOptions,
12
+ ...options,
13
+ };
14
+ return (schema) => {
15
+ var _a;
16
+ const queryTypeName = (_a = schema.getQueryType()) === null || _a === void 0 ? void 0 : _a.name;
17
+ (0, utils_1.mapSchema)(schema, {
18
+ [utils_1.MapperKind.OBJECT_TYPE]: type => {
19
+ var _a;
20
+ const keyDirective = (_a = (0, utils_1.getDirective)(schema, type, keyDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
21
+ if (keyDirective != null) {
22
+ (0, utils_1.parseSelectionSet)(keyDirective['selectionSet']);
23
+ }
24
+ return undefined;
25
+ },
26
+ [utils_1.MapperKind.OBJECT_FIELD]: (fieldConfig, _fieldName, typeName) => {
27
+ var _a, _b, _c;
28
+ const computedDirective = (_a = (0, utils_1.getDirective)(schema, fieldConfig, computedDirectiveName, pathToDirectivesInExtensions)) === null || _a === void 0 ? void 0 : _a[0];
29
+ if (computedDirective != null) {
30
+ (0, utils_1.parseSelectionSet)(computedDirective['selectionSet']);
31
+ }
32
+ const mergeDirective = (_b = (0, utils_1.getDirective)(schema, fieldConfig, mergeDirectiveName, pathToDirectivesInExtensions)) === null || _b === void 0 ? void 0 : _b[0];
33
+ if (mergeDirective != null) {
34
+ if (typeName !== queryTypeName) {
35
+ throw new Error('@merge directive may be used only for root fields of the root Query type.');
36
+ }
37
+ let returnType = (0, graphql_1.getNullableType)(fieldConfig.type);
38
+ if ((0, graphql_1.isListType)(returnType)) {
39
+ returnType = (0, graphql_1.getNullableType)(returnType.ofType);
40
+ }
41
+ if (!(0, graphql_1.isNamedType)(returnType)) {
42
+ throw new Error('@merge directive must be used on a field that returns an object or a list of objects.');
43
+ }
44
+ const mergeArgsExpr = mergeDirective['argsExpr'];
45
+ if (mergeArgsExpr != null) {
46
+ (0, parseMergeArgsExpr_js_1.parseMergeArgsExpr)(mergeArgsExpr);
47
+ }
48
+ const args = Object.keys((_c = fieldConfig.args) !== null && _c !== void 0 ? _c : {});
49
+ const keyArg = mergeDirective['keyArg'];
50
+ if (keyArg == null) {
51
+ if (!mergeArgsExpr && args.length !== 1) {
52
+ throw new Error('Cannot use @merge directive without `keyArg` argument if resolver takes more than one argument.');
53
+ }
54
+ }
55
+ else if (!keyArg.match(dottedNameRegEx)) {
56
+ throw new Error('`keyArg` argument for @merge directive must be a set of valid GraphQL SDL names separated by periods.');
57
+ // TODO: ideally we should check that the arg exists for the resolver
58
+ }
59
+ const keyField = mergeDirective['keyField'];
60
+ if (keyField != null && !keyField.match(dottedNameRegEx)) {
61
+ throw new Error('`keyField` argument for @merge directive must be a set of valid GraphQL SDL names separated by periods.');
62
+ // TODO: ideally we should check that it is part of the key
63
+ }
64
+ const key = mergeDirective['key'];
65
+ if (key != null) {
66
+ if (keyField != null) {
67
+ throw new Error('Cannot use @merge directive with both `keyField` and `key` arguments.');
68
+ }
69
+ for (const keyDef of key) {
70
+ let [aliasOrKeyPath, keyPath] = keyDef.split(':');
71
+ let aliasPath;
72
+ if (keyPath == null) {
73
+ keyPath = aliasPath = aliasOrKeyPath;
74
+ }
75
+ else {
76
+ aliasPath = aliasOrKeyPath;
77
+ }
78
+ if (keyPath != null && !keyPath.match(dottedNameRegEx)) {
79
+ 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.');
80
+ // TODO: ideally we should check that it is part of the key
81
+ }
82
+ if (aliasPath != null && !aliasOrKeyPath.match(dottedNameRegEx)) {
83
+ throw new Error('Each alias within the `key` argument for @merge directive must be a set of valid GraphQL SDL names separated by periods.');
84
+ // TODO: ideally we should check that the arg exists within the resolver
85
+ }
86
+ }
87
+ }
88
+ const additionalArgs = mergeDirective['additionalArgs'];
89
+ if (additionalArgs != null) {
90
+ (0, graphql_1.parseValue)(`{ ${additionalArgs} }`, { noLocation: true });
91
+ }
92
+ if (mergeArgsExpr != null && (keyArg != null || additionalArgs != null)) {
93
+ throw new Error('Cannot use @merge directive with both `argsExpr` argument and any additional argument.');
94
+ }
95
+ if (!(0, graphql_1.isInterfaceType)(returnType) && !(0, graphql_1.isUnionType)(returnType) && !(0, graphql_1.isObjectType)(returnType)) {
96
+ throw new Error('@merge directive may be used only with resolver that return an object, interface, or union.');
97
+ }
98
+ const typeNames = mergeDirective['types'];
99
+ if (typeNames != null) {
100
+ if (!(0, graphql_1.isAbstractType)(returnType)) {
101
+ throw new Error('Types argument can only be used with a field that returns an abstract type.');
102
+ }
103
+ const implementingTypes = (0, graphql_1.isInterfaceType)(returnType)
104
+ ? (0, utils_1.getImplementingTypes)(returnType.name, schema).map(typeName => schema.getType(typeName))
105
+ : returnType.getTypes();
106
+ const implementingTypeNames = implementingTypes.map(type => type === null || type === void 0 ? void 0 : type.name).filter(utils_1.isSome);
107
+ for (const typeName of typeNames) {
108
+ if (!implementingTypeNames.includes(typeName)) {
109
+ throw new Error(`Types argument can only include only type names that implement the field return type's abstract type.`);
110
+ }
111
+ }
112
+ }
113
+ }
114
+ return undefined;
115
+ },
116
+ });
117
+ return schema;
118
+ };
119
+ }
120
+ exports.stitchingDirectivesValidator = stitchingDirectivesValidator;
package/cjs/types.js ADDED
File without changes
@@ -0,0 +1,7 @@
1
+ export const defaultStitchingDirectiveOptions = {
2
+ keyDirectiveName: 'key',
3
+ computedDirectiveName: 'computed',
4
+ canonicalDirectiveName: 'canonical',
5
+ mergeDirectiveName: 'merge',
6
+ pathToDirectivesInExtensions: ['directives'],
7
+ };
@@ -0,0 +1,48 @@
1
+ import { Kind, visit } from 'graphql';
2
+ export function extractVariables(inputValue) {
3
+ const path = [];
4
+ const variablePaths = Object.create(null);
5
+ const keyPathVisitor = {
6
+ enter: (_node, key) => {
7
+ if (typeof key === 'number') {
8
+ path.push(key);
9
+ }
10
+ },
11
+ leave: (_node, key) => {
12
+ if (typeof key === 'number') {
13
+ path.pop();
14
+ }
15
+ },
16
+ };
17
+ const fieldPathVisitor = {
18
+ enter: (node) => {
19
+ path.push(node.name.value);
20
+ },
21
+ leave: () => {
22
+ path.pop();
23
+ },
24
+ };
25
+ const variableVisitor = {
26
+ enter: (node, key) => {
27
+ if (typeof key === 'number') {
28
+ variablePaths[node.name.value] = path.concat([key]);
29
+ }
30
+ else {
31
+ variablePaths[node.name.value] = path.slice();
32
+ }
33
+ return {
34
+ kind: Kind.NULL,
35
+ };
36
+ },
37
+ };
38
+ const newInputValue = visit(inputValue, {
39
+ [Kind.OBJECT]: keyPathVisitor,
40
+ [Kind.LIST]: keyPathVisitor,
41
+ [Kind.OBJECT_FIELD]: fieldPathVisitor,
42
+ [Kind.VARIABLE]: variableVisitor,
43
+ });
44
+ return {
45
+ inputValue: newInputValue,
46
+ variablePaths,
47
+ };
48
+ }