@wundergraph/composition 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE +18 -0
  2. package/README.md +3 -0
  3. package/dist/ast/ast.d.ts +84 -0
  4. package/dist/ast/ast.js +183 -0
  5. package/dist/ast/ast.js.map +1 -0
  6. package/dist/ast/utils.d.ts +130 -0
  7. package/dist/ast/utils.js +298 -0
  8. package/dist/ast/utils.js.map +1 -0
  9. package/dist/buildASTSchema/buildASTSchema.d.ts +22 -0
  10. package/dist/buildASTSchema/buildASTSchema.js +59 -0
  11. package/dist/buildASTSchema/buildASTSchema.js.map +1 -0
  12. package/dist/buildASTSchema/extendSchema.d.ts +21 -0
  13. package/dist/buildASTSchema/extendSchema.js +555 -0
  14. package/dist/buildASTSchema/extendSchema.js.map +1 -0
  15. package/dist/errors/errors.d.ts +60 -0
  16. package/dist/errors/errors.js +302 -0
  17. package/dist/errors/errors.js.map +1 -0
  18. package/dist/federation/federation-factory.d.ts +58 -0
  19. package/dist/federation/federation-factory.js +843 -0
  20. package/dist/federation/federation-factory.js.map +1 -0
  21. package/dist/federation/federation-result.d.ts +6 -0
  22. package/dist/federation/federation-result.js +10 -0
  23. package/dist/federation/federation-result.js.map +1 -0
  24. package/dist/federation/subgraph.d.ts +18 -0
  25. package/dist/federation/subgraph.js +305 -0
  26. package/dist/federation/subgraph.js.map +1 -0
  27. package/dist/index.d.ts +9 -0
  28. package/dist/index.js +26 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/normalization/normalization-factory.d.ts +54 -0
  31. package/dist/normalization/normalization-factory.js +882 -0
  32. package/dist/normalization/normalization-factory.js.map +1 -0
  33. package/dist/normalization/utils.d.ts +121 -0
  34. package/dist/normalization/utils.js +278 -0
  35. package/dist/normalization/utils.js.map +1 -0
  36. package/dist/tsconfig.tsbuildinfo +1 -0
  37. package/dist/type-merging/type-merging.d.ts +9 -0
  38. package/dist/type-merging/type-merging.js +112 -0
  39. package/dist/type-merging/type-merging.js.map +1 -0
  40. package/dist/utils/constants.d.ts +6 -0
  41. package/dist/utils/constants.js +157 -0
  42. package/dist/utils/constants.js.map +1 -0
  43. package/dist/utils/string-constants.d.ts +39 -0
  44. package/dist/utils/string-constants.js +43 -0
  45. package/dist/utils/string-constants.js.map +1 -0
  46. package/dist/utils/utils.d.ts +7 -0
  47. package/dist/utils/utils.js +80 -0
  48. package/dist/utils/utils.js.map +1 -0
  49. package/package.json +35 -0
@@ -0,0 +1,882 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NormalizationFactory = exports.normalizeSubgraph = exports.normalizeSubgraphFromString = void 0;
4
+ const graphql_1 = require("graphql");
5
+ const utils_1 = require("../ast/utils");
6
+ const utils_2 = require("./utils");
7
+ const constants_1 = require("../utils/constants");
8
+ const type_merging_1 = require("../type-merging/type-merging");
9
+ const utils_3 = require("../utils/utils");
10
+ const errors_1 = require("../errors/errors");
11
+ const string_constants_1 = require("../utils/string-constants");
12
+ const buildASTSchema_1 = require("../buildASTSchema/buildASTSchema");
13
+ function normalizeSubgraphFromString(subgraph) {
14
+ let document;
15
+ try {
16
+ document = (0, graphql_1.parse)(subgraph);
17
+ }
18
+ catch (err) {
19
+ return { errors: [(0, errors_1.subgraphInvalidSyntaxError)(err)] };
20
+ }
21
+ const normalizationFactory = new NormalizationFactory();
22
+ return normalizationFactory.normalize(document);
23
+ }
24
+ exports.normalizeSubgraphFromString = normalizeSubgraphFromString;
25
+ function normalizeSubgraph(document) {
26
+ const normalizationFactory = new NormalizationFactory();
27
+ return normalizationFactory.normalize(document);
28
+ }
29
+ exports.normalizeSubgraph = normalizeSubgraph;
30
+ class NormalizationFactory {
31
+ allDirectiveDefinitions = new Map();
32
+ customDirectiveDefinitions = new Map();
33
+ errors = [];
34
+ entityMap = new Map();
35
+ operationTypeNames = new Map();
36
+ parents = new Map();
37
+ parentTypeName = '';
38
+ extensions = new Map();
39
+ isChild = false;
40
+ isCurrentParentExtension = false;
41
+ isSubgraphVersionTwo = false;
42
+ schemaDefinition;
43
+ referencedDirectives = new Set();
44
+ referencedTypeNames = new Set();
45
+ constructor() {
46
+ for (const baseDirectiveDefinition of constants_1.BASE_DIRECTIVE_DEFINITIONS) {
47
+ this.allDirectiveDefinitions.set(baseDirectiveDefinition.name.value, baseDirectiveDefinition);
48
+ }
49
+ this.schemaDefinition = {
50
+ directives: new Map(),
51
+ kind: graphql_1.Kind.SCHEMA_DEFINITION,
52
+ name: (0, utils_1.stringToNameNode)(string_constants_1.SCHEMA),
53
+ operationTypes: new Map(),
54
+ };
55
+ }
56
+ extractDirectives(node, map) {
57
+ if (!node.directives) {
58
+ return map;
59
+ }
60
+ for (const directive of node.directives) {
61
+ const directiveName = directive.name.value;
62
+ const existingDirectives = map.get(directiveName);
63
+ if (existingDirectives) {
64
+ existingDirectives.push(directive);
65
+ continue;
66
+ }
67
+ map.set(directiveName, [directive]);
68
+ }
69
+ return map;
70
+ }
71
+ extractUniqueInterfaces(node, interfaces) {
72
+ if (!node.interfaces) {
73
+ return interfaces;
74
+ }
75
+ for (const face of node.interfaces) {
76
+ const name = face.name.value;
77
+ if (interfaces.has(name)) {
78
+ this.errors.push(new Error(`Interface "${name}" can only be defined on type "${this.parentTypeName}" once.`)); // TODO
79
+ continue;
80
+ }
81
+ interfaces.add(name);
82
+ }
83
+ return interfaces;
84
+ }
85
+ extractUniqueUnionMembers(members, map) {
86
+ for (const member of members) {
87
+ const name = member.name.value;
88
+ if (map.has(name)) {
89
+ this.errors.push(new Error(`Member "${name} can only be defined on union "${this.parentTypeName}" once.`));
90
+ continue;
91
+ }
92
+ if (!constants_1.BASE_SCALARS.has(name)) {
93
+ this.referencedTypeNames.add(name);
94
+ }
95
+ map.set(name, member);
96
+ }
97
+ return map;
98
+ }
99
+ mergeUniqueInterfaces(extensionInterfaces, interfaces, typeName) {
100
+ for (const interfaceName of extensionInterfaces) {
101
+ if (!interfaces.has(interfaceName)) {
102
+ interfaces.add(interfaceName);
103
+ continue;
104
+ }
105
+ this.errors.push((0, errors_1.duplicateInterfaceError)(interfaceName, typeName)); // TODO
106
+ }
107
+ }
108
+ mergeUniqueUnionMembers(baseUnion, extensionUnion) {
109
+ if (!extensionUnion) {
110
+ return;
111
+ }
112
+ const extensionMembers = extensionUnion.types;
113
+ const members = baseUnion.types;
114
+ const typeName = baseUnion.name.value;
115
+ for (const [memberName, namedTypeNode] of extensionMembers) {
116
+ if (!members.has(memberName)) {
117
+ members.set(memberName, namedTypeNode);
118
+ continue;
119
+ }
120
+ this.errors.push((0, errors_1.duplicateUnionMemberError)(memberName, typeName));
121
+ }
122
+ }
123
+ mergeDirectives(baseTypeDirectives, extension) {
124
+ if (!extension) {
125
+ return;
126
+ }
127
+ for (const [directiveName, directives] of extension.directives) {
128
+ const existingDirectives = baseTypeDirectives.get(directiveName);
129
+ if (existingDirectives) {
130
+ existingDirectives.push(...directives);
131
+ continue;
132
+ }
133
+ baseTypeDirectives.set(directiveName, [...directives]);
134
+ }
135
+ }
136
+ getValidatedAndNormalizedParentDirectives(parent) {
137
+ const parentTypeName = parent.name.value;
138
+ const normalizedDirectives = [];
139
+ for (const [directiveName, directives] of parent.directives) {
140
+ const definition = this.allDirectiveDefinitions.get(directiveName);
141
+ if (!definition) {
142
+ this.errors.push((0, errors_1.undefinedDirectiveError)(parentTypeName, directiveName));
143
+ continue;
144
+ }
145
+ const allArguments = new Set();
146
+ const requiredArguments = new Set();
147
+ (0, utils_2.getDirectiveDefinitionArgumentSets)(definition.arguments || [], allArguments, requiredArguments);
148
+ const entityKeys = new Set();
149
+ const errorMessages = [];
150
+ for (const directive of directives) {
151
+ if (!(0, utils_2.areNodeKindAndDirectiveLocationCompatible)(parent.kind, definition)) {
152
+ errorMessages.push((0, errors_1.invalidDirectiveLocationErrorMessage)(parentTypeName, parent.kind, directiveName));
153
+ }
154
+ if (!definition.repeatable && directives.length > 1) {
155
+ errorMessages.push((0, errors_1.invalidRepeatedDirectiveErrorMessage)(directiveName, parentTypeName));
156
+ }
157
+ if (!definition.arguments || definition.arguments.length < 1) {
158
+ if (directive.arguments && directive.arguments.length > 0) {
159
+ errorMessages.push((0, errors_1.unexpectedDirectiveArgumentsErrorMessage)(directive, parentTypeName));
160
+ }
161
+ else {
162
+ normalizedDirectives.push(directive);
163
+ }
164
+ continue;
165
+ }
166
+ if (!directive.arguments || directive.arguments.length < 1) {
167
+ if (requiredArguments.size > 0) {
168
+ errorMessages.push((0, errors_1.undefinedRequiredArgumentsErrorMessage)(directiveName, parentTypeName, Array.from(requiredArguments)));
169
+ }
170
+ else {
171
+ normalizedDirectives.push(directive);
172
+ }
173
+ continue;
174
+ }
175
+ const definedArguments = (0, utils_2.getDefinedArgumentsForDirective)(directive.arguments, allArguments, directiveName, parentTypeName, errorMessages);
176
+ const missingRequiredArguments = (0, utils_3.getEntriesNotInSet)(requiredArguments, definedArguments);
177
+ if (missingRequiredArguments.length > 0) {
178
+ errorMessages.push((0, errors_1.undefinedRequiredArgumentsErrorMessage)(directiveName, parentTypeName, Array.from(requiredArguments), missingRequiredArguments));
179
+ }
180
+ // Only add unique entity keys
181
+ if (directiveName === string_constants_1.KEY) {
182
+ const directiveKind = directive.arguments[0].value.kind;
183
+ if (directiveKind !== graphql_1.Kind.STRING) {
184
+ errorMessages.push((0, errors_1.invalidKeyDirectiveArgumentErrorMessage)(directiveKind));
185
+ continue;
186
+ }
187
+ const entityKey = directive.arguments[0].value.value;
188
+ if (entityKeys.has(entityKey)) {
189
+ continue;
190
+ }
191
+ entityKeys.add(entityKey);
192
+ }
193
+ normalizedDirectives.push(directive);
194
+ }
195
+ if (errorMessages.length > 0) {
196
+ this.errors.push((0, errors_1.invalidDirectiveError)(directiveName, parentTypeName, errorMessages));
197
+ }
198
+ }
199
+ return normalizedDirectives;
200
+ }
201
+ validateChildDirectives(child, hostPath) {
202
+ const childKind = child.node.kind;
203
+ for (const [directiveName, directives] of child.directives) {
204
+ const definition = this.allDirectiveDefinitions.get(directiveName);
205
+ if (!definition) {
206
+ this.errors.push((0, errors_1.undefinedDirectiveError)(hostPath, directiveName));
207
+ continue;
208
+ }
209
+ const allArguments = new Set();
210
+ const requiredArguments = new Set();
211
+ (0, utils_2.getDirectiveDefinitionArgumentSets)(definition.arguments || [], allArguments, requiredArguments);
212
+ const errorMessages = [];
213
+ for (const directive of directives) {
214
+ if (!(0, utils_2.areNodeKindAndDirectiveLocationCompatible)(childKind, definition)) {
215
+ errorMessages.push((0, errors_1.invalidDirectiveLocationErrorMessage)(hostPath, childKind, directiveName));
216
+ }
217
+ if (!definition.repeatable && directives.length > 1) {
218
+ errorMessages.push((0, errors_1.invalidRepeatedDirectiveErrorMessage)(directiveName, hostPath));
219
+ }
220
+ if (!definition.arguments || definition.arguments.length < 1) {
221
+ if (directive.arguments && directive.arguments.length > 0) {
222
+ errorMessages.push((0, errors_1.unexpectedDirectiveArgumentsErrorMessage)(directive, hostPath));
223
+ }
224
+ continue;
225
+ }
226
+ if (!directive.arguments || directive.arguments.length < 1) {
227
+ if (requiredArguments.size > 0) {
228
+ errorMessages.push((0, errors_1.undefinedRequiredArgumentsErrorMessage)(directiveName, hostPath, Array.from(requiredArguments)));
229
+ }
230
+ continue;
231
+ }
232
+ const definedArguments = (0, utils_2.getDefinedArgumentsForDirective)(directive.arguments, allArguments, directiveName, hostPath, errorMessages);
233
+ const missingRequiredArguments = (0, utils_3.getEntriesNotInSet)(requiredArguments, definedArguments);
234
+ if (missingRequiredArguments.length > 0) {
235
+ errorMessages.push((0, errors_1.undefinedRequiredArgumentsErrorMessage)(directiveName, hostPath, Array.from(requiredArguments), missingRequiredArguments));
236
+ }
237
+ }
238
+ if (errorMessages.length > 0) {
239
+ this.errors.push((0, errors_1.invalidDirectiveError)(directiveName, hostPath, errorMessages));
240
+ }
241
+ }
242
+ }
243
+ normalize(document) {
244
+ const factory = this;
245
+ (0, graphql_1.visit)(document, {
246
+ DirectiveDefinition: {
247
+ enter(node) {
248
+ const name = node.name.value;
249
+ // TODO These sets would potentially allow the user to define these directives more than once
250
+ // Add our definitions rather than the existing ones
251
+ if (constants_1.VERSION_TWO_DIRECTIVES.has(name)) {
252
+ factory.isSubgraphVersionTwo = true;
253
+ return false;
254
+ }
255
+ if (constants_1.VERSION_ONE_DIRECTIVES.has(name)) {
256
+ return false;
257
+ }
258
+ const directiveDefinition = factory.allDirectiveDefinitions.get(name);
259
+ if (directiveDefinition) {
260
+ factory.errors.push((0, errors_1.duplicateDirectiveDefinitionError)(name));
261
+ return false;
262
+ }
263
+ factory.allDirectiveDefinitions.set(name, node);
264
+ factory.customDirectiveDefinitions.set(name, node);
265
+ return false;
266
+ },
267
+ },
268
+ Directive: {
269
+ enter(node) {
270
+ const name = node.name.value;
271
+ if (constants_1.VERSION_TWO_DIRECTIVES.has(name)) {
272
+ factory.isSubgraphVersionTwo = true;
273
+ return false;
274
+ }
275
+ if (constants_1.VERSION_ONE_DIRECTIVES.has(name)) {
276
+ return false;
277
+ }
278
+ factory.referencedDirectives.add(name);
279
+ },
280
+ },
281
+ EnumTypeDefinition: {
282
+ enter(node) {
283
+ const name = node.name.value;
284
+ if (factory.parents.has(name)) {
285
+ factory.errors.push((0, errors_1.duplicateTypeDefinitionError)('enum', name));
286
+ return false;
287
+ }
288
+ factory.parentTypeName = name;
289
+ factory.parents.set(name, {
290
+ description: node.description,
291
+ directives: factory.extractDirectives(node, new Map()),
292
+ kind: node.kind,
293
+ name: node.name,
294
+ values: new Map(),
295
+ });
296
+ },
297
+ leave() {
298
+ factory.parentTypeName = '';
299
+ },
300
+ },
301
+ EnumTypeExtension: {
302
+ enter(node) {
303
+ const name = node.name.value;
304
+ factory.parentTypeName = name;
305
+ factory.isCurrentParentExtension = true;
306
+ const extension = factory.extensions.get(factory.parentTypeName);
307
+ if (extension) {
308
+ if (extension.kind !== graphql_1.Kind.ENUM_TYPE_EXTENSION) {
309
+ factory.errors.push((0, errors_1.incompatibleExtensionKindsError)(node, extension.kind));
310
+ return false;
311
+ }
312
+ factory.extractDirectives(node, extension.directives);
313
+ return;
314
+ }
315
+ factory.extensions.set(name, {
316
+ directives: factory.extractDirectives(node, new Map()),
317
+ kind: node.kind,
318
+ name: node.name,
319
+ values: new Map(),
320
+ });
321
+ },
322
+ leave() {
323
+ factory.isCurrentParentExtension = false;
324
+ factory.parentTypeName = '';
325
+ },
326
+ },
327
+ EnumValueDefinition: {
328
+ enter(node) {
329
+ const name = node.name.value;
330
+ const parent = factory.isCurrentParentExtension
331
+ ? (0, utils_3.getOrThrowError)(factory.extensions, factory.parentTypeName)
332
+ : (0, utils_3.getOrThrowError)(factory.parents, factory.parentTypeName);
333
+ if (parent.kind !== graphql_1.Kind.ENUM_TYPE_DEFINITION && parent.kind !== graphql_1.Kind.ENUM_TYPE_EXTENSION) {
334
+ throw new Error(''); // TODO
335
+ }
336
+ if (parent.values.has(name)) {
337
+ const error = factory.isCurrentParentExtension
338
+ ? (0, errors_1.duplicateValueExtensionError)('enum', factory.parentTypeName, name)
339
+ : (0, errors_1.duplicateEnumValueDefinitionError)(name, factory.parentTypeName);
340
+ factory.errors.push(error);
341
+ return;
342
+ }
343
+ parent.values.set(name, {
344
+ directives: factory.extractDirectives(node, new Map()),
345
+ name,
346
+ node,
347
+ });
348
+ },
349
+ },
350
+ FieldDefinition: {
351
+ enter(node) {
352
+ const name = node.name.value;
353
+ const fieldPath = `${factory.parentTypeName}.${name}`;
354
+ factory.isChild = true;
355
+ const fieldRootType = (0, type_merging_1.getNamedTypeForChild)(fieldPath, node.type);
356
+ if (!constants_1.BASE_SCALARS.has(fieldRootType)) {
357
+ factory.referencedTypeNames.add(fieldRootType);
358
+ }
359
+ const parent = factory.isCurrentParentExtension
360
+ ? (0, utils_3.getOrThrowError)(factory.extensions, factory.parentTypeName)
361
+ : (0, utils_3.getOrThrowError)(factory.parents, factory.parentTypeName);
362
+ if (parent.kind !== graphql_1.Kind.OBJECT_TYPE_DEFINITION &&
363
+ parent.kind !== graphql_1.Kind.OBJECT_TYPE_EXTENSION &&
364
+ parent.kind !== graphql_1.Kind.INTERFACE_TYPE_DEFINITION &&
365
+ parent.kind !== graphql_1.Kind.INTERFACE_TYPE_EXTENSION) {
366
+ throw new Error(''); // TODO
367
+ }
368
+ if (parent.fields.has(name)) {
369
+ const error = factory.isCurrentParentExtension
370
+ ? (0, errors_1.duplicateFieldExtensionError)(factory.parentTypeName, name)
371
+ : (0, errors_1.duplicateFieldDefinitionError)(name, factory.parentTypeName);
372
+ factory.errors.push(error);
373
+ return;
374
+ }
375
+ parent.fields.set(name, {
376
+ directives: factory.extractDirectives(node, new Map()),
377
+ name,
378
+ node,
379
+ });
380
+ },
381
+ leave() {
382
+ factory.isChild = false;
383
+ },
384
+ },
385
+ InputObjectTypeDefinition: {
386
+ enter(node) {
387
+ const name = node.name.value;
388
+ if (factory.parents.has(name)) {
389
+ factory.errors.push((0, errors_1.duplicateTypeDefinitionError)('input object', name));
390
+ return false;
391
+ }
392
+ factory.parentTypeName = name;
393
+ factory.parents.set(name, {
394
+ description: node.description,
395
+ directives: factory.extractDirectives(node, new Map()),
396
+ fields: new Map(),
397
+ kind: node.kind,
398
+ name: node.name,
399
+ });
400
+ },
401
+ leave() {
402
+ factory.parentTypeName = '';
403
+ },
404
+ },
405
+ InputObjectTypeExtension: {
406
+ enter(node) {
407
+ const name = node.name.value;
408
+ factory.parentTypeName = name;
409
+ factory.isCurrentParentExtension = true;
410
+ const extension = factory.extensions.get(factory.parentTypeName);
411
+ if (extension) {
412
+ if (extension.kind !== graphql_1.Kind.INPUT_OBJECT_TYPE_EXTENSION) {
413
+ factory.errors.push((0, errors_1.incompatibleExtensionKindsError)(node, extension.kind));
414
+ return false;
415
+ }
416
+ factory.extractDirectives(node, extension.directives);
417
+ return;
418
+ }
419
+ factory.extensions.set(name, {
420
+ directives: factory.extractDirectives(node, new Map()),
421
+ fields: new Map(),
422
+ kind: node.kind,
423
+ name: node.name,
424
+ });
425
+ },
426
+ leave() {
427
+ factory.isCurrentParentExtension = false;
428
+ factory.parentTypeName = '';
429
+ },
430
+ },
431
+ InputValueDefinition: {
432
+ enter(node) {
433
+ if (!factory.parentTypeName || factory.isChild) {
434
+ return;
435
+ }
436
+ const name = node.name.value;
437
+ const parent = factory.isCurrentParentExtension
438
+ ? (0, utils_3.getOrThrowError)(factory.extensions, factory.parentTypeName)
439
+ : (0, utils_3.getOrThrowError)(factory.parents, factory.parentTypeName);
440
+ if (parent.kind !== graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION && parent.kind !== graphql_1.Kind.INPUT_OBJECT_TYPE_EXTENSION) {
441
+ throw new Error(''); // TODO
442
+ }
443
+ if (parent.fields.has(name)) {
444
+ factory.errors.push((0, errors_1.duplicateValueExtensionError)('input', factory.parentTypeName, name));
445
+ return;
446
+ }
447
+ parent.fields.set(name, {
448
+ directives: factory.extractDirectives(node, new Map()),
449
+ name,
450
+ node,
451
+ });
452
+ },
453
+ },
454
+ InterfaceTypeDefinition: {
455
+ enter(node) {
456
+ const name = node.name.value;
457
+ if (factory.parents.has(name)) {
458
+ factory.errors.push((0, errors_1.duplicateTypeDefinitionError)('interface', name));
459
+ return false;
460
+ }
461
+ factory.parentTypeName = name;
462
+ factory.parents.set(name, {
463
+ description: node.description,
464
+ directives: factory.extractDirectives(node, new Map()),
465
+ fields: new Map(),
466
+ interfaces: (0, utils_1.extractInterfaces)(node, new Set()),
467
+ kind: node.kind,
468
+ name: node.name,
469
+ });
470
+ },
471
+ leave() {
472
+ factory.parentTypeName = '';
473
+ },
474
+ },
475
+ InterfaceTypeExtension: {
476
+ enter(node) {
477
+ const name = node.name.value;
478
+ factory.parentTypeName = name;
479
+ factory.isCurrentParentExtension = true;
480
+ const extension = factory.extensions.get(factory.parentTypeName);
481
+ if (extension) {
482
+ if (extension.kind !== graphql_1.Kind.INTERFACE_TYPE_EXTENSION) {
483
+ factory.errors.push((0, errors_1.incompatibleExtensionKindsError)(node, extension.kind));
484
+ return false;
485
+ }
486
+ factory.extractDirectives(node, extension.directives);
487
+ factory.extractUniqueInterfaces(node, extension.interfaces);
488
+ return;
489
+ }
490
+ const interfaces = new Set();
491
+ factory.extensions.set(name, {
492
+ directives: factory.extractDirectives(node, new Map()),
493
+ fields: new Map(),
494
+ interfaces: (0, utils_1.extractInterfaces)(node, interfaces),
495
+ kind: node.kind,
496
+ name: node.name,
497
+ });
498
+ },
499
+ leave() {
500
+ factory.isCurrentParentExtension = false;
501
+ factory.parentTypeName = '';
502
+ },
503
+ },
504
+ ObjectTypeDefinition: {
505
+ enter(node) {
506
+ const name = node.name.value;
507
+ if (factory.parents.has(name)) {
508
+ factory.errors.push((0, errors_1.duplicateTypeDefinitionError)('object', name));
509
+ return false;
510
+ }
511
+ factory.parentTypeName = name;
512
+ factory.parents.set(name, {
513
+ description: node.description,
514
+ directives: factory.extractDirectives(node, new Map()),
515
+ fields: new Map(),
516
+ interfaces: factory.extractUniqueInterfaces(node, new Set()),
517
+ kind: node.kind,
518
+ name: node.name,
519
+ });
520
+ if (!(0, utils_1.isObjectNodeEntity)(node)) {
521
+ return;
522
+ }
523
+ const existingEntityKeyMap = factory.entityMap.get(name);
524
+ const { entityKeyMap, errors } = (0, utils_1.getEntityKeyExtractionResults)(node, existingEntityKeyMap || new Map());
525
+ if (errors.length > 0) {
526
+ factory.errors.push(...errors);
527
+ }
528
+ if (!existingEntityKeyMap) {
529
+ factory.entityMap.set(name, entityKeyMap);
530
+ }
531
+ },
532
+ leave() {
533
+ factory.parentTypeName = '';
534
+ },
535
+ },
536
+ ObjectTypeExtension: {
537
+ enter(node) {
538
+ const name = node.name.value;
539
+ factory.parentTypeName = name;
540
+ factory.isCurrentParentExtension = true;
541
+ const extension = factory.extensions.get(factory.parentTypeName);
542
+ if (extension) {
543
+ if (extension.kind !== graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
544
+ factory.errors.push((0, errors_1.incompatibleExtensionKindsError)(node, extension.kind));
545
+ return false;
546
+ }
547
+ factory.extractDirectives(node, extension.directives);
548
+ factory.extractUniqueInterfaces(node, extension.interfaces);
549
+ return;
550
+ }
551
+ const interfaces = new Set();
552
+ factory.extensions.set(name, {
553
+ directives: factory.extractDirectives(node, new Map()),
554
+ fields: new Map(),
555
+ interfaces: (0, utils_1.extractInterfaces)(node, interfaces),
556
+ kind: node.kind,
557
+ name: node.name,
558
+ });
559
+ if (!(0, utils_1.isObjectNodeEntity)(node)) {
560
+ return;
561
+ }
562
+ const existingEntityKeyMap = factory.entityMap.get(name);
563
+ const { entityKeyMap, errors } = (0, utils_1.getEntityKeyExtractionResults)(node, existingEntityKeyMap || new Map());
564
+ if (errors.length > 0) {
565
+ factory.errors.push(...errors);
566
+ }
567
+ if (!existingEntityKeyMap) {
568
+ factory.entityMap.set(name, entityKeyMap);
569
+ }
570
+ },
571
+ leave() {
572
+ factory.isCurrentParentExtension = false;
573
+ factory.parentTypeName = '';
574
+ },
575
+ },
576
+ OperationTypeDefinition: {
577
+ enter(node) {
578
+ const operationType = node.operation;
579
+ const operationPath = `${factory.parentTypeName}.${operationType}`;
580
+ const definitionNode = factory.schemaDefinition.operationTypes.get(operationType);
581
+ const newTypeName = (0, type_merging_1.getNamedTypeForChild)(operationPath, node.type);
582
+ if (definitionNode) {
583
+ (0, errors_1.duplicateOperationTypeDefinitionError)(operationType, newTypeName, (0, type_merging_1.getNamedTypeForChild)(operationPath, definitionNode.type));
584
+ return false;
585
+ }
586
+ const existingOperationType = factory.operationTypeNames.get(newTypeName);
587
+ if (existingOperationType) {
588
+ factory.errors.push((0, errors_1.invalidOperationTypeDefinitionError)(existingOperationType, newTypeName, operationType));
589
+ }
590
+ else {
591
+ factory.operationTypeNames.set(newTypeName, operationType);
592
+ factory.schemaDefinition.operationTypes.set(operationType, node);
593
+ }
594
+ return false;
595
+ },
596
+ },
597
+ ScalarTypeDefinition: {
598
+ enter(node) {
599
+ const name = node.name.value;
600
+ const parent = factory.parents.get(name);
601
+ if (parent) {
602
+ factory.errors.push((0, errors_1.duplicateTypeDefinitionError)('scalar', name));
603
+ return false;
604
+ }
605
+ factory.parents.set(name, {
606
+ description: node.description,
607
+ directives: factory.extractDirectives(node, new Map()),
608
+ kind: graphql_1.Kind.SCALAR_TYPE_DEFINITION,
609
+ name: node.name,
610
+ });
611
+ },
612
+ },
613
+ ScalarTypeExtension: {
614
+ enter(node) {
615
+ const name = node.name.value;
616
+ const extension = factory.extensions.get(name);
617
+ if (extension) {
618
+ if (extension.kind !== graphql_1.Kind.SCALAR_TYPE_EXTENSION) {
619
+ factory.errors.push((0, errors_1.incompatibleExtensionKindsError)(node, extension.kind));
620
+ return false;
621
+ }
622
+ factory.extractDirectives(node, extension.directives);
623
+ }
624
+ else {
625
+ factory.extensions.set(name, {
626
+ directives: factory.extractDirectives(node, new Map()),
627
+ kind: node.kind,
628
+ name: node.name,
629
+ });
630
+ }
631
+ return false;
632
+ },
633
+ },
634
+ SchemaDefinition: {
635
+ enter(node) {
636
+ // Apollo allows multiple schema definitions
637
+ factory.extractDirectives(node, factory.schemaDefinition.directives);
638
+ factory.schemaDefinition.description = factory.schemaDefinition.description || node.description;
639
+ },
640
+ },
641
+ SchemaExtension: {
642
+ enter(node) {
643
+ factory.extractDirectives(node, factory.schemaDefinition.directives);
644
+ },
645
+ },
646
+ UnionTypeDefinition: {
647
+ enter(node) {
648
+ const name = node.name.value;
649
+ factory.parentTypeName = name;
650
+ const parent = factory.parents.get(name);
651
+ if (parent) {
652
+ factory.errors.push((0, errors_1.duplicateTypeDefinitionError)('union', name));
653
+ return false;
654
+ }
655
+ if (!node.types) {
656
+ factory.errors.push((0, errors_1.noDefinedUnionMembersError)(name));
657
+ return false;
658
+ }
659
+ factory.parents.set(name, {
660
+ description: node.description,
661
+ directives: factory.extractDirectives(node, new Map()),
662
+ kind: node.kind,
663
+ name: node.name,
664
+ types: factory.extractUniqueUnionMembers([...node.types], new Map()),
665
+ });
666
+ },
667
+ leave() {
668
+ factory.parentTypeName = '';
669
+ },
670
+ },
671
+ UnionTypeExtension: {
672
+ enter(node) {
673
+ const name = node.name.value;
674
+ const extension = factory.extensions.get(name);
675
+ if (!node.types) {
676
+ factory.errors.push();
677
+ return false;
678
+ }
679
+ if (extension) {
680
+ if (extension.kind !== graphql_1.Kind.UNION_TYPE_EXTENSION) {
681
+ factory.errors.push((0, errors_1.incompatibleExtensionKindsError)(node, extension.kind));
682
+ return false;
683
+ }
684
+ factory.extractDirectives(node, extension.directives);
685
+ }
686
+ else {
687
+ factory.extensions.set(name, {
688
+ directives: factory.extractDirectives(node, new Map()),
689
+ kind: node.kind,
690
+ name: node.name,
691
+ types: factory.extractUniqueUnionMembers([...node.types], new Map()),
692
+ });
693
+ }
694
+ return false;
695
+ },
696
+ },
697
+ });
698
+ const definitions = [];
699
+ for (const directiveDefinition of constants_1.BASE_DIRECTIVE_DEFINITIONS) {
700
+ definitions.push(directiveDefinition);
701
+ }
702
+ if (factory.isSubgraphVersionTwo) {
703
+ for (const directiveDefinition of constants_1.VERSION_TWO_DIRECTIVE_DEFINITIONS) {
704
+ definitions.push(directiveDefinition);
705
+ this.allDirectiveDefinitions.set(directiveDefinition.name.value, directiveDefinition);
706
+ }
707
+ }
708
+ for (const directiveDefinition of this.customDirectiveDefinitions.values()) {
709
+ definitions.push(directiveDefinition);
710
+ }
711
+ if (this.schemaDefinition.operationTypes.size > 0) {
712
+ definitions.push((0, utils_2.schemaContainerToNode)(this, this.schemaDefinition));
713
+ }
714
+ const validExtensionOrphans = new Set();
715
+ const parentsToIgnore = new Set();
716
+ for (const [typeName, extension] of this.extensions) {
717
+ const baseType = this.parents.get(typeName);
718
+ if (!baseType) {
719
+ if (extension.kind !== graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
720
+ this.errors.push((0, errors_1.noBaseTypeExtensionError)(typeName));
721
+ }
722
+ else {
723
+ (0, utils_2.validateEntityKeys)(this, typeName, true);
724
+ validExtensionOrphans.add(typeName);
725
+ definitions.push((0, utils_2.objectLikeContainerToNode)(this, extension));
726
+ }
727
+ continue;
728
+ }
729
+ if (!(0, utils_1.areBaseAndExtensionKindsCompatible)(baseType.kind, extension.kind)) {
730
+ this.errors.push(new Error(`Extension error:\n Incompatible types: ` +
731
+ `"${typeName}" is type "${baseType.kind}", but an extension of the same name is type "${extension.kind}.`));
732
+ continue;
733
+ }
734
+ switch (baseType.kind) {
735
+ case graphql_1.Kind.ENUM_TYPE_DEFINITION:
736
+ const enumExtension = extension;
737
+ for (const [valueName, enumValueDefinitionNode] of enumExtension.values) {
738
+ if (!baseType.values.has(valueName)) {
739
+ baseType.values.set(valueName, enumValueDefinitionNode);
740
+ continue;
741
+ }
742
+ this.errors.push((0, errors_1.duplicateEnumValueDefinitionError)(valueName, typeName));
743
+ }
744
+ definitions.push((0, utils_2.enumContainerToNode)(this, baseType, enumExtension));
745
+ break;
746
+ case graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION:
747
+ const inputExtension = extension;
748
+ for (const [fieldName, inputValueDefinitionNode] of inputExtension.fields) {
749
+ if (!baseType.fields.has(fieldName)) {
750
+ baseType.fields.set(fieldName, inputValueDefinitionNode);
751
+ continue;
752
+ }
753
+ this.errors.push((0, errors_1.duplicateFieldDefinitionError)(fieldName, typeName));
754
+ }
755
+ definitions.push((0, utils_2.inputObjectContainerToNode)(this, baseType, inputExtension));
756
+ break;
757
+ case graphql_1.Kind.INTERFACE_TYPE_DEFINITION:
758
+ // intentional fallthrough
759
+ case graphql_1.Kind.OBJECT_TYPE_DEFINITION:
760
+ const objectExtension = extension;
761
+ for (const [fieldName, fieldDefinitionNode] of objectExtension.fields) {
762
+ if (!baseType.fields.has(fieldName)) {
763
+ baseType.fields.set(fieldName, fieldDefinitionNode);
764
+ continue;
765
+ }
766
+ this.errors.push((0, errors_1.duplicateFieldDefinitionError)(fieldName, typeName));
767
+ }
768
+ (0, utils_2.validateEntityKeys)(this, typeName);
769
+ this.mergeUniqueInterfaces(objectExtension.interfaces, baseType.interfaces, typeName);
770
+ definitions.push((0, utils_2.objectLikeContainerToNode)(this, baseType, objectExtension));
771
+ break;
772
+ case graphql_1.Kind.SCALAR_TYPE_DEFINITION:
773
+ definitions.push((0, utils_2.scalarContainerToNode)(this, baseType, extension));
774
+ break;
775
+ case graphql_1.Kind.UNION_TYPE_DEFINITION:
776
+ const unionExtension = extension;
777
+ definitions.push((0, utils_2.unionContainerToNode)(this, baseType, unionExtension));
778
+ break;
779
+ default:
780
+ throw new Error('Unexpected kind'); // TODO
781
+ }
782
+ // At this point, the base type has been dealt with, so it doesn't need to be dealt with again
783
+ parentsToIgnore.add(typeName);
784
+ }
785
+ for (const [typeName, parentContainer] of this.parents) {
786
+ if (parentsToIgnore.has(typeName)) {
787
+ continue;
788
+ }
789
+ switch (parentContainer.kind) {
790
+ case graphql_1.Kind.ENUM_TYPE_DEFINITION:
791
+ definitions.push((0, utils_2.enumContainerToNode)(this, parentContainer));
792
+ break;
793
+ case graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION:
794
+ definitions.push((0, utils_2.inputObjectContainerToNode)(this, parentContainer));
795
+ break;
796
+ case graphql_1.Kind.INTERFACE_TYPE_DEFINITION:
797
+ // Intentional fallthrough
798
+ case graphql_1.Kind.OBJECT_TYPE_DEFINITION:
799
+ (0, utils_2.validateEntityKeys)(this, typeName);
800
+ definitions.push((0, utils_2.objectLikeContainerToNode)(this, parentContainer));
801
+ break;
802
+ case graphql_1.Kind.SCALAR_TYPE_DEFINITION:
803
+ definitions.push((0, utils_2.scalarContainerToNode)(this, parentContainer));
804
+ break;
805
+ case graphql_1.Kind.UNION_TYPE_DEFINITION:
806
+ definitions.push((0, utils_2.unionContainerToNode)(this, parentContainer));
807
+ break;
808
+ default:
809
+ throw (0, errors_1.unexpectedKindFatalError)(typeName);
810
+ }
811
+ }
812
+ // Check that explicitly defined operations types are valid objects and that their fields are also valid
813
+ for (const operationType of Object.values(graphql_1.OperationTypeNode)) {
814
+ const node = this.schemaDefinition.operationTypes.get(operationType);
815
+ const defaultTypeName = (0, utils_3.getOrThrowError)(utils_1.operationTypeNodeToDefaultType, operationType);
816
+ // If an operation type name was not declared, use the default
817
+ const operationTypeName = node ? (0, type_merging_1.getNamedTypeForChild)(`schema.${operationType}`, node.type) : defaultTypeName;
818
+ // If a custom type is used, the default type should not be defined
819
+ if (operationTypeName !== defaultTypeName &&
820
+ (this.parents.has(defaultTypeName) || this.extensions.has(defaultTypeName))) {
821
+ this.errors.push((0, errors_1.invalidRootTypeDefinitionError)(operationType, operationTypeName, defaultTypeName));
822
+ continue;
823
+ }
824
+ const object = this.parents.get(operationTypeName);
825
+ const extension = this.extensions.get(operationTypeName);
826
+ // Node is truthy of an operation type was explicitly declared
827
+ if (node) {
828
+ // If the type is not defined in the schema, it's always an error
829
+ if (!object && !extension) {
830
+ this.errors.push((0, errors_1.undefinedTypeError)(operationTypeName));
831
+ continue;
832
+ }
833
+ // Add the explicitly defined type to the map for the federation-factory
834
+ this.operationTypeNames.set(operationTypeName, operationType);
835
+ }
836
+ const containers = [object, extension];
837
+ for (const container of containers) {
838
+ if (!container) {
839
+ continue;
840
+ }
841
+ if (container.kind !== graphql_1.Kind.OBJECT_TYPE_DEFINITION && container.kind !== graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
842
+ this.errors.push((0, errors_1.operationDefinitionError)(operationTypeName, operationType, container.kind));
843
+ continue;
844
+ }
845
+ // Operations whose response type is an extension orphan could be valid through a federated graph
846
+ // However, the field would have to be shareable to ever be valid TODO
847
+ for (const fieldContainer of container.fields.values()) {
848
+ const fieldPath = `${operationTypeName}.${fieldContainer.name}`;
849
+ const fieldTypeName = (0, type_merging_1.getNamedTypeForChild)(fieldPath, fieldContainer.node.type);
850
+ if (!constants_1.BASE_SCALARS.has(fieldTypeName) &&
851
+ !this.parents.has(fieldTypeName) &&
852
+ !validExtensionOrphans.has(fieldTypeName)) {
853
+ this.errors.push((0, errors_1.undefinedTypeError)(fieldTypeName));
854
+ }
855
+ }
856
+ }
857
+ }
858
+ for (const referencedTypeName of this.referencedTypeNames) {
859
+ if (!this.parents.has(referencedTypeName) && !this.entityMap.has(referencedTypeName)) {
860
+ this.errors.push((0, errors_1.undefinedTypeError)(referencedTypeName));
861
+ }
862
+ }
863
+ if (this.errors.length > 0) {
864
+ return { errors: this.errors };
865
+ }
866
+ const newAST = {
867
+ kind: graphql_1.Kind.DOCUMENT,
868
+ definitions,
869
+ };
870
+ return {
871
+ normalizationResult: {
872
+ isVersionTwo: this.isSubgraphVersionTwo,
873
+ operationTypes: this.operationTypeNames,
874
+ subgraphAST: newAST,
875
+ subgraphString: (0, graphql_1.print)(newAST),
876
+ schema: (0, buildASTSchema_1.buildASTSchema)(newAST, { assumeValid: true }),
877
+ },
878
+ };
879
+ }
880
+ }
881
+ exports.NormalizationFactory = NormalizationFactory;
882
+ //# sourceMappingURL=normalization-factory.js.map