Updated the files.
This commit is contained in:
parent
1553e6b971
commit
753967d4f5
23418 changed files with 3784666 additions and 0 deletions
231
my-app/node_modules/webpack/lib/util/findGraphRoots.js
generated
vendored
Executable file
231
my-app/node_modules/webpack/lib/util/findGraphRoots.js
generated
vendored
Executable file
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const NO_MARKER = 0;
|
||||
const IN_PROGRESS_MARKER = 1;
|
||||
const DONE_MARKER = 2;
|
||||
const DONE_MAYBE_ROOT_CYCLE_MARKER = 3;
|
||||
const DONE_AND_ROOT_MARKER = 4;
|
||||
|
||||
/**
|
||||
* @template T
|
||||
*/
|
||||
class Node {
|
||||
/**
|
||||
* @param {T} item the value of the node
|
||||
*/
|
||||
constructor(item) {
|
||||
this.item = item;
|
||||
/** @type {Set<Node<T>>} */
|
||||
this.dependencies = new Set();
|
||||
this.marker = NO_MARKER;
|
||||
/** @type {Cycle<T> | undefined} */
|
||||
this.cycle = undefined;
|
||||
this.incoming = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
*/
|
||||
class Cycle {
|
||||
constructor() {
|
||||
/** @type {Set<Node<T>>} */
|
||||
this.nodes = new Set();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} StackEntry
|
||||
* @property {Node<T>} node
|
||||
* @property {Node<T>[]} openEdges
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param {Iterable<T>} items list of items
|
||||
* @param {function(T): Iterable<T>} getDependencies function to get dependencies of an item (items that are not in list are ignored)
|
||||
* @returns {Iterable<T>} graph roots of the items
|
||||
*/
|
||||
module.exports = (items, getDependencies) => {
|
||||
/** @type {Map<T, Node<T>>} */
|
||||
const itemToNode = new Map();
|
||||
for (const item of items) {
|
||||
const node = new Node(item);
|
||||
itemToNode.set(item, node);
|
||||
}
|
||||
|
||||
// early exit when there is only a single item
|
||||
if (itemToNode.size <= 1) return items;
|
||||
|
||||
// grab all the dependencies
|
||||
for (const node of itemToNode.values()) {
|
||||
for (const dep of getDependencies(node.item)) {
|
||||
const depNode = itemToNode.get(dep);
|
||||
if (depNode !== undefined) {
|
||||
node.dependencies.add(depNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set of current root modules
|
||||
// items will be removed if a new reference to it has been found
|
||||
/** @type {Set<Node<T>>} */
|
||||
const roots = new Set();
|
||||
|
||||
// Set of current cycles without references to it
|
||||
// cycles will be removed if a new reference to it has been found
|
||||
// that is not part of the cycle
|
||||
/** @type {Set<Cycle<T>>} */
|
||||
const rootCycles = new Set();
|
||||
|
||||
// For all non-marked nodes
|
||||
for (const selectedNode of itemToNode.values()) {
|
||||
if (selectedNode.marker === NO_MARKER) {
|
||||
// deep-walk all referenced modules
|
||||
// in a non-recursive way
|
||||
|
||||
// start by entering the selected node
|
||||
selectedNode.marker = IN_PROGRESS_MARKER;
|
||||
|
||||
// keep a stack to avoid recursive walk
|
||||
/** @type {StackEntry<T>[]} */
|
||||
const stack = [
|
||||
{
|
||||
node: selectedNode,
|
||||
openEdges: Array.from(selectedNode.dependencies)
|
||||
}
|
||||
];
|
||||
|
||||
// process the top item until stack is empty
|
||||
while (stack.length > 0) {
|
||||
const topOfStack = stack[stack.length - 1];
|
||||
|
||||
// Are there still edges unprocessed in the current node?
|
||||
if (topOfStack.openEdges.length > 0) {
|
||||
// Process one dependency
|
||||
const dependency =
|
||||
/** @type {Node<T>} */
|
||||
(topOfStack.openEdges.pop());
|
||||
switch (dependency.marker) {
|
||||
case NO_MARKER:
|
||||
// dependency has not be visited yet
|
||||
// mark it as in-progress and recurse
|
||||
stack.push({
|
||||
node: dependency,
|
||||
openEdges: Array.from(dependency.dependencies)
|
||||
});
|
||||
dependency.marker = IN_PROGRESS_MARKER;
|
||||
break;
|
||||
case IN_PROGRESS_MARKER: {
|
||||
// It's a in-progress cycle
|
||||
let cycle = dependency.cycle;
|
||||
if (!cycle) {
|
||||
cycle = new Cycle();
|
||||
cycle.nodes.add(dependency);
|
||||
dependency.cycle = cycle;
|
||||
}
|
||||
// set cycle property for each node in the cycle
|
||||
// if nodes are already part of a cycle
|
||||
// we merge the cycles to a shared cycle
|
||||
for (
|
||||
let i = stack.length - 1;
|
||||
stack[i].node !== dependency;
|
||||
i--
|
||||
) {
|
||||
const node = stack[i].node;
|
||||
if (node.cycle) {
|
||||
if (node.cycle !== cycle) {
|
||||
// merge cycles
|
||||
for (const cycleNode of node.cycle.nodes) {
|
||||
cycleNode.cycle = cycle;
|
||||
cycle.nodes.add(cycleNode);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
node.cycle = cycle;
|
||||
cycle.nodes.add(node);
|
||||
}
|
||||
}
|
||||
// don't recurse into dependencies
|
||||
// these are already on the stack
|
||||
break;
|
||||
}
|
||||
case DONE_AND_ROOT_MARKER:
|
||||
// This node has be visited yet and is currently a root node
|
||||
// But as this is a new reference to the node
|
||||
// it's not really a root
|
||||
// so we have to convert it to a normal node
|
||||
dependency.marker = DONE_MARKER;
|
||||
roots.delete(dependency);
|
||||
break;
|
||||
case DONE_MAYBE_ROOT_CYCLE_MARKER:
|
||||
// This node has be visited yet and
|
||||
// is maybe currently part of a completed root cycle
|
||||
// we found a new reference to the cycle
|
||||
// so it's not really a root cycle
|
||||
// remove the cycle from the root cycles
|
||||
// and convert it to a normal node
|
||||
rootCycles.delete(/** @type {Cycle<T>} */ (dependency.cycle));
|
||||
dependency.marker = DONE_MARKER;
|
||||
break;
|
||||
// DONE_MARKER: nothing to do, don't recurse into dependencies
|
||||
}
|
||||
} else {
|
||||
// All dependencies of the current node has been visited
|
||||
// we leave the node
|
||||
stack.pop();
|
||||
topOfStack.node.marker = DONE_MARKER;
|
||||
}
|
||||
}
|
||||
const cycle = selectedNode.cycle;
|
||||
if (cycle) {
|
||||
for (const node of cycle.nodes) {
|
||||
node.marker = DONE_MAYBE_ROOT_CYCLE_MARKER;
|
||||
}
|
||||
rootCycles.add(cycle);
|
||||
} else {
|
||||
selectedNode.marker = DONE_AND_ROOT_MARKER;
|
||||
roots.add(selectedNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extract roots from root cycles
|
||||
// We take the nodes with most incoming edges
|
||||
// inside of the cycle
|
||||
for (const cycle of rootCycles) {
|
||||
let max = 0;
|
||||
/** @type {Set<Node<T>>} */
|
||||
const cycleRoots = new Set();
|
||||
const nodes = cycle.nodes;
|
||||
for (const node of nodes) {
|
||||
for (const dep of node.dependencies) {
|
||||
if (nodes.has(dep)) {
|
||||
dep.incoming++;
|
||||
if (dep.incoming < max) continue;
|
||||
if (dep.incoming > max) {
|
||||
cycleRoots.clear();
|
||||
max = dep.incoming;
|
||||
}
|
||||
cycleRoots.add(dep);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const cycleRoot of cycleRoots) {
|
||||
roots.add(cycleRoot);
|
||||
}
|
||||
}
|
||||
|
||||
// When roots were found, return them
|
||||
if (roots.size > 0) {
|
||||
return Array.from(roots, r => r.item);
|
||||
} else {
|
||||
throw new Error("Implementation of findGraphRoots is broken");
|
||||
}
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue