source: frontend/node_modules/webpack/lib/util/topologicalSort.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 12 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 2.3 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3*/
4
5"use strict";
6
7/**
8 * Topologically sort `nodes` using Kahn's algorithm with source-order
9 * tie-breaking. Nodes that participate in a cycle remain unvisited —
10 * `visit` is never called for them — so the caller can naturally keep
11 * them in their original position by treating "no visit" as "keep
12 * source order".
13 *
14 * Precondition: every node appearing in `graph` (as a key OR inside any
15 * successor set) must also appear in `nodes`. The caller owns this
16 * invariant; the function does not validate it.
17 *
18 * Complexity: O(V·(V + E)). Each outer iteration scans the ready set
19 * linearly to find the smallest source-index node. CSS composes graphs
20 * are small (a handful of files per module) so this is fine; if a much
21 * larger graph ever needs sorting here, swap in a min-heap.
22 * @template T
23 * @param {Map<T, Set<T>>} graph adjacency list (`a -> b` means `a` must come before `b`)
24 * @param {T[]} nodes nodes in source first-appearance order
25 * @param {(node: T, index: number) => void} visit called once per non-cyclic node in topological order
26 * @returns {void}
27 */
28module.exports = (graph, nodes, visit) => {
29 /** @type {Map<T, number>} */
30 const inDegree = new Map();
31 /** @type {Map<T, number>} */
32 const sourceIndex = new Map();
33 for (let i = 0; i < nodes.length; i++) {
34 inDegree.set(nodes[i], 0);
35 sourceIndex.set(nodes[i], i);
36 }
37 for (const successors of graph.values()) {
38 for (const to of successors) {
39 inDegree.set(to, /** @type {number} */ (inDegree.get(to)) + 1);
40 }
41 }
42
43 const ready = nodes.filter((n) => inDegree.get(n) === 0);
44 let index = 0;
45 while (ready.length > 0) {
46 // Smallest-source-index wins ties. Linear scan + swap-with-last
47 // + pop avoids re-sorting the ready set on every iteration.
48 let minIdx = 0;
49 for (let i = 1; i < ready.length; i++) {
50 if (
51 /** @type {number} */ (sourceIndex.get(ready[i])) <
52 /** @type {number} */ (sourceIndex.get(ready[minIdx]))
53 ) {
54 minIdx = i;
55 }
56 }
57 const node = ready[minIdx];
58 ready[minIdx] = ready[ready.length - 1];
59 ready.pop();
60 visit(node, index++);
61 const successors = graph.get(node);
62 if (!successors) continue;
63 for (const to of successors) {
64 const newDeg = /** @type {number} */ (inDegree.get(to)) - 1;
65 inDegree.set(to, newDeg);
66 if (newDeg === 0) ready.push(to);
67 }
68 }
69};
Note: See TracBrowser for help on using the repository browser.