This repository has been archived by the owner on Jan 20, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 64
/
Copy pathcalc-dep-flags.js
115 lines (99 loc) · 3.07 KB
/
calc-dep-flags.js
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
const { depth } = require('treeverse')
const calcDepFlags = (tree, resetRoot = true) => {
if (resetRoot) {
tree.dev = false
tree.optional = false
tree.devOptional = false
tree.peer = false
}
const ret = depth({
tree,
visit: node => calcDepFlagsStep(node),
filter: node => node,
getChildren: (node, tree) =>
[...tree.edgesOut.values()].map(edge => edge.to),
})
return ret
}
const calcDepFlagsStep = (node) => {
// This rewalk is necessary to handle cases where devDep and optional
// or normal dependency graphs overlap deep in the dep graph.
// Since we're only walking through deps that are not already flagged
// as non-dev/non-optional, it's typically a very shallow traversal
node.extraneous = false
resetParents(node, 'extraneous')
resetParents(node, 'dev')
resetParents(node, 'peer')
resetParents(node, 'devOptional')
resetParents(node, 'optional')
// for links, map their hierarchy appropriately
if (node.isLink) {
node.target.dev = node.dev
node.target.optional = node.optional
node.target.devOptional = node.devOptional
node.target.peer = node.peer
return calcDepFlagsStep(node.target)
}
node.edgesOut.forEach(({ peer, optional, dev, to }) => {
// if the dep is missing, then its flags are already maximally unset
if (!to) {
return
}
// everything with any kind of edge into it is not extraneous
to.extraneous = false
// devOptional is the *overlap* of the dev and optional tree.
// however, for convenience and to save an extra rewalk, we leave
// it set when we are in *either* tree, and then omit it from the
// package-lock if either dev or optional are set.
const unsetDevOpt = !node.devOptional && !node.dev && !node.optional &&
!dev && !optional
// if we are not in the devOpt tree, then we're also not in
// either the dev or opt trees
const unsetDev = unsetDevOpt || !node.dev && !dev
const unsetOpt = unsetDevOpt ||
!node.optional && !optional
const unsetPeer = !node.peer && !peer
if (unsetPeer) {
unsetFlag(to, 'peer')
}
if (unsetDevOpt) {
unsetFlag(to, 'devOptional')
}
if (unsetDev) {
unsetFlag(to, 'dev')
}
if (unsetOpt) {
unsetFlag(to, 'optional')
}
})
return node
}
const resetParents = (node, flag) => {
if (node[flag]) {
return
}
for (let p = node; p && (p === node || p[flag]); p = p.resolveParent) {
p[flag] = false
}
}
// typically a short walk, since it only traverses deps that
// have the flag set.
const unsetFlag = (node, flag) => {
if (node[flag]) {
node[flag] = false
depth({
tree: node,
visit: node => {
node.extraneous = node[flag] = false
if (node.isLink) {
node.target.extraneous = node.target[flag] = false
}
},
getChildren: node => [...node.target.edgesOut.values()]
.filter(edge => edge.to && edge.to[flag] &&
(flag !== 'peer' && edge.type === 'peer' || edge.type === 'prod'))
.map(edge => edge.to),
})
}
}
module.exports = calcDepFlags