@wundergraph/composition 0.5.2 → 0.6.0
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.
- package/dist/ast/ast.d.ts +21 -3
- package/dist/ast/ast.js +23 -11
- package/dist/ast/ast.js.map +1 -1
- package/dist/ast/utils.d.ts +16 -103
- package/dist/ast/utils.js +132 -16
- package/dist/ast/utils.js.map +1 -1
- package/dist/errors/errors.d.ts +16 -4
- package/dist/errors/errors.js +97 -21
- package/dist/errors/errors.js.map +1 -1
- package/dist/federation/federation-factory.d.ts +28 -22
- package/dist/federation/federation-factory.js +611 -429
- package/dist/federation/federation-factory.js.map +1 -1
- package/dist/federation/utils.d.ts +130 -0
- package/dist/federation/utils.js +15 -0
- package/dist/federation/utils.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/normalization/normalization-factory.d.ts +9 -3
- package/dist/normalization/normalization-factory.js +221 -75
- package/dist/normalization/normalization-factory.js.map +1 -1
- package/dist/normalization/utils.d.ts +4 -0
- package/dist/normalization/utils.js +12 -5
- package/dist/normalization/utils.js.map +1 -1
- package/dist/subgraph/field-configuration.d.ts +12 -1
- package/dist/subgraph/subgraph.d.ts +2 -2
- package/dist/subgraph/subgraph.js +45 -82
- package/dist/subgraph/subgraph.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/constants.js +26 -8
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/string-constants.d.ts +13 -1
- package/dist/utils/string-constants.js +15 -2
- package/dist/utils/string-constants.js.map +1 -1
- package/dist/utils/utils.d.ts +15 -3
- package/dist/utils/utils.js +58 -23
- package/dist/utils/utils.js.map +1 -1
- package/package.json +4 -3
- package/dist/federation/federation-result.d.ts +0 -6
- package/dist/federation/federation-result.js +0 -3
- package/dist/federation/federation-result.js.map +0 -1
|
@@ -11,6 +11,7 @@ const errors_1 = require("../errors/errors");
|
|
|
11
11
|
const string_constants_1 = require("../utils/string-constants");
|
|
12
12
|
const buildASTSchema_1 = require("../buildASTSchema/buildASTSchema");
|
|
13
13
|
const merge_1 = require("@graphql-tools/merge");
|
|
14
|
+
const ast_1 = require("../ast/ast");
|
|
14
15
|
function normalizeSubgraphFromString(subgraph) {
|
|
15
16
|
let document;
|
|
16
17
|
try {
|
|
@@ -29,6 +30,7 @@ function normalizeSubgraph(document) {
|
|
|
29
30
|
}
|
|
30
31
|
exports.normalizeSubgraph = normalizeSubgraph;
|
|
31
32
|
class NormalizationFactory {
|
|
33
|
+
abstractToConcreteTypeNames = new Map();
|
|
32
34
|
allDirectiveDefinitions = new Map();
|
|
33
35
|
customDirectiveDefinitions = new Map();
|
|
34
36
|
errors = [];
|
|
@@ -36,6 +38,7 @@ class NormalizationFactory {
|
|
|
36
38
|
operationTypeNames = new Map();
|
|
37
39
|
parents = new Map();
|
|
38
40
|
parentTypeName = '';
|
|
41
|
+
parentsWithChildArguments = new Set();
|
|
39
42
|
extensions = new Map();
|
|
40
43
|
isChild = false;
|
|
41
44
|
isCurrentParentExtension = false;
|
|
@@ -54,20 +57,55 @@ class NormalizationFactory {
|
|
|
54
57
|
operationTypes: new Map(),
|
|
55
58
|
};
|
|
56
59
|
}
|
|
57
|
-
|
|
60
|
+
validateInputNamedType(namedType) {
|
|
61
|
+
if (constants_1.BASE_SCALARS.has(namedType)) {
|
|
62
|
+
return { hasUnhandledError: false, typeString: '' };
|
|
63
|
+
}
|
|
64
|
+
const parentContainer = this.parents.get(namedType);
|
|
65
|
+
if (!parentContainer) {
|
|
66
|
+
this.errors.push((0, errors_1.undefinedTypeError)(namedType));
|
|
67
|
+
return { hasUnhandledError: false, typeString: '' };
|
|
68
|
+
}
|
|
69
|
+
switch (parentContainer.kind) {
|
|
70
|
+
case graphql_1.Kind.ENUM_TYPE_DEFINITION:
|
|
71
|
+
case graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION:
|
|
72
|
+
case graphql_1.Kind.SCALAR_TYPE_DEFINITION:
|
|
73
|
+
return { hasUnhandledError: false, typeString: '' };
|
|
74
|
+
default:
|
|
75
|
+
return { hasUnhandledError: true, typeString: (0, utils_3.kindToTypeString)(parentContainer.kind) };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
extractArguments(node, argumentByName, fieldPath) {
|
|
58
79
|
if (!node.arguments) {
|
|
59
|
-
return
|
|
80
|
+
return argumentByName;
|
|
60
81
|
}
|
|
82
|
+
this.parentsWithChildArguments.add(this.parentTypeName);
|
|
83
|
+
const duplicatedArguments = new Set();
|
|
61
84
|
for (const argumentNode of node.arguments) {
|
|
62
85
|
const argumentName = argumentNode.name.value;
|
|
63
|
-
if (
|
|
64
|
-
|
|
65
|
-
this.errors.push(new Error('duplicate argument'));
|
|
86
|
+
if (argumentByName.has(argumentName)) {
|
|
87
|
+
duplicatedArguments.add(argumentName);
|
|
66
88
|
continue;
|
|
67
89
|
}
|
|
68
|
-
|
|
90
|
+
argumentByName.set(argumentName, (0, ast_1.inputValueDefinitionNodeToMutable)(argumentNode, this.parentTypeName));
|
|
91
|
+
}
|
|
92
|
+
if (duplicatedArguments.size > 0) {
|
|
93
|
+
this.errors.push((0, errors_1.duplicateArgumentsError)(fieldPath, [...duplicatedArguments]));
|
|
94
|
+
}
|
|
95
|
+
return argumentByName;
|
|
96
|
+
}
|
|
97
|
+
validateArguments(fieldContainer, fieldPath) {
|
|
98
|
+
const invalidArguments = [];
|
|
99
|
+
for (const [argumentName, argumentNode] of fieldContainer.arguments) {
|
|
100
|
+
const namedType = (0, type_merging_1.getNamedTypeForChild)(fieldPath + `(${argumentName}...)`, argumentNode.type);
|
|
101
|
+
const { hasUnhandledError, typeString } = this.validateInputNamedType(namedType);
|
|
102
|
+
if (hasUnhandledError) {
|
|
103
|
+
invalidArguments.push({ argumentName, namedType, typeString, typeName: (0, merge_1.printTypeNode)(argumentNode.type) });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (invalidArguments.length > 0) {
|
|
107
|
+
this.errors.push((0, errors_1.invalidArgumentsError)(fieldPath, invalidArguments));
|
|
69
108
|
}
|
|
70
|
-
return map;
|
|
71
109
|
}
|
|
72
110
|
extractDirectives(node, map) {
|
|
73
111
|
if (!node.directives) {
|
|
@@ -292,13 +330,45 @@ class NormalizationFactory {
|
|
|
292
330
|
}
|
|
293
331
|
}
|
|
294
332
|
}
|
|
333
|
+
isTypeValidImplementation(originalType, implementationType) {
|
|
334
|
+
if (originalType.kind === graphql_1.Kind.NON_NULL_TYPE) {
|
|
335
|
+
if (implementationType.kind !== graphql_1.Kind.NON_NULL_TYPE) {
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
return this.isTypeValidImplementation(originalType.type, implementationType.type);
|
|
339
|
+
}
|
|
340
|
+
if (implementationType.kind === graphql_1.Kind.NON_NULL_TYPE) {
|
|
341
|
+
return this.isTypeValidImplementation(originalType, implementationType.type);
|
|
342
|
+
}
|
|
343
|
+
switch (originalType.kind) {
|
|
344
|
+
case graphql_1.Kind.NAMED_TYPE:
|
|
345
|
+
if (implementationType.kind === graphql_1.Kind.NAMED_TYPE) {
|
|
346
|
+
const originalTypeName = originalType.name.value;
|
|
347
|
+
const implementationTypeName = implementationType.name.value;
|
|
348
|
+
if (originalTypeName === implementationTypeName) {
|
|
349
|
+
return true;
|
|
350
|
+
}
|
|
351
|
+
const concreteTypes = this.abstractToConcreteTypeNames.get(originalTypeName);
|
|
352
|
+
if (!concreteTypes) {
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
return concreteTypes.has(implementationTypeName);
|
|
356
|
+
}
|
|
357
|
+
return false;
|
|
358
|
+
default:
|
|
359
|
+
if (implementationType.kind === graphql_1.Kind.LIST_TYPE) {
|
|
360
|
+
return this.isTypeValidImplementation(originalType.type, implementationType.type);
|
|
361
|
+
}
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
295
365
|
validateInterfaceImplementations(container) {
|
|
296
366
|
if (container.interfaces.size < 1) {
|
|
297
367
|
return;
|
|
298
368
|
}
|
|
299
369
|
const implementationErrorsMap = new Map();
|
|
300
370
|
for (const interfaceName of container.interfaces) {
|
|
301
|
-
const interfaceContainer = (0, utils_3.getOrThrowError)(this.parents, interfaceName);
|
|
371
|
+
const interfaceContainer = (0, utils_3.getOrThrowError)(this.parents, interfaceName, string_constants_1.PARENTS);
|
|
302
372
|
if (interfaceContainer.kind !== graphql_1.Kind.INTERFACE_TYPE_DEFINITION) {
|
|
303
373
|
throw (0, errors_1.incompatibleParentKindFatalError)(interfaceName, graphql_1.Kind.INTERFACE_TYPE_DEFINITION, interfaceContainer.kind);
|
|
304
374
|
}
|
|
@@ -322,7 +392,7 @@ class NormalizationFactory {
|
|
|
322
392
|
unimplementedArguments: new Set(),
|
|
323
393
|
};
|
|
324
394
|
// The implemented field type must be equally or more restrictive than the original interface field type
|
|
325
|
-
if (!
|
|
395
|
+
if (!this.isTypeValidImplementation(interfaceField.node.type, containerField.node.type)) {
|
|
326
396
|
hasErrors = true;
|
|
327
397
|
hasNestedErrors = true;
|
|
328
398
|
invalidFieldImplementation.implementedResponseType = (0, merge_1.printTypeNode)(containerField.node.type);
|
|
@@ -373,24 +443,31 @@ class NormalizationFactory {
|
|
|
373
443
|
}
|
|
374
444
|
normalize(document) {
|
|
375
445
|
const factory = this;
|
|
446
|
+
/* factory.allDirectiveDefinitions is initialized with v1 directive definitions, and v2 definitions are only added
|
|
447
|
+
after the visitor has visited the entire schema and the subgraph is known to be a V2 graph. Consequently,
|
|
448
|
+
allDirectiveDefinitions cannot be used to check for duplicate definitions, and another set (below) is required */
|
|
449
|
+
const definedDirectives = new Set();
|
|
450
|
+
let isCurrentParentRootType = false;
|
|
376
451
|
(0, graphql_1.visit)(document, {
|
|
377
452
|
DirectiveDefinition: {
|
|
378
453
|
enter(node) {
|
|
379
454
|
const name = node.name.value;
|
|
380
|
-
|
|
381
|
-
|
|
455
|
+
if (definedDirectives.has(name)) {
|
|
456
|
+
factory.errors.push((0, errors_1.duplicateDirectiveDefinitionError)(name));
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
definedDirectives.add(name);
|
|
461
|
+
}
|
|
462
|
+
// Normalize federation directives by replacing them with predefined definitions
|
|
382
463
|
if (constants_1.VERSION_TWO_DIRECTIVES.has(name)) {
|
|
383
464
|
factory.isSubgraphVersionTwo = true;
|
|
384
465
|
return false;
|
|
385
466
|
}
|
|
467
|
+
// The V1 directives are always injected
|
|
386
468
|
if (constants_1.VERSION_ONE_DIRECTIVES.has(name)) {
|
|
387
469
|
return false;
|
|
388
470
|
}
|
|
389
|
-
const directiveDefinition = factory.allDirectiveDefinitions.get(name);
|
|
390
|
-
if (directiveDefinition) {
|
|
391
|
-
factory.errors.push((0, errors_1.duplicateDirectiveDefinitionError)(name));
|
|
392
|
-
return false;
|
|
393
|
-
}
|
|
394
471
|
factory.allDirectiveDefinitions.set(name, node);
|
|
395
472
|
factory.customDirectiveDefinitions.set(name, node);
|
|
396
473
|
return false;
|
|
@@ -418,7 +495,7 @@ class NormalizationFactory {
|
|
|
418
495
|
}
|
|
419
496
|
factory.parentTypeName = name;
|
|
420
497
|
factory.parents.set(name, {
|
|
421
|
-
description: node.description,
|
|
498
|
+
description: (0, utils_1.formatDescription)(node.description),
|
|
422
499
|
directives: factory.extractDirectives(node, new Map()),
|
|
423
500
|
kind: node.kind,
|
|
424
501
|
name: node.name,
|
|
@@ -459,8 +536,8 @@ class NormalizationFactory {
|
|
|
459
536
|
enter(node) {
|
|
460
537
|
const name = node.name.value;
|
|
461
538
|
const parent = factory.isCurrentParentExtension
|
|
462
|
-
? (0, utils_3.getOrThrowError)(factory.extensions, factory.parentTypeName)
|
|
463
|
-
: (0, utils_3.getOrThrowError)(factory.parents, factory.parentTypeName);
|
|
539
|
+
? (0, utils_3.getOrThrowError)(factory.extensions, factory.parentTypeName, string_constants_1.EXTENSIONS)
|
|
540
|
+
: (0, utils_3.getOrThrowError)(factory.parents, factory.parentTypeName, string_constants_1.PARENTS);
|
|
464
541
|
if (parent.kind !== graphql_1.Kind.ENUM_TYPE_DEFINITION && parent.kind !== graphql_1.Kind.ENUM_TYPE_EXTENSION) {
|
|
465
542
|
throw (0, errors_1.unexpectedKindFatalError)(name);
|
|
466
543
|
}
|
|
@@ -474,13 +551,16 @@ class NormalizationFactory {
|
|
|
474
551
|
parent.values.set(name, {
|
|
475
552
|
directives: factory.extractDirectives(node, new Map()),
|
|
476
553
|
name,
|
|
477
|
-
node,
|
|
554
|
+
node: { ...node, description: (0, utils_1.formatDescription)(node.description) },
|
|
478
555
|
});
|
|
479
556
|
},
|
|
480
557
|
},
|
|
481
558
|
FieldDefinition: {
|
|
482
559
|
enter(node) {
|
|
483
560
|
const name = node.name.value;
|
|
561
|
+
if (isCurrentParentRootType && (name === string_constants_1.SERVICE_FIELD || name === string_constants_1.ENTITIES_FIELD)) {
|
|
562
|
+
return false;
|
|
563
|
+
}
|
|
484
564
|
const fieldPath = `${factory.parentTypeName}.${name}`;
|
|
485
565
|
factory.isChild = true;
|
|
486
566
|
const fieldRootType = (0, type_merging_1.getNamedTypeForChild)(fieldPath, node.type);
|
|
@@ -488,8 +568,8 @@ class NormalizationFactory {
|
|
|
488
568
|
factory.referencedTypeNames.add(fieldRootType);
|
|
489
569
|
}
|
|
490
570
|
const parent = factory.isCurrentParentExtension
|
|
491
|
-
? (0, utils_3.getOrThrowError)(factory.extensions, factory.parentTypeName)
|
|
492
|
-
: (0, utils_3.getOrThrowError)(factory.parents, factory.parentTypeName);
|
|
571
|
+
? (0, utils_3.getOrThrowError)(factory.extensions, factory.parentTypeName, string_constants_1.EXTENSIONS)
|
|
572
|
+
: (0, utils_3.getOrThrowError)(factory.parents, factory.parentTypeName, string_constants_1.PARENTS);
|
|
493
573
|
if (parent.kind !== graphql_1.Kind.OBJECT_TYPE_DEFINITION &&
|
|
494
574
|
parent.kind !== graphql_1.Kind.OBJECT_TYPE_EXTENSION &&
|
|
495
575
|
parent.kind !== graphql_1.Kind.INTERFACE_TYPE_DEFINITION &&
|
|
@@ -503,11 +583,18 @@ class NormalizationFactory {
|
|
|
503
583
|
factory.errors.push(error);
|
|
504
584
|
return;
|
|
505
585
|
}
|
|
586
|
+
// recreate the node so the argument descriptions are updated
|
|
506
587
|
parent.fields.set(name, {
|
|
507
|
-
arguments: factory.extractArguments(node, new Map),
|
|
588
|
+
arguments: factory.extractArguments(node, new Map(), fieldPath),
|
|
508
589
|
directives: factory.extractDirectives(node, new Map()),
|
|
509
590
|
name,
|
|
510
|
-
node
|
|
591
|
+
node: {
|
|
592
|
+
...node,
|
|
593
|
+
arguments: node.arguments?.map((arg) => ({
|
|
594
|
+
...arg,
|
|
595
|
+
description: (0, utils_1.formatDescription)(arg.description),
|
|
596
|
+
})),
|
|
597
|
+
}
|
|
511
598
|
});
|
|
512
599
|
},
|
|
513
600
|
leave() {
|
|
@@ -523,7 +610,7 @@ class NormalizationFactory {
|
|
|
523
610
|
}
|
|
524
611
|
factory.parentTypeName = name;
|
|
525
612
|
factory.parents.set(name, {
|
|
526
|
-
description: node.description,
|
|
613
|
+
description: (0, utils_1.formatDescription)(node.description),
|
|
527
614
|
directives: factory.extractDirectives(node, new Map()),
|
|
528
615
|
fields: new Map(),
|
|
529
616
|
kind: node.kind,
|
|
@@ -566,9 +653,13 @@ class NormalizationFactory {
|
|
|
566
653
|
return;
|
|
567
654
|
}
|
|
568
655
|
const name = node.name.value;
|
|
656
|
+
const valueRootTypeName = (0, type_merging_1.getNamedTypeForChild)(`${factory.parentTypeName}.${name}`, node.type);
|
|
657
|
+
if (!constants_1.BASE_SCALARS.has(valueRootTypeName)) {
|
|
658
|
+
factory.referencedTypeNames.add(valueRootTypeName);
|
|
659
|
+
}
|
|
569
660
|
const parent = factory.isCurrentParentExtension
|
|
570
|
-
? (0, utils_3.getOrThrowError)(factory.extensions, factory.parentTypeName)
|
|
571
|
-
: (0, utils_3.getOrThrowError)(factory.parents, factory.parentTypeName);
|
|
661
|
+
? (0, utils_3.getOrThrowError)(factory.extensions, factory.parentTypeName, string_constants_1.EXTENSIONS)
|
|
662
|
+
: (0, utils_3.getOrThrowError)(factory.parents, factory.parentTypeName, string_constants_1.PARENTS);
|
|
572
663
|
if (parent.kind !== graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION && parent.kind !== graphql_1.Kind.INPUT_OBJECT_TYPE_EXTENSION) {
|
|
573
664
|
throw (0, errors_1.unexpectedKindFatalError)(factory.parentTypeName);
|
|
574
665
|
}
|
|
@@ -579,7 +670,7 @@ class NormalizationFactory {
|
|
|
579
670
|
parent.fields.set(name, {
|
|
580
671
|
directives: factory.extractDirectives(node, new Map()),
|
|
581
672
|
name,
|
|
582
|
-
node,
|
|
673
|
+
node: { ...node, description: (0, utils_1.formatDescription)(node.description) },
|
|
583
674
|
});
|
|
584
675
|
},
|
|
585
676
|
},
|
|
@@ -595,7 +686,7 @@ class NormalizationFactory {
|
|
|
595
686
|
return false;
|
|
596
687
|
}
|
|
597
688
|
factory.parents.set(name, {
|
|
598
|
-
description: node.description,
|
|
689
|
+
description: (0, utils_1.formatDescription)(node.description),
|
|
599
690
|
directives: factory.extractDirectives(node, new Map()),
|
|
600
691
|
fields: new Map(),
|
|
601
692
|
interfaces: (0, utils_1.extractInterfaces)(node, new Set(), factory.errors),
|
|
@@ -621,7 +712,12 @@ class NormalizationFactory {
|
|
|
621
712
|
ObjectTypeDefinition: {
|
|
622
713
|
enter(node) {
|
|
623
714
|
const name = node.name.value;
|
|
715
|
+
if (name === string_constants_1.SERVICE) {
|
|
716
|
+
return false;
|
|
717
|
+
}
|
|
718
|
+
isCurrentParentRootType = string_constants_1.ROOT_TYPES.has(name);
|
|
624
719
|
factory.parentTypeName = name;
|
|
720
|
+
(0, utils_1.addConcreteTypesForImplementedInterfaces)(node, factory.abstractToConcreteTypeNames);
|
|
625
721
|
// handling for @extends directive
|
|
626
722
|
if ((0, utils_1.isNodeExtension)(node)) {
|
|
627
723
|
return factory.handleObjectLikeExtension(node);
|
|
@@ -632,7 +728,7 @@ class NormalizationFactory {
|
|
|
632
728
|
}
|
|
633
729
|
const isEntity = (0, utils_1.isObjectLikeNodeEntity)(node);
|
|
634
730
|
factory.parents.set(name, {
|
|
635
|
-
description: node.description,
|
|
731
|
+
description: (0, utils_1.formatDescription)(node.description),
|
|
636
732
|
directives: factory.extractDirectives(node, new Map()),
|
|
637
733
|
fields: new Map(),
|
|
638
734
|
interfaces: (0, utils_1.extractInterfaces)(node, new Set(), factory.errors),
|
|
@@ -654,16 +750,24 @@ class NormalizationFactory {
|
|
|
654
750
|
},
|
|
655
751
|
leave() {
|
|
656
752
|
factory.isCurrentParentExtension = false;
|
|
753
|
+
isCurrentParentRootType = false;
|
|
657
754
|
factory.parentTypeName = '';
|
|
658
755
|
},
|
|
659
756
|
},
|
|
660
757
|
ObjectTypeExtension: {
|
|
661
758
|
enter(node) {
|
|
662
|
-
|
|
759
|
+
const name = node.name.value;
|
|
760
|
+
if (name === string_constants_1.SERVICE) {
|
|
761
|
+
return false;
|
|
762
|
+
}
|
|
763
|
+
isCurrentParentRootType = string_constants_1.ROOT_TYPES.has(name);
|
|
764
|
+
factory.parentTypeName = name;
|
|
765
|
+
(0, utils_1.addConcreteTypesForImplementedInterfaces)(node, factory.abstractToConcreteTypeNames);
|
|
663
766
|
return factory.handleObjectLikeExtension(node);
|
|
664
767
|
},
|
|
665
768
|
leave() {
|
|
666
769
|
factory.isCurrentParentExtension = false;
|
|
770
|
+
isCurrentParentRootType = false;
|
|
667
771
|
factory.parentTypeName = '';
|
|
668
772
|
},
|
|
669
773
|
},
|
|
@@ -697,7 +801,7 @@ class NormalizationFactory {
|
|
|
697
801
|
return false;
|
|
698
802
|
}
|
|
699
803
|
factory.parents.set(name, {
|
|
700
|
-
description: node.description,
|
|
804
|
+
description: (0, utils_1.formatDescription)(node.description),
|
|
701
805
|
directives: factory.extractDirectives(node, new Map()),
|
|
702
806
|
kind: graphql_1.Kind.SCALAR_TYPE_DEFINITION,
|
|
703
807
|
name: node.name,
|
|
@@ -728,7 +832,7 @@ class NormalizationFactory {
|
|
|
728
832
|
SchemaDefinition: {
|
|
729
833
|
enter(node) {
|
|
730
834
|
factory.extractDirectives(node, factory.schemaDefinition.directives);
|
|
731
|
-
factory.schemaDefinition.description =
|
|
835
|
+
factory.schemaDefinition.description = node.description;
|
|
732
836
|
},
|
|
733
837
|
},
|
|
734
838
|
SchemaExtension: {
|
|
@@ -749,8 +853,9 @@ class NormalizationFactory {
|
|
|
749
853
|
factory.errors.push((0, errors_1.noDefinedUnionMembersError)(name));
|
|
750
854
|
return false;
|
|
751
855
|
}
|
|
856
|
+
(0, utils_1.addConcreteTypesForUnion)(node, factory.abstractToConcreteTypeNames);
|
|
752
857
|
factory.parents.set(name, {
|
|
753
|
-
description: node.description,
|
|
858
|
+
description: (0, utils_1.formatDescription)(node.description),
|
|
754
859
|
directives: factory.extractDirectives(node, new Map()),
|
|
755
860
|
kind: node.kind,
|
|
756
861
|
name: node.name,
|
|
@@ -769,6 +874,7 @@ class NormalizationFactory {
|
|
|
769
874
|
factory.errors.push();
|
|
770
875
|
return false;
|
|
771
876
|
}
|
|
877
|
+
(0, utils_1.addConcreteTypesForUnion)(node, factory.abstractToConcreteTypeNames);
|
|
772
878
|
if (extension) {
|
|
773
879
|
if (extension.kind !== graphql_1.Kind.UNION_TYPE_EXTENSION) {
|
|
774
880
|
factory.errors.push((0, errors_1.incompatibleExtensionKindsError)(node, extension.kind));
|
|
@@ -809,91 +915,107 @@ class NormalizationFactory {
|
|
|
809
915
|
const configurationDataMap = new Map();
|
|
810
916
|
const validExtensionOrphans = new Set();
|
|
811
917
|
const parentsToIgnore = new Set();
|
|
812
|
-
for (const [
|
|
813
|
-
const entity = this.entityMap.get(
|
|
918
|
+
for (const [extensionTypeName, extensionContainer] of this.extensions) {
|
|
919
|
+
const entity = this.entityMap.get(extensionTypeName);
|
|
814
920
|
const configurationData = {
|
|
815
921
|
fieldNames: new Set(),
|
|
816
922
|
isRootNode: !!entity,
|
|
817
|
-
|
|
818
|
-
typeName,
|
|
923
|
+
typeName: extensionTypeName,
|
|
819
924
|
};
|
|
820
|
-
if (
|
|
821
|
-
|
|
822
|
-
|
|
925
|
+
if (entity) {
|
|
926
|
+
configurationData.keys = [...entity.keys()].map((selectionSet) => ({
|
|
927
|
+
fieldName: '', selectionSet,
|
|
928
|
+
}));
|
|
929
|
+
}
|
|
930
|
+
if (extensionContainer.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
|
|
931
|
+
if (this.operationTypeNames.has(extensionTypeName)) {
|
|
932
|
+
extensionContainer.fields.delete(string_constants_1.SERVICE_FIELD);
|
|
933
|
+
extensionContainer.fields.delete(string_constants_1.ENTITIES_FIELD);
|
|
934
|
+
}
|
|
935
|
+
(0, utils_3.addIterableValuesToSet)(extensionContainer.fields.keys(), configurationData.fieldNames);
|
|
936
|
+
configurationDataMap.set(extensionTypeName, configurationData);
|
|
823
937
|
}
|
|
824
|
-
const baseType = this.parents.get(
|
|
938
|
+
const baseType = this.parents.get(extensionTypeName);
|
|
825
939
|
if (!baseType) {
|
|
826
|
-
if (
|
|
827
|
-
this.errors.push((0, errors_1.noBaseTypeExtensionError)(
|
|
940
|
+
if (extensionContainer.kind !== graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
|
|
941
|
+
this.errors.push((0, errors_1.noBaseTypeExtensionError)(extensionTypeName));
|
|
828
942
|
}
|
|
829
943
|
else {
|
|
830
|
-
(0, utils_2.validateEntityKeys)(this,
|
|
831
|
-
this.validateInterfaceImplementations(
|
|
832
|
-
validExtensionOrphans.add(
|
|
833
|
-
definitions.push((0, utils_2.objectLikeContainerToNode)(this,
|
|
944
|
+
(0, utils_2.validateEntityKeys)(this, extensionTypeName, true);
|
|
945
|
+
this.validateInterfaceImplementations(extensionContainer);
|
|
946
|
+
validExtensionOrphans.add(extensionTypeName);
|
|
947
|
+
definitions.push((0, utils_2.objectLikeContainerToNode)(this, extensionContainer));
|
|
834
948
|
}
|
|
835
949
|
continue;
|
|
836
950
|
}
|
|
837
|
-
if (!(0, utils_1.areBaseAndExtensionKindsCompatible)(baseType.kind,
|
|
838
|
-
this.errors.push((0, errors_1.incompatibleExtensionError)(
|
|
951
|
+
if (!(0, utils_1.areBaseAndExtensionKindsCompatible)(baseType.kind, extensionContainer.kind, extensionTypeName)) {
|
|
952
|
+
this.errors.push((0, errors_1.incompatibleExtensionError)(extensionTypeName, baseType.kind, extensionContainer.kind));
|
|
839
953
|
continue;
|
|
840
954
|
}
|
|
841
955
|
switch (baseType.kind) {
|
|
842
956
|
case graphql_1.Kind.ENUM_TYPE_DEFINITION:
|
|
843
|
-
const enumExtension =
|
|
957
|
+
const enumExtension = extensionContainer;
|
|
844
958
|
for (const [valueName, enumValueDefinitionNode] of enumExtension.values) {
|
|
845
959
|
if (!baseType.values.has(valueName)) {
|
|
846
960
|
baseType.values.set(valueName, enumValueDefinitionNode);
|
|
847
961
|
continue;
|
|
848
962
|
}
|
|
849
|
-
this.errors.push((0, errors_1.duplicateEnumValueDefinitionError)(valueName,
|
|
963
|
+
this.errors.push((0, errors_1.duplicateEnumValueDefinitionError)(valueName, extensionTypeName));
|
|
850
964
|
}
|
|
851
965
|
definitions.push((0, utils_2.enumContainerToNode)(this, baseType, enumExtension));
|
|
852
966
|
break;
|
|
853
967
|
case graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION:
|
|
854
|
-
const inputExtension =
|
|
968
|
+
const inputExtension = extensionContainer;
|
|
855
969
|
for (const [fieldName, inputValueDefinitionNode] of inputExtension.fields) {
|
|
856
970
|
if (!baseType.fields.has(fieldName)) {
|
|
857
971
|
baseType.fields.set(fieldName, inputValueDefinitionNode);
|
|
858
972
|
continue;
|
|
859
973
|
}
|
|
860
|
-
this.errors.push((0, errors_1.duplicateFieldDefinitionError)(fieldName,
|
|
974
|
+
this.errors.push((0, errors_1.duplicateFieldDefinitionError)(fieldName, extensionTypeName));
|
|
861
975
|
}
|
|
862
976
|
definitions.push((0, utils_2.inputObjectContainerToNode)(this, baseType, inputExtension));
|
|
863
977
|
break;
|
|
864
978
|
case graphql_1.Kind.INTERFACE_TYPE_DEFINITION:
|
|
865
979
|
// intentional fallthrough
|
|
866
980
|
case graphql_1.Kind.OBJECT_TYPE_DEFINITION:
|
|
867
|
-
const objectLikeExtension =
|
|
981
|
+
const objectLikeExtension = extensionContainer;
|
|
982
|
+
if (this.operationTypeNames.has(extensionTypeName)) {
|
|
983
|
+
objectLikeExtension.fields.delete(string_constants_1.SERVICE_FIELD);
|
|
984
|
+
objectLikeExtension.fields.delete(string_constants_1.ENTITIES_FIELD);
|
|
985
|
+
}
|
|
868
986
|
for (const [fieldName, fieldContainer] of objectLikeExtension.fields) {
|
|
987
|
+
if (fieldContainer.arguments.size > 0) {
|
|
988
|
+
// Arguments can only be fully validated once all parents types are known
|
|
989
|
+
this.validateArguments(fieldContainer, `${extensionTypeName}.${fieldName}`);
|
|
990
|
+
}
|
|
869
991
|
if (baseType.fields.has(fieldName)) {
|
|
870
|
-
this.errors.push((0, errors_1.duplicateFieldDefinitionError)(fieldName,
|
|
992
|
+
this.errors.push((0, errors_1.duplicateFieldDefinitionError)(fieldName, extensionTypeName));
|
|
871
993
|
continue;
|
|
872
994
|
}
|
|
873
995
|
baseType.fields.set(fieldName, fieldContainer);
|
|
874
996
|
configurationData.fieldNames.add(fieldName);
|
|
875
997
|
}
|
|
876
|
-
(0, utils_2.validateEntityKeys)(this,
|
|
877
|
-
this.mergeUniqueInterfaces(objectLikeExtension.interfaces, baseType.interfaces,
|
|
998
|
+
(0, utils_2.validateEntityKeys)(this, extensionTypeName);
|
|
999
|
+
this.mergeUniqueInterfaces(objectLikeExtension.interfaces, baseType.interfaces, extensionTypeName);
|
|
878
1000
|
this.validateInterfaceImplementations(baseType);
|
|
879
|
-
configurationDataMap.set(
|
|
1001
|
+
configurationDataMap.set(extensionTypeName, configurationData);
|
|
880
1002
|
definitions.push((0, utils_2.objectLikeContainerToNode)(this, baseType, objectLikeExtension));
|
|
881
1003
|
break;
|
|
882
1004
|
case graphql_1.Kind.SCALAR_TYPE_DEFINITION:
|
|
883
|
-
definitions.push((0, utils_2.scalarContainerToNode)(this, baseType,
|
|
1005
|
+
definitions.push((0, utils_2.scalarContainerToNode)(this, baseType, extensionContainer));
|
|
884
1006
|
break;
|
|
885
1007
|
case graphql_1.Kind.UNION_TYPE_DEFINITION:
|
|
886
|
-
const unionExtension =
|
|
1008
|
+
const unionExtension = extensionContainer;
|
|
887
1009
|
definitions.push((0, utils_2.unionContainerToNode)(this, baseType, unionExtension));
|
|
888
1010
|
break;
|
|
889
1011
|
default:
|
|
890
|
-
throw (0, errors_1.unexpectedKindFatalError)(
|
|
1012
|
+
throw (0, errors_1.unexpectedKindFatalError)(extensionTypeName);
|
|
891
1013
|
}
|
|
892
1014
|
// At this point, the base type has been dealt with, so it doesn't need to be dealt with again
|
|
893
|
-
parentsToIgnore.add(
|
|
1015
|
+
parentsToIgnore.add(extensionTypeName);
|
|
894
1016
|
}
|
|
895
|
-
for (const [
|
|
896
|
-
if (parentsToIgnore.has(
|
|
1017
|
+
for (const [parentTypeName, parentContainer] of this.parents) {
|
|
1018
|
+
if (parentsToIgnore.has(parentTypeName)) {
|
|
897
1019
|
continue;
|
|
898
1020
|
}
|
|
899
1021
|
switch (parentContainer.kind) {
|
|
@@ -906,17 +1028,36 @@ class NormalizationFactory {
|
|
|
906
1028
|
case graphql_1.Kind.INTERFACE_TYPE_DEFINITION:
|
|
907
1029
|
// intentional fallthrough
|
|
908
1030
|
case graphql_1.Kind.OBJECT_TYPE_DEFINITION:
|
|
909
|
-
const entity = this.entityMap.get(
|
|
1031
|
+
const entity = this.entityMap.get(parentTypeName);
|
|
1032
|
+
if (this.operationTypeNames.has(parentTypeName)) {
|
|
1033
|
+
parentContainer.fields.delete(string_constants_1.SERVICE_FIELD);
|
|
1034
|
+
parentContainer.fields.delete(string_constants_1.ENTITIES_FIELD);
|
|
1035
|
+
}
|
|
1036
|
+
if (this.parentsWithChildArguments.has(parentTypeName)) {
|
|
1037
|
+
const parentContainer = (0, utils_3.getOrThrowError)(this.parents, parentTypeName, string_constants_1.PARENTS);
|
|
1038
|
+
if (parentContainer.kind !== graphql_1.Kind.OBJECT_TYPE_DEFINITION
|
|
1039
|
+
&& parentContainer.kind !== graphql_1.Kind.INTERFACE_TYPE_DEFINITION) {
|
|
1040
|
+
continue;
|
|
1041
|
+
}
|
|
1042
|
+
for (const [fieldName, fieldContainer] of parentContainer.fields) {
|
|
1043
|
+
// Arguments can only be fully validated once all parents types are known
|
|
1044
|
+
this.validateArguments(fieldContainer, `${parentTypeName}.${fieldName}`);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
910
1047
|
const configurationData = {
|
|
911
1048
|
fieldNames: new Set(),
|
|
912
1049
|
isRootNode: !!entity,
|
|
913
|
-
|
|
914
|
-
typeName,
|
|
1050
|
+
typeName: parentTypeName,
|
|
915
1051
|
};
|
|
1052
|
+
if (entity) {
|
|
1053
|
+
configurationData.keys = [...entity.keys()].map((selectionSet) => ({
|
|
1054
|
+
fieldName: '', selectionSet,
|
|
1055
|
+
}));
|
|
1056
|
+
}
|
|
916
1057
|
(0, utils_3.addIterableValuesToSet)(parentContainer.fields.keys(), configurationData.fieldNames);
|
|
917
|
-
(0, utils_2.validateEntityKeys)(this,
|
|
1058
|
+
(0, utils_2.validateEntityKeys)(this, parentTypeName);
|
|
918
1059
|
this.validateInterfaceImplementations(parentContainer);
|
|
919
|
-
configurationDataMap.set(
|
|
1060
|
+
configurationDataMap.set(parentTypeName, configurationData);
|
|
920
1061
|
definitions.push((0, utils_2.objectLikeContainerToNode)(this, parentContainer));
|
|
921
1062
|
break;
|
|
922
1063
|
case graphql_1.Kind.SCALAR_TYPE_DEFINITION:
|
|
@@ -926,15 +1067,16 @@ class NormalizationFactory {
|
|
|
926
1067
|
definitions.push((0, utils_2.unionContainerToNode)(this, parentContainer));
|
|
927
1068
|
break;
|
|
928
1069
|
default:
|
|
929
|
-
throw (0, errors_1.unexpectedKindFatalError)(
|
|
1070
|
+
throw (0, errors_1.unexpectedKindFatalError)(parentTypeName);
|
|
930
1071
|
}
|
|
931
1072
|
}
|
|
932
1073
|
// Check that explicitly defined operations types are valid objects and that their fields are also valid
|
|
933
1074
|
for (const operationType of Object.values(graphql_1.OperationTypeNode)) {
|
|
934
1075
|
const node = this.schemaDefinition.operationTypes.get(operationType);
|
|
935
|
-
const defaultTypeName = (0, utils_3.getOrThrowError)(utils_1.operationTypeNodeToDefaultType, operationType);
|
|
1076
|
+
const defaultTypeName = (0, utils_3.getOrThrowError)(utils_1.operationTypeNodeToDefaultType, operationType, string_constants_1.OPERATION_TO_DEFAULT);
|
|
936
1077
|
// If an operation type name was not declared, use the default
|
|
937
|
-
const operationTypeName = node ? (0, type_merging_1.getNamedTypeForChild)(`schema.${operationType}`, node.type)
|
|
1078
|
+
const operationTypeName = node ? (0, type_merging_1.getNamedTypeForChild)(`schema.${operationType}`, node.type)
|
|
1079
|
+
: defaultTypeName;
|
|
938
1080
|
// If a custom type is used, the default type should not be defined
|
|
939
1081
|
if (operationTypeName !== defaultTypeName &&
|
|
940
1082
|
(this.parents.has(defaultTypeName) || this.extensions.has(defaultTypeName))) {
|
|
@@ -970,7 +1112,7 @@ class NormalizationFactory {
|
|
|
970
1112
|
this.errors.push((0, errors_1.operationDefinitionError)(operationTypeName, operationType, container.kind));
|
|
971
1113
|
continue;
|
|
972
1114
|
}
|
|
973
|
-
//
|
|
1115
|
+
// Root types fields whose response type is an extension orphan could be valid through a federated graph
|
|
974
1116
|
// However, the field would have to be shareable to ever be valid TODO
|
|
975
1117
|
for (const fieldContainer of container.fields.values()) {
|
|
976
1118
|
const fieldName = fieldContainer.name;
|
|
@@ -985,7 +1127,11 @@ class NormalizationFactory {
|
|
|
985
1127
|
}
|
|
986
1128
|
}
|
|
987
1129
|
for (const referencedTypeName of this.referencedTypeNames) {
|
|
988
|
-
if (
|
|
1130
|
+
if (this.parents.has(referencedTypeName) || this.entityMap.has(referencedTypeName)) {
|
|
1131
|
+
continue;
|
|
1132
|
+
}
|
|
1133
|
+
const extension = this.extensions.get(referencedTypeName);
|
|
1134
|
+
if (!extension || extension.kind !== graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
|
|
989
1135
|
this.errors.push((0, errors_1.undefinedTypeError)(referencedTypeName));
|
|
990
1136
|
}
|
|
991
1137
|
}
|