UNPKG

2.12 kBJavaScriptView Raw
1import { GraphQLError } from "../../error/GraphQLError.mjs";
2export function NoFragmentCyclesRule(context) {
3 // Tracks already visited fragments to maintain O(N) and to ensure that cycles
4 // are not redundantly reported.
5 var visitedFrags = Object.create(null); // Array of AST nodes used to produce meaningful errors
6
7 var spreadPath = []; // Position in the spread path
8
9 var spreadPathIndexByName = Object.create(null);
10 return {
11 OperationDefinition: function OperationDefinition() {
12 return false;
13 },
14 FragmentDefinition: function FragmentDefinition(node) {
15 detectCycleRecursive(node);
16 return false;
17 }
18 }; // This does a straight-forward DFS to find cycles.
19 // It does not terminate when a cycle was found but continues to explore
20 // the graph to find all possible cycles.
21
22 function detectCycleRecursive(fragment) {
23 if (visitedFrags[fragment.name.value]) {
24 return;
25 }
26
27 var fragmentName = fragment.name.value;
28 visitedFrags[fragmentName] = true;
29 var spreadNodes = context.getFragmentSpreads(fragment.selectionSet);
30
31 if (spreadNodes.length === 0) {
32 return;
33 }
34
35 spreadPathIndexByName[fragmentName] = spreadPath.length;
36
37 for (var _i2 = 0; _i2 < spreadNodes.length; _i2++) {
38 var spreadNode = spreadNodes[_i2];
39 var spreadName = spreadNode.name.value;
40 var cycleIndex = spreadPathIndexByName[spreadName];
41 spreadPath.push(spreadNode);
42
43 if (cycleIndex === undefined) {
44 var spreadFragment = context.getFragment(spreadName);
45
46 if (spreadFragment) {
47 detectCycleRecursive(spreadFragment);
48 }
49 } else {
50 var cyclePath = spreadPath.slice(cycleIndex);
51 var viaPath = cyclePath.slice(0, -1).map(function (s) {
52 return '"' + s.name.value + '"';
53 }).join(', ');
54 context.reportError(new GraphQLError("Cannot spread fragment \"".concat(spreadName, "\" within itself") + (viaPath !== '' ? " via ".concat(viaPath, ".") : '.'), cyclePath));
55 }
56
57 spreadPath.pop();
58 }
59
60 spreadPathIndexByName[fragmentName] = undefined;
61 }
62}