@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,675 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Graph = void 0;
4
+ const graphql_1 = require("graphql");
5
+ const state_1 = require("../../../../utils/state");
6
+ const constants_1 = require("./constants");
7
+ const edge_1 = require("./edge");
8
+ const helpers_1 = require("./helpers");
9
+ const moves_1 = require("./moves");
10
+ const node_1 = require("./node");
11
+ class Graph {
12
+ name;
13
+ supergraphState;
14
+ fieldsResolver;
15
+ ignoreInaccessible;
16
+ _warnedAboutIncorrectEdge = false;
17
+ nodesByTypeIndex = [];
18
+ edgesByHeadTypeIndex = [];
19
+ edgesByTailTypeIndex = [];
20
+ typeNameToNodeIndexes = new Map();
21
+ typeChildren = [];
22
+ typeChildrenCache = new Map();
23
+ isSubgraph;
24
+ logger;
25
+ id;
26
+ idSymbol;
27
+ constructor(logger, id, name, supergraphState, fieldsResolver, ignoreInaccessible = false) {
28
+ this.name = name;
29
+ this.supergraphState = supergraphState;
30
+ this.fieldsResolver = fieldsResolver;
31
+ this.ignoreInaccessible = ignoreInaccessible;
32
+ this.logger = logger.create('Graph');
33
+ if (typeof id === 'string') {
34
+ this.idSymbol = Symbol.for(id);
35
+ this.id = id;
36
+ this.isSubgraph = true;
37
+ }
38
+ else {
39
+ this.idSymbol = id;
40
+ this.id = id.toString();
41
+ this.isSubgraph = this.idSymbol !== constants_1.SUPERGRAPH_ID;
42
+ }
43
+ }
44
+ addUnreachableTypes() {
45
+ if (!this.isSupergraph()) {
46
+ for (const [typeName, state] of this.supergraphState.objectTypes) {
47
+ if (state.byGraph.has(this.id)) {
48
+ this.createNodesAndEdgesForType(typeName);
49
+ }
50
+ }
51
+ for (const [typeName, state] of this.supergraphState.scalarTypes) {
52
+ if (state.byGraph.has(this.id)) {
53
+ this.createNodeForScalarType(typeName);
54
+ }
55
+ }
56
+ for (const [_, state] of this.supergraphState.enumTypes) {
57
+ if (state.byGraph.has(this.id)) {
58
+ this.createNodeForEnumType(state);
59
+ }
60
+ }
61
+ for (const [_, state] of this.supergraphState.unionTypes) {
62
+ if (state.byGraph.has(this.id)) {
63
+ this.createNodeForUnionType(state);
64
+ }
65
+ }
66
+ for (const [_, state] of this.supergraphState.interfaceTypes) {
67
+ if (state.byGraph.has(this.id)) {
68
+ this.createNodeForInterfaceType(state);
69
+ }
70
+ }
71
+ }
72
+ return this;
73
+ }
74
+ addFromRoots() {
75
+ for (const typeName of ['Query', 'Mutation', 'Subscription']) {
76
+ const typeState = this.supergraphState.objectTypes.get(typeName);
77
+ if (typeState && this.trueOrIfSubgraphThen(() => typeState.byGraph.has(this.id))) {
78
+ this.createNodesAndEdgesForType(typeState.name);
79
+ }
80
+ }
81
+ return this;
82
+ }
83
+ addFromEntities() {
84
+ for (const typeState of this.supergraphState.objectTypes.values()) {
85
+ if (typeState?.isEntity && this.trueOrIfSubgraphThen(() => typeState.byGraph.has(this.id))) {
86
+ this.createNodesAndEdgesForType(typeState.name);
87
+ }
88
+ }
89
+ return this;
90
+ }
91
+ addSubgraph(graph) {
92
+ for (const node of graph.nodesByTypeIndex.flat()) {
93
+ this.addNode(node.withoutState());
94
+ }
95
+ for (const edges of graph.edgesByHeadTypeIndex) {
96
+ for (const edge of edges) {
97
+ this.addEdge(edge);
98
+ }
99
+ }
100
+ }
101
+ connectUnionOrInterface(nodeIndex, sameTypeNameNodeIndexes, edgesToAdd) {
102
+ for (const headNode of this.nodesByTypeIndex[nodeIndex]) {
103
+ const edges = this.edgesOfTail(headNode);
104
+ if (edges.length === 0) {
105
+ continue;
106
+ }
107
+ for (const otherNodeIndex of sameTypeNameNodeIndexes) {
108
+ if (nodeIndex === otherNodeIndex) {
109
+ continue;
110
+ }
111
+ for (const tailNode of this.nodesByTypeIndex[otherNodeIndex]) {
112
+ if (headNode === tailNode) {
113
+ continue;
114
+ }
115
+ for (const edge of edges) {
116
+ edgesToAdd.push(new edge_1.Edge(edge.head, edge.move, tailNode));
117
+ }
118
+ }
119
+ }
120
+ }
121
+ }
122
+ connectEntities(nodeIndex, sameTypeNameNodeIndexes, edgesToAdd) {
123
+ for (const headNode of this.nodesByTypeIndex[nodeIndex]) {
124
+ for (const otherNodeIndex of sameTypeNameNodeIndexes) {
125
+ if (nodeIndex === otherNodeIndex) {
126
+ continue;
127
+ }
128
+ for (const tailNode of this.nodesByTypeIndex[otherNodeIndex]) {
129
+ if (!(tailNode.typeState && 'isEntity' in tailNode.typeState && tailNode.typeState.isEntity)) {
130
+ continue;
131
+ }
132
+ const typeStateInGraph = tailNode.typeState.byGraph.get(tailNode.graphId);
133
+ const keys = (typeStateInGraph?.keys ?? [])
134
+ .slice()
135
+ .sort((a, b) => (0, helpers_1.scoreKeyFields)(a.fields) - (0, helpers_1.scoreKeyFields)(b.fields));
136
+ for (const key of keys) {
137
+ if (key.resolvable) {
138
+ edgesToAdd.push(new edge_1.Edge(headNode, new moves_1.EntityMove(this.fieldsResolver.resolve(headNode.typeName, key.fields)), tailNode));
139
+ }
140
+ }
141
+ }
142
+ }
143
+ }
144
+ }
145
+ addProvidedInterfaceFields(head, providedFields, queue) {
146
+ const abstractIndexes = head.getAbstractEdgeIndexes(head.typeName);
147
+ if (!abstractIndexes || abstractIndexes.length === 0) {
148
+ throw new Error('Expected abstract indexes to be defined');
149
+ }
150
+ const interfaceFields = [];
151
+ const fieldsByType = new Map();
152
+ for (const providedField of providedFields) {
153
+ if (providedField.typeName === head.typeName) {
154
+ interfaceFields.push(providedField);
155
+ continue;
156
+ }
157
+ const existing = fieldsByType.get(providedField.typeName);
158
+ if (existing) {
159
+ existing.push(providedField);
160
+ }
161
+ else {
162
+ fieldsByType.set(providedField.typeName, [providedField]);
163
+ }
164
+ }
165
+ for (const [typeName, providedFields] of fieldsByType) {
166
+ let edgeIndex;
167
+ let edge;
168
+ for (let i = 0; i < abstractIndexes.length; i++) {
169
+ const index = abstractIndexes[i];
170
+ const potentialEdge = this.edgesByHeadTypeIndex[head.index][index];
171
+ if (!potentialEdge) {
172
+ throw new Error('Expected edge to be defined');
173
+ }
174
+ if (potentialEdge.tail.typeName === typeName) {
175
+ edgeIndex = index;
176
+ edge = potentialEdge;
177
+ break;
178
+ }
179
+ }
180
+ if (typeof edgeIndex === 'undefined' || !edge) {
181
+ throw new Error(`Expected an abstract edge matching "${typeName}" to be defined`);
182
+ }
183
+ const newTail = this.duplicateNode(edge.tail);
184
+ const newEdge = new edge_1.Edge(edge.head, edge.move, newTail);
185
+ this.replaceEdgeAt(edge.head.index, edge.tail.index, newEdge, edgeIndex);
186
+ queue.push({
187
+ head: newTail,
188
+ providedFields,
189
+ });
190
+ }
191
+ if (!interfaceFields.length) {
192
+ return;
193
+ }
194
+ for (const index of abstractIndexes) {
195
+ const edge = this.edgesByHeadTypeIndex[head.index][index];
196
+ if (!edge) {
197
+ throw new Error('Expected edge to be defined');
198
+ }
199
+ (0, edge_1.assertAbstractEdge)(edge);
200
+ if (edge.isCrossGraphEdge()) {
201
+ continue;
202
+ }
203
+ const newTail = this.duplicateNode(edge.tail);
204
+ const newEdge = new edge_1.Edge(edge.head, new moves_1.AbstractMove(), newTail);
205
+ this.replaceEdgeAt(edge.head.index, edge.tail.index, newEdge, index);
206
+ queue.push({
207
+ head: newTail,
208
+ providedFields: interfaceFields.map(f => ({
209
+ ...f,
210
+ typeName: newTail.typeName,
211
+ })),
212
+ });
213
+ }
214
+ }
215
+ addProvidedField(head, providedField, queue) {
216
+ if (providedField.fieldName === '__typename') {
217
+ return;
218
+ }
219
+ const indexes = head.getFieldEdgeIndexes(providedField.fieldName);
220
+ if (!indexes || indexes.length === 0) {
221
+ if (head.typeState?.kind === 'object') {
222
+ throw new Error('Expected indexes to be defined: ' +
223
+ providedField.typeName +
224
+ '.' +
225
+ providedField.fieldName);
226
+ }
227
+ else {
228
+ throw new Error(`Expected ${providedField.typeName}.${providedField.fieldName} to be point to an object type, other kinds are not supported (received: ${head.typeState?.kind})`);
229
+ }
230
+ }
231
+ for (const index of indexes) {
232
+ const edge = this.edgesByHeadTypeIndex[head.index][index];
233
+ if (!edge) {
234
+ throw new Error('Expected edge to be defined');
235
+ }
236
+ (0, edge_1.assertFieldEdge)(edge);
237
+ if (edge.isCrossGraphEdge()) {
238
+ continue;
239
+ }
240
+ const newTail = this.duplicateNode(edge.tail);
241
+ const newEdge = new edge_1.Edge(edge.head, new moves_1.FieldMove(edge.move.typeName, edge.move.fieldName, edge.move.requires, edge.move.provides, true), newTail);
242
+ this.replaceEdgeAt(edge.head.index, edge.tail.index, newEdge, index);
243
+ if (providedField.selectionSet) {
244
+ queue.push({
245
+ head: newTail,
246
+ providedFields: providedField.selectionSet,
247
+ });
248
+ }
249
+ }
250
+ }
251
+ joinSubgraphs() {
252
+ const edgesToAdd = [];
253
+ for (let i = 0; i < this.nodesByTypeIndex.length; i++) {
254
+ const typeNode = this.nodesByTypeIndex[i][0];
255
+ if (!typeNode.typeState) {
256
+ continue;
257
+ }
258
+ const otherNodesIndexes = this.getIndexesOfType(typeNode.typeName);
259
+ if (!Array.isArray(otherNodesIndexes)) {
260
+ continue;
261
+ }
262
+ if (typeNode.typeState?.kind === 'object' && typeNode.typeState?.isEntity) {
263
+ this.connectEntities(i, otherNodesIndexes, edgesToAdd);
264
+ }
265
+ else if (typeNode.typeState.kind === 'union' || typeNode.typeState.kind === 'interface') {
266
+ this.connectUnionOrInterface(i, otherNodesIndexes, edgesToAdd);
267
+ }
268
+ }
269
+ while (edgesToAdd.length > 0) {
270
+ const edge = edgesToAdd.pop();
271
+ if (!edge) {
272
+ throw new Error('Expected edge to be defined');
273
+ }
274
+ this.addEdge(edge);
275
+ }
276
+ for (let headIndex = 0; headIndex < this.edgesByHeadTypeIndex.length; headIndex++) {
277
+ const edges = this.edgesByHeadTypeIndex[headIndex];
278
+ for (let edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
279
+ const edge = edges[edgeIndex];
280
+ if (edge.isCrossGraphEdge()) {
281
+ continue;
282
+ }
283
+ if (!((0, edge_1.isFieldEdge)(edge) && edge.move.provides)) {
284
+ continue;
285
+ }
286
+ const newTail = this.duplicateNode(edge.tail);
287
+ const newEdge = new edge_1.Edge(edge.head, edge.move, newTail);
288
+ this.replaceEdgeAt(headIndex, edge.tail.index, newEdge, edgeIndex);
289
+ const queue = [
290
+ {
291
+ head: newTail,
292
+ providedFields: edge.move.provides.fields,
293
+ },
294
+ ];
295
+ while (queue.length > 0) {
296
+ const item = queue.pop();
297
+ if (!item) {
298
+ throw new Error('Expected item to be defined');
299
+ }
300
+ const { head, providedFields } = item;
301
+ if (head.typeState?.kind === 'interface') {
302
+ this.addProvidedInterfaceFields(head, providedFields, queue);
303
+ continue;
304
+ }
305
+ for (const providedField of providedFields) {
306
+ this.addProvidedField(head, providedField, queue);
307
+ }
308
+ }
309
+ }
310
+ }
311
+ return this;
312
+ }
313
+ duplicateNode(originalNode) {
314
+ const newNode = this.createNode(originalNode.typeName, originalNode.typeState, originalNode.graphId, originalNode.graphName);
315
+ for (const edge of this.edgesOfHead(originalNode)) {
316
+ this.addEdge(new edge_1.Edge(newNode, edge.move, edge.tail));
317
+ }
318
+ return newNode;
319
+ }
320
+ replaceEdgeAt(headIndex, tailIndex, newEdge, edgeIndex) {
321
+ this.edgesByHeadTypeIndex[headIndex][edgeIndex] = newEdge;
322
+ const newEdgesByTail = [];
323
+ for (const edge of this.edgesByTailTypeIndex[tailIndex]) {
324
+ if (edge !== newEdge) {
325
+ newEdgesByTail.push(edge);
326
+ }
327
+ }
328
+ newEdgesByTail.push(newEdge);
329
+ this.edgesByTailTypeIndex[tailIndex] = newEdgesByTail;
330
+ }
331
+ print(asLink = false) {
332
+ let str = 'digraph G {';
333
+ if (this.supergraphState.objectTypes.has('Query')) {
334
+ str += '\n root -> Query';
335
+ }
336
+ if (this.supergraphState.objectTypes.has('Mutation')) {
337
+ str += '\n root -> Mutation';
338
+ }
339
+ if (this.supergraphState.objectTypes.has('Subscription')) {
340
+ str += '\n root -> Subscription';
341
+ }
342
+ for (const edge of this.edgesByHeadTypeIndex.flat()) {
343
+ if (edge.head.typeName === 'Query') {
344
+ str += `\n "Query" -> "${edge.head}";`;
345
+ }
346
+ else if (edge.head.typeName === 'Mutation') {
347
+ str += `\n "Mutation" -> "${edge.head}";`;
348
+ }
349
+ else if (edge.head.typeName === 'Subscription') {
350
+ str += `\n "Subscription" -> "${edge.head}";`;
351
+ }
352
+ str += `\n "${edge.head}" -> "${edge.tail}" [label="${edge.move}"];`;
353
+ }
354
+ str += '\n}';
355
+ if (asLink) {
356
+ return `https://dreampuf.github.io/GraphvizOnline/#${encodeURIComponent(str)}`;
357
+ }
358
+ return str;
359
+ }
360
+ graphNameToId(graphName) {
361
+ for (const [id, { graph }] of this.supergraphState.subgraphs) {
362
+ if (graph.name === graphName) {
363
+ return id;
364
+ }
365
+ }
366
+ }
367
+ nodeOf(typeName, failIfMissing = true) {
368
+ const indexes = this.getIndexesOfType(typeName);
369
+ if (!Array.isArray(indexes)) {
370
+ if (failIfMissing) {
371
+ throw new Error(`Expected TypeNode(${typeName}) to be inserted first in graph ${this.id}`);
372
+ }
373
+ return undefined;
374
+ }
375
+ if (indexes.length > 1) {
376
+ throw new Error(`Expected only one node for ${typeName} in graph ${this.id}`);
377
+ }
378
+ return this.nodesByTypeIndex[indexes[0]][0];
379
+ }
380
+ nodesOf(typeName, failIfMissing = true) {
381
+ const indexes = this.getIndexesOfType(typeName);
382
+ if (!Array.isArray(indexes)) {
383
+ if (failIfMissing) {
384
+ throw new Error(`Expected TypeNode(${typeName}) to be inserted first in graph ${this.id}`);
385
+ }
386
+ return [];
387
+ }
388
+ const nodes = [];
389
+ for (const i of indexes) {
390
+ for (const node of this.nodesByTypeIndex[i]) {
391
+ nodes.push(node);
392
+ }
393
+ }
394
+ return nodes;
395
+ }
396
+ getSameGraphEdgesOfIndex(head, indexes, kind) {
397
+ const edges = [];
398
+ if (!indexes) {
399
+ return [];
400
+ }
401
+ for (const i of indexes) {
402
+ const edge = this.edgesByHeadTypeIndex[head.index][i];
403
+ if (!edge) {
404
+ throw new Error(`Expected edge to be defined at index ${i}`);
405
+ }
406
+ if (edge.head.graphName === head.graphName) {
407
+ edges.push(edge);
408
+ continue;
409
+ }
410
+ if (!this._warnedAboutIncorrectEdge) {
411
+ console.error(`Expected edge to be in the same graph as head (${kind})` + edge.toString());
412
+ this._warnedAboutIncorrectEdge = true;
413
+ }
414
+ }
415
+ return edges;
416
+ }
417
+ fieldEdgesOfHead(head, fieldName) {
418
+ return this.getSameGraphEdgesOfIndex(head, head.getFieldEdgeIndexes(fieldName), 'field');
419
+ }
420
+ abstractEdgesOfHead(head) {
421
+ return this.getSameGraphEdgesOfIndex(head, head.getAbstractEdgeIndexes(head.typeName), 'abstract');
422
+ }
423
+ entityEdgesOfHead(head) {
424
+ return this.getSameGraphEdgesOfIndex(head, head.getEntityEdgeIndexes(head.typeName), 'entity');
425
+ }
426
+ crossGraphEdgesOfHead(head) {
427
+ return this.getSameGraphEdgesOfIndex(head, head.getCrossGraphEdgeIndexes(head.typeName), 'cross-graph');
428
+ }
429
+ edgesOfHead(head) {
430
+ return this.edgesByHeadTypeIndex[head.index]?.filter(e => e.head === head) ?? [];
431
+ }
432
+ edgesOfTail(tail) {
433
+ return this.edgesByTailTypeIndex[tail.index]?.filter(e => e.tail === tail) ?? [];
434
+ }
435
+ possibleTypesOf(typeName) {
436
+ if (this.supergraphState.interfaceTypes.has(typeName)) {
437
+ return Array.from(this.supergraphState.interfaceTypes.get(typeName).implementedBy);
438
+ }
439
+ if (this.supergraphState.unionTypes.has(typeName)) {
440
+ return Array.from(this.supergraphState.unionTypes.get(typeName).members);
441
+ }
442
+ return [typeName];
443
+ }
444
+ canReachTypeFromType(fromTypeName, toTypeName) {
445
+ if (fromTypeName === toTypeName) {
446
+ return true;
447
+ }
448
+ const fromTypeIndexes = this.getIndexesOfType(fromTypeName);
449
+ if (!fromTypeIndexes) {
450
+ return false;
451
+ }
452
+ const visited = new Array(this.typeChildren.length).fill(false);
453
+ const queue = [];
454
+ for (const i of fromTypeIndexes) {
455
+ visited[i] = true;
456
+ }
457
+ queue.push(fromTypeName);
458
+ while (queue.length > 0) {
459
+ const typeName = queue.shift();
460
+ if (!typeName) {
461
+ throw new Error('Unexpected end of queue');
462
+ }
463
+ const typeIndexes = this.getIndexesOfType(typeName);
464
+ if (typeof typeIndexes === 'undefined') {
465
+ throw new Error(`Could not find an index of type: ${typeName}`);
466
+ }
467
+ this.typeChildrenCache.set(`${fromTypeName} -> ${typeName}`, true);
468
+ if (typeName === toTypeName) {
469
+ return true;
470
+ }
471
+ for (const typeIndex of typeIndexes) {
472
+ const children = this.typeChildren[typeIndex];
473
+ for (const childTypeName of children) {
474
+ const childTypeIndexes = this.getIndexesOfType(childTypeName);
475
+ if (typeof childTypeIndexes === 'undefined') {
476
+ throw new Error(`Could not find an index of type: ${typeName}`);
477
+ }
478
+ for (const childTypeIndex of childTypeIndexes) {
479
+ if (!visited[childTypeIndex]) {
480
+ visited[childTypeIndex] = true;
481
+ this.typeChildrenCache.set(`${fromTypeName} -> ${childTypeName}`, true);
482
+ this.typeChildrenCache.set(`${typeName} -> ${childTypeName}`, true);
483
+ queue.push(childTypeName);
484
+ }
485
+ }
486
+ }
487
+ }
488
+ }
489
+ this.typeChildrenCache.set(`${fromTypeName} -> ${toTypeName}`, false);
490
+ return false;
491
+ }
492
+ createNodesAndEdgesForType(typeName) {
493
+ if (this.supergraphState.objectTypes.has(typeName)) {
494
+ return this.createNodesAndEdgesForObjectType(this.supergraphState.objectTypes.get(typeName));
495
+ }
496
+ if (graphql_1.specifiedScalarTypes.some(t => t.name === typeName) ||
497
+ this.supergraphState.scalarTypes.has(typeName)) {
498
+ return this.createNodeForScalarType(typeName);
499
+ }
500
+ if (this.supergraphState.enumTypes.has(typeName)) {
501
+ return this.createNodeForEnumType(this.supergraphState.enumTypes.get(typeName));
502
+ }
503
+ if (this.supergraphState.unionTypes.has(typeName)) {
504
+ return this.createNodeForUnionType(this.supergraphState.unionTypes.get(typeName));
505
+ }
506
+ if (this.supergraphState.interfaceTypes.has(typeName)) {
507
+ return this.createNodeForInterfaceType(this.supergraphState.interfaceTypes.get(typeName));
508
+ }
509
+ throw new Error(`Not implemented path: createNodesAndEdgesForType(${typeName})`);
510
+ }
511
+ ensureNonOrSingleNode(typeName) {
512
+ const indexes = this.typeNameToNodeIndexes.get(typeName);
513
+ if (!Array.isArray(indexes)) {
514
+ return;
515
+ }
516
+ if (indexes.length > 1) {
517
+ throw new Error(`Expected only one node for ${typeName} in graph ${this.id}`);
518
+ }
519
+ return this.nodesByTypeIndex[indexes[0]][0];
520
+ }
521
+ createNodesAndEdgesForObjectType(typeState) {
522
+ const existing = this.ensureNonOrSingleNode(typeState.name);
523
+ if (existing) {
524
+ return existing;
525
+ }
526
+ const head = this.createTypeNode(typeState.name, typeState);
527
+ for (const field of typeState.fields.values()) {
528
+ if (this.trueOrIfSubgraphThen(() => field.byGraph.has(this.id))) {
529
+ this.createEdgeForObjectTypeField(head, field);
530
+ }
531
+ }
532
+ return head;
533
+ }
534
+ createNodeForScalarType(typeName) {
535
+ const existing = this.ensureNonOrSingleNode(typeName);
536
+ if (existing) {
537
+ return existing;
538
+ }
539
+ return this.createTypeNode(typeName, this.supergraphState.scalarTypes.get(typeName) ?? null);
540
+ }
541
+ createNodeForEnumType(typeState) {
542
+ const existing = this.ensureNonOrSingleNode(typeState.name);
543
+ if (existing) {
544
+ return existing;
545
+ }
546
+ return this.createTypeNode(typeState.name, typeState);
547
+ }
548
+ createNodeForUnionType(typeState) {
549
+ const existing = this.ensureNonOrSingleNode(typeState.name);
550
+ if (existing) {
551
+ return existing;
552
+ }
553
+ const head = this.createTypeNode(typeState.name, typeState);
554
+ const members = this.isSupergraph()
555
+ ? typeState.members
556
+ : typeState.byGraph.get(this.id)?.members;
557
+ if (members) {
558
+ for (const memberTypeName of members) {
559
+ const tail = this.createNodesAndEdgesForType(memberTypeName);
560
+ this.addEdge(new edge_1.Edge(head, new moves_1.AbstractMove(), tail));
561
+ }
562
+ }
563
+ return head;
564
+ }
565
+ createNodeForInterfaceType(typeState) {
566
+ const existing = this.ensureNonOrSingleNode(typeState.name);
567
+ if (existing) {
568
+ return existing;
569
+ }
570
+ const head = this.createTypeNode(typeState.name, typeState);
571
+ const implementedBy = this.isSupergraph()
572
+ ? typeState.implementedBy
573
+ : typeState.byGraph.get(this.id)?.implementedBy;
574
+ if (implementedBy) {
575
+ for (const memberTypeName of implementedBy) {
576
+ const tail = this.createNodesAndEdgesForType(memberTypeName);
577
+ this.addEdge(new edge_1.Edge(head, new moves_1.AbstractMove(), tail));
578
+ }
579
+ }
580
+ return head;
581
+ }
582
+ createEdgeForObjectTypeField(head, field) {
583
+ if (this.ignoreInaccessible && field.inaccessible) {
584
+ return;
585
+ }
586
+ if (this.isSupergraph() && field.byGraph.size === 1) {
587
+ const graphId = Array.from(field.byGraph.keys())[0];
588
+ const isExternal = field.byGraph.get(graphId)?.external === true;
589
+ const isFederationV1 = this.supergraphState.subgraphs.get(graphId)?.version === 'v1.0';
590
+ if (isExternal && isFederationV1) {
591
+ return;
592
+ }
593
+ }
594
+ const outputTypeName = (0, state_1.stripTypeModifiers)(field.type);
595
+ const tail = this.createNodesAndEdgesForType(outputTypeName);
596
+ if (!tail) {
597
+ throw new Error(`Failed to create Node for ${outputTypeName} in subgraph ${this.id}`);
598
+ }
599
+ if (this.isSupergraph()) {
600
+ return this.addEdge(new edge_1.Edge(head, new moves_1.FieldMove(head.typeName, field.name), tail));
601
+ }
602
+ const requires = field.byGraph.get(head.graphId)?.requires;
603
+ const provides = field.byGraph.get(head.graphId)?.provides;
604
+ return this.addEdge(new edge_1.Edge(head, new moves_1.FieldMove(head.typeName, field.name, requires ? this.fieldsResolver.resolve(head.typeName, requires) : null, provides ? this.fieldsResolver.resolve(outputTypeName, provides) : null), tail));
605
+ }
606
+ createTypeNode(typeName, typeState) {
607
+ if (this.typeNameToNodeIndexes.has(typeName)) {
608
+ throw new Error(`Node for ${typeName} already exists in subgraph ${this.id}`);
609
+ }
610
+ return this.createNode(typeName, typeState, this.id, this.name);
611
+ }
612
+ createNode(typeName, typeState, graphId, graphName) {
613
+ const index = this.nodesByTypeIndex.push([]) - 1;
614
+ const node = new node_1.Node(index, typeName, typeState, graphId, graphName);
615
+ this.nodesByTypeIndex[node.index].push(node);
616
+ this.edgesByHeadTypeIndex.push([]);
617
+ this.edgesByTailTypeIndex.push([]);
618
+ this.typeChildren.push(new Set());
619
+ const existing = this.typeNameToNodeIndexes.get(typeName);
620
+ if (Array.isArray(existing)) {
621
+ existing.push(index);
622
+ }
623
+ else {
624
+ this.typeNameToNodeIndexes.set(typeName, [index]);
625
+ }
626
+ return node;
627
+ }
628
+ addNode(node) {
629
+ const newIndex = this.nodesByTypeIndex.push([]) - 1;
630
+ node.index = newIndex;
631
+ this.nodesByTypeIndex[node.index].push(node);
632
+ this.edgesByHeadTypeIndex.push([]);
633
+ this.edgesByTailTypeIndex.push([]);
634
+ this.typeChildren.push(new Set());
635
+ const existing = this.typeNameToNodeIndexes.get(node.typeName);
636
+ if (Array.isArray(existing)) {
637
+ existing.push(newIndex);
638
+ }
639
+ else {
640
+ this.typeNameToNodeIndexes.set(node.typeName, [newIndex]);
641
+ }
642
+ return node;
643
+ }
644
+ addEdge(edge) {
645
+ const edgeIndex = this.edgesByHeadTypeIndex[edge.head.index].push(edge) - 1;
646
+ this.edgesByTailTypeIndex[edge.tail.index].push(edge);
647
+ this.typeChildren[edge.head.index].add(edge.tail.typeName);
648
+ if ((0, edge_1.isFieldEdge)(edge)) {
649
+ edge.head.addFieldEdge(edge.move.fieldName, edgeIndex);
650
+ }
651
+ else if ((0, edge_1.isEntityEdge)(edge)) {
652
+ edge.head.addEntityEdge(edge.head.typeName, edgeIndex);
653
+ }
654
+ else if ((0, edge_1.isAbstractEdge)(edge)) {
655
+ edge.head.addAbstractEdge(edge.head.typeName, edgeIndex);
656
+ }
657
+ if (edge.isCrossGraphEdge()) {
658
+ edge.head.addCrossGraphEdge(edge.head.typeName, edgeIndex);
659
+ }
660
+ return edge;
661
+ }
662
+ getIndexesOfType(typeName) {
663
+ return this.typeNameToNodeIndexes.get(typeName);
664
+ }
665
+ trueOrIfSubgraphThen(conditionFn) {
666
+ if (this.isSubgraph) {
667
+ return conditionFn();
668
+ }
669
+ return true;
670
+ }
671
+ isSupergraph() {
672
+ return this.isSubgraph === false;
673
+ }
674
+ }
675
+ exports.Graph = Graph;