You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

41 lines
1.1 KiB
JavaScript

"use strict";
const findCycle = require("find-cycle/directed");
module.exports = function findCycleSets(nodes) {
let queue = nodes.slice();
let cycleSets = [];
let innocentNodes = [];
let lastQueueLength = queue.length;
while (queue.length > 0) {
let queueSet = new Set(queue);
let cycle = findCycle(queue, (node) => {
return node.children.filter((child) => {
// We want to prevent findCycle from discovering and traversing any nodes that are not in our "conflict set"; otherwise a second pass will fail, because it will rediscover already-handled nodes (that have been removed from the queue) indirectly, and endlessly loop on discovering that cycle.
return queueSet.has(child);
});
});
if (cycle != null) {
cycleSets.push(cycle);
queue = queue.filter((node) => !cycle.includes(node));
if (queue.length === lastQueueLength) {
throw new Error(`Failed to reduce queue length; this is a bug, please report it!`);
} else {
lastQueueLength = queue.length;
}
} else {
innocentNodes = queue;
break;
}
}
return {
cycleSets: cycleSets,
innocentNodes: innocentNodes
};
};