-
Notifications
You must be signed in to change notification settings - Fork 0
/
dependencyTree.ts
80 lines (65 loc) · 2.15 KB
/
dependencyTree.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
import { Class, DependencyConfig } from "./types";
class CustomMap<K, V> extends Map<K, V> {
public setNX(key: K, value: V): boolean {
if (!this.has(key)) {
this.set(key, value);
return true;
}
return false;
}
public getWithDefault(key: K, defaultValue: V): V {
if (!this.has(key)) {
return defaultValue;
} else {
return this.get(key);
}
}
}
interface dependencyNode {
cls: Class;
parents?: dependencyNode[];
dependents?: dependencyNode[];
}
interface dependencyTreeResult {
tree: dependencyNode[];
loadSequence: dependencyNode[];
}
const dependencyMap = new CustomMap<Class, dependencyNode>();
export function calcDependencyTree(classes: Class[]): dependencyTreeResult {
const tree: dependencyNode[] = [];
classes.forEach(cls => {
if (dependencyMap.has(cls)) return;
const node: dependencyNode = { cls };
const deps: DependencyConfig[] = Reflect.getMetadata("DEP", cls) ?? [];
if (deps.length === 0) {
tree.push(node);
}
deps.forEach(dep => {
const parentNode = dependencyMap.getWithDefault(dep.dep, {
cls: dep.dep,
dependents: [],
});
parentNode.dependents ? parentNode.dependents.push(node) : parentNode.dependents = [node];
dependencyMap.set(cls, parentNode);
node.parents = node.parents ? [...node.parents, parentNode] : [parentNode];
});
dependencyMap.setNX(cls, node);
});
function getSequence(node: dependencyNode): dependencyNode[] {
const result: dependencyNode[] = [];
result.push(node);
node.dependents?.forEach(n => result.push(...getSequence(n)));
return result;
}
const loadSequence: dependencyNode[] = tree.reduce<dependencyNode[]>((prev, curr) => [...prev, ...getSequence(curr)], []);
const distinct = new Map<dependencyNode, number>();
loadSequence.forEach(seq => distinct.set(seq, loadSequence.lastIndexOf(seq)));
const loadSequenceDistinct = new Array<dependencyNode | null>(loadSequence.length).fill(null);
for (const node of distinct) {
loadSequenceDistinct[node[1]] = node[0];
}
return {
tree,
loadSequence: loadSequenceDistinct.filter(v => v !== null),
};
}