/
executionOrder.ts
82 lines (70 loc) · 2.14 KB
/
executionOrder.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import ExternalModule from '../ExternalModule';
import Module from '../Module';
import relativeId from './relativeId';
interface OrderedExecutionUnit {
execIndex: number;
}
const compareExecIndex = <T extends OrderedExecutionUnit>(unitA: T, unitB: T) =>
unitA.execIndex > unitB.execIndex ? 1 : -1;
export function sortByExecutionOrder(units: OrderedExecutionUnit[]) {
units.sort(compareExecIndex);
}
export function analyseModuleExecution(entryModules: Module[]) {
let nextExecIndex = 0;
const cyclePaths: string[][] = [];
const analysedModules: { [id: string]: boolean } = {};
const orderedModules: Module[] = [];
const dynamicImports: Module[] = [];
const parents: { [id: string]: string | null } = {};
const analyseModule = (module: Module | ExternalModule) => {
if (analysedModules[module.id]) return;
if (module instanceof ExternalModule) {
module.execIndex = nextExecIndex++;
analysedModules[module.id] = true;
return;
}
for (const dependency of module.dependencies) {
if (dependency.id in parents) {
if (!analysedModules[dependency.id]) {
cyclePaths.push(getCyclePath(dependency.id, module.id, parents));
}
continue;
}
parents[dependency.id] = module.id;
analyseModule(dependency);
}
for (const { resolution } of module.dynamicImports) {
if (resolution instanceof Module && dynamicImports.indexOf(resolution) === -1) {
dynamicImports.push(resolution);
}
}
module.execIndex = nextExecIndex++;
analysedModules[module.id] = true;
orderedModules.push(module);
};
for (const curEntry of entryModules) {
if (!parents[curEntry.id]) {
parents[curEntry.id] = null;
analyseModule(curEntry);
}
}
for (const curEntry of dynamicImports) {
if (!parents[curEntry.id]) {
parents[curEntry.id] = null;
analyseModule(curEntry);
}
}
return { orderedModules, cyclePaths };
}
function getCyclePath(id: string, parentId: string, parents: { [id: string]: string | null }) {
const path = [relativeId(id)];
let curId = parentId;
while (curId !== id) {
path.push(relativeId(curId));
curId = parents[curId];
if (!curId) break;
}
path.push(path[0]);
path.reverse();
return path;
}