@theguild/federation-composition 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +2 -1
  2. package/cjs/specifications/link.js +40 -5
  3. package/cjs/subgraph/helpers.js +2 -2
  4. package/cjs/subgraph/state.js +8 -0
  5. package/cjs/subgraph/validation/rules/elements/provides.js +8 -6
  6. package/cjs/subgraph/validation/rules/elements/requires.js +9 -7
  7. package/cjs/subgraph/validation/validate-state.js +9 -3
  8. package/cjs/subgraph/validation/validate-subgraph.js +4 -2
  9. package/cjs/subgraph/validation/validation-context.js +10 -0
  10. package/cjs/supergraph/composition/directive.js +3 -0
  11. package/cjs/supergraph/composition/enum-type.js +3 -0
  12. package/cjs/supergraph/composition/input-object-type.js +3 -0
  13. package/cjs/supergraph/composition/interface-type.js +4 -0
  14. package/cjs/supergraph/composition/object-type.js +18 -20
  15. package/cjs/supergraph/composition/scalar-type.js +2 -0
  16. package/cjs/supergraph/composition/union-type.js +2 -0
  17. package/cjs/supergraph/state.js +24 -26
  18. package/cjs/supergraph/validation/rules/fields-of-the-same-type-rule.js +35 -0
  19. package/cjs/supergraph/validation/rules/invalid-field-sharing-rule.js +4 -1
  20. package/cjs/supergraph/validation/rules/satisfiablity/constants.js +4 -0
  21. package/cjs/supergraph/validation/rules/satisfiablity/edge.js +64 -0
  22. package/cjs/supergraph/validation/rules/satisfiablity/errors.js +44 -0
  23. package/cjs/supergraph/validation/rules/satisfiablity/fields.js +147 -0
  24. package/cjs/supergraph/validation/rules/satisfiablity/finder.js +267 -0
  25. package/cjs/supergraph/validation/rules/satisfiablity/graph.js +675 -0
  26. package/cjs/supergraph/validation/rules/satisfiablity/helpers.js +41 -0
  27. package/cjs/supergraph/validation/rules/satisfiablity/move-validator.js +337 -0
  28. package/cjs/supergraph/validation/rules/satisfiablity/moves.js +52 -0
  29. package/cjs/supergraph/validation/rules/satisfiablity/node.js +89 -0
  30. package/cjs/supergraph/validation/rules/satisfiablity/operation-path.js +70 -0
  31. package/cjs/supergraph/validation/rules/satisfiablity/supergraph.js +37 -0
  32. package/cjs/supergraph/validation/rules/satisfiablity/walker.js +306 -0
  33. package/cjs/supergraph/validation/rules/satisfiablity-rule.js +45 -1081
  34. package/cjs/supergraph/validation/validate-supergraph.js +1 -1
  35. package/cjs/utils/logger.js +127 -0
  36. package/esm/specifications/link.js +40 -5
  37. package/esm/subgraph/helpers.js +2 -2
  38. package/esm/subgraph/state.js +8 -0
  39. package/esm/subgraph/validation/rules/elements/provides.js +8 -6
  40. package/esm/subgraph/validation/rules/elements/requires.js +9 -7
  41. package/esm/subgraph/validation/validate-state.js +9 -3
  42. package/esm/subgraph/validation/validate-subgraph.js +4 -2
  43. package/esm/subgraph/validation/validation-context.js +11 -1
  44. package/esm/supergraph/composition/directive.js +3 -0
  45. package/esm/supergraph/composition/enum-type.js +3 -0
  46. package/esm/supergraph/composition/input-object-type.js +3 -0
  47. package/esm/supergraph/composition/interface-type.js +4 -0
  48. package/esm/supergraph/composition/object-type.js +18 -20
  49. package/esm/supergraph/composition/scalar-type.js +2 -0
  50. package/esm/supergraph/composition/union-type.js +2 -0
  51. package/esm/supergraph/state.js +24 -26
  52. package/esm/supergraph/validation/rules/fields-of-the-same-type-rule.js +35 -0
  53. package/esm/supergraph/validation/rules/invalid-field-sharing-rule.js +4 -1
  54. package/esm/supergraph/validation/rules/satisfiablity/constants.js +1 -0
  55. package/esm/supergraph/validation/rules/satisfiablity/edge.js +54 -0
  56. package/esm/supergraph/validation/rules/satisfiablity/errors.js +40 -0
  57. package/esm/supergraph/validation/rules/satisfiablity/fields.js +142 -0
  58. package/esm/supergraph/validation/rules/satisfiablity/finder.js +261 -0
  59. package/esm/supergraph/validation/rules/satisfiablity/graph.js +671 -0
  60. package/esm/supergraph/validation/rules/satisfiablity/helpers.js +35 -0
  61. package/esm/supergraph/validation/rules/satisfiablity/move-validator.js +333 -0
  62. package/esm/supergraph/validation/rules/satisfiablity/moves.js +46 -0
  63. package/esm/supergraph/validation/rules/satisfiablity/node.js +85 -0
  64. package/esm/supergraph/validation/rules/satisfiablity/operation-path.js +66 -0
  65. package/esm/supergraph/validation/rules/satisfiablity/supergraph.js +33 -0
  66. package/esm/supergraph/validation/rules/satisfiablity/walker.js +301 -0
  67. package/esm/supergraph/validation/rules/satisfiablity-rule.js +40 -1076
  68. package/esm/supergraph/validation/validate-supergraph.js +1 -1
  69. package/esm/utils/logger.js +119 -0
  70. package/package.json +2 -1
  71. package/typings/subgraph/state.d.cts +2 -0
  72. package/typings/subgraph/state.d.ts +2 -0
  73. package/typings/subgraph/validation/validate-state.d.cts +2 -1
  74. package/typings/subgraph/validation/validate-state.d.ts +2 -1
  75. package/typings/subgraph/validation/validation-context.d.cts +3 -0
  76. package/typings/subgraph/validation/validation-context.d.ts +3 -0
  77. package/typings/supergraph/composition/common.d.cts +2 -1
  78. package/typings/supergraph/composition/common.d.ts +2 -1
  79. package/typings/supergraph/composition/directive.d.cts +4 -0
  80. package/typings/supergraph/composition/directive.d.ts +4 -0
  81. package/typings/supergraph/composition/enum-type.d.cts +4 -0
  82. package/typings/supergraph/composition/enum-type.d.ts +4 -0
  83. package/typings/supergraph/composition/input-object-type.d.cts +4 -0
  84. package/typings/supergraph/composition/input-object-type.d.ts +4 -0
  85. package/typings/supergraph/composition/interface-type.d.cts +5 -0
  86. package/typings/supergraph/composition/interface-type.d.ts +5 -0
  87. package/typings/supergraph/composition/object-type.d.cts +5 -0
  88. package/typings/supergraph/composition/object-type.d.ts +5 -0
  89. package/typings/supergraph/composition/scalar-type.d.cts +3 -0
  90. package/typings/supergraph/composition/scalar-type.d.ts +3 -0
  91. package/typings/supergraph/composition/union-type.d.cts +3 -0
  92. package/typings/supergraph/composition/union-type.d.ts +3 -0
  93. package/typings/supergraph/state.d.cts +4 -4
  94. package/typings/supergraph/state.d.ts +4 -4
  95. package/typings/supergraph/validation/rules/satisfiablity/constants.d.cts +2 -0
  96. package/typings/supergraph/validation/rules/satisfiablity/constants.d.ts +2 -0
  97. package/typings/supergraph/validation/rules/satisfiablity/edge.d.cts +31 -0
  98. package/typings/supergraph/validation/rules/satisfiablity/edge.d.ts +31 -0
  99. package/typings/supergraph/validation/rules/satisfiablity/errors.d.cts +17 -0
  100. package/typings/supergraph/validation/rules/satisfiablity/errors.d.ts +17 -0
  101. package/typings/supergraph/validation/rules/satisfiablity/fields.d.cts +33 -0
  102. package/typings/supergraph/validation/rules/satisfiablity/fields.d.ts +33 -0
  103. package/typings/supergraph/validation/rules/satisfiablity/finder.d.cts +28 -0
  104. package/typings/supergraph/validation/rules/satisfiablity/finder.d.ts +28 -0
  105. package/typings/supergraph/validation/rules/satisfiablity/graph.d.cts +63 -0
  106. package/typings/supergraph/validation/rules/satisfiablity/graph.d.ts +63 -0
  107. package/typings/supergraph/validation/rules/satisfiablity/helpers.d.cts +7 -0
  108. package/typings/supergraph/validation/rules/satisfiablity/helpers.d.ts +7 -0
  109. package/typings/supergraph/validation/rules/satisfiablity/move-validator.d.cts +25 -0
  110. package/typings/supergraph/validation/rules/satisfiablity/move-validator.d.ts +25 -0
  111. package/typings/supergraph/validation/rules/satisfiablity/moves.d.cts +24 -0
  112. package/typings/supergraph/validation/rules/satisfiablity/moves.d.ts +24 -0
  113. package/typings/supergraph/validation/rules/satisfiablity/node.d.cts +31 -0
  114. package/typings/supergraph/validation/rules/satisfiablity/node.d.ts +31 -0
  115. package/typings/supergraph/validation/rules/satisfiablity/operation-path.d.cts +29 -0
  116. package/typings/supergraph/validation/rules/satisfiablity/operation-path.d.ts +29 -0
  117. package/typings/supergraph/validation/rules/satisfiablity/supergraph.d.cts +14 -0
  118. package/typings/supergraph/validation/rules/satisfiablity/supergraph.d.ts +14 -0
  119. package/typings/supergraph/validation/rules/satisfiablity/walker.d.cts +35 -0
  120. package/typings/supergraph/validation/rules/satisfiablity/walker.d.ts +35 -0
  121. package/typings/utils/logger.d.cts +33 -0
  122. package/typings/utils/logger.d.ts +33 -0
  123. package/cjs/utils/dependency-graph.js +0 -227
  124. package/esm/utils/dependency-graph.js +0 -222
  125. package/typings/utils/dependency-graph.d.cts +0 -31
  126. package/typings/utils/dependency-graph.d.ts +0 -31
@@ -0,0 +1,267 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PathFinder = exports.concatIfNotExistsFields = exports.concatIfNotExistsString = void 0;
4
+ const edge_1 = require("./edge");
5
+ const errors_1 = require("./errors");
6
+ function concatIfNotExistsString(list, item) {
7
+ if (list.includes(item)) {
8
+ return list;
9
+ }
10
+ return list.concat(item);
11
+ }
12
+ exports.concatIfNotExistsString = concatIfNotExistsString;
13
+ function concatIfNotExistsFields(list, item) {
14
+ if (list.some(f => f.equals(item))) {
15
+ return list;
16
+ }
17
+ return list.concat(item);
18
+ }
19
+ exports.concatIfNotExistsFields = concatIfNotExistsFields;
20
+ class PathFinder {
21
+ logger;
22
+ graph;
23
+ moveValidator;
24
+ constructor(logger, graph, moveValidator) {
25
+ this.logger = logger;
26
+ this.graph = graph;
27
+ this.moveValidator = moveValidator;
28
+ }
29
+ findDirectPaths(path, typeName, fieldName, visitedEdges) {
30
+ const nextPaths = [];
31
+ const errors = [];
32
+ const tail = path.tail() ?? path.rootNode();
33
+ const isFieldTarget = fieldName !== null;
34
+ const id = isFieldTarget ? `${typeName}.${fieldName}` : `... on ${typeName}`;
35
+ this.logger.group(() => 'Direct paths to ' + id + ' from: ' + tail);
36
+ const edges = isFieldTarget
37
+ ? this.graph.fieldEdgesOfHead(tail, fieldName)
38
+ : this.graph.abstractEdgesOfHead(tail);
39
+ this.logger.log(() => 'Checking ' + edges.length + ' edges');
40
+ let i = 0;
41
+ for (const edge of edges) {
42
+ this.logger.group(() => 'Checking #' + i++ + ' ' + edge);
43
+ if (edge.isCrossGraphEdge()) {
44
+ this.logger.groupEnd(() => 'Cross graph edge: ' + edge);
45
+ continue;
46
+ }
47
+ if (visitedEdges.includes(edge)) {
48
+ this.logger.groupEnd(() => 'Already visited: ' + edge);
49
+ continue;
50
+ }
51
+ if (!isFieldTarget) {
52
+ if ((0, edge_1.isAbstractEdge)(edge) && edge.tail.typeName === typeName) {
53
+ this.logger.groupEnd(() => 'Resolvable: ' + edge);
54
+ const newPath = path.clone().move(edge);
55
+ nextPaths.push(newPath);
56
+ continue;
57
+ }
58
+ }
59
+ if (isFieldTarget &&
60
+ (0, edge_1.isFieldEdge)(edge) &&
61
+ edge.move.typeName === typeName &&
62
+ edge.move.fieldName === fieldName) {
63
+ const resolvable = this.moveValidator.isEdgeResolvable(edge, path, [], [], []);
64
+ if (!resolvable.success) {
65
+ errors.push(resolvable.error);
66
+ this.logger.groupEnd(() => 'Not resolvable: ' + edge);
67
+ continue;
68
+ }
69
+ this.logger.groupEnd(() => 'Resolvable: ' + edge);
70
+ const newPath = path.clone().move(edge);
71
+ nextPaths.push(newPath);
72
+ continue;
73
+ }
74
+ this.logger.groupEnd(() => 'Not matching');
75
+ }
76
+ this.logger.groupEnd(() => 'Found ' + nextPaths.length + ' direct paths');
77
+ if (nextPaths.length === 0) {
78
+ if (errors.length === 0) {
79
+ if (isFieldTarget) {
80
+ errors.push(errors_1.SatisfiabilityError.forMissingField(tail.graphName, typeName, fieldName));
81
+ const typeNodes = this.graph.nodesOf(typeName);
82
+ for (const typeNode of typeNodes) {
83
+ const edges = this.graph.fieldEdgesOfHead(typeNode, fieldName);
84
+ for (const edge of edges) {
85
+ if ((0, edge_1.isFieldEdge)(edge) &&
86
+ edge.move.typeName === typeName &&
87
+ edge.move.fieldName === fieldName &&
88
+ !this.moveValidator.isExternal(edge)) {
89
+ const typeStateInGraph = edge.head.typeState &&
90
+ edge.head.typeState.kind === 'object' &&
91
+ edge.head.typeState.byGraph.get(edge.head.graphId);
92
+ const keys = typeStateInGraph
93
+ ? typeStateInGraph.keys.filter(key => key.resolvable)
94
+ : [];
95
+ if (keys.length === 0) {
96
+ errors.push(errors_1.SatisfiabilityError.forNoKey(tail.graphName, edge.tail.graphName, typeName, fieldName));
97
+ }
98
+ }
99
+ }
100
+ }
101
+ }
102
+ else {
103
+ return {
104
+ success: true,
105
+ errors: undefined,
106
+ paths: [],
107
+ };
108
+ }
109
+ }
110
+ return {
111
+ success: false,
112
+ errors,
113
+ paths: undefined,
114
+ };
115
+ }
116
+ return {
117
+ success: true,
118
+ paths: nextPaths,
119
+ errors: undefined,
120
+ };
121
+ }
122
+ findIndirectPaths(path, typeName, fieldName, visitedEdges, visitedGraphs, visitedFields) {
123
+ const errors = [];
124
+ const tail = path.tail() ?? path.rootNode();
125
+ const sourceGraphName = tail.graphName;
126
+ const isFieldTarget = fieldName !== null;
127
+ const id = isFieldTarget ? `${typeName}.${fieldName}` : `... on ${typeName}`;
128
+ this.logger.group(() => 'Indirect paths to ' + id + ' from: ' + tail);
129
+ const queue = [[visitedGraphs, visitedFields, path]];
130
+ const finalPaths = [];
131
+ const shortestPathPerGraph = new Map();
132
+ const edgesToIgnore = visitedEdges.slice();
133
+ while (queue.length > 0) {
134
+ const item = queue.pop();
135
+ if (!item) {
136
+ throw new Error('Unexpected end of queue');
137
+ }
138
+ const [visitedGraphs, visitedFields, path] = item;
139
+ const tail = path.tail() ?? path.rootNode();
140
+ const edges = this.graph.crossGraphEdgesOfHead(tail);
141
+ if (!this.graph.canReachTypeFromType(tail.typeName, typeName)) {
142
+ this.logger.log(() => 'Cannot reach ' + typeName + ' from ' + tail.typeName);
143
+ continue;
144
+ }
145
+ this.logger.log(() => 'At path: ' + path);
146
+ this.logger.log(() => 'Checking ' + edges.length + ' edges');
147
+ let i = 0;
148
+ for (const edge of edges) {
149
+ this.logger.group(() => 'Checking #' + i++ + ' ' + edge);
150
+ this.logger.log(() => 'Visited graphs: ' + visitedGraphs.join(','));
151
+ if (visitedGraphs.includes(edge.tail.graphName)) {
152
+ this.logger.groupEnd(() => 'Ignore: already visited graph');
153
+ continue;
154
+ }
155
+ if (!edge.isCrossGraphEdge()) {
156
+ this.logger.groupEnd(() => 'Not cross-graph edge');
157
+ continue;
158
+ }
159
+ if (edgesToIgnore.includes(edge)) {
160
+ this.logger.groupEnd(() => 'Ignore: already visited edge');
161
+ continue;
162
+ }
163
+ if (edge.tail.graphName === sourceGraphName && !(0, edge_1.isAbstractEdge)(edge)) {
164
+ this.logger.groupEnd(() => 'Ignore: we are back to the same graph');
165
+ continue;
166
+ }
167
+ if (isFieldTarget && (0, edge_1.isEntityEdge)(edge)) {
168
+ if (visitedFields.some(f => f.equals(edge.move.keyFields))) {
169
+ this.logger.groupEnd(() => 'Ignore: already visited fields');
170
+ continue;
171
+ }
172
+ const shortestPathToThisGraph = shortestPathPerGraph.get(edge.tail.graphName);
173
+ if (shortestPathToThisGraph && shortestPathToThisGraph.depth() <= path.depth()) {
174
+ this.logger.groupEnd(() => 'Already found a shorter path to ' + edge.tail);
175
+ continue;
176
+ }
177
+ const resolvable = this.moveValidator.isEdgeResolvable(edge, path, edgesToIgnore.concat(edge), visitedGraphs, visitedFields);
178
+ if (!resolvable.success) {
179
+ errors.push(resolvable.error);
180
+ this.logger.groupEnd(() => 'Not resolvable: ' + resolvable.error);
181
+ continue;
182
+ }
183
+ const newPath = path.clone().move(edge);
184
+ this.logger.log(() => 'From indirect path, look for direct paths to ' + id + ' from: ' + edge);
185
+ const direct = this.findDirectPaths(newPath, typeName, fieldName, [edge]);
186
+ if (direct.success) {
187
+ this.logger.groupEnd(() => 'Resolvable: ' + edge + ' with ' + direct.paths.length + ' paths');
188
+ finalPaths.push(...direct.paths);
189
+ continue;
190
+ }
191
+ errors.push(...direct.errors);
192
+ setShortest(newPath, shortestPathPerGraph);
193
+ queue.push([
194
+ concatIfNotExistsString(visitedGraphs, edge.tail.graphName),
195
+ concatIfNotExistsFields(visitedFields, edge.move.keyFields),
196
+ newPath,
197
+ ]);
198
+ this.logger.log(() => 'Did not find direct paths');
199
+ this.logger.groupEnd(() => 'Adding to queue: ' + newPath);
200
+ }
201
+ else if (isFieldTarget && (0, edge_1.isFieldEdge)(edge)) {
202
+ this.logger.log(() => 'Cross graph field move:' + edge.move);
203
+ if (path.isVisitedEdge(edge)) {
204
+ this.logger.groupEnd(() => 'Already visited');
205
+ continue;
206
+ }
207
+ if (isFieldTarget && edge.move.requires?.contains(typeName, fieldName)) {
208
+ errors.push(errors_1.SatisfiabilityError.forRequire(tail.graphName, typeName, fieldName));
209
+ this.logger.groupEnd(() => 'Ignored');
210
+ continue;
211
+ }
212
+ if (edge.move.requires && visitedFields.some(f => f.equals(edge.move.requires))) {
213
+ this.logger.groupEnd(() => 'Ignore: already visited fields');
214
+ continue;
215
+ }
216
+ const resolvable = this.moveValidator.isEdgeResolvable(edge, path, visitedEdges.concat(edge), visitedGraphs, edge.move.requires
217
+ ? concatIfNotExistsFields(visitedFields, edge.move.requires)
218
+ : visitedFields);
219
+ if (!resolvable.success) {
220
+ errors.push(resolvable.error);
221
+ this.logger.groupEnd(() => 'Not resolvable: ' + resolvable.error);
222
+ continue;
223
+ }
224
+ setShortest(path.clone().move(edge), shortestPathPerGraph);
225
+ this.logger.groupEnd(() => 'Resolvable: ' + edge);
226
+ }
227
+ else if (!isFieldTarget && (0, edge_1.isAbstractEdge)(edge)) {
228
+ if (shortestPathPerGraph.has(edge.tail.graphName)) {
229
+ this.logger.groupEnd(() => 'Already found a shorter path to ' + edge.tail);
230
+ continue;
231
+ }
232
+ const newPath = path.clone().move(edge);
233
+ setShortest(newPath, shortestPathPerGraph);
234
+ finalPaths.push(newPath);
235
+ this.logger.groupEnd(() => 'Resolvable');
236
+ }
237
+ else {
238
+ this.logger.groupEnd(() => 'Ignored...');
239
+ }
240
+ }
241
+ }
242
+ this.logger.groupEnd(() => 'Found ' + finalPaths.length + ' indirect paths');
243
+ if (finalPaths.length === 0) {
244
+ return {
245
+ success: false,
246
+ errors,
247
+ paths: undefined,
248
+ };
249
+ }
250
+ return {
251
+ success: true,
252
+ paths: finalPaths,
253
+ errors: undefined,
254
+ };
255
+ }
256
+ }
257
+ exports.PathFinder = PathFinder;
258
+ function setShortest(path, shortestPathPerGraph) {
259
+ const edge = path.edge();
260
+ if (!edge) {
261
+ throw new Error('Unexpected end of path');
262
+ }
263
+ const shortest = shortestPathPerGraph.get(edge.tail.graphName);
264
+ if (!shortest || shortest.depth() > path.depth()) {
265
+ shortestPathPerGraph.set(edge.tail.graphName, path);
266
+ }
267
+ }