Add support for cyclical JS dependencies
parent
3efa28c9f1
commit
a76b759a01
@ -0,0 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
const createError = require("create-error");
|
||||
|
||||
module.exports = createError("CycleError");
|
@ -0,0 +1,40 @@
|
||||
"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
|
||||
};
|
||||
};
|
Loading…
Reference in New Issue