@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.
Files changed (100) hide show
  1. package/README.md +3 -16
  2. package/cjs/subgraph/helpers.js +1 -1
  3. package/cjs/subgraph/state.js +183 -4
  4. package/cjs/subgraph/validation/rules/elements/interface-object.js +19 -3
  5. package/cjs/subgraph/validation/rules/elements/key.js +3 -2
  6. package/cjs/subgraph/validation/rules/elements/policy.js +3 -2
  7. package/cjs/subgraph/validation/rules/elements/shareable.js +3 -2
  8. package/cjs/subgraph/validation/rules/elements/tag.js +2 -1
  9. package/cjs/subgraph/validation/rules/known-federation-directive-rule.js +4 -0
  10. package/cjs/subgraph/validation/rules/only-interface-implementation-rule.js +67 -0
  11. package/cjs/subgraph/validation/validate-subgraph.js +2 -0
  12. package/cjs/subgraph/validation/validation-context.js +18 -11
  13. package/cjs/supergraph/composition/interface-type.js +45 -9
  14. package/cjs/supergraph/composition/object-type.js +54 -1
  15. package/cjs/supergraph/composition/visitor.js +7 -0
  16. package/cjs/supergraph/validation/rules/interface-key-missing-implementation-type.js +9 -1
  17. package/cjs/supergraph/validation/rules/interface-object-usage-error.js +24 -0
  18. package/cjs/supergraph/validation/rules/invalid-field-sharing-rule.js +93 -2
  19. package/cjs/supergraph/validation/rules/only-inaccessible-children-rule.js +9 -0
  20. package/cjs/supergraph/validation/rules/satisfiablity/errors.js +3 -0
  21. package/cjs/supergraph/validation/rules/satisfiablity/finder.js +139 -120
  22. package/cjs/supergraph/validation/rules/satisfiablity/graph.js +111 -10
  23. package/cjs/supergraph/validation/rules/satisfiablity/move-validator.js +118 -156
  24. package/cjs/supergraph/validation/rules/satisfiablity/moves.js +6 -1
  25. package/cjs/supergraph/validation/rules/satisfiablity/{fields.js → selection.js} +64 -47
  26. package/cjs/supergraph/validation/rules/satisfiablity/supergraph.js +7 -7
  27. package/cjs/supergraph/validation/rules/satisfiablity/walker.js +5 -4
  28. package/cjs/supergraph/validation/rules/satisfiablity-rule.js +82 -47
  29. package/cjs/supergraph/validation/rules/types-of-the-same-kind-rule.js +21 -4
  30. package/cjs/supergraph/validation/validate-supergraph.js +2 -0
  31. package/cjs/utils/version.js +16 -0
  32. package/esm/subgraph/helpers.js +1 -1
  33. package/esm/subgraph/state.js +183 -4
  34. package/esm/subgraph/validation/rules/elements/interface-object.js +20 -4
  35. package/esm/subgraph/validation/rules/elements/key.js +3 -2
  36. package/esm/subgraph/validation/rules/elements/policy.js +3 -2
  37. package/esm/subgraph/validation/rules/elements/shareable.js +3 -2
  38. package/esm/subgraph/validation/rules/elements/tag.js +2 -1
  39. package/esm/subgraph/validation/rules/known-federation-directive-rule.js +4 -0
  40. package/esm/subgraph/validation/rules/only-interface-implementation-rule.js +63 -0
  41. package/esm/subgraph/validation/validate-subgraph.js +2 -0
  42. package/esm/subgraph/validation/validation-context.js +18 -11
  43. package/esm/supergraph/composition/interface-type.js +45 -9
  44. package/esm/supergraph/composition/object-type.js +54 -1
  45. package/esm/supergraph/composition/visitor.js +7 -0
  46. package/esm/supergraph/validation/rules/interface-key-missing-implementation-type.js +9 -1
  47. package/esm/supergraph/validation/rules/interface-object-usage-error.js +20 -0
  48. package/esm/supergraph/validation/rules/invalid-field-sharing-rule.js +93 -2
  49. package/esm/supergraph/validation/rules/only-inaccessible-children-rule.js +9 -0
  50. package/esm/supergraph/validation/rules/satisfiablity/errors.js +3 -0
  51. package/esm/supergraph/validation/rules/satisfiablity/finder.js +139 -120
  52. package/esm/supergraph/validation/rules/satisfiablity/graph.js +111 -10
  53. package/esm/supergraph/validation/rules/satisfiablity/move-validator.js +119 -157
  54. package/esm/supergraph/validation/rules/satisfiablity/moves.js +6 -1
  55. package/esm/supergraph/validation/rules/satisfiablity/{fields.js → selection.js} +61 -44
  56. package/esm/supergraph/validation/rules/satisfiablity/supergraph.js +7 -7
  57. package/esm/supergraph/validation/rules/satisfiablity/walker.js +5 -4
  58. package/esm/supergraph/validation/rules/satisfiablity-rule.js +83 -48
  59. package/esm/supergraph/validation/rules/types-of-the-same-kind-rule.js +21 -4
  60. package/esm/supergraph/validation/validate-supergraph.js +2 -0
  61. package/esm/utils/version.js +12 -0
  62. package/package.json +1 -1
  63. package/typings/specifications/federation.d.cts +1 -0
  64. package/typings/specifications/federation.d.ts +1 -0
  65. package/typings/subgraph/state.d.cts +8 -0
  66. package/typings/subgraph/state.d.ts +8 -0
  67. package/typings/subgraph/validation/rules/only-interface-implementation-rule.d.cts +4 -0
  68. package/typings/subgraph/validation/rules/only-interface-implementation-rule.d.ts +4 -0
  69. package/typings/subgraph/validation/validation-context.d.cts +4 -0
  70. package/typings/subgraph/validation/validation-context.d.ts +4 -0
  71. package/typings/supergraph/composition/interface-type.d.cts +9 -1
  72. package/typings/supergraph/composition/interface-type.d.ts +9 -1
  73. package/typings/supergraph/composition/object-type.d.cts +1 -0
  74. package/typings/supergraph/composition/object-type.d.ts +1 -0
  75. package/typings/supergraph/composition/visitor.d.cts +2 -1
  76. package/typings/supergraph/composition/visitor.d.ts +2 -1
  77. package/typings/supergraph/validation/rules/interface-object-usage-error.d.cts +4 -0
  78. package/typings/supergraph/validation/rules/interface-object-usage-error.d.ts +4 -0
  79. package/typings/supergraph/validation/rules/invalid-field-sharing-rule.d.cts +2 -1
  80. package/typings/supergraph/validation/rules/invalid-field-sharing-rule.d.ts +2 -1
  81. package/typings/supergraph/validation/rules/satisfiablity/errors.d.cts +2 -1
  82. package/typings/supergraph/validation/rules/satisfiablity/errors.d.ts +2 -1
  83. package/typings/supergraph/validation/rules/satisfiablity/finder.d.cts +5 -3
  84. package/typings/supergraph/validation/rules/satisfiablity/finder.d.ts +5 -3
  85. package/typings/supergraph/validation/rules/satisfiablity/graph.d.cts +9 -5
  86. package/typings/supergraph/validation/rules/satisfiablity/graph.d.ts +9 -5
  87. package/typings/supergraph/validation/rules/satisfiablity/move-validator.d.cts +5 -4
  88. package/typings/supergraph/validation/rules/satisfiablity/move-validator.d.ts +5 -4
  89. package/typings/supergraph/validation/rules/satisfiablity/moves.d.cts +9 -6
  90. package/typings/supergraph/validation/rules/satisfiablity/moves.d.ts +9 -6
  91. package/typings/supergraph/validation/rules/satisfiablity/selection.d.cts +36 -0
  92. package/typings/supergraph/validation/rules/satisfiablity/selection.d.ts +36 -0
  93. package/typings/supergraph/validation/rules/satisfiablity/supergraph.d.cts +2 -2
  94. package/typings/supergraph/validation/rules/satisfiablity/supergraph.d.ts +2 -2
  95. package/typings/supergraph/validation/rules/types-of-the-same-kind-rule.d.cts +4 -0
  96. package/typings/supergraph/validation/rules/types-of-the-same-kind-rule.d.ts +4 -0
  97. package/typings/utils/version.d.cts +3 -0
  98. package/typings/utils/version.d.ts +3 -0
  99. package/typings/supergraph/validation/rules/satisfiablity/fields.d.cts +0 -33
  100. 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
- const [sign, ver] = range.split(' ');
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 && typeDef.kind === state_js_2.TypeKind.OBJECT) {
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: field.byGraph.size === interfaceType.byGraph.size
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 "${objectTypeState.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
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;