@npmcli/arborist 2.8.2 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/actual.js +4 -2
- package/bin/audit.js +12 -6
- package/bin/dedupe.js +6 -3
- package/bin/funding.js +4 -2
- package/bin/ideal.js +2 -1
- package/bin/lib/logging.js +4 -3
- package/bin/lib/options.js +14 -12
- package/bin/lib/timers.js +6 -3
- package/bin/license.js +9 -5
- package/bin/prune.js +6 -3
- package/bin/reify.js +6 -3
- package/bin/virtual.js +4 -2
- package/lib/add-rm-pkg-deps.js +28 -15
- package/lib/arborist/audit.js +2 -1
- package/lib/arborist/build-ideal-tree.js +139 -72
- package/lib/arborist/deduper.js +2 -1
- package/lib/arborist/index.js +8 -4
- package/lib/arborist/load-actual.js +28 -13
- package/lib/arborist/load-virtual.js +37 -20
- package/lib/arborist/load-workspaces.js +4 -2
- package/lib/arborist/rebuild.js +34 -17
- package/lib/arborist/reify.js +153 -76
- package/lib/audit-report.js +44 -23
- package/lib/calc-dep-flags.js +18 -9
- package/lib/can-place-dep.js +59 -30
- package/lib/case-insensitive-map.js +4 -2
- package/lib/consistent-resolve.js +2 -1
- package/lib/deepest-nesting-target.js +4 -2
- package/lib/dep-valid.js +8 -4
- package/lib/diff.js +74 -22
- package/lib/edge.js +26 -13
- package/lib/gather-dep-set.js +2 -1
- package/lib/inventory.js +12 -6
- package/lib/link.js +14 -9
- package/lib/node.js +216 -113
- package/lib/optional-set.js +4 -2
- package/lib/peer-entry-sets.js +10 -5
- package/lib/place-dep.js +111 -37
- package/lib/printable.js +46 -25
- package/lib/realpath.js +12 -6
- package/lib/shrinkwrap.js +164 -90
- package/lib/signal-handling.js +6 -3
- package/lib/spec-from-lock.js +7 -4
- package/lib/tracker.js +24 -18
- package/lib/tree-check.js +12 -6
- package/lib/version-from-tgz.js +4 -2
- package/lib/vuln.js +44 -22
- package/lib/yarn-lock.js +34 -21
- package/package.json +8 -10
package/lib/diff.js
CHANGED
|
@@ -31,7 +31,12 @@ class Diff {
|
|
|
31
31
|
this.removed = []
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
static calculate ({
|
|
34
|
+
static calculate ({
|
|
35
|
+
actual,
|
|
36
|
+
ideal,
|
|
37
|
+
filterNodes = [],
|
|
38
|
+
shrinkwrapInflated = new Set(),
|
|
39
|
+
}) {
|
|
35
40
|
// if there's a filterNode, then:
|
|
36
41
|
// - get the path from the root to the filterNode. The root or
|
|
37
42
|
// root.target should have an edge either to the filterNode or
|
|
@@ -43,8 +48,9 @@ class Diff {
|
|
|
43
48
|
const extraneous = new Set()
|
|
44
49
|
for (const filterNode of filterNodes) {
|
|
45
50
|
const { root } = filterNode
|
|
46
|
-
if (root !== ideal && root !== actual)
|
|
51
|
+
if (root !== ideal && root !== actual) {
|
|
47
52
|
throw new Error('invalid filterNode: outside idealTree/actualTree')
|
|
53
|
+
}
|
|
48
54
|
const rootTarget = root.target
|
|
49
55
|
const edge = [...rootTarget.edgesOut.values()].filter(e => {
|
|
50
56
|
return e.to && (e.to === filterNode || e.to.target === filterNode)
|
|
@@ -73,8 +79,9 @@ class Diff {
|
|
|
73
79
|
: [...actualNode.edgesOut.values()].filter(e => e.to).map(e => e.to)
|
|
74
80
|
if (actualNode) {
|
|
75
81
|
for (const child of actualNode.children.values()) {
|
|
76
|
-
if (child.extraneous)
|
|
82
|
+
if (child.extraneous) {
|
|
77
83
|
extraneous.add(child)
|
|
84
|
+
}
|
|
78
85
|
}
|
|
79
86
|
}
|
|
80
87
|
|
|
@@ -82,8 +89,9 @@ class Diff {
|
|
|
82
89
|
},
|
|
83
90
|
})
|
|
84
91
|
}
|
|
85
|
-
for (const extra of extraneous)
|
|
92
|
+
for (const extra of extraneous) {
|
|
86
93
|
filterSet.add(extra)
|
|
94
|
+
}
|
|
87
95
|
|
|
88
96
|
return depth({
|
|
89
97
|
tree: new Diff({actual, ideal, filterSet, shrinkwrapInflated}),
|
|
@@ -94,23 +102,27 @@ class Diff {
|
|
|
94
102
|
}
|
|
95
103
|
|
|
96
104
|
const getAction = ({actual, ideal}) => {
|
|
97
|
-
if (!ideal)
|
|
105
|
+
if (!ideal) {
|
|
98
106
|
return 'REMOVE'
|
|
107
|
+
}
|
|
99
108
|
|
|
100
109
|
// bundled meta-deps are copied over to the ideal tree when we visit it,
|
|
101
110
|
// so they'll appear to be missing here. There's no need to handle them
|
|
102
111
|
// in the diff, though, because they'll be replaced at reify time anyway
|
|
103
112
|
// Otherwise, add the missing node.
|
|
104
|
-
if (!actual)
|
|
113
|
+
if (!actual) {
|
|
105
114
|
return ideal.inDepBundle ? null : 'ADD'
|
|
115
|
+
}
|
|
106
116
|
|
|
107
117
|
// always ignore the root node
|
|
108
|
-
if (ideal.isRoot && actual.isRoot)
|
|
118
|
+
if (ideal.isRoot && actual.isRoot) {
|
|
109
119
|
return null
|
|
120
|
+
}
|
|
110
121
|
|
|
111
122
|
// if the versions don't match, it's a change no matter what
|
|
112
|
-
if (ideal.version !== actual.version)
|
|
123
|
+
if (ideal.version !== actual.version) {
|
|
113
124
|
return 'CHANGE'
|
|
125
|
+
}
|
|
114
126
|
|
|
115
127
|
const binsExist = ideal.binPaths.every((path) => existsSync(path))
|
|
116
128
|
|
|
@@ -125,33 +137,38 @@ const getAction = ({actual, ideal}) => {
|
|
|
125
137
|
const noIntegrity = !ideal.integrity && !actual.integrity
|
|
126
138
|
const noResolved = !ideal.resolved && !actual.resolved
|
|
127
139
|
const resolvedMatch = ideal.resolved && ideal.resolved === actual.resolved
|
|
128
|
-
if (noIntegrity && binsExist && (resolvedMatch || noResolved))
|
|
140
|
+
if (noIntegrity && binsExist && (resolvedMatch || noResolved)) {
|
|
129
141
|
return null
|
|
142
|
+
}
|
|
130
143
|
|
|
131
144
|
// otherwise, verify that it's the same bits
|
|
132
145
|
// note that if ideal has integrity, and resolved doesn't, we treat
|
|
133
146
|
// that as a 'change', so that it gets re-fetched and locked down.
|
|
134
147
|
const integrityMismatch = !ideal.integrity || !actual.integrity ||
|
|
135
148
|
!ssri.parse(ideal.integrity).match(actual.integrity)
|
|
136
|
-
if (integrityMismatch || !binsExist)
|
|
149
|
+
if (integrityMismatch || !binsExist) {
|
|
137
150
|
return 'CHANGE'
|
|
151
|
+
}
|
|
138
152
|
|
|
139
153
|
return null
|
|
140
154
|
}
|
|
141
155
|
|
|
142
156
|
const allChildren = node => {
|
|
143
|
-
if (!node)
|
|
157
|
+
if (!node) {
|
|
144
158
|
return new Map()
|
|
159
|
+
}
|
|
145
160
|
|
|
146
161
|
// if the node is root, and also a link, then what we really
|
|
147
162
|
// want is to traverse the target's children
|
|
148
|
-
if (node.isRoot && node.isLink)
|
|
163
|
+
if (node.isRoot && node.isLink) {
|
|
149
164
|
return allChildren(node.target)
|
|
165
|
+
}
|
|
150
166
|
|
|
151
167
|
const kids = new Map()
|
|
152
168
|
for (const n of [node, ...node.fsChildren]) {
|
|
153
|
-
for (const kid of n.children.values())
|
|
169
|
+
for (const kid of n.children.values()) {
|
|
154
170
|
kids.set(kid.path, kid)
|
|
171
|
+
}
|
|
155
172
|
}
|
|
156
173
|
return kids
|
|
157
174
|
}
|
|
@@ -160,7 +177,14 @@ const allChildren = node => {
|
|
|
160
177
|
// to create the diff tree
|
|
161
178
|
const getChildren = diff => {
|
|
162
179
|
const children = []
|
|
163
|
-
const {
|
|
180
|
+
const {
|
|
181
|
+
actual,
|
|
182
|
+
ideal,
|
|
183
|
+
unchanged,
|
|
184
|
+
removed,
|
|
185
|
+
filterSet,
|
|
186
|
+
shrinkwrapInflated,
|
|
187
|
+
} = diff
|
|
164
188
|
|
|
165
189
|
// Note: we DON'T diff fsChildren themselves, because they are either
|
|
166
190
|
// included in the package contents, or part of some other project, and
|
|
@@ -182,26 +206,45 @@ const getChildren = diff => {
|
|
|
182
206
|
for (const path of paths) {
|
|
183
207
|
const actual = actualKids.get(path)
|
|
184
208
|
const ideal = idealKids.get(path)
|
|
185
|
-
diffNode(
|
|
209
|
+
diffNode({
|
|
210
|
+
actual,
|
|
211
|
+
ideal,
|
|
212
|
+
children,
|
|
213
|
+
unchanged,
|
|
214
|
+
removed,
|
|
215
|
+
filterSet,
|
|
216
|
+
shrinkwrapInflated,
|
|
217
|
+
})
|
|
186
218
|
}
|
|
187
219
|
|
|
188
|
-
if (diff.leaves && !children.length)
|
|
220
|
+
if (diff.leaves && !children.length) {
|
|
189
221
|
diff.leaves.push(diff)
|
|
222
|
+
}
|
|
190
223
|
|
|
191
224
|
return children
|
|
192
225
|
}
|
|
193
226
|
|
|
194
|
-
const diffNode = (
|
|
195
|
-
|
|
227
|
+
const diffNode = ({
|
|
228
|
+
actual,
|
|
229
|
+
ideal,
|
|
230
|
+
children,
|
|
231
|
+
unchanged,
|
|
232
|
+
removed,
|
|
233
|
+
filterSet,
|
|
234
|
+
shrinkwrapInflated,
|
|
235
|
+
}) => {
|
|
236
|
+
if (filterSet.size && !(filterSet.has(ideal) || filterSet.has(actual))) {
|
|
196
237
|
return
|
|
238
|
+
}
|
|
197
239
|
|
|
198
240
|
const action = getAction({actual, ideal})
|
|
199
241
|
|
|
200
242
|
// if it's a match, then get its children
|
|
201
243
|
// otherwise, this is the child diff node
|
|
202
244
|
if (action || (!shrinkwrapInflated.has(ideal) && ideal.hasShrinkwrap)) {
|
|
203
|
-
if (action === 'REMOVE')
|
|
245
|
+
if (action === 'REMOVE') {
|
|
204
246
|
removed.push(actual)
|
|
247
|
+
}
|
|
205
248
|
children.push(new Diff({actual, ideal, filterSet, shrinkwrapInflated}))
|
|
206
249
|
} else {
|
|
207
250
|
unchanged.push(ideal)
|
|
@@ -227,13 +270,22 @@ const diffNode = (actual, ideal, children, unchanged, removed, filterSet, shrink
|
|
|
227
270
|
if (actual && bd && bd.length) {
|
|
228
271
|
const bundledChildren = []
|
|
229
272
|
for (const node of actual.children.values()) {
|
|
230
|
-
if (node.inBundle)
|
|
273
|
+
if (node.inBundle) {
|
|
231
274
|
bundledChildren.push(node)
|
|
275
|
+
}
|
|
232
276
|
}
|
|
233
|
-
for (const node of bundledChildren)
|
|
277
|
+
for (const node of bundledChildren) {
|
|
234
278
|
node.parent = ideal
|
|
279
|
+
}
|
|
235
280
|
}
|
|
236
|
-
children.push(...getChildren({
|
|
281
|
+
children.push(...getChildren({
|
|
282
|
+
actual,
|
|
283
|
+
ideal,
|
|
284
|
+
unchanged,
|
|
285
|
+
removed,
|
|
286
|
+
filterSet,
|
|
287
|
+
shrinkwrapInflated,
|
|
288
|
+
}))
|
|
237
289
|
}
|
|
238
290
|
}
|
|
239
291
|
|
package/lib/edge.js
CHANGED
|
@@ -45,22 +45,26 @@ class Edge {
|
|
|
45
45
|
constructor (options) {
|
|
46
46
|
const { type, name, spec, accept, from } = options
|
|
47
47
|
|
|
48
|
-
if (typeof spec !== 'string')
|
|
48
|
+
if (typeof spec !== 'string') {
|
|
49
49
|
throw new TypeError('must provide string spec')
|
|
50
|
+
}
|
|
50
51
|
|
|
51
|
-
if (type === 'workspace' && npa(spec).type !== 'directory')
|
|
52
|
+
if (type === 'workspace' && npa(spec).type !== 'directory') {
|
|
52
53
|
throw new TypeError('workspace edges must be a symlink')
|
|
54
|
+
}
|
|
53
55
|
|
|
54
56
|
this[_spec] = spec
|
|
55
57
|
|
|
56
58
|
if (accept !== undefined) {
|
|
57
|
-
if (typeof accept !== 'string')
|
|
59
|
+
if (typeof accept !== 'string') {
|
|
58
60
|
throw new TypeError('accept field must be a string if provided')
|
|
61
|
+
}
|
|
59
62
|
this[_accept] = accept || '*'
|
|
60
63
|
}
|
|
61
64
|
|
|
62
|
-
if (typeof name !== 'string')
|
|
65
|
+
if (typeof name !== 'string') {
|
|
63
66
|
throw new TypeError('must provide dependency name')
|
|
67
|
+
}
|
|
64
68
|
this[_name] = name
|
|
65
69
|
|
|
66
70
|
if (!types.has(type)) {
|
|
@@ -69,20 +73,23 @@ class Edge {
|
|
|
69
73
|
`(valid types are: ${Edge.types.join(', ')})`)
|
|
70
74
|
}
|
|
71
75
|
this[_type] = type
|
|
72
|
-
if (!from)
|
|
76
|
+
if (!from) {
|
|
73
77
|
throw new TypeError('must provide "from" node')
|
|
78
|
+
}
|
|
74
79
|
this[_setFrom](from)
|
|
75
80
|
this[_error] = this[_loadError]()
|
|
76
81
|
this.overridden = false
|
|
77
82
|
}
|
|
78
83
|
|
|
79
84
|
satisfiedBy (node) {
|
|
80
|
-
return node.name === this.name &&
|
|
85
|
+
return node.name === this.name &&
|
|
86
|
+
depValid(node, this.spec, this.accept, this.from)
|
|
81
87
|
}
|
|
82
88
|
|
|
83
89
|
explain (seen = []) {
|
|
84
|
-
if (this[_explanation])
|
|
90
|
+
if (this[_explanation]) {
|
|
85
91
|
return this[_explanation]
|
|
92
|
+
}
|
|
86
93
|
|
|
87
94
|
return this[_explanation] = this[_explain](seen)
|
|
88
95
|
}
|
|
@@ -101,8 +108,9 @@ class Edge {
|
|
|
101
108
|
}
|
|
102
109
|
|
|
103
110
|
get bundled () {
|
|
104
|
-
if (!this.from)
|
|
111
|
+
if (!this.from) {
|
|
105
112
|
return false
|
|
113
|
+
}
|
|
106
114
|
const { package: { bundleDependencies = [] } } = this.from
|
|
107
115
|
return bundleDependencies.includes(this.name)
|
|
108
116
|
}
|
|
@@ -175,20 +183,24 @@ class Edge {
|
|
|
175
183
|
this[_explanation] = null
|
|
176
184
|
const newTo = this[_from].resolve(this.name)
|
|
177
185
|
if (newTo !== this[_to]) {
|
|
178
|
-
if (this[_to])
|
|
186
|
+
if (this[_to]) {
|
|
179
187
|
this[_to].edgesIn.delete(this)
|
|
188
|
+
}
|
|
180
189
|
this[_to] = newTo
|
|
181
190
|
this[_error] = this[_loadError]()
|
|
182
|
-
if (this[_to])
|
|
191
|
+
if (this[_to]) {
|
|
183
192
|
this[_to].addEdgeIn(this)
|
|
184
|
-
|
|
193
|
+
}
|
|
194
|
+
} else if (hard) {
|
|
185
195
|
this[_error] = this[_loadError]()
|
|
196
|
+
}
|
|
186
197
|
}
|
|
187
198
|
|
|
188
199
|
detach () {
|
|
189
200
|
this[_explanation] = null
|
|
190
|
-
if (this[_to])
|
|
201
|
+
if (this[_to]) {
|
|
191
202
|
this[_to].edgesIn.delete(this)
|
|
203
|
+
}
|
|
192
204
|
this[_from].edgesOut.delete(this.name)
|
|
193
205
|
this[_to] = null
|
|
194
206
|
this[_error] = 'DETACHED'
|
|
@@ -198,8 +210,9 @@ class Edge {
|
|
|
198
210
|
[_setFrom] (node) {
|
|
199
211
|
this[_explanation] = null
|
|
200
212
|
this[_from] = node
|
|
201
|
-
if (node.edgesOut.has(this.name))
|
|
213
|
+
if (node.edgesOut.has(this.name)) {
|
|
202
214
|
node.edgesOut.get(this.name).detach()
|
|
215
|
+
}
|
|
203
216
|
node.addEdgeOut(this)
|
|
204
217
|
this.reload()
|
|
205
218
|
}
|
package/lib/gather-dep-set.js
CHANGED
|
@@ -14,8 +14,9 @@ const gatherDepSet = (set, edgeFilter) => {
|
|
|
14
14
|
// as the deps set increases in size.
|
|
15
15
|
for (const node of deps) {
|
|
16
16
|
for (const edge of node.edgesOut.values()) {
|
|
17
|
-
if (edge.to && edgeFilter(edge))
|
|
17
|
+
if (edge.to && edgeFilter(edge)) {
|
|
18
18
|
deps.add(edge.to)
|
|
19
|
+
}
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
|
package/lib/inventory.js
CHANGED
|
@@ -13,11 +13,13 @@ const debug = require('./debug.js')
|
|
|
13
13
|
const getLicense = pkg => {
|
|
14
14
|
if (pkg) {
|
|
15
15
|
const lic = pkg.license || pkg.licence
|
|
16
|
-
if (lic)
|
|
16
|
+
if (lic) {
|
|
17
17
|
return lic
|
|
18
|
+
}
|
|
18
19
|
const lics = pkg.licenses || pkg.licences
|
|
19
|
-
if (Array.isArray(lics))
|
|
20
|
+
if (Array.isArray(lics)) {
|
|
20
21
|
return lics[0]
|
|
22
|
+
}
|
|
21
23
|
}
|
|
22
24
|
}
|
|
23
25
|
|
|
@@ -42,8 +44,9 @@ class Inventory extends Map {
|
|
|
42
44
|
|
|
43
45
|
* filter (fn) {
|
|
44
46
|
for (const node of this.values()) {
|
|
45
|
-
if (fn(node))
|
|
47
|
+
if (fn(node)) {
|
|
46
48
|
yield node
|
|
49
|
+
}
|
|
47
50
|
}
|
|
48
51
|
}
|
|
49
52
|
|
|
@@ -62,8 +65,9 @@ class Inventory extends Map {
|
|
|
62
65
|
|
|
63
66
|
const current = super.get(node[this.primaryKey])
|
|
64
67
|
if (current) {
|
|
65
|
-
if (current === node)
|
|
68
|
+
if (current === node) {
|
|
66
69
|
return
|
|
70
|
+
}
|
|
67
71
|
this.delete(current)
|
|
68
72
|
}
|
|
69
73
|
super.set(node[this.primaryKey], node)
|
|
@@ -85,8 +89,9 @@ class Inventory extends Map {
|
|
|
85
89
|
}
|
|
86
90
|
|
|
87
91
|
delete (node) {
|
|
88
|
-
if (!this.has(node))
|
|
92
|
+
if (!this.has(node)) {
|
|
89
93
|
return
|
|
94
|
+
}
|
|
90
95
|
|
|
91
96
|
super.delete(node[this.primaryKey])
|
|
92
97
|
for (const [key, map] of this[_index].entries()) {
|
|
@@ -95,8 +100,9 @@ class Inventory extends Map {
|
|
|
95
100
|
const set = map.get(val)
|
|
96
101
|
if (set) {
|
|
97
102
|
set.delete(node)
|
|
98
|
-
if (set.size === 0)
|
|
103
|
+
if (set.size === 0) {
|
|
99
104
|
map.delete(node[key])
|
|
105
|
+
}
|
|
100
106
|
}
|
|
101
107
|
}
|
|
102
108
|
}
|
package/lib/link.js
CHANGED
|
@@ -11,8 +11,9 @@ class Link extends Node {
|
|
|
11
11
|
constructor (options) {
|
|
12
12
|
const { root, realpath, target, parent, fsParent } = options
|
|
13
13
|
|
|
14
|
-
if (!realpath && !(target && target.path))
|
|
14
|
+
if (!realpath && !(target && target.path)) {
|
|
15
15
|
throw new TypeError('must provide realpath for Link node')
|
|
16
|
+
}
|
|
16
17
|
|
|
17
18
|
super({
|
|
18
19
|
...options,
|
|
@@ -23,11 +24,11 @@ class Link extends Node {
|
|
|
23
24
|
: null),
|
|
24
25
|
})
|
|
25
26
|
|
|
26
|
-
if (target)
|
|
27
|
+
if (target) {
|
|
27
28
|
this.target = target
|
|
28
|
-
else if (this.realpath === this.root.path)
|
|
29
|
+
} else if (this.realpath === this.root.path) {
|
|
29
30
|
this.target = this.root
|
|
30
|
-
else {
|
|
31
|
+
} else {
|
|
31
32
|
this.target = new Node({
|
|
32
33
|
...options,
|
|
33
34
|
path: realpath,
|
|
@@ -48,8 +49,9 @@ class Link extends Node {
|
|
|
48
49
|
|
|
49
50
|
set target (target) {
|
|
50
51
|
const current = this[_target]
|
|
51
|
-
if (target === current)
|
|
52
|
+
if (target === current) {
|
|
52
53
|
return
|
|
54
|
+
}
|
|
53
55
|
|
|
54
56
|
if (current && current.then) {
|
|
55
57
|
debug(() => {
|
|
@@ -72,25 +74,28 @@ class Link extends Node {
|
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
if (!target) {
|
|
75
|
-
if (current && current.linksIn)
|
|
77
|
+
if (current && current.linksIn) {
|
|
76
78
|
current.linksIn.delete(this)
|
|
79
|
+
}
|
|
77
80
|
if (this.path) {
|
|
78
81
|
this[_delistFromMeta]()
|
|
79
82
|
this[_target] = null
|
|
80
83
|
this.package = {}
|
|
81
84
|
this[_refreshLocation]()
|
|
82
|
-
} else
|
|
85
|
+
} else {
|
|
83
86
|
this[_target] = null
|
|
87
|
+
}
|
|
84
88
|
return
|
|
85
89
|
}
|
|
86
90
|
|
|
87
91
|
if (!this.path) {
|
|
88
92
|
// temp node pending assignment to a tree
|
|
89
93
|
// we know it's not in the inventory yet, because no path.
|
|
90
|
-
if (target.path)
|
|
94
|
+
if (target.path) {
|
|
91
95
|
this.realpath = target.path
|
|
92
|
-
else
|
|
96
|
+
} else {
|
|
93
97
|
target.path = target.realpath = this.realpath
|
|
98
|
+
}
|
|
94
99
|
target.root = this.root
|
|
95
100
|
this[_target] = target
|
|
96
101
|
target.linksIn.add(this)
|