@wundergraph/composition 0.46.0 → 0.46.1

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 (58) hide show
  1. package/dist/errors/errors.d.ts +1 -1
  2. package/dist/index.d.ts +4 -1
  3. package/dist/index.js +4 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/resolvability-graph/constants/string-constants.d.ts +8 -0
  6. package/dist/resolvability-graph/constants/string-constants.js +12 -0
  7. package/dist/resolvability-graph/constants/string-constants.js.map +1 -0
  8. package/dist/resolvability-graph/graph-nodes.d.ts +15 -14
  9. package/dist/resolvability-graph/graph-nodes.js +8 -8
  10. package/dist/resolvability-graph/graph-nodes.js.map +1 -1
  11. package/dist/resolvability-graph/graph.d.ts +27 -21
  12. package/dist/resolvability-graph/graph.js +284 -286
  13. package/dist/resolvability-graph/graph.js.map +1 -1
  14. package/dist/resolvability-graph/node-resolution-data/node-resolution-data.d.ts +16 -0
  15. package/dist/resolvability-graph/node-resolution-data/node-resolution-data.js +62 -0
  16. package/dist/resolvability-graph/node-resolution-data/node-resolution-data.js.map +1 -0
  17. package/dist/resolvability-graph/node-resolution-data/types/params.d.ts +9 -0
  18. package/dist/resolvability-graph/node-resolution-data/types/params.js +3 -0
  19. package/dist/resolvability-graph/node-resolution-data/types/params.js.map +1 -0
  20. package/dist/resolvability-graph/types/params.d.ts +22 -0
  21. package/dist/resolvability-graph/types/params.js +3 -0
  22. package/dist/resolvability-graph/types/params.js.map +1 -0
  23. package/dist/resolvability-graph/types/types.d.ts +23 -0
  24. package/dist/resolvability-graph/types/types.js +3 -0
  25. package/dist/resolvability-graph/types/types.js.map +1 -0
  26. package/dist/resolvability-graph/utils/types/params.d.ts +50 -0
  27. package/dist/resolvability-graph/utils/types/params.js +3 -0
  28. package/dist/resolvability-graph/utils/types/params.js.map +1 -0
  29. package/dist/resolvability-graph/utils/types/types.d.ts +16 -0
  30. package/dist/resolvability-graph/utils/types/types.js +3 -0
  31. package/dist/resolvability-graph/utils/types/types.js.map +1 -0
  32. package/dist/resolvability-graph/utils/utils.d.ts +19 -0
  33. package/dist/resolvability-graph/utils/utils.js +230 -0
  34. package/dist/resolvability-graph/utils/utils.js.map +1 -0
  35. package/dist/resolvability-graph/walker/entity-walker/entity-walker.d.ts +21 -0
  36. package/dist/resolvability-graph/walker/entity-walker/entity-walker.js +194 -0
  37. package/dist/resolvability-graph/walker/entity-walker/entity-walker.js.map +1 -0
  38. package/dist/resolvability-graph/walker/entity-walker/types/params.d.ts +40 -0
  39. package/dist/resolvability-graph/walker/entity-walker/types/params.js +3 -0
  40. package/dist/resolvability-graph/walker/entity-walker/types/params.js.map +1 -0
  41. package/dist/resolvability-graph/walker/root-field-walkers/root-field-walker.d.ts +23 -0
  42. package/dist/resolvability-graph/walker/root-field-walkers/root-field-walker.js +250 -0
  43. package/dist/resolvability-graph/walker/root-field-walkers/root-field-walker.js.map +1 -0
  44. package/dist/resolvability-graph/walker/root-field-walkers/types/params.d.ts +38 -0
  45. package/dist/resolvability-graph/walker/root-field-walkers/types/params.js +3 -0
  46. package/dist/resolvability-graph/walker/root-field-walkers/types/params.js.map +1 -0
  47. package/dist/tsconfig.tsbuildinfo +1 -1
  48. package/dist/utils/composition-version.js +1 -1
  49. package/dist/utils/utils.d.ts +1 -1
  50. package/dist/utils/utils.js +2 -2
  51. package/dist/utils/utils.js.map +1 -1
  52. package/dist/v1/federation/federation-factory.js +4 -4
  53. package/dist/v1/federation/federation-factory.js.map +1 -1
  54. package/dist/v1/normalization/normalization-factory.js +1 -1
  55. package/package.json +2 -2
  56. package/dist/resolvability-graph/utils.d.ts +0 -65
  57. package/dist/resolvability-graph/utils.js +0 -143
  58. package/dist/resolvability-graph/utils.js.map +0 -1
@@ -2,25 +2,26 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Graph = void 0;
4
4
  const graph_nodes_1 = require("./graph-nodes");
5
- const utils_1 = require("./utils");
6
- const string_constants_1 = require("../utils/string-constants");
5
+ const utils_1 = require("./utils/utils");
7
6
  const utils_2 = require("../utils/utils");
7
+ const string_constants_1 = require("./constants/string-constants");
8
+ const entity_walker_1 = require("./walker/entity-walker/entity-walker");
9
+ const root_field_walker_1 = require("./walker/root-field-walkers/root-field-walker");
8
10
  class Graph {
9
11
  edgeId = -1;
10
- entityDataNodes = new Map();
11
- entityNodeNamesBySharedFieldPath = new Map();
12
+ entityDataNodeByTypeName = new Map();
12
13
  nodeByNodeName = new Map();
13
14
  nodesByTypeName = new Map();
14
- rootNodeByRootTypeName = new Map();
15
+ resolvedRootFieldNodeNames = new Set();
16
+ rootNodeByTypeName = new Map();
15
17
  subgraphName = string_constants_1.NOT_APPLICABLE;
16
- resolvableFieldNamesByRelativeFieldPathByEntityNodeName = new Map();
17
- nodeResolutionDataByFieldPath = new Map();
18
- unresolvableFieldPaths = new Set();
19
- failureResultByEntityNodeName = new Map();
18
+ resDataByNodeName = new Map();
19
+ resDataByRelativePathByEntity = new Map();
20
+ visitedEntitiesByOriginEntity = new Map();
20
21
  walkerIndex = -1;
21
22
  constructor() { }
22
23
  getRootNode(typeName) {
23
- return (0, utils_2.getValueOrDefault)(this.rootNodeByRootTypeName, typeName, () => new graph_nodes_1.RootNode(typeName));
24
+ return (0, utils_2.getValueOrDefault)(this.rootNodeByTypeName, typeName, () => new graph_nodes_1.RootNode(typeName));
24
25
  }
25
26
  addOrUpdateNode(typeName, options) {
26
27
  const nodeName = `${this.subgraphName}.${typeName}`;
@@ -40,7 +41,7 @@ class Graph {
40
41
  addEdge(headNode, tailNode, fieldName, isAbstractEdge = false) {
41
42
  if (headNode.isRootNode) {
42
43
  const edge = new graph_nodes_1.Edge(this.getNextEdgeId(), tailNode, fieldName);
43
- (0, utils_2.getValueOrDefault)(headNode.headToShareableTailEdges, fieldName, () => []).push(edge);
44
+ (0, utils_2.getValueOrDefault)(headNode.headToSharedTailEdges, fieldName, () => []).push(edge);
44
45
  return edge;
45
46
  }
46
47
  const headGraphNode = headNode;
@@ -49,17 +50,20 @@ class Graph {
49
50
  return headToTailEdge;
50
51
  }
51
52
  addEntityDataNode(typeName) {
52
- const node = this.entityDataNodes.get(typeName);
53
+ const node = this.entityDataNodeByTypeName.get(typeName);
53
54
  if (node) {
54
55
  return node;
55
56
  }
56
57
  const newNode = new graph_nodes_1.EntityDataNode(typeName);
57
- this.entityDataNodes.set(typeName, newNode);
58
+ this.entityDataNodeByTypeName.set(typeName, newNode);
58
59
  return newNode;
59
60
  }
60
61
  getNextEdgeId() {
61
62
  return (this.edgeId += 1);
62
63
  }
64
+ getNextWalkerIndex() {
65
+ return (this.walkerIndex += 1);
66
+ }
63
67
  setNodeInaccessible(typeName) {
64
68
  const nodes = this.nodesByTypeName.get(typeName);
65
69
  if (!nodes) {
@@ -69,12 +73,12 @@ class Graph {
69
73
  node.isInaccessible = true;
70
74
  }
71
75
  }
72
- initializeNode(typeName, fieldDataByFieldName) {
73
- const entityDataNode = this.entityDataNodes.get(typeName);
76
+ initializeNode(typeName, fieldDataByName) {
77
+ const entityDataNode = this.entityDataNodeByTypeName.get(typeName);
74
78
  if (string_constants_1.ROOT_TYPE_NAMES.has(typeName)) {
75
79
  const rootNode = this.getRootNode(typeName);
76
- rootNode.removeInaccessibleEdges(fieldDataByFieldName);
77
- rootNode.fieldDataByFieldName = fieldDataByFieldName;
80
+ rootNode.removeInaccessibleEdges(fieldDataByName);
81
+ rootNode.fieldDataByName = fieldDataByName;
78
82
  return;
79
83
  }
80
84
  const nodes = this.nodesByTypeName.get(typeName);
@@ -82,7 +86,7 @@ class Graph {
82
86
  return;
83
87
  }
84
88
  for (const node of nodes) {
85
- node.fieldDataByFieldName = fieldDataByFieldName;
89
+ node.fieldDataByName = fieldDataByName;
86
90
  node.handleInaccessibleEdges();
87
91
  node.isLeaf = false;
88
92
  if (!entityDataNode) {
@@ -91,7 +95,7 @@ class Graph {
91
95
  node.hasEntitySiblings = true;
92
96
  for (const fieldSet of node.satisfiedFieldSets) {
93
97
  const subgraphNames = entityDataNode.targetSubgraphNamesByFieldSet.get(fieldSet);
94
- for (const subgraphName of subgraphNames || []) {
98
+ for (const subgraphName of subgraphNames ?? []) {
95
99
  // A subgraph should not jump to itself
96
100
  if (subgraphName === node.subgraphName) {
97
101
  continue;
@@ -107,300 +111,294 @@ class Graph {
107
111
  setSubgraphName(subgraphName) {
108
112
  this.subgraphName = subgraphName;
109
113
  }
110
- validateEntities(entityNodeNamesBySharedFieldPath, rootFieldData) {
111
- const nestedEntityNodeNamesBySharedFieldPathByParentNodeName = new Map();
112
- for (const [sharedFieldPath, entityNodeNames] of entityNodeNamesBySharedFieldPath) {
113
- const isFieldShared = entityNodeNames.size > 1;
114
- let failureResult;
115
- /* In the event of a shared entity field, the validation changes slightly.
116
- * The fields are linked through a mutual entity ancestor, and may/may not have additional routing through a key.
117
- * In this case, the following must occur:
118
- * 1. sharedResolvableFieldNamesByRelativeFieldPath will be created and passed to ensure the resolvability of
119
- * paths are assessed collectively, rather than by a single instance of the shared fields
120
- * */
121
- const sharedResolvableFieldNamesByRelativeFieldPath = isFieldShared
122
- ? new Map()
123
- : undefined;
124
- /*
125
- * 2. unresolvableSharedFieldPaths is used to determine whether there are still unresolvable paths even after
126
- * all shared fields have been analysed.
127
- * */
128
- const unresolvableSharedFieldPaths = new Set();
129
- /*
130
- * 3. nestedEntityNodeNamesBySharedFieldPath should be a reference to the same set, to ensure nested shared fields
131
- * are analysed as shared fields when moving deeper.
132
- * */
133
- const sharedNestedEntityNodeNamesBySharedFieldPath = new Map();
134
- for (const entityNodeName of entityNodeNames) {
135
- const entityNode = this.nodeByNodeName.get(entityNodeName);
136
- if (!entityNode) {
137
- throw new Error(`Fatal: Could not find entity node for "${entityNodeName}".`);
138
- }
139
- const resolvableFieldNamesByRelativeFieldPath = this.resolvableFieldNamesByRelativeFieldPathByEntityNodeName.get(entityNodeName);
140
- if (resolvableFieldNamesByRelativeFieldPath) {
141
- // If at least one of the referenced entities is always fully resolvable, the path is resolvable.
142
- const entityFailureResult = this.failureResultByEntityNodeName.get(entityNodeName);
143
- if (!entityFailureResult) {
144
- failureResult = undefined;
145
- break;
146
- }
147
- // If the path is shared, it must be assessed collectively
148
- if (!isFieldShared) {
149
- return entityFailureResult;
150
- }
151
- }
152
- const interSubgraphNodes = this.nodesByTypeName.get(entityNode.typeName) || [];
153
- const nestedEntityNodeNamesBySharedFieldPath = (0, utils_2.getValueOrDefault)(nestedEntityNodeNamesBySharedFieldPathByParentNodeName, entityNodeName, () => (isFieldShared ? sharedNestedEntityNodeNamesBySharedFieldPath : new Map()));
154
- const walker = new Walker({
155
- interSubgraphNodes,
156
- entityNodeNamesBySharedFieldPath: nestedEntityNodeNamesBySharedFieldPath,
157
- originNode: entityNode,
158
- resolvableFieldNamesByRelativeFieldPathByEntityNodeName: this.resolvableFieldNamesByRelativeFieldPathByEntityNodeName,
159
- walkerIndex: (this.walkerIndex += 1),
160
- sharedResolvableFieldNamesByRelativeFieldPath,
161
- unresolvableSharedFieldPaths,
162
- });
163
- walker.visitEntityNode(entityNode);
164
- if (walker.unresolvableFieldPaths.size > 0) {
165
- if (isFieldShared && unresolvableSharedFieldPaths.size < 1) {
166
- failureResult = undefined;
167
- break;
168
- }
169
- failureResult = {
170
- entityAncestorData: {
171
- fieldSetsByTargetSubgraphName: (0, utils_2.getOrThrowError)(this.entityDataNodes, entityNode.typeName, 'entityDataNodes').fieldSetsByTargetSubgraphName,
172
- subgraphName: entityNode.subgraphName,
173
- typeName: entityNode.typeName,
174
- },
175
- nodeName: entityNodeName,
176
- parentFieldPathForEntityReference: [sharedFieldPath],
177
- success: false,
178
- typeName: entityNode.typeName,
179
- unresolvableFieldPaths: isFieldShared ? unresolvableSharedFieldPaths : walker.unresolvableFieldPaths,
180
- };
181
- this.failureResultByEntityNodeName.set(entityNodeName, failureResult);
182
- continue;
183
- }
184
- // In a shared path, only a single instance need succeed
185
- failureResult = undefined;
186
- break;
114
+ visitEntity({ encounteredEntityNodeNames, entityNodeName, relativeOriginPaths, resDataByRelativeOriginPath, subgraphNameByUnresolvablePath, visitedEntities, }) {
115
+ const entityNode = this.nodeByNodeName.get(entityNodeName);
116
+ if (!entityNode) {
117
+ throw new Error(`Fatal: Could not find entity node for "${entityNodeName}".`);
118
+ }
119
+ visitedEntities.add(entityNodeName);
120
+ const interSubgraphNodes = this.nodesByTypeName.get(entityNode.typeName);
121
+ if (!interSubgraphNodes?.length) {
122
+ throw new Error(`Fatal: Could not find any nodes for "${entityNodeName}".`);
123
+ }
124
+ const walker = new entity_walker_1.EntityWalker({
125
+ encounteredEntityNodeNames,
126
+ index: this.getNextWalkerIndex(),
127
+ relativeOriginPaths,
128
+ resDataByNodeName: this.resDataByNodeName,
129
+ resDataByRelativeOriginPath,
130
+ subgraphNameByUnresolvablePath,
131
+ visitedEntities,
132
+ });
133
+ const accessibleEntityNodeNames = entityNode.getAllAccessibleEntityNodeNames();
134
+ for (const siblingEntityNode of interSubgraphNodes) {
135
+ if (siblingEntityNode.nodeName !== entityNode.nodeName &&
136
+ !accessibleEntityNodeNames.has(siblingEntityNode.nodeName)) {
137
+ continue;
187
138
  }
188
- if (failureResult) {
189
- if (isFieldShared && sharedResolvableFieldNamesByRelativeFieldPath) {
190
- this.resolvableFieldNamesByRelativeFieldPathByEntityNodeName.set(failureResult.nodeName, sharedResolvableFieldNamesByRelativeFieldPath);
191
- }
192
- return failureResult;
139
+ const { areDescendantsResolved } = walker.visitEntityDescendantConcreteNode({
140
+ node: siblingEntityNode,
141
+ selectionPath: '',
142
+ });
143
+ // All fields and descendent fields are resolved; nothing more to do for this entity.
144
+ if (areDescendantsResolved) {
145
+ return;
193
146
  }
194
147
  }
195
- if (nestedEntityNodeNamesBySharedFieldPathByParentNodeName.size > 0) {
196
- for (const [parentNodeName, fieldPathsByNestedNodeName,] of nestedEntityNodeNamesBySharedFieldPathByParentNodeName) {
197
- const result = this.validateEntities(fieldPathsByNestedNodeName, rootFieldData);
198
- if (result.success) {
199
- continue;
200
- }
201
- for (const [sharedFieldPath, entityNodeNames] of entityNodeNamesBySharedFieldPath) {
202
- if (!entityNodeNames.has(parentNodeName)) {
203
- continue;
204
- }
205
- result.parentFieldPathForEntityReference.push(sharedFieldPath);
206
- break;
207
- }
208
- return result;
209
- }
148
+ // Because of shared entity descendant paths, we can only assess the errors after checking all nested entities.
149
+ for (const [nestedEntityNodeName, selectionPath] of walker.selectionPathByEntityNodeName) {
150
+ /* Short circuiting on failures here can cause false positives.
151
+ * For example, an Object that is an entity at least one graph and defines at least one unique (nested) field.
152
+ * If that Object has no accessible keys but is accessible through an ancestor, short-circuiting here would
153
+ * produce an error before that shared path has been visited.
154
+ */
155
+ this.visitEntity({
156
+ encounteredEntityNodeNames,
157
+ entityNodeName: nestedEntityNodeName,
158
+ relativeOriginPaths: (0, utils_1.getMultipliedRelativeOriginPaths)({
159
+ relativeOriginPaths,
160
+ selectionPath: selectionPath,
161
+ }),
162
+ resDataByRelativeOriginPath,
163
+ subgraphNameByUnresolvablePath,
164
+ visitedEntities,
165
+ });
210
166
  }
211
- return { success: true };
212
167
  }
213
168
  validate() {
214
- const errors = [];
215
- for (const rootNode of this.rootNodeByRootTypeName.values()) {
216
- shareableRootFieldLoop: for (const [rootFieldName, shareableRootFieldEdges,] of rootNode.headToShareableTailEdges) {
217
- for (const rootFieldEdge of shareableRootFieldEdges) {
218
- if (rootFieldEdge.isInaccessible) {
219
- continue shareableRootFieldLoop;
169
+ for (const rootNode of this.rootNodeByTypeName.values()) {
170
+ for (const [rootFieldName, sharedRootFieldEdges] of rootNode.headToSharedTailEdges) {
171
+ const isSharedRootField = sharedRootFieldEdges.length > 1;
172
+ if (!isSharedRootField) {
173
+ const namedTypeNodeName = sharedRootFieldEdges[0].node.nodeName;
174
+ if (this.resolvedRootFieldNodeNames.has(namedTypeNodeName)) {
175
+ continue;
220
176
  }
221
- this.walkerIndex += 1;
222
- this.visitEdge(rootFieldEdge, `${rootNode.typeName.toLowerCase()}`);
177
+ this.resolvedRootFieldNodeNames.add(namedTypeNodeName);
223
178
  }
224
- const fieldData = (0, utils_2.getOrThrowError)(rootNode.fieldDataByFieldName, rootFieldName, 'fieldDataByFieldName');
225
- const rootFieldData = (0, utils_1.newRootFieldData)(rootNode.typeName, rootFieldName, fieldData.subgraphNames);
226
- if (this.unresolvableFieldPaths.size > 0) {
227
- (0, utils_1.generateResolvabilityErrors)({
228
- unresolvableFieldPaths: this.unresolvableFieldPaths,
229
- nodeResolutionDataByFieldPath: this.nodeResolutionDataByFieldPath,
230
- rootFieldData,
231
- errors,
232
- });
179
+ const rootFieldWalker = new root_field_walker_1.RootFieldWalker({
180
+ index: this.getNextWalkerIndex(),
181
+ nodeResolutionDataByNodeName: this.resDataByNodeName,
182
+ });
183
+ if (rootFieldWalker.visitRootFieldEdges({
184
+ edges: sharedRootFieldEdges,
185
+ rootTypeName: rootNode.typeName.toLowerCase(),
186
+ }).areDescendantsResolved) {
187
+ continue;
233
188
  }
234
- if (this.entityNodeNamesBySharedFieldPath.size > 0) {
235
- const result = this.validateEntities(this.entityNodeNamesBySharedFieldPath, rootFieldData);
236
- if (!result.success) {
237
- this.generateEntityResolvabilityErrors(result, rootFieldData, errors);
238
- }
189
+ const involvesEntities = isSharedRootField
190
+ ? rootFieldWalker.entityNodeNamesByPath.size > 0
191
+ : rootFieldWalker.pathsByEntityNodeName.size > 0;
192
+ if (rootFieldWalker.unresolvablePaths.size < 1 && !involvesEntities) {
193
+ continue;
239
194
  }
240
- if (errors.length > 0) {
241
- return errors;
195
+ const fieldData = (0, utils_2.getOrThrowError)(rootNode.fieldDataByName, rootFieldName, 'fieldDataByName');
196
+ const rootFieldData = (0, utils_1.newRootFieldData)(rootNode.typeName, rootFieldName, fieldData.subgraphNames);
197
+ // If there are no nested entities, then the unresolvable fields must be impossible to resolve.
198
+ if (!involvesEntities) {
199
+ return {
200
+ errors: (0, utils_1.generateRootResolvabilityErrors)({
201
+ unresolvablePaths: rootFieldWalker.unresolvablePaths,
202
+ resDataByPath: rootFieldWalker.resDataByPath,
203
+ rootFieldData,
204
+ }),
205
+ success: false,
206
+ };
207
+ }
208
+ const result = this.validateEntities({ isSharedRootField, rootFieldData, walker: rootFieldWalker });
209
+ if (!result.success) {
210
+ return result;
242
211
  }
243
- this.entityNodeNamesBySharedFieldPath = new Map();
244
212
  }
245
213
  }
246
- return [];
214
+ return {
215
+ success: true,
216
+ };
247
217
  }
248
- // Returns true if the edge is visited and false otherwise (e.g., inaccessible)
249
- visitEdge(edge, fieldPath) {
250
- if (edge.isInaccessible || edge.node.isInaccessible) {
251
- return false;
252
- }
253
- if (!(0, utils_2.add)(edge.visitedIndices, this.walkerIndex) || edge.node.isLeaf) {
254
- return true;
255
- }
256
- if (edge.node.isAbstract) {
257
- this.validateAbstractNode(edge.node, `${fieldPath}.${edge.edgeName}`);
258
- }
259
- else {
260
- this.validateConcreteNode(edge.node, `${fieldPath}.${edge.edgeName}`);
261
- }
262
- return true;
263
- }
264
- validateConcreteNode(node, fieldPath) {
265
- if (node.headToTailEdges.size < 1) {
266
- return;
267
- }
268
- if (node.hasEntitySiblings) {
269
- (0, utils_2.getValueOrDefault)(this.entityNodeNamesBySharedFieldPath, fieldPath, () => new Set()).add(node.nodeName);
270
- return;
271
- }
272
- const resolvedFieldNames = (0, utils_2.getValueOrDefault)(this.nodeResolutionDataByFieldPath, fieldPath, () => new utils_1.NodeResolutionData(node.typeName, node.fieldDataByFieldName));
273
- for (const [fieldName, edge] of node.headToTailEdges) {
274
- // Returns true if the edge was visited
275
- if (this.visitEdge(edge, fieldPath)) {
276
- resolvedFieldNames.add(fieldName);
218
+ consolidateUnresolvableRootWithEntityPaths({ pathFromRoot, resDataByRelativeOriginPath, subgraphNameByUnresolvablePath, walker, }) {
219
+ for (const unresolvableRootPath of walker.unresolvablePaths) {
220
+ if (!unresolvableRootPath.startsWith(pathFromRoot)) {
221
+ continue;
277
222
  }
278
- }
279
- if (resolvedFieldNames.isResolved) {
280
- this.unresolvableFieldPaths.delete(fieldPath);
281
- }
282
- else {
283
- this.unresolvableFieldPaths.add(fieldPath);
284
- }
285
- }
286
- validateAbstractNode(node, fieldPath) {
287
- if (node.headToTailEdges.size < 1) {
288
- return;
289
- }
290
- for (const edge of node.headToTailEdges.values()) {
291
- this.visitEdge(edge, fieldPath);
223
+ const relativePath = unresolvableRootPath.slice(pathFromRoot.length);
224
+ const rootResData = (0, utils_2.getOrThrowError)(walker.resDataByPath, unresolvableRootPath, `rootFieldWalker.unresolvablePaths`);
225
+ const entityResData = resDataByRelativeOriginPath.get(relativePath);
226
+ if (!entityResData) {
227
+ continue;
228
+ }
229
+ rootResData.addData(entityResData);
230
+ entityResData.addData(rootResData);
231
+ if (!rootResData.isResolved()) {
232
+ // Delete the root path so that the error only propagates once through the entity.
233
+ walker.unresolvablePaths.delete(unresolvableRootPath);
234
+ continue;
235
+ }
236
+ walker.unresolvablePaths.delete(unresolvableRootPath);
237
+ subgraphNameByUnresolvablePath.delete(relativePath);
292
238
  }
293
239
  }
294
- generateEntityResolvabilityErrors(result, rootFieldData, errors) {
295
- const nodeResolutionDataByFieldPath = (0, utils_2.getOrThrowError)(this.resolvableFieldNamesByRelativeFieldPathByEntityNodeName, result.nodeName, 'resolvableFieldNamesByRelativeFieldPathByEntityNodeName');
296
- let pathFromRoot = '';
297
- // Reconstruct the path
298
- for (const fieldPath of result.parentFieldPathForEntityReference) {
299
- pathFromRoot = fieldPath + pathFromRoot;
240
+ consolidateUnresolvableEntityWithRootPaths({ pathFromRoot, resDataByRelativeOriginPath, subgraphNameByUnresolvablePath, walker, }) {
241
+ for (const unresolvableEntityPath of subgraphNameByUnresolvablePath.keys()) {
242
+ const entityResData = (0, utils_2.getOrThrowError)(resDataByRelativeOriginPath, unresolvableEntityPath, `resDataByRelativeOriginPath`);
243
+ const fullPath = `${pathFromRoot}${unresolvableEntityPath}`;
244
+ const rootResData = (0, utils_2.getOrThrowError)(walker.resDataByPath, fullPath, `rootFieldWalker.resDataByPath`);
245
+ entityResData.addData(rootResData);
246
+ rootResData.addData(entityResData);
247
+ if (!entityResData.isResolved()) {
248
+ continue;
249
+ }
250
+ subgraphNameByUnresolvablePath.delete(unresolvableEntityPath);
300
251
  }
301
- (0, utils_1.generateResolvabilityErrors)({
302
- unresolvableFieldPaths: result.unresolvableFieldPaths,
303
- nodeResolutionDataByFieldPath,
304
- rootFieldData: rootFieldData,
305
- errors,
306
- pathFromRoot,
307
- entityAncestorData: result.entityAncestorData,
308
- });
309
252
  }
310
- }
311
- exports.Graph = Graph;
312
- class Walker {
313
- entityNodeNamesBySharedFieldPath;
314
- interSubgraphNodes;
315
- originNode;
316
- resolvableFieldNamesByRelativeFieldPath;
317
- resolvableFieldNamesByRelativeFieldPathByEntityNodeName;
318
- unresolvableFieldPaths = new Set();
319
- unresolvableSharedFieldPaths;
320
- walkerIndex;
321
- sharedResolvableFieldNamesByRelativeFieldPath;
322
- constructor({ entityNodeNamesBySharedFieldPath, interSubgraphNodes, originNode, resolvableFieldNamesByRelativeFieldPathByEntityNodeName, unresolvableSharedFieldPaths, walkerIndex, sharedResolvableFieldNamesByRelativeFieldPath, }) {
323
- this.entityNodeNamesBySharedFieldPath = entityNodeNamesBySharedFieldPath;
324
- this.interSubgraphNodes = interSubgraphNodes;
325
- this.originNode = originNode;
326
- this.resolvableFieldNamesByRelativeFieldPathByEntityNodeName =
327
- resolvableFieldNamesByRelativeFieldPathByEntityNodeName;
328
- this.resolvableFieldNamesByRelativeFieldPath = (0, utils_2.getValueOrDefault)(this.resolvableFieldNamesByRelativeFieldPathByEntityNodeName, originNode.nodeName, () => new Map());
329
- this.unresolvableSharedFieldPaths = unresolvableSharedFieldPaths;
330
- this.walkerIndex = walkerIndex;
331
- this.sharedResolvableFieldNamesByRelativeFieldPath = sharedResolvableFieldNamesByRelativeFieldPath;
253
+ validateSharedRootFieldEntities({ rootFieldData, walker }) {
254
+ for (const [pathFromRoot, entityNodeNames] of walker.entityNodeNamesByPath) {
255
+ const subgraphNameByUnresolvablePath = new Map();
256
+ // Shared fields are unique contexts, so the resolution data cannot be reused.
257
+ const resDataByRelativeOriginPath = new Map();
258
+ /* The entity nodes are connected through the root (and not necessarily through a key), so all origins must be
259
+ * explored before an error can be propagated with certainty.
260
+ * */
261
+ for (const entityNodeName of entityNodeNames) {
262
+ this.visitEntity({
263
+ encounteredEntityNodeNames: new Set(),
264
+ entityNodeName,
265
+ resDataByRelativeOriginPath: resDataByRelativeOriginPath,
266
+ subgraphNameByUnresolvablePath,
267
+ visitedEntities: new Set(),
268
+ });
269
+ }
270
+ /* There might be root errors that rely on entity data propagation.
271
+ * Always propagate entity resolution data to the root data before moving on.
272
+ * */
273
+ this.consolidateUnresolvableRootWithEntityPaths({
274
+ pathFromRoot,
275
+ resDataByRelativeOriginPath,
276
+ subgraphNameByUnresolvablePath,
277
+ walker,
278
+ });
279
+ if (subgraphNameByUnresolvablePath.size < 1) {
280
+ continue;
281
+ }
282
+ this.consolidateUnresolvableEntityWithRootPaths({
283
+ pathFromRoot,
284
+ resDataByRelativeOriginPath,
285
+ subgraphNameByUnresolvablePath,
286
+ walker,
287
+ });
288
+ const errors = new Array();
289
+ if (subgraphNameByUnresolvablePath.size > 0) {
290
+ errors.push(...this.getSharedEntityResolvabilityErrors({
291
+ entityNodeNames,
292
+ resDataByPath: resDataByRelativeOriginPath,
293
+ pathFromRoot,
294
+ rootFieldData,
295
+ subgraphNameByUnresolvablePath,
296
+ }));
297
+ }
298
+ if (walker.unresolvablePaths.size > 0) {
299
+ errors.push(...(0, utils_1.generateRootResolvabilityErrors)({
300
+ unresolvablePaths: walker.unresolvablePaths,
301
+ resDataByPath: walker.resDataByPath,
302
+ rootFieldData,
303
+ }));
304
+ }
305
+ if (errors.length < 1) {
306
+ continue;
307
+ }
308
+ return {
309
+ errors,
310
+ success: false,
311
+ };
312
+ }
313
+ if (walker.unresolvablePaths.size > 0) {
314
+ return {
315
+ errors: (0, utils_1.generateRootResolvabilityErrors)({
316
+ resDataByPath: walker.resDataByPath,
317
+ rootFieldData,
318
+ unresolvablePaths: walker.unresolvablePaths,
319
+ }),
320
+ success: false,
321
+ };
322
+ }
323
+ return {
324
+ success: true,
325
+ };
332
326
  }
333
- visitEntityNode(node) {
334
- this.validateEntityRelatedConcreteNode(node, '');
335
- const accessibleEntityNodeNames = node.getAllAccessibleEntityNodeNames();
336
- for (const sibling of this.interSubgraphNodes) {
337
- if (this.unresolvableFieldPaths.size < 0) {
338
- return;
327
+ validateRootFieldEntities({ rootFieldData, walker }) {
328
+ for (const [entityNodeName, entityPaths] of walker.pathsByEntityNodeName) {
329
+ const subgraphNameByUnresolvablePath = new Map();
330
+ if (this.resDataByNodeName.has(entityNodeName)) {
331
+ continue;
339
332
  }
340
- if (!accessibleEntityNodeNames.has(sibling.nodeName)) {
333
+ const resDataByRelativeOriginPath = (0, utils_2.getValueOrDefault)(this.resDataByRelativePathByEntity, entityNodeName, () => new Map());
334
+ this.visitEntity({
335
+ encounteredEntityNodeNames: new Set(),
336
+ entityNodeName,
337
+ resDataByRelativeOriginPath: resDataByRelativeOriginPath,
338
+ subgraphNameByUnresolvablePath,
339
+ visitedEntities: (0, utils_2.getValueOrDefault)(this.visitedEntitiesByOriginEntity, entityNodeName, () => new Set()),
340
+ });
341
+ if (subgraphNameByUnresolvablePath.size < 1) {
341
342
  continue;
342
343
  }
343
- this.validateEntityRelatedConcreteNode(sibling, '');
344
- }
344
+ return {
345
+ errors: this.getEntityResolvabilityErrors({
346
+ entityNodeName,
347
+ // Propagate errors for the first encounter only.
348
+ pathFromRoot: (0, utils_2.getFirstEntry)(entityPaths) ?? '',
349
+ rootFieldData,
350
+ subgraphNameByUnresolvablePath,
351
+ }),
352
+ success: false,
353
+ };
354
+ }
355
+ return {
356
+ success: true,
357
+ };
345
358
  }
346
- // Returns true if the edge is visited and false if it's inaccessible
347
- visitEntityRelatedEdge(edge, fieldPath) {
348
- if (edge.isInaccessible || edge.node.isInaccessible) {
349
- return false;
350
- }
351
- if (!(0, utils_2.add)(edge.visitedIndices, this.walkerIndex) || edge.node.isLeaf) {
352
- return true;
353
- }
354
- if (edge.node.hasEntitySiblings) {
355
- (0, utils_2.getValueOrDefault)(this.entityNodeNamesBySharedFieldPath, `${fieldPath}.${edge.edgeName}`, () => new Set()).add(edge.node.nodeName);
356
- return true;
357
- }
358
- if (edge.node.isAbstract) {
359
- this.validateEntityRelatedAbstractNode(edge.node, `${fieldPath}.${edge.edgeName}`);
359
+ validateEntities(params) {
360
+ if (params.isSharedRootField) {
361
+ return this.validateSharedRootFieldEntities(params);
360
362
  }
361
- else {
362
- this.validateEntityRelatedConcreteNode(edge.node, `${fieldPath}.${edge.edgeName}`);
363
- }
364
- return true;
363
+ return this.validateRootFieldEntities(params);
365
364
  }
366
- validateEntityRelatedConcreteNode(node, fieldPath) {
367
- if (node.headToTailEdges.size < 1) {
368
- return;
369
- }
370
- const originResolvedFieldNames = (0, utils_2.getValueOrDefault)(this.resolvableFieldNamesByRelativeFieldPath, fieldPath, () => new utils_1.NodeResolutionData(node.typeName, node.fieldDataByFieldName));
371
- const sharedResolvedFieldNames = this.sharedResolvableFieldNamesByRelativeFieldPath
372
- ? (0, utils_2.getValueOrDefault)(this.sharedResolvableFieldNamesByRelativeFieldPath, fieldPath, () => new utils_1.NodeResolutionData(node.typeName, node.fieldDataByFieldName))
373
- : undefined;
374
- for (const [fieldName, edge] of node.headToTailEdges) {
375
- // Returns true if the edge is visited
376
- if (this.visitEntityRelatedEdge(edge, fieldPath)) {
377
- originResolvedFieldNames.add(fieldName);
378
- sharedResolvedFieldNames?.add(fieldName);
379
- }
380
- }
381
- if (originResolvedFieldNames.isResolved) {
382
- this.unresolvableFieldPaths.delete(fieldPath);
383
- }
384
- else {
385
- this.unresolvableFieldPaths.add(fieldPath);
386
- }
387
- if (!sharedResolvedFieldNames) {
388
- return;
389
- }
390
- if (sharedResolvedFieldNames.isResolved) {
391
- this.unresolvableSharedFieldPaths.delete(fieldPath);
392
- }
393
- else {
394
- this.unresolvableSharedFieldPaths.add(fieldPath);
395
- }
365
+ getEntityResolvabilityErrors({ entityNodeName, pathFromRoot, rootFieldData, subgraphNameByUnresolvablePath, }) {
366
+ const nodeResolutionDataByFieldPath = (0, utils_2.getOrThrowError)(this.resDataByRelativePathByEntity, entityNodeName, 'resDataByRelativePathByEntity');
367
+ const entityTypeName = entityNodeName.split(string_constants_1.LITERAL_PERIOD)[1];
368
+ const { fieldSetsByTargetSubgraphName } = (0, utils_2.getOrThrowError)(this.entityDataNodeByTypeName, entityTypeName, 'entityDataNodeByTypeName');
369
+ return (0, utils_1.generateEntityResolvabilityErrors)({
370
+ entityAncestorData: {
371
+ fieldSetsByTargetSubgraphName,
372
+ subgraphName: '',
373
+ typeName: entityTypeName,
374
+ },
375
+ pathFromRoot,
376
+ resDataByPath: nodeResolutionDataByFieldPath,
377
+ rootFieldData: rootFieldData,
378
+ subgraphNameByUnresolvablePath,
379
+ });
396
380
  }
397
- validateEntityRelatedAbstractNode(node, fieldPath) {
398
- if (node.headToTailEdges.size < 1) {
399
- return;
400
- }
401
- for (const edge of node.headToTailEdges.values()) {
402
- this.visitEntityRelatedEdge(edge, fieldPath);
403
- }
381
+ getSharedEntityResolvabilityErrors({ entityNodeNames, pathFromRoot, rootFieldData, resDataByPath, subgraphNameByUnresolvablePath, }) {
382
+ let entityTypeName = undefined;
383
+ const subgraphNames = new Array();
384
+ for (const entityNodeName of entityNodeNames) {
385
+ const segments = entityNodeName.split(string_constants_1.LITERAL_PERIOD);
386
+ entityTypeName ??= segments[1];
387
+ subgraphNames.push(segments[0]);
388
+ }
389
+ const { fieldSetsByTargetSubgraphName } = (0, utils_2.getOrThrowError)(this.entityDataNodeByTypeName, entityTypeName, 'entityDataNodeByTypeName');
390
+ return (0, utils_1.generateSharedEntityResolvabilityErrors)({
391
+ entityAncestors: {
392
+ fieldSetsByTargetSubgraphName,
393
+ subgraphNames,
394
+ typeName: entityTypeName,
395
+ },
396
+ pathFromRoot,
397
+ resDataByPath,
398
+ rootFieldData: rootFieldData,
399
+ subgraphNameByUnresolvablePath,
400
+ });
404
401
  }
405
402
  }
403
+ exports.Graph = Graph;
406
404
  //# sourceMappingURL=graph.js.map