archunit
Version:
ArchUnit TypeScript is an architecture testing library, to specify and assert architecture rules in your TypeScript app
107 lines • 3.51 kB
JavaScript
"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