UNPKG

topological-sort

Version:
74 lines 2.91 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const assert = require("assert"); class TopologicalSort { constructor(nodes) { this.nodes = new Map(); this.addMultipleInternalNodes(nodes); } addNode(key, node) { return this.addInternalNode(key, node); } addNodes(nodes) { this.addMultipleInternalNodes(nodes); } addEdge(fromKey, toKey) { assert(this.nodes.has(fromKey), `Source node with ${fromKey} key should exist`); assert(this.nodes.has(toKey), `Target node with ${toKey} key should exist`); const sourceNode = this.nodes.get(fromKey); const targetNode = this.nodes.get(toKey); assert.strictEqual(sourceNode !== undefined, true, `Source node with key ${fromKey} doesn't exist`); assert.strictEqual(targetNode !== undefined, true, `Target node with key ${toKey} doesn't exist`); assert.strictEqual(sourceNode.children.has(toKey), false, `Source node ${fromKey} already has an adge to target node ${toKey}`); sourceNode.children.set(toKey, targetNode); } sort() { this.visitedNodes = new Set(); this.sortedKeysStack = []; const output = new Map(); for (const [key] of this.nodes) { this.exploreNode(key, []); } for (let i = this.sortedKeysStack.length - 1; i >= 0; i--) { const node = this.nodes.get(this.sortedKeysStack[i]); output.set(this.sortedKeysStack[i], node); } return output; } exploreNode(nodeKey, explorePath) { const newExplorePath = [...explorePath, nodeKey]; // we should check circular dependencies starting from node 2 if (explorePath.length) { assert(!explorePath.includes(nodeKey), `Node ${nodeKey} forms circular dependency: ${newExplorePath.join(' -> ')}`); } const node = this.nodes.get(nodeKey); if (this.visitedNodes.has(node)) { return; } // mark node as visited so that it and its children // won't be explored next time this.visitedNodes.add(node); for (const [childNodeKey] of node.children) { this.exploreNode(childNodeKey, newExplorePath); } this.sortedKeysStack.push(nodeKey); } addInternalNode(key, node) { assert.strictEqual(this.nodes.has(key), false, `Node ${key} already exists`); this.nodes.set(key, { children: new Map(), node, }); return this; } addMultipleInternalNodes(nodes) { const nodesFlat = [...nodes]; for (let i = nodes.size - 1; i >= 0; i--) { const [key, node] = nodesFlat[i]; this.addInternalNode(key, node); } } } exports.TopologicalSort = TopologicalSort; exports.default = TopologicalSort; //# sourceMappingURL=index.js.map