@theguild/federation-composition 0.10.1 → 0.11.0-alpha-20240315131906-9fcd4e6
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/README.md +3 -16
- package/cjs/subgraph/helpers.js +1 -1
- package/cjs/subgraph/state.js +183 -4
- package/cjs/subgraph/validation/rules/elements/interface-object.js +19 -3
- package/cjs/subgraph/validation/rules/elements/key.js +3 -2
- package/cjs/subgraph/validation/rules/elements/policy.js +3 -2
- package/cjs/subgraph/validation/rules/elements/shareable.js +3 -2
- package/cjs/subgraph/validation/rules/elements/tag.js +2 -1
- package/cjs/subgraph/validation/rules/known-federation-directive-rule.js +4 -0
- package/cjs/subgraph/validation/rules/only-interface-implementation-rule.js +67 -0
- package/cjs/subgraph/validation/validate-subgraph.js +2 -0
- package/cjs/subgraph/validation/validation-context.js +18 -11
- package/cjs/supergraph/composition/interface-type.js +45 -9
- package/cjs/supergraph/composition/object-type.js +54 -1
- package/cjs/supergraph/composition/visitor.js +7 -0
- package/cjs/supergraph/validation/rules/interface-key-missing-implementation-type.js +9 -1
- package/cjs/supergraph/validation/rules/interface-object-usage-error.js +24 -0
- package/cjs/supergraph/validation/rules/invalid-field-sharing-rule.js +93 -2
- package/cjs/supergraph/validation/rules/only-inaccessible-children-rule.js +9 -0
- package/cjs/supergraph/validation/rules/satisfiablity/errors.js +3 -0
- package/cjs/supergraph/validation/rules/satisfiablity/finder.js +139 -120
- package/cjs/supergraph/validation/rules/satisfiablity/graph.js +111 -10
- package/cjs/supergraph/validation/rules/satisfiablity/move-validator.js +118 -156
- package/cjs/supergraph/validation/rules/satisfiablity/moves.js +6 -1
- package/cjs/supergraph/validation/rules/satisfiablity/{fields.js → selection.js} +64 -47
- package/cjs/supergraph/validation/rules/satisfiablity/supergraph.js +7 -7
- package/cjs/supergraph/validation/rules/satisfiablity/walker.js +5 -4
- package/cjs/supergraph/validation/rules/satisfiablity-rule.js +82 -47
- package/cjs/supergraph/validation/rules/types-of-the-same-kind-rule.js +21 -4
- package/cjs/supergraph/validation/validate-supergraph.js +2 -0
- package/cjs/utils/version.js +16 -0
- package/esm/subgraph/helpers.js +1 -1
- package/esm/subgraph/state.js +183 -4
- package/esm/subgraph/validation/rules/elements/interface-object.js +20 -4
- package/esm/subgraph/validation/rules/elements/key.js +3 -2
- package/esm/subgraph/validation/rules/elements/policy.js +3 -2
- package/esm/subgraph/validation/rules/elements/shareable.js +3 -2
- package/esm/subgraph/validation/rules/elements/tag.js +2 -1
- package/esm/subgraph/validation/rules/known-federation-directive-rule.js +4 -0
- package/esm/subgraph/validation/rules/only-interface-implementation-rule.js +63 -0
- package/esm/subgraph/validation/validate-subgraph.js +2 -0
- package/esm/subgraph/validation/validation-context.js +18 -11
- package/esm/supergraph/composition/interface-type.js +45 -9
- package/esm/supergraph/composition/object-type.js +54 -1
- package/esm/supergraph/composition/visitor.js +7 -0
- package/esm/supergraph/validation/rules/interface-key-missing-implementation-type.js +9 -1
- package/esm/supergraph/validation/rules/interface-object-usage-error.js +20 -0
- package/esm/supergraph/validation/rules/invalid-field-sharing-rule.js +93 -2
- package/esm/supergraph/validation/rules/only-inaccessible-children-rule.js +9 -0
- package/esm/supergraph/validation/rules/satisfiablity/errors.js +3 -0
- package/esm/supergraph/validation/rules/satisfiablity/finder.js +139 -120
- package/esm/supergraph/validation/rules/satisfiablity/graph.js +111 -10
- package/esm/supergraph/validation/rules/satisfiablity/move-validator.js +119 -157
- package/esm/supergraph/validation/rules/satisfiablity/moves.js +6 -1
- package/esm/supergraph/validation/rules/satisfiablity/{fields.js → selection.js} +61 -44
- package/esm/supergraph/validation/rules/satisfiablity/supergraph.js +7 -7
- package/esm/supergraph/validation/rules/satisfiablity/walker.js +5 -4
- package/esm/supergraph/validation/rules/satisfiablity-rule.js +83 -48
- package/esm/supergraph/validation/rules/types-of-the-same-kind-rule.js +21 -4
- package/esm/supergraph/validation/validate-supergraph.js +2 -0
- package/esm/utils/version.js +12 -0
- package/package.json +1 -1
- package/typings/specifications/federation.d.cts +1 -0
- package/typings/specifications/federation.d.ts +1 -0
- package/typings/subgraph/state.d.cts +8 -0
- package/typings/subgraph/state.d.ts +8 -0
- package/typings/subgraph/validation/rules/only-interface-implementation-rule.d.cts +4 -0
- package/typings/subgraph/validation/rules/only-interface-implementation-rule.d.ts +4 -0
- package/typings/subgraph/validation/validation-context.d.cts +4 -0
- package/typings/subgraph/validation/validation-context.d.ts +4 -0
- package/typings/supergraph/composition/interface-type.d.cts +9 -1
- package/typings/supergraph/composition/interface-type.d.ts +9 -1
- package/typings/supergraph/composition/object-type.d.cts +1 -0
- package/typings/supergraph/composition/object-type.d.ts +1 -0
- package/typings/supergraph/composition/visitor.d.cts +2 -1
- package/typings/supergraph/composition/visitor.d.ts +2 -1
- package/typings/supergraph/validation/rules/interface-object-usage-error.d.cts +4 -0
- package/typings/supergraph/validation/rules/interface-object-usage-error.d.ts +4 -0
- package/typings/supergraph/validation/rules/invalid-field-sharing-rule.d.cts +2 -1
- package/typings/supergraph/validation/rules/invalid-field-sharing-rule.d.ts +2 -1
- package/typings/supergraph/validation/rules/satisfiablity/errors.d.cts +2 -1
- package/typings/supergraph/validation/rules/satisfiablity/errors.d.ts +2 -1
- package/typings/supergraph/validation/rules/satisfiablity/finder.d.cts +5 -3
- package/typings/supergraph/validation/rules/satisfiablity/finder.d.ts +5 -3
- package/typings/supergraph/validation/rules/satisfiablity/graph.d.cts +9 -5
- package/typings/supergraph/validation/rules/satisfiablity/graph.d.ts +9 -5
- package/typings/supergraph/validation/rules/satisfiablity/move-validator.d.cts +5 -4
- package/typings/supergraph/validation/rules/satisfiablity/move-validator.d.ts +5 -4
- package/typings/supergraph/validation/rules/satisfiablity/moves.d.cts +9 -6
- package/typings/supergraph/validation/rules/satisfiablity/moves.d.ts +9 -6
- package/typings/supergraph/validation/rules/satisfiablity/selection.d.cts +36 -0
- package/typings/supergraph/validation/rules/satisfiablity/selection.d.ts +36 -0
- package/typings/supergraph/validation/rules/satisfiablity/supergraph.d.cts +2 -2
- package/typings/supergraph/validation/rules/satisfiablity/supergraph.d.ts +2 -2
- package/typings/supergraph/validation/rules/types-of-the-same-kind-rule.d.cts +4 -0
- package/typings/supergraph/validation/rules/types-of-the-same-kind-rule.d.ts +4 -0
- package/typings/utils/version.d.cts +3 -0
- package/typings/utils/version.d.ts +3 -0
- package/typings/supergraph/validation/rules/satisfiablity/fields.d.cts +0 -33
- package/typings/supergraph/validation/rules/satisfiablity/fields.d.ts +0 -33
package/README.md
CHANGED
|
@@ -179,31 +179,18 @@ Your feedback and bug reports are welcome and appreciated.
|
|
|
179
179
|
- ✅ `REQUIRES_DIRECTIVE_IN_FIELDS_ARG`
|
|
180
180
|
- ✅ `TYPE_DEFINITION_INVALID`
|
|
181
181
|
- ✅ `OVERRIDE_COLLISION_WITH_ANOTHER_DIRECTIVE`
|
|
182
|
+
- ✅ `INTERFACE_OBJECT_USAGE_ERROR`
|
|
183
|
+
- ✅ `REQUIRED_INACCESSIBLE`
|
|
184
|
+
- ✅ `SATISFIABILITY_ERROR`
|
|
182
185
|
|
|
183
186
|
### TODOs
|
|
184
187
|
|
|
185
|
-
- [ ] `INTERFACE_OBJECT_USAGE_ERROR`
|
|
186
188
|
- [ ] `INTERFACE_FIELD_NO_IMPLEM`
|
|
187
|
-
- [ ] `SATISFIABILITY_ERROR`
|
|
188
189
|
- [ ] `DISALLOWED_INACCESSIBLE`
|
|
189
|
-
- [ ] `DOWNSTREAM_SERVICE_ERROR`
|
|
190
190
|
- [ ] `EXTERNAL_ARGUMENT_DEFAULT_MISMATCH`
|
|
191
191
|
- [ ] `EXTERNAL_ARGUMENT_TYPE_MISMATCH`
|
|
192
192
|
- [ ] `EXTERNAL_COLLISION_WITH_ANOTHER_DIRECTIVE`
|
|
193
193
|
- [ ] `IMPLEMENTED_BY_INACCESSIBLE`
|
|
194
|
-
- [ ] `INVALID_FEDERATION_SUPERGRAPH`
|
|
195
194
|
- [ ] `LINK_IMPORT_NAME_MISMATCH`
|
|
196
|
-
- [ ] `REQUIRED_INACCESSIBLE`
|
|
197
|
-
- [ ] `SHAREABLE_HAS_MISMATCHED_RUNTIME_TYPES`
|
|
198
|
-
- [ ] `UNSUPPORTED_FEATURE`
|
|
199
195
|
- [ ] `UNSUPPORTED_LINKED_FEATURE`
|
|
200
196
|
- [ ] `TYPE_WITH_ONLY_UNUSED_EXTERNAL`
|
|
201
|
-
- [ ] `SATISFIABILITY_ERROR` - deeply nested key fields
|
|
202
|
-
- [ ] `SATISFIABILITY_ERROR` - fragments in keys
|
|
203
|
-
- [ ] `SATISFIABILITY_ERROR` - support interfaces... (kill me)
|
|
204
|
-
- [ ] `SATISFIABILITY_ERROR` - @require - check if fields defined by @require can be resolved by
|
|
205
|
-
current subgraph or by moving to other subgraphs.
|
|
206
|
-
- [ ] `SATISFIABILITY_ERROR` - @provides?
|
|
207
|
-
- [ ] more accurate key fields comparison (I did string ≠ string but we need to make it better)
|
|
208
|
-
- [ ] support `@interfaceObject`
|
|
209
|
-
- [ ] support `[String!]!` and `[String!]` comparison, not only `String!` vs `String`
|
package/cjs/subgraph/helpers.js
CHANGED
package/cjs/subgraph/state.js
CHANGED
|
@@ -42,14 +42,23 @@ function createSubgraphStateBuilder(graph, typeDefs, version, links) {
|
|
|
42
42
|
version,
|
|
43
43
|
};
|
|
44
44
|
const schemaDef = typeDefs.definitions.find(isSchemaDefinition);
|
|
45
|
+
const leafTypeNames = new Set(specifiedScalars);
|
|
46
|
+
for (const typeDef of typeDefs.definitions) {
|
|
47
|
+
if (typeDef.kind === graphql_1.Kind.SCALAR_TYPE_DEFINITION ||
|
|
48
|
+
typeDef.kind === graphql_1.Kind.SCALAR_TYPE_EXTENSION ||
|
|
49
|
+
typeDef.kind === graphql_1.Kind.ENUM_TYPE_DEFINITION ||
|
|
50
|
+
typeDef.kind === graphql_1.Kind.ENUM_TYPE_EXTENSION) {
|
|
51
|
+
leafTypeNames.add(typeDef.name.value);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
45
54
|
const expectedQueryTypeName = decideOnRootTypeName(schemaDef, graphql_1.OperationTypeNode.QUERY, 'Query');
|
|
46
55
|
const expectedMutationTypeName = decideOnRootTypeName(schemaDef, graphql_1.OperationTypeNode.MUTATION, 'Mutation');
|
|
47
56
|
const expectedSubscriptionTypeName = decideOnRootTypeName(schemaDef, graphql_1.OperationTypeNode.SUBSCRIPTION, 'Subscription');
|
|
48
57
|
const composedDirectives = new Set();
|
|
49
58
|
const directiveBuilder = directiveFactory(state);
|
|
50
59
|
const scalarTypeBuilder = scalarTypeFactory(state);
|
|
51
|
-
const objectTypeBuilder = objectTypeFactory(state, renameObjectType);
|
|
52
60
|
const interfaceTypeBuilder = interfaceTypeFactory(state);
|
|
61
|
+
const objectTypeBuilder = objectTypeFactory(state, renameObjectType, interfaceTypeBuilder, isInterfaceObject);
|
|
53
62
|
const inputObjectTypeBuilder = inputObjectTypeFactory(state);
|
|
54
63
|
const unionTypeBuilder = unionTypeFactory(state);
|
|
55
64
|
const enumTypeBuilder = enumTypeFactory(state);
|
|
@@ -65,7 +74,18 @@ function createSubgraphStateBuilder(graph, typeDefs, version, links) {
|
|
|
65
74
|
}
|
|
66
75
|
return typeName;
|
|
67
76
|
}
|
|
77
|
+
function isInterfaceObject(typeName) {
|
|
78
|
+
const found = state.types.get(typeName);
|
|
79
|
+
if (!found) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
if (found.kind !== TypeKind.INTERFACE) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
return found.isInterfaceObject;
|
|
86
|
+
}
|
|
68
87
|
return {
|
|
88
|
+
isInterfaceObject,
|
|
69
89
|
directive: directiveBuilder,
|
|
70
90
|
scalarType: scalarTypeBuilder,
|
|
71
91
|
objectType: objectTypeBuilder,
|
|
@@ -92,18 +112,26 @@ function createSubgraphStateBuilder(graph, typeDefs, version, links) {
|
|
|
92
112
|
const isObjectType = typeDef.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION ||
|
|
93
113
|
typeDef.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION;
|
|
94
114
|
const outputTypeName = resolveTypeName(node.type);
|
|
115
|
+
const isLeaf = leafTypeNames.has(outputTypeName);
|
|
95
116
|
const referencesEnumType = enumTypesByName.has(outputTypeName);
|
|
96
117
|
if (referencesEnumType) {
|
|
97
118
|
enumTypeBuilder.setReferencedByOutputType(outputTypeName, `${typeDef.name.value}.${node.name.value}`);
|
|
98
119
|
}
|
|
99
|
-
if (isInterfaceType) {
|
|
120
|
+
if (isInterfaceType || isInterfaceObject(typeDef.name.value)) {
|
|
100
121
|
interfaceTypeBuilder.field.setType(typeDef.name.value, node.name.value, (0, helpers_js_1.printOutputType)(node.type));
|
|
122
|
+
interfaceTypeBuilder.field.setUsed(typeDef.name.value, node.name.value);
|
|
123
|
+
if (isLeaf) {
|
|
124
|
+
interfaceTypeBuilder.field.setLeaf(typeDef.name.value, node.name.value);
|
|
125
|
+
}
|
|
101
126
|
return;
|
|
102
127
|
}
|
|
103
128
|
if (!isObjectType) {
|
|
104
129
|
throw new Error(`Expected to find an object type`);
|
|
105
130
|
}
|
|
106
131
|
objectTypeBuilder.field.setType(typeDef.name.value, node.name.value, (0, helpers_js_1.printOutputType)(node.type));
|
|
132
|
+
if (isLeaf) {
|
|
133
|
+
objectTypeBuilder.field.setLeaf(typeDef.name.value, node.name.value);
|
|
134
|
+
}
|
|
107
135
|
if (typeDef.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
|
|
108
136
|
objectTypeBuilder.field.setExtension(typeDef.name.value, node.name.value);
|
|
109
137
|
}
|
|
@@ -155,6 +183,16 @@ function createSubgraphStateBuilder(graph, typeDefs, version, links) {
|
|
|
155
183
|
}
|
|
156
184
|
},
|
|
157
185
|
ObjectTypeDefinition(node) {
|
|
186
|
+
if (hasInterfaceObjectDirective(node)) {
|
|
187
|
+
interfaceTypeBuilder.setDefinition(node.name.value);
|
|
188
|
+
interfaceTypeBuilder.setInterfaceObject(node.name.value);
|
|
189
|
+
if (node.interfaces) {
|
|
190
|
+
for (const interfaceNode of node.interfaces) {
|
|
191
|
+
interfaceTypeBuilder.setInterface(node.name.value, interfaceNode.name.value);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
158
196
|
objectTypeBuilder.setDefinition(node.name.value);
|
|
159
197
|
if (node.name.value === expectedQueryTypeName) {
|
|
160
198
|
state.schema.queryType = renameObjectType(node.name.value);
|
|
@@ -172,6 +210,8 @@ function createSubgraphStateBuilder(graph, typeDefs, version, links) {
|
|
|
172
210
|
}
|
|
173
211
|
},
|
|
174
212
|
ObjectTypeExtension(node) {
|
|
213
|
+
if (hasInterfaceObjectDirective(node)) {
|
|
214
|
+
}
|
|
175
215
|
if (node.name.value === expectedQueryTypeName) {
|
|
176
216
|
state.schema.queryType = renameObjectType(node.name.value);
|
|
177
217
|
}
|
|
@@ -539,12 +579,18 @@ function scalarTypeFactory(state) {
|
|
|
539
579
|
},
|
|
540
580
|
};
|
|
541
581
|
}
|
|
542
|
-
function objectTypeFactory(state, renameObject) {
|
|
582
|
+
function objectTypeFactory(state, renameObject, interfaceTypeBuilder, isInterfaceObject) {
|
|
543
583
|
return {
|
|
544
584
|
setDefinition(typeName) {
|
|
585
|
+
if (isInterfaceObject(typeName)) {
|
|
586
|
+
return interfaceTypeBuilder.setDefinition(typeName);
|
|
587
|
+
}
|
|
545
588
|
getOrCreateObjectType(state, renameObject, typeName).isDefinition = true;
|
|
546
589
|
},
|
|
547
590
|
setExtension(typeName, extensionType) {
|
|
591
|
+
if (isInterfaceObject(typeName)) {
|
|
592
|
+
return interfaceTypeBuilder.setExtension(typeName);
|
|
593
|
+
}
|
|
548
594
|
const objectType = getOrCreateObjectType(state, renameObject, typeName);
|
|
549
595
|
objectType.extension = true;
|
|
550
596
|
if (objectType.extensionType !== '@extends') {
|
|
@@ -552,9 +598,15 @@ function objectTypeFactory(state, renameObject) {
|
|
|
552
598
|
}
|
|
553
599
|
},
|
|
554
600
|
setDescription(typeName, description) {
|
|
601
|
+
if (isInterfaceObject(typeName)) {
|
|
602
|
+
return interfaceTypeBuilder.setDescription(typeName, description);
|
|
603
|
+
}
|
|
555
604
|
getOrCreateObjectType(state, renameObject, typeName).description = description;
|
|
556
605
|
},
|
|
557
606
|
setExternal(typeName) {
|
|
607
|
+
if (isInterfaceObject(typeName)) {
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
558
610
|
const objectType = getOrCreateObjectType(state, renameObject, typeName);
|
|
559
611
|
objectType.external = true;
|
|
560
612
|
for (const field of objectType.fields.values()) {
|
|
@@ -562,10 +614,16 @@ function objectTypeFactory(state, renameObject) {
|
|
|
562
614
|
}
|
|
563
615
|
},
|
|
564
616
|
setInterface(typeName, interfaceName) {
|
|
617
|
+
if (isInterfaceObject(typeName)) {
|
|
618
|
+
return interfaceTypeBuilder.setInterface(typeName, interfaceName);
|
|
619
|
+
}
|
|
565
620
|
getOrCreateObjectType(state, renameObject, typeName).interfaces.add(interfaceName);
|
|
566
621
|
getOrCreateInterfaceType(state, interfaceName).implementedBy.add(typeName);
|
|
567
622
|
},
|
|
568
623
|
setKey(typeName, fields, fieldsUsedInKey, resolvable) {
|
|
624
|
+
if (isInterfaceObject(typeName)) {
|
|
625
|
+
return interfaceTypeBuilder.setKey(typeName, fields, fieldsUsedInKey, resolvable);
|
|
626
|
+
}
|
|
569
627
|
const objectType = getOrCreateObjectType(state, renameObject, typeName);
|
|
570
628
|
objectType.keys.push({ fields, resolvable });
|
|
571
629
|
for (const field of fieldsUsedInKey) {
|
|
@@ -573,110 +631,212 @@ function objectTypeFactory(state, renameObject) {
|
|
|
573
631
|
}
|
|
574
632
|
},
|
|
575
633
|
setInaccessible(typeName) {
|
|
634
|
+
if (isInterfaceObject(typeName)) {
|
|
635
|
+
return interfaceTypeBuilder.setInaccessible(typeName);
|
|
636
|
+
}
|
|
576
637
|
const objectType = getOrCreateObjectType(state, renameObject, typeName);
|
|
577
638
|
objectType.inaccessible = true;
|
|
578
639
|
},
|
|
579
640
|
setAuthenticated(typeName) {
|
|
641
|
+
if (isInterfaceObject(typeName)) {
|
|
642
|
+
return interfaceTypeBuilder.setAuthenticated(typeName);
|
|
643
|
+
}
|
|
580
644
|
const objectType = getOrCreateObjectType(state, renameObject, typeName);
|
|
581
645
|
objectType.authenticated = true;
|
|
582
646
|
},
|
|
583
647
|
setPolicies(typeName, policies) {
|
|
648
|
+
if (isInterfaceObject(typeName)) {
|
|
649
|
+
return interfaceTypeBuilder.setPolicies(typeName, policies);
|
|
650
|
+
}
|
|
584
651
|
getOrCreateObjectType(state, renameObject, typeName).policies.push(...policies);
|
|
585
652
|
},
|
|
586
653
|
setScopes(typeName, scopes) {
|
|
654
|
+
if (isInterfaceObject(typeName)) {
|
|
655
|
+
return interfaceTypeBuilder.setScopes(typeName, scopes);
|
|
656
|
+
}
|
|
587
657
|
getOrCreateObjectType(state, renameObject, typeName).scopes.push(...scopes);
|
|
588
658
|
},
|
|
589
659
|
setShareable(typeName) {
|
|
660
|
+
if (isInterfaceObject(typeName)) {
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
590
663
|
getOrCreateObjectType(state, renameObject, typeName).shareable = true;
|
|
591
664
|
},
|
|
592
665
|
setTag(typeName, tag) {
|
|
666
|
+
if (isInterfaceObject(typeName)) {
|
|
667
|
+
return interfaceTypeBuilder.setTag(typeName, tag);
|
|
668
|
+
}
|
|
593
669
|
getOrCreateObjectType(state, renameObject, typeName).tags.add(tag);
|
|
594
670
|
},
|
|
595
671
|
setDirective(typeName, directive) {
|
|
672
|
+
if (isInterfaceObject(typeName)) {
|
|
673
|
+
return interfaceTypeBuilder.setDirective(typeName, directive);
|
|
674
|
+
}
|
|
596
675
|
getOrCreateObjectType(state, renameObject, typeName).ast.directives.push(directive);
|
|
597
676
|
},
|
|
598
677
|
field: {
|
|
599
678
|
setType(typeName, fieldName, fieldType) {
|
|
679
|
+
if (isInterfaceObject(typeName)) {
|
|
680
|
+
return interfaceTypeBuilder.field.setType(typeName, fieldName, fieldType);
|
|
681
|
+
}
|
|
600
682
|
getOrCreateObjectField(state, renameObject, typeName, fieldName).type = fieldType;
|
|
601
683
|
},
|
|
684
|
+
setLeaf(typeName, fieldName) {
|
|
685
|
+
if (isInterfaceObject(typeName)) {
|
|
686
|
+
return interfaceTypeBuilder.field.setLeaf(typeName, fieldName);
|
|
687
|
+
}
|
|
688
|
+
getOrCreateObjectField(state, renameObject, typeName, fieldName).isLeaf = true;
|
|
689
|
+
},
|
|
602
690
|
setExtension(typeName, fieldName) {
|
|
691
|
+
if (isInterfaceObject(typeName)) {
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
603
694
|
getOrCreateObjectField(state, renameObject, typeName, fieldName).extension = true;
|
|
604
695
|
},
|
|
605
696
|
setDirective(typeName, fieldName, directive) {
|
|
697
|
+
if (isInterfaceObject(typeName)) {
|
|
698
|
+
return interfaceTypeBuilder.field.setDirective(typeName, fieldName, directive);
|
|
699
|
+
}
|
|
606
700
|
getOrCreateObjectField(state, renameObject, typeName, fieldName).ast.directives.push(directive);
|
|
607
701
|
},
|
|
608
702
|
setDescription(typeName, fieldName, description) {
|
|
703
|
+
if (isInterfaceObject(typeName)) {
|
|
704
|
+
return interfaceTypeBuilder.field.setDescription(typeName, fieldName, description);
|
|
705
|
+
}
|
|
609
706
|
getOrCreateObjectField(state, renameObject, typeName, fieldName).description = description;
|
|
610
707
|
},
|
|
611
708
|
setDeprecated(typeName, fieldName, reason) {
|
|
709
|
+
if (isInterfaceObject(typeName)) {
|
|
710
|
+
return interfaceTypeBuilder.field.setDeprecated(typeName, fieldName, reason);
|
|
711
|
+
}
|
|
612
712
|
getOrCreateObjectField(state, renameObject, typeName, fieldName).deprecated = {
|
|
613
713
|
reason,
|
|
614
714
|
deprecated: true,
|
|
615
715
|
};
|
|
616
716
|
},
|
|
617
717
|
setAuthenticated(typeName, fieldName) {
|
|
718
|
+
if (isInterfaceObject(typeName)) {
|
|
719
|
+
return interfaceTypeBuilder.field.setAuthenticated(typeName, fieldName);
|
|
720
|
+
}
|
|
618
721
|
getOrCreateObjectField(state, renameObject, typeName, fieldName).authenticated = true;
|
|
619
722
|
},
|
|
620
723
|
setPolicies(typeName, fieldName, policies) {
|
|
724
|
+
if (isInterfaceObject(typeName)) {
|
|
725
|
+
return interfaceTypeBuilder.field.setPolicies(typeName, fieldName, policies);
|
|
726
|
+
}
|
|
621
727
|
getOrCreateObjectField(state, renameObject, typeName, fieldName).policies.push(...policies);
|
|
622
728
|
},
|
|
623
729
|
setScopes(typeName, fieldName, scopes) {
|
|
730
|
+
if (isInterfaceObject(typeName)) {
|
|
731
|
+
return interfaceTypeBuilder.field.setScopes(typeName, fieldName, scopes);
|
|
732
|
+
}
|
|
624
733
|
getOrCreateObjectField(state, renameObject, typeName, fieldName).scopes.push(...scopes);
|
|
625
734
|
},
|
|
626
735
|
setExternal(typeName, fieldName) {
|
|
736
|
+
if (isInterfaceObject(typeName)) {
|
|
737
|
+
return interfaceTypeBuilder.field.setExternal(typeName, fieldName);
|
|
738
|
+
}
|
|
627
739
|
getOrCreateObjectField(state, renameObject, typeName, fieldName).external = true;
|
|
628
740
|
},
|
|
629
741
|
setInaccessible(typeName, fieldName) {
|
|
742
|
+
if (isInterfaceObject(typeName)) {
|
|
743
|
+
return interfaceTypeBuilder.field.setInaccessible(typeName, fieldName);
|
|
744
|
+
}
|
|
630
745
|
getOrCreateObjectField(state, renameObject, typeName, fieldName).inaccessible = true;
|
|
631
746
|
},
|
|
632
747
|
setOverride(typeName, fieldName, override) {
|
|
748
|
+
if (isInterfaceObject(typeName)) {
|
|
749
|
+
return interfaceTypeBuilder.field.setOverride(typeName, fieldName, override);
|
|
750
|
+
}
|
|
633
751
|
getOrCreateObjectField(state, renameObject, typeName, fieldName).override = override;
|
|
634
752
|
},
|
|
635
753
|
setProvides(typeName, fieldName, provides) {
|
|
754
|
+
if (isInterfaceObject(typeName)) {
|
|
755
|
+
return;
|
|
756
|
+
}
|
|
636
757
|
getOrCreateObjectField(state, renameObject, typeName, fieldName).provides = provides;
|
|
637
758
|
},
|
|
638
759
|
setRequires(typeName, fieldName, requires) {
|
|
760
|
+
if (isInterfaceObject(typeName)) {
|
|
761
|
+
return interfaceTypeBuilder.field.setRequires(typeName, fieldName, requires);
|
|
762
|
+
}
|
|
639
763
|
getOrCreateObjectField(state, renameObject, typeName, fieldName).requires = requires;
|
|
640
764
|
},
|
|
641
765
|
markAsProvided(typeName, fieldName) {
|
|
766
|
+
if (isInterfaceObject(typeName)) {
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
642
769
|
getOrCreateObjectField(state, renameObject, typeName, fieldName).provided = true;
|
|
643
770
|
},
|
|
644
771
|
markedAsRequired(typeName, fieldName) {
|
|
772
|
+
if (isInterfaceObject(typeName)) {
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
645
775
|
getOrCreateObjectField(state, renameObject, typeName, fieldName).required = true;
|
|
646
776
|
},
|
|
647
777
|
setShareable(typeName, fieldName) {
|
|
778
|
+
if (isInterfaceObject(typeName)) {
|
|
779
|
+
return interfaceTypeBuilder.field.setShareable(typeName, fieldName);
|
|
780
|
+
}
|
|
648
781
|
getOrCreateObjectField(state, renameObject, typeName, fieldName).shareable = true;
|
|
649
782
|
},
|
|
650
783
|
setTag(typeName, fieldName, tag) {
|
|
784
|
+
if (isInterfaceObject(typeName)) {
|
|
785
|
+
return interfaceTypeBuilder.field.setTag(typeName, fieldName, tag);
|
|
786
|
+
}
|
|
651
787
|
getOrCreateObjectField(state, renameObject, typeName, fieldName).tags.add(tag);
|
|
652
788
|
},
|
|
653
789
|
setUsed(typeName, fieldName) {
|
|
790
|
+
if (isInterfaceObject(typeName)) {
|
|
791
|
+
return interfaceTypeBuilder.field.setUsed(typeName, fieldName);
|
|
792
|
+
}
|
|
654
793
|
getOrCreateObjectField(state, renameObject, typeName, fieldName).used = true;
|
|
655
794
|
},
|
|
656
795
|
arg: {
|
|
657
796
|
setType(typeName, fieldName, argName, argType) {
|
|
797
|
+
if (isInterfaceObject(typeName)) {
|
|
798
|
+
return interfaceTypeBuilder.field.arg.setType(typeName, fieldName, argName, argType);
|
|
799
|
+
}
|
|
658
800
|
getOrCreateObjectFieldArgument(state, renameObject, typeName, fieldName, argName).type =
|
|
659
801
|
argType;
|
|
660
802
|
},
|
|
661
803
|
setDescription(typeName, fieldName, argName, description) {
|
|
804
|
+
if (isInterfaceObject(typeName)) {
|
|
805
|
+
return interfaceTypeBuilder.field.arg.setDescription(typeName, fieldName, argName, description);
|
|
806
|
+
}
|
|
662
807
|
getOrCreateObjectFieldArgument(state, renameObject, typeName, fieldName, argName).description = description;
|
|
663
808
|
},
|
|
664
809
|
setDeprecated(typeName, fieldName, argName, reason) {
|
|
810
|
+
if (isInterfaceObject(typeName)) {
|
|
811
|
+
return interfaceTypeBuilder.field.arg.setDeprecated(typeName, fieldName, argName, reason);
|
|
812
|
+
}
|
|
665
813
|
getOrCreateObjectFieldArgument(state, renameObject, typeName, fieldName, argName).deprecated = {
|
|
666
814
|
reason,
|
|
667
815
|
deprecated: true,
|
|
668
816
|
};
|
|
669
817
|
},
|
|
670
818
|
setDirective(typeName, fieldName, argName, directive) {
|
|
819
|
+
if (isInterfaceObject(typeName)) {
|
|
820
|
+
return interfaceTypeBuilder.field.arg.setDirective(typeName, fieldName, argName, directive);
|
|
821
|
+
}
|
|
671
822
|
getOrCreateObjectFieldArgument(state, renameObject, typeName, fieldName, argName).ast.directives.push(directive);
|
|
672
823
|
},
|
|
673
824
|
setDefaultValue(typeName, fieldName, argName, defaultValue) {
|
|
825
|
+
if (isInterfaceObject(typeName)) {
|
|
826
|
+
return interfaceTypeBuilder.field.arg.setDefaultValue(typeName, fieldName, argName, defaultValue);
|
|
827
|
+
}
|
|
674
828
|
getOrCreateObjectFieldArgument(state, renameObject, typeName, fieldName, argName).defaultValue = defaultValue;
|
|
675
829
|
},
|
|
676
830
|
setInaccessible(typeName, fieldName, argName) {
|
|
831
|
+
if (isInterfaceObject(typeName)) {
|
|
832
|
+
return interfaceTypeBuilder.field.arg.setInaccessible(typeName, fieldName, argName);
|
|
833
|
+
}
|
|
677
834
|
getOrCreateObjectFieldArgument(state, renameObject, typeName, fieldName, argName).inaccessible = true;
|
|
678
835
|
},
|
|
679
836
|
setTag(typeName, fieldName, argName, tag) {
|
|
837
|
+
if (isInterfaceObject(typeName)) {
|
|
838
|
+
return interfaceTypeBuilder.field.arg.setTag(typeName, fieldName, argName, tag);
|
|
839
|
+
}
|
|
680
840
|
getOrCreateObjectFieldArgument(state, renameObject, typeName, fieldName, argName).tags.add(tag);
|
|
681
841
|
},
|
|
682
842
|
},
|
|
@@ -694,8 +854,15 @@ function interfaceTypeFactory(state) {
|
|
|
694
854
|
setInterface(typeName, interfaceName) {
|
|
695
855
|
getOrCreateInterfaceType(state, typeName).interfaces.add(interfaceName);
|
|
696
856
|
},
|
|
857
|
+
setInterfaceObject(typeName) {
|
|
858
|
+
getOrCreateInterfaceType(state, typeName).isInterfaceObject = true;
|
|
859
|
+
},
|
|
697
860
|
setKey(typeName, fields, fieldsUsedInKey, resolvable) {
|
|
698
|
-
getOrCreateInterfaceType(state, typeName)
|
|
861
|
+
const interfaceType = getOrCreateInterfaceType(state, typeName);
|
|
862
|
+
interfaceType.keys.push({ fields, resolvable });
|
|
863
|
+
for (const field of fieldsUsedInKey) {
|
|
864
|
+
interfaceType.fieldsUsedAsKeys.add(field);
|
|
865
|
+
}
|
|
699
866
|
},
|
|
700
867
|
setInaccessible(typeName) {
|
|
701
868
|
const objectType = getOrCreateInterfaceType(state, typeName);
|
|
@@ -724,6 +891,9 @@ function interfaceTypeFactory(state) {
|
|
|
724
891
|
setType(typeName, fieldName, fieldType) {
|
|
725
892
|
getOrCreateInterfaceField(state, typeName, fieldName).type = fieldType;
|
|
726
893
|
},
|
|
894
|
+
setLeaf(typeName, fieldName) {
|
|
895
|
+
getOrCreateInterfaceField(state, typeName, fieldName).isLeaf = true;
|
|
896
|
+
},
|
|
727
897
|
setExternal(typeName, fieldName) {
|
|
728
898
|
getOrCreateInterfaceField(state, typeName, fieldName).external = true;
|
|
729
899
|
},
|
|
@@ -1020,6 +1190,7 @@ function getOrCreateInterfaceType(state, typeName) {
|
|
|
1020
1190
|
kind: TypeKind.INTERFACE,
|
|
1021
1191
|
name: typeName,
|
|
1022
1192
|
fields: new Map(),
|
|
1193
|
+
fieldsUsedAsKeys: new Set(),
|
|
1023
1194
|
extension: false,
|
|
1024
1195
|
keys: [],
|
|
1025
1196
|
inaccessible: false,
|
|
@@ -1030,6 +1201,7 @@ function getOrCreateInterfaceType(state, typeName) {
|
|
|
1030
1201
|
interfaces: new Set(),
|
|
1031
1202
|
implementedBy: new Set(),
|
|
1032
1203
|
isDefinition: false,
|
|
1204
|
+
isInterfaceObject: false,
|
|
1033
1205
|
ast: {
|
|
1034
1206
|
directives: [],
|
|
1035
1207
|
},
|
|
@@ -1111,6 +1283,8 @@ function getOrCreateObjectField(state, renameObject, typeName, fieldName) {
|
|
|
1111
1283
|
const field = {
|
|
1112
1284
|
name: fieldName,
|
|
1113
1285
|
type: MISSING,
|
|
1286
|
+
usedAsKey: false,
|
|
1287
|
+
isLeaf: false,
|
|
1114
1288
|
external: false,
|
|
1115
1289
|
inaccessible: false,
|
|
1116
1290
|
authenticated: false,
|
|
@@ -1141,6 +1315,8 @@ function getOrCreateInterfaceField(state, typeName, fieldName) {
|
|
|
1141
1315
|
}
|
|
1142
1316
|
const field = {
|
|
1143
1317
|
name: fieldName,
|
|
1318
|
+
usedAsKey: false,
|
|
1319
|
+
isLeaf: false,
|
|
1144
1320
|
type: MISSING,
|
|
1145
1321
|
external: false,
|
|
1146
1322
|
inaccessible: false,
|
|
@@ -1251,3 +1427,6 @@ function decideOnRootTypeName(schemaDef, kind, defaultName) {
|
|
|
1251
1427
|
return (schemaDef?.operationTypes?.find(operationType => operationType.operation === kind)?.type.name
|
|
1252
1428
|
.value ?? defaultName);
|
|
1253
1429
|
}
|
|
1430
|
+
function hasInterfaceObjectDirective(node) {
|
|
1431
|
+
return node.directives?.some(d => d.name.value === 'interfaceObject');
|
|
1432
|
+
}
|
|
@@ -12,9 +12,25 @@ function InterfaceObjectRules(context) {
|
|
|
12
12
|
if (!context.isAvailableFederationDirective('interfaceObject', node)) {
|
|
13
13
|
return;
|
|
14
14
|
}
|
|
15
|
-
context.
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
if (context.satisfiesVersionRange('< v2.3')) {
|
|
16
|
+
context.reportError(new graphql_1.GraphQLError(`@interfaceObject is not yet supported. See https://github.com/the-guild-org/federation/issues/7`, {
|
|
17
|
+
extensions: { code: 'UNSUPPORTED_FEATURE' },
|
|
18
|
+
}));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const typeDef = context.typeNodeInfo.getTypeDef();
|
|
22
|
+
if (!typeDef) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (typeDef.kind !== graphql_1.Kind.OBJECT_TYPE_DEFINITION &&
|
|
26
|
+
typeDef.kind !== graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (!typeDef.directives?.some(d => d.name.value === 'key')) {
|
|
30
|
+
context.reportError(new graphql_1.GraphQLError(`The @interfaceObject directive can only be applied to entity types but type "${typeDef.name.value}" has no @key in this subgraph.`, {
|
|
31
|
+
extensions: { code: 'INTERFACE_OBJECT_USAGE_ERROR' },
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
18
34
|
},
|
|
19
35
|
};
|
|
20
36
|
}
|
|
@@ -18,9 +18,10 @@ function KeyRules(context) {
|
|
|
18
18
|
return;
|
|
19
19
|
}
|
|
20
20
|
const typeCoordinate = typeDef.name.value;
|
|
21
|
-
const usedOnInterface = typeDef.kind === graphql_1.Kind.INTERFACE_TYPE_DEFINITION ||
|
|
22
|
-
typeDef.kind === graphql_1.Kind.INTERFACE_TYPE_EXTENSION;
|
|
23
21
|
const usedOnObject = typeDef.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION || typeDef.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION;
|
|
22
|
+
const usedOnInterface = typeDef.kind === graphql_1.Kind.INTERFACE_TYPE_DEFINITION ||
|
|
23
|
+
typeDef.kind === graphql_1.Kind.INTERFACE_TYPE_EXTENSION ||
|
|
24
|
+
(usedOnObject && context.stateBuilder.isInterfaceObject(typeDef.name.value));
|
|
24
25
|
if (!usedOnObject && !usedOnInterface) {
|
|
25
26
|
return;
|
|
26
27
|
}
|
|
@@ -55,8 +55,9 @@ function PolicyRule(context) {
|
|
|
55
55
|
if (!typeDef) {
|
|
56
56
|
throw new Error('Could not find the parent type of the field annotated with @policy');
|
|
57
57
|
}
|
|
58
|
-
if (typeDef.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION ||
|
|
59
|
-
typeDef.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION)
|
|
58
|
+
if ((typeDef.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION ||
|
|
59
|
+
typeDef.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION) &&
|
|
60
|
+
!context.stateBuilder.isInterfaceObject(typeDef.name.value)) {
|
|
60
61
|
context.stateBuilder.objectType.field.setPolicies(typeDef.name.value, parent.name.value, policies);
|
|
61
62
|
}
|
|
62
63
|
break;
|
|
@@ -17,8 +17,9 @@ function ShareableRules(context) {
|
|
|
17
17
|
if (!typeDef) {
|
|
18
18
|
return;
|
|
19
19
|
}
|
|
20
|
-
if (typeDef.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION ||
|
|
21
|
-
typeDef.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION)
|
|
20
|
+
if ((typeDef.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION ||
|
|
21
|
+
typeDef.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION) &&
|
|
22
|
+
!context.stateBuilder.isInterfaceObject(typeDef.name.value)) {
|
|
22
23
|
if (fieldDef) {
|
|
23
24
|
context.stateBuilder.objectType.field.setShareable(typeDef.name.value, fieldDef.name.value);
|
|
24
25
|
}
|
|
@@ -45,7 +45,8 @@ function TagRules(context) {
|
|
|
45
45
|
throw new Error('Could not find the parent type of the field annotated with @tag');
|
|
46
46
|
}
|
|
47
47
|
if (typeDef.kind === graphql_1.Kind.INTERFACE_TYPE_DEFINITION ||
|
|
48
|
-
typeDef.kind === graphql_1.Kind.INTERFACE_TYPE_EXTENSION
|
|
48
|
+
typeDef.kind === graphql_1.Kind.INTERFACE_TYPE_EXTENSION ||
|
|
49
|
+
context.stateBuilder.isInterfaceObject(typeDef.name.value)) {
|
|
49
50
|
context.stateBuilder.interfaceType.field.setTag(typeDef.name.value, parent.name.value, tag);
|
|
50
51
|
}
|
|
51
52
|
else {
|
|
@@ -22,6 +22,10 @@ function KnownFederationDirectivesRule(context) {
|
|
|
22
22
|
return {
|
|
23
23
|
Directive(node) {
|
|
24
24
|
const name = node.name.value;
|
|
25
|
+
if (!availableDirectivesSet.has(name) && name === 'interfaceObject') {
|
|
26
|
+
context.reportError(new graphql_1.GraphQLError(`Unknown directive "@interfaceObject". If you meant the "@interfaceObject" federation 2 directive, note that this schema is a federation 1 schema. To be a federation 2 schema, it needs to @link to the federation specification v2.`, { nodes: node, extensions: { code: 'INVALID_GRAPHQL' } }));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
25
29
|
if (!availableDirectivesSet.has(name) &&
|
|
26
30
|
knownDirectivesSet.has(name) &&
|
|
27
31
|
!name.startsWith('federation__')) {
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OnlyInterfaceImplementationRule = void 0;
|
|
4
|
+
const graphql_1 = require("graphql");
|
|
5
|
+
function OnlyInterfaceImplementationRule(context) {
|
|
6
|
+
const { definitions } = context.getDocument();
|
|
7
|
+
let filled = false;
|
|
8
|
+
const typeNameToKind = new Map();
|
|
9
|
+
function fillTypeNameToKindMap() {
|
|
10
|
+
for (const node of definitions) {
|
|
11
|
+
switch (node.kind) {
|
|
12
|
+
case graphql_1.Kind.OBJECT_TYPE_DEFINITION:
|
|
13
|
+
case graphql_1.Kind.OBJECT_TYPE_EXTENSION:
|
|
14
|
+
typeNameToKind.set(node.name.value, 'ObjectType');
|
|
15
|
+
break;
|
|
16
|
+
case graphql_1.Kind.INTERFACE_TYPE_DEFINITION:
|
|
17
|
+
case graphql_1.Kind.INTERFACE_TYPE_EXTENSION:
|
|
18
|
+
typeNameToKind.set(node.name.value, 'InterfaceType');
|
|
19
|
+
break;
|
|
20
|
+
case graphql_1.Kind.UNION_TYPE_DEFINITION:
|
|
21
|
+
case graphql_1.Kind.UNION_TYPE_EXTENSION:
|
|
22
|
+
typeNameToKind.set(node.name.value, 'UnionType');
|
|
23
|
+
break;
|
|
24
|
+
case graphql_1.Kind.ENUM_TYPE_DEFINITION:
|
|
25
|
+
case graphql_1.Kind.ENUM_TYPE_EXTENSION:
|
|
26
|
+
typeNameToKind.set(node.name.value, 'EnumType');
|
|
27
|
+
break;
|
|
28
|
+
case graphql_1.Kind.SCALAR_TYPE_DEFINITION:
|
|
29
|
+
case graphql_1.Kind.SCALAR_TYPE_EXTENSION:
|
|
30
|
+
typeNameToKind.set(node.name.value, 'ScalarType');
|
|
31
|
+
break;
|
|
32
|
+
case graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION:
|
|
33
|
+
case graphql_1.Kind.INPUT_OBJECT_TYPE_EXTENSION:
|
|
34
|
+
typeNameToKind.set(node.name.value, 'InputObjectType');
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
filled = true;
|
|
39
|
+
}
|
|
40
|
+
function findKindByName(typeName) {
|
|
41
|
+
if (!filled) {
|
|
42
|
+
fillTypeNameToKindMap();
|
|
43
|
+
}
|
|
44
|
+
return typeNameToKind.get(typeName);
|
|
45
|
+
}
|
|
46
|
+
function check(node) {
|
|
47
|
+
if (!node.interfaces) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
for (const interfaceNode of node.interfaces) {
|
|
51
|
+
const interfaceName = interfaceNode.name.value;
|
|
52
|
+
const kind = findKindByName(interfaceName);
|
|
53
|
+
if (kind && kind !== 'InterfaceType') {
|
|
54
|
+
context.reportError(new graphql_1.GraphQLError(`Cannot implement non-interface type ${interfaceName} (of type ObjectType)`, {
|
|
55
|
+
extensions: {
|
|
56
|
+
code: 'INVALID_GRAPHQL',
|
|
57
|
+
},
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
ObjectTypeDefinition: check,
|
|
64
|
+
ObjectTypeExtension: check,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
exports.OnlyInterfaceImplementationRule = OnlyInterfaceImplementationRule;
|
|
@@ -26,6 +26,7 @@ const known_federation_directive_rule_js_1 = require("./rules/known-federation-d
|
|
|
26
26
|
const known_root_type_rule_js_1 = require("./rules/known-root-type-rule.js");
|
|
27
27
|
const known_type_names_rule_js_1 = require("./rules/known-type-names-rule.js");
|
|
28
28
|
const lone_schema_definition_rule_js_1 = require("./rules/lone-schema-definition-rule.js");
|
|
29
|
+
const only_interface_implementation_rule_js_1 = require("./rules/only-interface-implementation-rule.js");
|
|
29
30
|
const provided_arguments_on_directives_rule_js_1 = require("./rules/provided-arguments-on-directives-rule.js");
|
|
30
31
|
const provided_required_arguments_on_directives_rule_js_1 = require("./rules/provided-required-arguments-on-directives-rule.js");
|
|
31
32
|
const query_root_type_inaccessible_rule_js_1 = require("./rules/query-root-type-inaccessible-rule.js");
|
|
@@ -116,6 +117,7 @@ function validateSubgraph(subgraph, stateBuilder, federation, __internal) {
|
|
|
116
117
|
compose_directive_js_1.ComposeDirectiveRules,
|
|
117
118
|
];
|
|
118
119
|
const graphqlRules = [
|
|
120
|
+
only_interface_implementation_rule_js_1.OnlyInterfaceImplementationRule,
|
|
119
121
|
lone_schema_definition_rule_js_1.LoneSchemaDefinitionRule,
|
|
120
122
|
unique_operation_types_rule_js_1.UniqueOperationTypesRule,
|
|
121
123
|
unique_type_names_rule_js_1.UniqueTypeNamesRule,
|