topological-sort-group
Version:
Topological sorting and cycle detection. Optional grouping for parallel processing
52 lines (51 loc) • 1.78 kB
JavaScript
import cycles from './cycles.js';
import { SortMode } from './types.js';
// find nodes with no incoming nodes
function findRoots(graph, degrees) {
const sources = [];
for(const fromKey in degrees){
if (degrees[fromKey] === 0) sources.push(graph.nodeMap[fromKey].value);
}
return sources;
}
export default function sort(graph, mode = SortMode.Group) {
const degrees = graph.degrees();
// process the nodes level by level
const nodes = [];
let currentLevel = findRoots(graph, degrees);
while(currentLevel.length > 0){
nodes.push(currentLevel.slice());
// track next level's nodes
const nextLevel = [];
const processed = {};
// process all nodes in current level
currentLevel.forEach((node)=>{
const nodeKey = graph.key(node);
// remove the node
degrees[nodeKey] = -1;
// reduce degrees for all neighbors
graph.edges(nodeKey).forEach((neighborKey)=>{
degrees[neighborKey]--;
// If neighbor has no more dependencies and hasn't been processed
if (degrees[neighborKey] === 0 && processed[neighborKey] === undefined) {
nextLevel.push(graph.value(neighborKey));
processed[neighborKey] = true;
}
});
});
// Move to next level
currentLevel = nextLevel;
}
// Check for cycles
let hasCycles = false;
for(const from in degrees){
if (degrees[from] > 0) {
hasCycles = true;
break;
}
}
return {
nodes: mode === SortMode.Flat ? nodes.reduce((m, l)=>m.concat(l), []) : nodes,
cycles: hasCycles ? cycles(graph) : []
};
}