UNPKG

7.98 kBJavaScriptView Raw
1"use strict";
2/**
3 * This source code is from https://github.com/jriecken/dependency-graph
4 * Just added "any" types here, wrapper everything into exported class.
5 * We cant use a package itself because we want to package "everything-in-it" for the frontend users of TypeORM.
6 */
7Object.defineProperty(exports, "__esModule", { value: true });
8/**
9 * A simple dependency graph
10 */
11/**
12 * Helper for creating a Depth-First-Search on
13 * a set of edges.
14 *
15 * Detects cycles and throws an Error if one is detected.
16 *
17 * @param edges The set of edges to DFS through
18 * @param leavesOnly Whether to only return "leaf" nodes (ones who have no edges)
19 * @param result An array in which the results will be populated
20 */
21function createDFS(edges, leavesOnly, result) {
22 var currentPath = [];
23 var visited = {};
24 return function DFS(currentNode) {
25 visited[currentNode] = true;
26 currentPath.push(currentNode);
27 edges[currentNode].forEach(function (node) {
28 if (!visited[node]) {
29 DFS(node);
30 }
31 else if (currentPath.indexOf(node) >= 0) {
32 currentPath.push(node);
33 throw new Error("Dependency Cycle Found: " + currentPath.join(" -> "));
34 }
35 });
36 currentPath.pop();
37 if ((!leavesOnly || edges[currentNode].length === 0) && result.indexOf(currentNode) === -1) {
38 result.push(currentNode);
39 }
40 };
41}
42var DepGraph = /** @class */ (function () {
43 function DepGraph() {
44 this.nodes = {};
45 this.outgoingEdges = {}; // Node -> [Dependency Node]
46 this.incomingEdges = {}; // Node -> [Dependant Node]
47 }
48 /**
49 * Add a node to the dependency graph. If a node already exists, this method will do nothing.
50 */
51 DepGraph.prototype.addNode = function (node, data) {
52 if (!this.hasNode(node)) {
53 // Checking the arguments length allows the user to add a node with undefined data
54 if (arguments.length === 2) {
55 this.nodes[node] = data;
56 }
57 else {
58 this.nodes[node] = node;
59 }
60 this.outgoingEdges[node] = [];
61 this.incomingEdges[node] = [];
62 }
63 };
64 /**
65 * Remove a node from the dependency graph. If a node does not exist, this method will do nothing.
66 */
67 DepGraph.prototype.removeNode = function (node) {
68 if (this.hasNode(node)) {
69 delete this.nodes[node];
70 delete this.outgoingEdges[node];
71 delete this.incomingEdges[node];
72 [this.incomingEdges, this.outgoingEdges].forEach(function (edgeList) {
73 Object.keys(edgeList).forEach(function (key) {
74 var idx = edgeList[key].indexOf(node);
75 if (idx >= 0) {
76 edgeList[key].splice(idx, 1);
77 }
78 }, this);
79 });
80 }
81 };
82 /**
83 * Check if a node exists in the graph
84 */
85 DepGraph.prototype.hasNode = function (node) {
86 return this.nodes.hasOwnProperty(node);
87 };
88 /**
89 * Get the data associated with a node name
90 */
91 DepGraph.prototype.getNodeData = function (node) {
92 if (this.hasNode(node)) {
93 return this.nodes[node];
94 }
95 else {
96 throw new Error("Node does not exist: " + node);
97 }
98 };
99 /**
100 * Set the associated data for a given node name. If the node does not exist, this method will throw an error
101 */
102 DepGraph.prototype.setNodeData = function (node, data) {
103 if (this.hasNode(node)) {
104 this.nodes[node] = data;
105 }
106 else {
107 throw new Error("Node does not exist: " + node);
108 }
109 };
110 /**
111 * Add a dependency between two nodes. If either of the nodes does not exist,
112 * an Error will be thrown.
113 */
114 DepGraph.prototype.addDependency = function (from, to) {
115 if (!this.hasNode(from)) {
116 throw new Error("Node does not exist: " + from);
117 }
118 if (!this.hasNode(to)) {
119 throw new Error("Node does not exist: " + to);
120 }
121 if (this.outgoingEdges[from].indexOf(to) === -1) {
122 this.outgoingEdges[from].push(to);
123 }
124 if (this.incomingEdges[to].indexOf(from) === -1) {
125 this.incomingEdges[to].push(from);
126 }
127 return true;
128 };
129 /**
130 * Remove a dependency between two nodes.
131 */
132 DepGraph.prototype.removeDependency = function (from, to) {
133 var idx;
134 if (this.hasNode(from)) {
135 idx = this.outgoingEdges[from].indexOf(to);
136 if (idx >= 0) {
137 this.outgoingEdges[from].splice(idx, 1);
138 }
139 }
140 if (this.hasNode(to)) {
141 idx = this.incomingEdges[to].indexOf(from);
142 if (idx >= 0) {
143 this.incomingEdges[to].splice(idx, 1);
144 }
145 }
146 };
147 /**
148 * Get an array containing the nodes that the specified node depends on (transitively).
149 *
150 * Throws an Error if the graph has a cycle, or the specified node does not exist.
151 *
152 * If `leavesOnly` is true, only nodes that do not depend on any other nodes will be returned
153 * in the array.
154 */
155 DepGraph.prototype.dependenciesOf = function (node, leavesOnly) {
156 if (this.hasNode(node)) {
157 var result = [];
158 var DFS = createDFS(this.outgoingEdges, leavesOnly, result);
159 DFS(node);
160 var idx = result.indexOf(node);
161 if (idx >= 0) {
162 result.splice(idx, 1);
163 }
164 return result;
165 }
166 else {
167 throw new Error("Node does not exist: " + node);
168 }
169 };
170 /**
171 * get an array containing the nodes that depend on the specified node (transitively).
172 *
173 * Throws an Error if the graph has a cycle, or the specified node does not exist.
174 *
175 * If `leavesOnly` is true, only nodes that do not have any dependants will be returned in the array.
176 */
177 DepGraph.prototype.dependantsOf = function (node, leavesOnly) {
178 if (this.hasNode(node)) {
179 var result = [];
180 var DFS = createDFS(this.incomingEdges, leavesOnly, result);
181 DFS(node);
182 var idx = result.indexOf(node);
183 if (idx >= 0) {
184 result.splice(idx, 1);
185 }
186 return result;
187 }
188 else {
189 throw new Error("Node does not exist: " + node);
190 }
191 };
192 /**
193 * Construct the overall processing order for the dependency graph.
194 *
195 * Throws an Error if the graph has a cycle.
196 *
197 * If `leavesOnly` is true, only nodes that do not depend on any other nodes will be returned.
198 */
199 DepGraph.prototype.overallOrder = function (leavesOnly) {
200 var self = this;
201 var result = [];
202 var keys = Object.keys(this.nodes);
203 if (keys.length === 0) {
204 return result; // Empty graph
205 }
206 else {
207 // Look for cycles - we run the DFS starting at all the nodes in case there
208 // are several disconnected subgraphs inside this dependency graph.
209 var CycleDFS_1 = createDFS(this.outgoingEdges, false, []);
210 keys.forEach(function (n) {
211 CycleDFS_1(n);
212 });
213 var DFS_1 = createDFS(this.outgoingEdges, leavesOnly, result);
214 // Find all potential starting points (nodes with nothing depending on them) an
215 // run a DFS starting at these points to get the order
216 keys.filter(function (node) {
217 return self.incomingEdges[node].length === 0;
218 }).forEach(function (n) {
219 DFS_1(n);
220 });
221 return result;
222 }
223 };
224 return DepGraph;
225}());
226exports.DepGraph = DepGraph;
227
228//# sourceMappingURL=DepGraph.js.map