UNPKG

archunit

Version:

ArchUnit TypeScript is an architecture testing library, to specify and assert architecture rules in your TypeScript app

107 lines 3.51 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.JohnsonsAPSP = void 0; const cycle_utils_1 = require("./cycle-utils"); /** * See: * https://www.youtube.com/watch?v=johyrWospv0 */ class JohnsonsAPSP { constructor() { this.blocked = []; this.stack = []; this.blockedMap = []; this.graph = []; this.start = null; this.cycles = []; } findSimpleCycles(edges) { this.init(edges); this.graph.forEach((node) => { this.start = node; this.stack.push(node); this.blocked.push(node); this.exploreNeighbours(node); this.removeFromGraph(node); }); return this.cycles; } exploreNeighbours(currentNode) { cycle_utils_1.CycleUtils.getOutgoingNeighbours(currentNode, this.graph).forEach((neighbour) => { if (this.foundCycle(neighbour)) { this.cycles.push(this.buildCycle()); } if (!this.isBlocked(neighbour)) { this.stack.push(neighbour); this.blocked.push(neighbour); this.exploreNeighbours(neighbour); } }); this.stack.pop(); if (this.isPartOfCurrentStartCycle(currentNode)) { this.unblock(currentNode); } else { cycle_utils_1.CycleUtils.getOutgoingNeighbours(currentNode, this.graph).forEach((neighbour) => { if (this.isBlocked(neighbour)) { this.blockedMap.push({ blocked: currentNode, by: neighbour }); } }); } } unblock(node) { this.blocked = this.blocked.filter((x) => x !== node); const toRemove = []; this.blockedMap.forEach((blocker) => { if (blocker.by === node) { this.unblock(blocker.blocked); toRemove.push(blocker); } }); this.blockedMap = this.blockedMap.filter((x) => !toRemove.includes(x)); } isPartOfCurrentStartCycle(currentNode) { if (!this.start) { return false; } return (this.cycles.filter((x) => x[0].from === this.start.node && x.find((y) => y.from === currentNode.node)).length > 0); } init(edges) { this.blocked = []; this.stack = []; this.blockedMap = []; this.graph = cycle_utils_1.CycleUtils.transformEdgeData(edges); this.cycles = []; } isBlocked(child) { return this.blocked.indexOf(child) !== -1; } removeFromGraph(toRemove) { this.graph.forEach((node) => { node.incoming = node.incoming.filter((x) => x.from !== toRemove.node && x.to !== toRemove.node); node.outgoing = node.outgoing.filter((x) => x.from !== toRemove.node && x.to !== toRemove.node); }); } foundCycle(currentNode) { return currentNode === this.start; } buildCycle() { const cycleEdges = []; this.stack .map((x) => x.node) .forEach((id, i) => { cycleEdges.push({ from: id, to: -1 }); if (i >= 1) { cycleEdges[i - 1].to = id; } }); if (this.start) { // Add null check. cycleEdges[cycleEdges.length - 1].to = this.start.node; } return cycleEdges; } } exports.JohnsonsAPSP = JohnsonsAPSP; //# sourceMappingURL=johnsons-apsp.js.map