@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
|
@@ -5,6 +5,7 @@ const graphql_1 = require("graphql");
|
|
|
5
5
|
const federation_js_1 = require("../../specifications/federation.js");
|
|
6
6
|
const link_js_1 = require("../../specifications/link.js");
|
|
7
7
|
const state_js_1 = require("../../utils/state.js");
|
|
8
|
+
const version_js_1 = require("../../utils/version.js");
|
|
8
9
|
const state_js_2 = require("../state.js");
|
|
9
10
|
const linkSpec = (0, graphql_1.parse)(link_js_1.sdl);
|
|
10
11
|
const linkSpecDirectives = linkSpec.definitions.filter((def) => def.kind === graphql_1.Kind.DIRECTIVE_DEFINITION);
|
|
@@ -180,16 +181,7 @@ function createSubgraphValidationContext(subgraph, federation, typeNodeInfo, sta
|
|
|
180
181
|
return false;
|
|
181
182
|
},
|
|
182
183
|
satisfiesVersionRange(range) {
|
|
183
|
-
|
|
184
|
-
const versionInRange = parseFloat(ver.replace('v', ''));
|
|
185
|
-
const detectedVersion = parseFloat(version.replace('v', ''));
|
|
186
|
-
if (sign === '<') {
|
|
187
|
-
return detectedVersion < versionInRange;
|
|
188
|
-
}
|
|
189
|
-
if (sign === '>') {
|
|
190
|
-
return detectedVersion > versionInRange;
|
|
191
|
-
}
|
|
192
|
-
return detectedVersion >= versionInRange;
|
|
184
|
+
return (0, version_js_1.satisfiesVersionRange)(version, range);
|
|
193
185
|
},
|
|
194
186
|
getKnownFederationDirectives() {
|
|
195
187
|
return knownSpec.directives;
|
|
@@ -268,8 +260,12 @@ function createSubgraphValidationContext(subgraph, federation, typeNodeInfo, sta
|
|
|
268
260
|
return unused.filter(coordinate => {
|
|
269
261
|
const [typeName, fieldName] = coordinate.split('.');
|
|
270
262
|
const typeDef = stateBuilder.state.types.get(typeName);
|
|
271
|
-
if (typeDef
|
|
263
|
+
if (!typeDef) {
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
if (typeDef.kind === state_js_2.TypeKind.OBJECT && !stateBuilder.isInterfaceObject(typeName)) {
|
|
272
267
|
const fieldDef = typeDef.fields.get(fieldName);
|
|
268
|
+
debugger;
|
|
273
269
|
if (fieldDef) {
|
|
274
270
|
const outputTypeName = (0, state_js_1.stripTypeModifiers)(fieldDef.type);
|
|
275
271
|
const outputType = stateBuilder.state.types.get(outputTypeName);
|
|
@@ -277,6 +273,17 @@ function createSubgraphValidationContext(subgraph, federation, typeNodeInfo, sta
|
|
|
277
273
|
return false;
|
|
278
274
|
}
|
|
279
275
|
}
|
|
276
|
+
for (const interfaceName of typeDef.interfaces) {
|
|
277
|
+
const iDef = stateBuilder.state.types.get(interfaceName);
|
|
278
|
+
if (!iDef) {
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
if (iDef.kind === state_js_2.TypeKind.INTERFACE && iDef.fields.has(fieldName)) {
|
|
282
|
+
if (iDef.fields.has(fieldName)) {
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
280
287
|
}
|
|
281
288
|
return true;
|
|
282
289
|
});
|
|
@@ -23,6 +23,9 @@ function interfaceTypeBuilder() {
|
|
|
23
23
|
if (type.isDefinition) {
|
|
24
24
|
interfaceTypeState.hasDefinition = true;
|
|
25
25
|
}
|
|
26
|
+
if (type.isInterfaceObject) {
|
|
27
|
+
interfaceTypeState.hasInterfaceObject = true;
|
|
28
|
+
}
|
|
26
29
|
if (type.description && !interfaceTypeState.description) {
|
|
27
30
|
interfaceTypeState.description = type.description;
|
|
28
31
|
}
|
|
@@ -31,11 +34,15 @@ function interfaceTypeBuilder() {
|
|
|
31
34
|
});
|
|
32
35
|
type.interfaces.forEach(interfaceName => interfaceTypeState.interfaces.add(interfaceName));
|
|
33
36
|
type.implementedBy.forEach(objectTypeName => interfaceTypeState.implementedBy.add(objectTypeName));
|
|
37
|
+
if (type.keys.length) {
|
|
38
|
+
interfaceTypeState.isEntity = true;
|
|
39
|
+
}
|
|
34
40
|
interfaceTypeState.byGraph.set(graph.id, {
|
|
35
41
|
extension: type.extension,
|
|
36
42
|
keys: type.keys,
|
|
37
43
|
interfaces: type.interfaces,
|
|
38
44
|
implementedBy: type.implementedBy,
|
|
45
|
+
isInterfaceObject: type.isInterfaceObject,
|
|
39
46
|
version: graph.version,
|
|
40
47
|
});
|
|
41
48
|
for (const field of type.fields.values()) {
|
|
@@ -44,6 +51,9 @@ function interfaceTypeBuilder() {
|
|
|
44
51
|
if (!field.type.endsWith('!') && fieldState.type.endsWith('!')) {
|
|
45
52
|
fieldState.type = field.type;
|
|
46
53
|
}
|
|
54
|
+
if (field.isLeaf) {
|
|
55
|
+
fieldState.isLeaf = true;
|
|
56
|
+
}
|
|
47
57
|
if (field.inaccessible) {
|
|
48
58
|
fieldState.inaccessible = true;
|
|
49
59
|
}
|
|
@@ -65,12 +75,19 @@ function interfaceTypeBuilder() {
|
|
|
65
75
|
field.ast.directives.forEach(directive => {
|
|
66
76
|
fieldState.ast.directives.push(directive);
|
|
67
77
|
});
|
|
78
|
+
const usedAsKey = type.fieldsUsedAsKeys.has(field.name);
|
|
79
|
+
if (usedAsKey) {
|
|
80
|
+
fieldState.usedAsKey = true;
|
|
81
|
+
}
|
|
68
82
|
fieldState.byGraph.set(graph.id, {
|
|
69
83
|
type: field.type,
|
|
70
84
|
override: field.override,
|
|
71
85
|
provides: field.provides,
|
|
72
86
|
requires: field.requires,
|
|
73
87
|
version: graph.version,
|
|
88
|
+
external: field.external,
|
|
89
|
+
shareable: field.shareable,
|
|
90
|
+
usedAsKey,
|
|
74
91
|
});
|
|
75
92
|
for (const arg of field.args.values()) {
|
|
76
93
|
const argState = getOrCreateArg(fieldState, arg.name, arg.type);
|
|
@@ -102,6 +119,27 @@ function interfaceTypeBuilder() {
|
|
|
102
119
|
return (0, ast_js_1.createInterfaceTypeNode)({
|
|
103
120
|
name: interfaceType.name,
|
|
104
121
|
fields: Array.from(interfaceType.fields.values()).map(field => {
|
|
122
|
+
let nonEmptyJoinField = false;
|
|
123
|
+
const joinFields = [];
|
|
124
|
+
if (field.byGraph.size !== interfaceType.byGraph.size) {
|
|
125
|
+
for (const [graphId, meta] of field.byGraph.entries()) {
|
|
126
|
+
if (meta.type !== field.type ||
|
|
127
|
+
meta.override ||
|
|
128
|
+
meta.provides ||
|
|
129
|
+
meta.requires ||
|
|
130
|
+
meta.external) {
|
|
131
|
+
nonEmptyJoinField = true;
|
|
132
|
+
}
|
|
133
|
+
joinFields.push({
|
|
134
|
+
graph: graphId,
|
|
135
|
+
type: meta.type === field.type ? undefined : meta.type,
|
|
136
|
+
override: meta.override ?? undefined,
|
|
137
|
+
provides: meta.provides ?? undefined,
|
|
138
|
+
requires: meta.requires ?? undefined,
|
|
139
|
+
external: meta.external,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
105
143
|
return {
|
|
106
144
|
name: field.name,
|
|
107
145
|
type: field.type,
|
|
@@ -136,15 +174,7 @@ function interfaceTypeBuilder() {
|
|
|
136
174
|
};
|
|
137
175
|
}),
|
|
138
176
|
join: {
|
|
139
|
-
field:
|
|
140
|
-
? []
|
|
141
|
-
: Array.from(field.byGraph.entries()).map(([graphName, meta]) => ({
|
|
142
|
-
graph: graphName.toUpperCase(),
|
|
143
|
-
type: meta.type === field.type ? undefined : meta.type,
|
|
144
|
-
override: meta.override ?? undefined,
|
|
145
|
-
provides: meta.provides ?? undefined,
|
|
146
|
-
requires: meta.requires ?? undefined,
|
|
147
|
-
})),
|
|
177
|
+
field: joinFields,
|
|
148
178
|
},
|
|
149
179
|
};
|
|
150
180
|
}),
|
|
@@ -166,6 +196,8 @@ function interfaceTypeBuilder() {
|
|
|
166
196
|
graph: graphId,
|
|
167
197
|
key: key.fields,
|
|
168
198
|
extension: meta.extension,
|
|
199
|
+
isInterfaceObject: meta.isInterfaceObject,
|
|
200
|
+
resolvable: key.resolvable,
|
|
169
201
|
}));
|
|
170
202
|
}
|
|
171
203
|
return [
|
|
@@ -208,6 +240,8 @@ function getOrCreateInterfaceType(state, typeName) {
|
|
|
208
240
|
policies: [],
|
|
209
241
|
scopes: [],
|
|
210
242
|
hasDefinition: false,
|
|
243
|
+
hasInterfaceObject: false,
|
|
244
|
+
isEntity: false,
|
|
211
245
|
byGraph: new Map(),
|
|
212
246
|
fields: new Map(),
|
|
213
247
|
interfaces: new Set(),
|
|
@@ -227,6 +261,8 @@ function getOrCreateInterfaceField(interfaceTypeState, fieldName, fieldType) {
|
|
|
227
261
|
const def = {
|
|
228
262
|
name: fieldName,
|
|
229
263
|
type: fieldType,
|
|
264
|
+
isLeaf: false,
|
|
265
|
+
usedAsKey: false,
|
|
230
266
|
tags: new Set(),
|
|
231
267
|
inaccessible: false,
|
|
232
268
|
authenticated: false,
|
|
@@ -83,6 +83,9 @@ function objectTypeBuilder() {
|
|
|
83
83
|
if (shouldChangeType) {
|
|
84
84
|
fieldState.type = field.type;
|
|
85
85
|
}
|
|
86
|
+
if (field.isLeaf) {
|
|
87
|
+
fieldState.isLeaf = true;
|
|
88
|
+
}
|
|
86
89
|
if (!fieldState.internal.seenNonExternal && !isExternal) {
|
|
87
90
|
fieldState.internal.seenNonExternal = true;
|
|
88
91
|
}
|
|
@@ -182,6 +185,7 @@ function objectTypeBuilder() {
|
|
|
182
185
|
})
|
|
183
186
|
.flat(1);
|
|
184
187
|
const fieldNamesOfImplementedInterfaces = {};
|
|
188
|
+
const resolvableFieldsFromInterfaceObjects = [];
|
|
185
189
|
for (const interfaceName of objectType.interfaces) {
|
|
186
190
|
const interfaceState = supergraphState.interfaceTypes.get(interfaceName);
|
|
187
191
|
if (!interfaceState) {
|
|
@@ -197,6 +201,12 @@ function objectTypeBuilder() {
|
|
|
197
201
|
else {
|
|
198
202
|
fieldNamesOfImplementedInterfaces[interfaceFieldName] = new Set(Array.from(interfaceField.byGraph.keys()));
|
|
199
203
|
}
|
|
204
|
+
if (!interfaceState.hasInterfaceObject) {
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
if (!resolvableFieldsFromInterfaceObjects.some(f => f.name === interfaceFieldName)) {
|
|
208
|
+
resolvableFieldsFromInterfaceObjects.push(interfaceField);
|
|
209
|
+
}
|
|
200
210
|
}
|
|
201
211
|
}
|
|
202
212
|
if (objectType.isEntity) {
|
|
@@ -439,7 +449,49 @@ function objectTypeBuilder() {
|
|
|
439
449
|
}),
|
|
440
450
|
};
|
|
441
451
|
})
|
|
442
|
-
.filter(helpers_js_1.isDefined)
|
|
452
|
+
.filter(helpers_js_1.isDefined)
|
|
453
|
+
.concat(resolvableFieldsFromInterfaceObjects
|
|
454
|
+
.filter(f => !objectType.fields.has(f.name))
|
|
455
|
+
.map(field => {
|
|
456
|
+
return {
|
|
457
|
+
name: field.name,
|
|
458
|
+
type: field.type,
|
|
459
|
+
inaccessible: field.inaccessible,
|
|
460
|
+
authenticated: field.authenticated,
|
|
461
|
+
policies: field.policies,
|
|
462
|
+
scopes: field.scopes,
|
|
463
|
+
tags: Array.from(field.tags),
|
|
464
|
+
description: field.description,
|
|
465
|
+
deprecated: field.deprecated,
|
|
466
|
+
ast: {
|
|
467
|
+
directives: (0, common_js_1.convertToConst)(field.ast.directives),
|
|
468
|
+
},
|
|
469
|
+
join: {
|
|
470
|
+
field: [{}],
|
|
471
|
+
},
|
|
472
|
+
arguments: Array.from(field.args.values())
|
|
473
|
+
.filter(arg => {
|
|
474
|
+
if (arg.byGraph.size !== field.byGraph.size) {
|
|
475
|
+
return false;
|
|
476
|
+
}
|
|
477
|
+
return true;
|
|
478
|
+
})
|
|
479
|
+
.map(arg => {
|
|
480
|
+
return {
|
|
481
|
+
name: arg.name,
|
|
482
|
+
type: arg.type,
|
|
483
|
+
inaccessible: false,
|
|
484
|
+
tags: Array.from(arg.tags),
|
|
485
|
+
defaultValue: arg.defaultValue,
|
|
486
|
+
description: arg.description,
|
|
487
|
+
deprecated: arg.deprecated,
|
|
488
|
+
ast: {
|
|
489
|
+
directives: (0, common_js_1.convertToConst)(arg.ast.directives),
|
|
490
|
+
},
|
|
491
|
+
};
|
|
492
|
+
}),
|
|
493
|
+
};
|
|
494
|
+
})),
|
|
443
495
|
interfaces: Array.from(objectType.interfaces),
|
|
444
496
|
tags: Array.from(objectType.tags),
|
|
445
497
|
inaccessible: objectType.inaccessible,
|
|
@@ -510,6 +562,7 @@ function getOrCreateField(objectTypeState, fieldName, fieldType) {
|
|
|
510
562
|
const def = {
|
|
511
563
|
name: fieldName,
|
|
512
564
|
type: fieldType,
|
|
565
|
+
isLeaf: false,
|
|
513
566
|
tags: new Set(),
|
|
514
567
|
inaccessible: false,
|
|
515
568
|
authenticated: false,
|
|
@@ -50,6 +50,13 @@ function visitSupergraphState(supergraphState, visitors) {
|
|
|
50
50
|
visitor.InterfaceType(interfaceTypeState);
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
+
for (const fieldState of interfaceTypeState.fields.values()) {
|
|
54
|
+
for (const visitor of visitors) {
|
|
55
|
+
if (visitor.InterfaceTypeField) {
|
|
56
|
+
visitor.InterfaceTypeField(interfaceTypeState, fieldState);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
53
60
|
});
|
|
54
61
|
supergraphState.directives.forEach(directiveState => {
|
|
55
62
|
for (const visitor of visitors) {
|
|
@@ -2,15 +2,23 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.InterfaceKeyMissingImplementationTypeRule = void 0;
|
|
4
4
|
const graphql_1 = require("graphql");
|
|
5
|
+
const version_js_1 = require("../../../utils/version.js");
|
|
5
6
|
function InterfaceKeyMissingImplementationTypeRule(context) {
|
|
6
7
|
return {
|
|
7
8
|
InterfaceType(interfaceState) {
|
|
9
|
+
if (!interfaceState.isEntity || interfaceState.hasInterfaceObject) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
8
12
|
let someSubgraphsAreMissingImplementation = false;
|
|
9
13
|
for (const interfaceStateInGraph of interfaceState.byGraph.values()) {
|
|
14
|
+
if ((0, version_js_1.satisfiesVersionRange)(interfaceStateInGraph.version, '< v2.3')) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
10
17
|
if (interfaceStateInGraph.keys.length === 0) {
|
|
11
18
|
continue;
|
|
12
19
|
}
|
|
13
|
-
if (interfaceStateInGraph.implementedBy.size === 0
|
|
20
|
+
if (interfaceStateInGraph.implementedBy.size === 0 &&
|
|
21
|
+
!interfaceStateInGraph.isInterfaceObject) {
|
|
14
22
|
someSubgraphsAreMissingImplementation = true;
|
|
15
23
|
break;
|
|
16
24
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InterfaceObjectUsageErrorRule = void 0;
|
|
4
|
+
const graphql_1 = require("graphql");
|
|
5
|
+
function InterfaceObjectUsageErrorRule(context) {
|
|
6
|
+
return {
|
|
7
|
+
InterfaceType(interfaceState) {
|
|
8
|
+
if (!interfaceState.hasInterfaceObject) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
for (const [_, interfaceStateInGraph] of interfaceState.byGraph) {
|
|
12
|
+
if (!interfaceStateInGraph.isInterfaceObject) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
context.reportError(new graphql_1.GraphQLError(`Type "${interfaceState.name}" is declared with @interfaceObject in all the subgraphs in which is is defined`, {
|
|
17
|
+
extensions: {
|
|
18
|
+
code: 'INTERFACE_OBJECT_USAGE_ERROR',
|
|
19
|
+
},
|
|
20
|
+
}));
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
exports.InterfaceObjectUsageErrorRule = InterfaceObjectUsageErrorRule;
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.InvalidFieldSharingRule = void 0;
|
|
4
4
|
const graphql_1 = require("graphql");
|
|
5
5
|
const format_js_1 = require("../../../utils/format.js");
|
|
6
|
-
function InvalidFieldSharingRule(context) {
|
|
6
|
+
function InvalidFieldSharingRule(context, supergraphState) {
|
|
7
7
|
return {
|
|
8
8
|
ObjectTypeField(objectTypeState, fieldState) {
|
|
9
9
|
if (Array.from(objectTypeState.byGraph.keys()).some(graph => context.subgraphStates.get(graph)?.schema.subscriptionType === objectTypeState.name)) {
|
|
@@ -46,9 +46,100 @@ function InvalidFieldSharingRule(context) {
|
|
|
46
46
|
nonSharableIn.push(graphId);
|
|
47
47
|
resolvableIn.push(graphId);
|
|
48
48
|
}
|
|
49
|
+
const interfaceObjectFieldIn = [];
|
|
50
|
+
if (nonSharableIn.length > 0) {
|
|
51
|
+
for (const interfaceName of objectTypeState.interfaces) {
|
|
52
|
+
const interfaceState = supergraphState.interfaceTypes.get(interfaceName);
|
|
53
|
+
if (!interfaceState || !interfaceState.hasInterfaceObject) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const interfaceObjectFieldState = interfaceState.fields.get(fieldState.name);
|
|
57
|
+
if (!interfaceObjectFieldState || interfaceObjectFieldState.usedAsKey) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
for (const [graphId, field] of interfaceObjectFieldState.byGraph) {
|
|
61
|
+
const isInterfaceObject = interfaceState.byGraph.get(graphId)?.isInterfaceObject === true;
|
|
62
|
+
if (!isInterfaceObject) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const fieldIsShareable = field.shareable;
|
|
66
|
+
const fieldIsExternal = field.external;
|
|
67
|
+
const fieldHasOverride = field.override;
|
|
68
|
+
const fieldIsUsedAsKey = field.usedAsKey;
|
|
69
|
+
if (fieldIsExternal) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (fieldHasOverride) {
|
|
73
|
+
const overrideGraphId = context.graphNameToId(fieldHasOverride);
|
|
74
|
+
if (overrideGraphId && fieldState.byGraph.has(overrideGraphId)) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
interfaceObjectFieldIn.push([graphId, interfaceName]);
|
|
79
|
+
if (fieldIsShareable || fieldIsUsedAsKey) {
|
|
80
|
+
resolvableIn.push(graphId);
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
nonSharableIn.push(graphId);
|
|
84
|
+
resolvableIn.push(graphId);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (nonSharableIn.length >= 1 && resolvableIn.length > 1) {
|
|
89
|
+
const isNonSharableInAll = resolvableIn.every(graphId => nonSharableIn.includes(graphId));
|
|
90
|
+
const message = `Non-shareable field "${objectTypeState.name}.${fieldState.name}" is resolved from multiple subgraphs: it is resolved from subgraphs ${(0, format_js_1.andList)(resolvableIn.map(graphId => {
|
|
91
|
+
const name = context.graphIdToName(graphId);
|
|
92
|
+
const interfaceObjectField = interfaceObjectFieldIn.find(([g, _]) => g === graphId);
|
|
93
|
+
if (!interfaceObjectField) {
|
|
94
|
+
return `"${name}"`;
|
|
95
|
+
}
|
|
96
|
+
return `"${name}" (through @interfaceObject field "${interfaceObjectField[1]}.${fieldState.name}")`;
|
|
97
|
+
}), false)} and defined as non-shareable in ${isNonSharableInAll
|
|
98
|
+
? 'all of them'
|
|
99
|
+
: `subgraph${nonSharableIn.length > 1 ? 's' : ''} ${(0, format_js_1.andList)(nonSharableIn.map(context.graphIdToName), true, '"')}`}`;
|
|
100
|
+
context.reportError(new graphql_1.GraphQLError(message, {
|
|
101
|
+
extensions: {
|
|
102
|
+
code: 'INVALID_FIELD_SHARING',
|
|
103
|
+
},
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
InterfaceTypeField(interfaceTypeState, fieldState) {
|
|
108
|
+
if (!interfaceTypeState.hasInterfaceObject) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const nonSharableIn = [];
|
|
112
|
+
const resolvableIn = [];
|
|
113
|
+
const interfaceObjectFieldIn = [];
|
|
114
|
+
for (const [graphId, field] of fieldState.byGraph) {
|
|
115
|
+
const isInterfaceObject = interfaceTypeState.byGraph.get(graphId)?.isInterfaceObject === true;
|
|
116
|
+
if (!isInterfaceObject) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
const fieldIsShareable = field.shareable;
|
|
120
|
+
const fieldIsExternal = field.external;
|
|
121
|
+
const fieldHasOverride = field.override;
|
|
122
|
+
const fieldIsUsedAsKey = field.usedAsKey;
|
|
123
|
+
if (fieldIsExternal) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (fieldHasOverride) {
|
|
127
|
+
const overrideGraphId = context.graphNameToId(fieldHasOverride);
|
|
128
|
+
if (overrideGraphId && fieldState.byGraph.has(overrideGraphId)) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (fieldIsShareable || fieldIsUsedAsKey) {
|
|
133
|
+
resolvableIn.push(graphId);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
nonSharableIn.push(graphId);
|
|
137
|
+
resolvableIn.push(graphId);
|
|
138
|
+
interfaceObjectFieldIn.push(graphId);
|
|
139
|
+
}
|
|
49
140
|
if (nonSharableIn.length >= 1 && resolvableIn.length > 1) {
|
|
50
141
|
const isNonSharableInAll = resolvableIn.every(graphId => nonSharableIn.includes(graphId));
|
|
51
|
-
const message = `Non-shareable field "${
|
|
142
|
+
const message = `Non-shareable field "${interfaceTypeState.name}.${fieldState.name}" is resolved from multiple subgraphs: it is resolved from subgraphs ${(0, format_js_1.andList)(resolvableIn.map(context.graphIdToName), false, '"')} and defined as non-shareable in ${isNonSharableInAll
|
|
52
143
|
? 'all of them'
|
|
53
144
|
: `subgraph${nonSharableIn.length > 1 ? 's' : ''} ${(0, format_js_1.andList)(nonSharableIn.map(context.graphIdToName), true, '"')}`}`;
|
|
54
145
|
context.reportError(new graphql_1.GraphQLError(message, {
|
|
@@ -22,6 +22,15 @@ function OnlyInaccessibleChildrenRule(context) {
|
|
|
22
22
|
}));
|
|
23
23
|
}
|
|
24
24
|
},
|
|
25
|
+
InterfaceType(interfaceState) {
|
|
26
|
+
if (interfaceState.inaccessible === false && areAllInaccessible(interfaceState.fields)) {
|
|
27
|
+
context.reportError(new graphql_1.GraphQLError(`Type "${interfaceState.name}" is in the API schema but all of its fields are @inaccessible.`, {
|
|
28
|
+
extensions: {
|
|
29
|
+
code: 'ONLY_INACCESSIBLE_CHILDREN',
|
|
30
|
+
},
|
|
31
|
+
}));
|
|
32
|
+
}
|
|
33
|
+
},
|
|
25
34
|
InputObjectType(inputObjectTypeState) {
|
|
26
35
|
if (inputObjectTypeState.inaccessible === false &&
|
|
27
36
|
areAllInaccessible(inputObjectTypeState.fields)) {
|
|
@@ -21,6 +21,9 @@ class SatisfiabilityError extends Error {
|
|
|
21
21
|
static forNoKey(sourceGraphName, targetGraphName, typeName, fieldName) {
|
|
22
22
|
return new SatisfiabilityError('NO_KEY', sourceGraphName, typeName, fieldName, `cannot move to subgraph "${targetGraphName}", which has field "${typeName}.${fieldName}", because type "${typeName}" has no @key defined in subgraph "${targetGraphName}".`);
|
|
23
23
|
}
|
|
24
|
+
static forNoImplementation(sourceGraphName, typeName) {
|
|
25
|
+
return new SatisfiabilityError('NO_IMPLEMENTATION', sourceGraphName, typeName, null, `no subgraph can be reached to resolve the implementation type of @interfaceObject type "${typeName}".`);
|
|
26
|
+
}
|
|
24
27
|
constructor(kind, sourceGraphName, typeName, fieldName, message) {
|
|
25
28
|
super(message);
|
|
26
29
|
this.kind = kind;
|