dag-iterator
Version:
utility tool to traverse DAG graphs in JavaScript
102 lines (101 loc) • 3.83 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
var TraversalMode;
(function (TraversalMode) {
TraversalMode[TraversalMode["DFS"] = 0] = "DFS";
TraversalMode[TraversalMode["BFS"] = 1] = "BFS";
})(TraversalMode = exports.TraversalMode || (exports.TraversalMode = {}));
function iterateDfs(nodes, edges, func, untilNode) {
var options = {
traversalMode: TraversalMode.DFS,
untilNode: untilNode,
};
return _iterate(nodes, edges, func, options);
}
exports.iterateDfs = iterateDfs;
function iterateBfs(nodes, edges, func, untilNode) {
var options = {
traversalMode: TraversalMode.BFS,
untilNode: untilNode,
};
return _iterate(nodes, edges, func, options);
}
exports.iterateBfs = iterateBfs;
function iterate(nodes, edges, func, untilNode) {
return iterateDfs(nodes, edges, func, untilNode);
}
exports.iterate = iterate;
function _iterate(nodes, edges, func, options) {
if (nodes.length === 0 || edges.length === 0) {
return;
}
var nodeStorage = [];
var nodeVisited = {};
var nodeMap = arrToObj(nodes, 'name');
var edgeSrcMap = tuplesToObj(edges.map(function (edge) {
return [edge.src, edge.dst];
}));
var edgeDstMap = tuplesToObj(edges.map(function (edge) {
return [edge.dst, edge.src];
}));
Array.prototype.push.apply(nodeStorage, getFirstNodes());
var i = 0;
while (nodeStorage.length) {
var node = getNextNode(nodeStorage, options.traversalMode);
var parentNodes = getParentNodes(node);
nodeVisited[node] = parentNodes.reduce(function (prev, curr) {
return Math.max(prev, nodeVisited[curr] + 1);
}, 0);
var nodeData = getDataFromNode(node);
var parentNodesData = parentNodes.map(getDataFromNode);
func.call(null, nodeData, parentNodesData, i++, nodeVisited[node]);
if (options.untilNode && node == options.untilNode) {
break;
}
getChildNodes(node, true).forEach(function (childNode) {
var unvisitedParents = getParentNodes(childNode, true);
if (unvisitedParents.length === 0) {
nodeStorage.push(childNode);
}
});
}
function getFirstNodes() {
return nodes.filter(function (node) {
return edgeSrcMap.hasOwnProperty(node.name) && !edgeDstMap.hasOwnProperty(node.name);
})
.map(function (node) { return node.name; });
}
function getNextNode(arr, traversalMode) {
return traversalMode === TraversalMode.DFS ? arr.pop() : arr.shift();
}
function getParentNodes(nodeName, onlyUnvisited) {
if (onlyUnvisited === void 0) { onlyUnvisited = false; }
var parentNodes = edgeDstMap[nodeName] || [];
return onlyUnvisited === false ? parentNodes : parentNodes.filter(filterNotVisited);
}
function getChildNodes(nodeName, onlyUnvisited) {
if (onlyUnvisited === void 0) { onlyUnvisited = false; }
var childNodes = edgeSrcMap[nodeName] || [];
return onlyUnvisited === false ? childNodes : childNodes.filter(filterNotVisited);
}
function filterNotVisited(nodeName) {
return !nodeVisited.hasOwnProperty(nodeName);
}
function getDataFromNode(nodeName) {
return nodeMap[nodeName].data;
}
}
function tuplesToObj(tuples) {
return tuples.reduce(function (prev, curr) {
var key = curr[0], val = curr[1];
prev[key] = prev.hasOwnProperty(key) ? [].concat(prev[key], val) : [val];
return prev;
}, {});
}
function arrToObj(arr, attr) {
return arr.reduce(function (prev, curr) {
var key = curr[attr], val = curr;
prev[key] = prev.hasOwnProperty(key) ? [].concat(prev[key], val) : val;
return prev;
}, {});
}