@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/optional-set.js
CHANGED
|
@@ -10,8 +10,9 @@
|
|
|
10
10
|
|
|
11
11
|
const gatherDepSet = require('./gather-dep-set.js')
|
|
12
12
|
const optionalSet = node => {
|
|
13
|
-
if (!node.optional)
|
|
13
|
+
if (!node.optional) {
|
|
14
14
|
return new Set()
|
|
15
|
+
}
|
|
15
16
|
|
|
16
17
|
// start with the node, then walk up the dependency graph until we
|
|
17
18
|
// get to the boundaries that define the optional set. since the
|
|
@@ -21,8 +22,9 @@ const optionalSet = node => {
|
|
|
21
22
|
const set = new Set([node])
|
|
22
23
|
for (const node of set) {
|
|
23
24
|
for (const edge of node.edgesIn) {
|
|
24
|
-
if (!edge.optional)
|
|
25
|
+
if (!edge.optional) {
|
|
25
26
|
set.add(edge.from)
|
|
27
|
+
}
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
30
|
|
package/lib/peer-entry-sets.js
CHANGED
|
@@ -15,12 +15,14 @@ const peerEntrySets = node => {
|
|
|
15
15
|
const unionSet = new Set([node])
|
|
16
16
|
for (const node of unionSet) {
|
|
17
17
|
for (const edge of node.edgesOut.values()) {
|
|
18
|
-
if (edge.valid && edge.peer && edge.to)
|
|
18
|
+
if (edge.valid && edge.peer && edge.to) {
|
|
19
19
|
unionSet.add(edge.to)
|
|
20
|
+
}
|
|
20
21
|
}
|
|
21
22
|
for (const edge of node.edgesIn) {
|
|
22
|
-
if (edge.valid && edge.peer)
|
|
23
|
+
if (edge.valid && edge.peer) {
|
|
23
24
|
unionSet.add(edge.from)
|
|
25
|
+
}
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
28
|
const entrySets = new Map()
|
|
@@ -28,16 +30,18 @@ const peerEntrySets = node => {
|
|
|
28
30
|
for (const edge of peer.edgesIn) {
|
|
29
31
|
// if not valid, it doesn't matter anyway. either it's been previously
|
|
30
32
|
// overridden, or it's the thing we're interested in replacing.
|
|
31
|
-
if (!edge.valid)
|
|
33
|
+
if (!edge.valid) {
|
|
32
34
|
continue
|
|
35
|
+
}
|
|
33
36
|
// this is the entry point into the peer set
|
|
34
37
|
if (!edge.peer || edge.from.isTop) {
|
|
35
38
|
// get the subset of peer brought in by this peer entry edge
|
|
36
39
|
const sub = new Set([peer])
|
|
37
40
|
for (const peer of sub) {
|
|
38
41
|
for (const edge of peer.edgesOut.values()) {
|
|
39
|
-
if (edge.valid && edge.peer && edge.to)
|
|
42
|
+
if (edge.valid && edge.peer && edge.to) {
|
|
40
43
|
sub.add(edge.to)
|
|
44
|
+
}
|
|
41
45
|
}
|
|
42
46
|
}
|
|
43
47
|
// if this subset does not include the node we are focused on,
|
|
@@ -60,8 +64,9 @@ const peerEntrySets = node => {
|
|
|
60
64
|
// Edge(a->b) => Set(b, d, e, f, g)
|
|
61
65
|
// Edge(a->d) => Set(d, e, f, g)
|
|
62
66
|
// }
|
|
63
|
-
if (sub.has(node))
|
|
67
|
+
if (sub.has(node)) {
|
|
64
68
|
entrySets.set(edge, sub)
|
|
69
|
+
}
|
|
65
70
|
}
|
|
66
71
|
}
|
|
67
72
|
}
|
package/lib/place-dep.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// and saves a set of what was placed and what needs re-evaluation as
|
|
8
8
|
// a result.
|
|
9
9
|
|
|
10
|
+
const localeCompare = require('@isaacs/string-locale-compare')('en')
|
|
10
11
|
const log = require('proc-log')
|
|
11
12
|
const deepestNestingTarget = require('./deepest-nesting-target.js')
|
|
12
13
|
const CanPlaceDep = require('./can-place-dep.js')
|
|
@@ -63,6 +64,8 @@ class PlaceDep {
|
|
|
63
64
|
this.parent = parent
|
|
64
65
|
this.peerConflict = null
|
|
65
66
|
|
|
67
|
+
this.needEvaluation = new Set()
|
|
68
|
+
|
|
66
69
|
this.checks = new Map()
|
|
67
70
|
|
|
68
71
|
this.place()
|
|
@@ -85,8 +88,9 @@ class PlaceDep {
|
|
|
85
88
|
!edge.error &&
|
|
86
89
|
!explicitRequest &&
|
|
87
90
|
!updateNames.includes(edge.name) &&
|
|
88
|
-
!this.isVulnerable(edge.to))
|
|
91
|
+
!this.isVulnerable(edge.to)) {
|
|
89
92
|
return
|
|
93
|
+
}
|
|
90
94
|
|
|
91
95
|
// walk up the tree until we hit either a top/root node, or a place
|
|
92
96
|
// where the dep is not a peer dep.
|
|
@@ -110,8 +114,9 @@ class PlaceDep {
|
|
|
110
114
|
// but we CAN place it under a, so the correct thing to do is keep
|
|
111
115
|
// walking up the tree.
|
|
112
116
|
const targetEdge = target.edgesOut.get(edge.name)
|
|
113
|
-
if (!target.isTop && targetEdge && targetEdge.peer)
|
|
117
|
+
if (!target.isTop && targetEdge && targetEdge.peer) {
|
|
114
118
|
continue
|
|
119
|
+
}
|
|
115
120
|
|
|
116
121
|
const cpd = new CanPlaceDep({
|
|
117
122
|
dep,
|
|
@@ -141,34 +146,39 @@ class PlaceDep {
|
|
|
141
146
|
// should treat (b) and (d) as OK, and place them in the last place
|
|
142
147
|
// where they did not themselves conflict, and skip c@2 if conflict
|
|
143
148
|
// is ok by virtue of being forced or not ours and not strict.
|
|
144
|
-
if (cpd.canPlaceSelf !== CONFLICT)
|
|
149
|
+
if (cpd.canPlaceSelf !== CONFLICT) {
|
|
145
150
|
canPlaceSelf = cpd
|
|
151
|
+
}
|
|
146
152
|
|
|
147
153
|
// we found a place this can go, along with all its peer friends.
|
|
148
154
|
// we break when we get the first conflict
|
|
149
|
-
if (cpd.canPlace !== CONFLICT)
|
|
155
|
+
if (cpd.canPlace !== CONFLICT) {
|
|
150
156
|
canPlace = cpd
|
|
151
|
-
else
|
|
157
|
+
} else {
|
|
152
158
|
break
|
|
159
|
+
}
|
|
153
160
|
|
|
154
161
|
// if it's a load failure, just plop it in the first place attempted,
|
|
155
162
|
// since we're going to crash the build or prune it out anyway.
|
|
156
163
|
// but, this will frequently NOT be a successful canPlace, because
|
|
157
164
|
// it'll have no version or other information.
|
|
158
|
-
if (dep.errors.length)
|
|
165
|
+
if (dep.errors.length) {
|
|
159
166
|
break
|
|
167
|
+
}
|
|
160
168
|
|
|
161
169
|
// nest packages like npm v1 and v2
|
|
162
170
|
// very disk-inefficient
|
|
163
|
-
if (legacyBundling)
|
|
171
|
+
if (legacyBundling) {
|
|
164
172
|
break
|
|
173
|
+
}
|
|
165
174
|
|
|
166
175
|
// when installing globally, or just in global style, we never place
|
|
167
176
|
// deps above the first level.
|
|
168
177
|
if (globalStyle) {
|
|
169
178
|
const rp = target.resolveParent
|
|
170
|
-
if (rp && rp.isProjectRoot)
|
|
179
|
+
if (rp && rp.isProjectRoot) {
|
|
171
180
|
break
|
|
181
|
+
}
|
|
172
182
|
}
|
|
173
183
|
}
|
|
174
184
|
|
|
@@ -183,8 +193,9 @@ class PlaceDep {
|
|
|
183
193
|
if (!canPlace) {
|
|
184
194
|
// if not forced, or it's our dep, or strictPeerDeps is set, then
|
|
185
195
|
// this is an ERESOLVE error.
|
|
186
|
-
if (!this.conflictOk)
|
|
196
|
+
if (!this.conflictOk) {
|
|
187
197
|
return this.failPeerConflict()
|
|
198
|
+
}
|
|
188
199
|
|
|
189
200
|
// ok! we're gonna allow the conflict, but we should still warn
|
|
190
201
|
// if we have a current, then we treat CONFLICT as a KEEP.
|
|
@@ -237,8 +248,9 @@ class PlaceDep {
|
|
|
237
248
|
// it's a conflict. Treat it as a KEEP, but warn and move on.
|
|
238
249
|
if (placementType === KEEP) {
|
|
239
250
|
// this was an overridden peer dep
|
|
240
|
-
if (edge.peer && !edge.valid)
|
|
251
|
+
if (edge.peer && !edge.valid) {
|
|
241
252
|
this.warnPeerConflict()
|
|
253
|
+
}
|
|
242
254
|
|
|
243
255
|
// if we get a KEEP in a update scenario, then we MAY have something
|
|
244
256
|
// already duplicating this unnecessarily! For example:
|
|
@@ -287,21 +299,24 @@ class PlaceDep {
|
|
|
287
299
|
})
|
|
288
300
|
|
|
289
301
|
this.oldDep = target.children.get(this.name)
|
|
290
|
-
if (this.oldDep)
|
|
302
|
+
if (this.oldDep) {
|
|
291
303
|
this.replaceOldDep()
|
|
292
|
-
else
|
|
304
|
+
} else {
|
|
293
305
|
this.placed.parent = target
|
|
306
|
+
}
|
|
294
307
|
|
|
295
308
|
// if it's an overridden peer dep, warn about it
|
|
296
|
-
if (edge.peer && !this.placed.satisfies(edge))
|
|
309
|
+
if (edge.peer && !this.placed.satisfies(edge)) {
|
|
297
310
|
this.warnPeerConflict()
|
|
311
|
+
}
|
|
298
312
|
|
|
299
313
|
// If the edge is not an error, then we're updating something, and
|
|
300
314
|
// MAY end up putting a better/identical node further up the tree in
|
|
301
315
|
// a way that causes an unnecessary duplication. If so, remove the
|
|
302
316
|
// now-unnecessary node.
|
|
303
|
-
if (edge.valid && edge.to && edge.to !== this.placed)
|
|
317
|
+
if (edge.valid && edge.to && edge.to !== this.placed) {
|
|
304
318
|
this.pruneDedupable(edge.to, false)
|
|
319
|
+
}
|
|
305
320
|
|
|
306
321
|
// in case we just made some duplicates that can be removed,
|
|
307
322
|
// prune anything deeper in the tree that can be replaced by this
|
|
@@ -310,8 +325,9 @@ class PlaceDep {
|
|
|
310
325
|
this.pruneDedupable(node, false)
|
|
311
326
|
// only walk the direct children of the ones we kept
|
|
312
327
|
if (node.root === target.root) {
|
|
313
|
-
for (const kid of node.children.values())
|
|
328
|
+
for (const kid of node.children.values()) {
|
|
314
329
|
this.pruneDedupable(kid, false)
|
|
330
|
+
}
|
|
315
331
|
}
|
|
316
332
|
}
|
|
317
333
|
}
|
|
@@ -323,8 +339,9 @@ class PlaceDep {
|
|
|
323
339
|
// otherwise they'd be gone and the peer set would change throughout
|
|
324
340
|
// this loop.
|
|
325
341
|
for (const peerEdge of this.placed.edgesOut.values()) {
|
|
326
|
-
if (peerEdge.valid || !peerEdge.peer || peerEdge.overridden)
|
|
342
|
+
if (peerEdge.valid || !peerEdge.peer || peerEdge.overridden) {
|
|
327
343
|
continue
|
|
344
|
+
}
|
|
328
345
|
|
|
329
346
|
const peer = virtualRoot.children.get(peerEdge.name)
|
|
330
347
|
|
|
@@ -332,12 +349,14 @@ class PlaceDep {
|
|
|
332
349
|
// it's an optional peer dep. If it's not being properly met (ie,
|
|
333
350
|
// peerEdge.valid is false), then this is likely heading for an
|
|
334
351
|
// ERESOLVE error, unless it can walk further up the tree.
|
|
335
|
-
if (!peer)
|
|
352
|
+
if (!peer) {
|
|
336
353
|
continue
|
|
354
|
+
}
|
|
337
355
|
|
|
338
356
|
// overridden peerEdge, just accept what's there already
|
|
339
|
-
if (!peer.satisfies(peerEdge))
|
|
357
|
+
if (!peer.satisfies(peerEdge)) {
|
|
340
358
|
continue
|
|
359
|
+
}
|
|
341
360
|
|
|
342
361
|
this.children.push(new PlaceDep({
|
|
343
362
|
parent: this,
|
|
@@ -349,6 +368,8 @@ class PlaceDep {
|
|
|
349
368
|
}
|
|
350
369
|
|
|
351
370
|
replaceOldDep () {
|
|
371
|
+
const target = this.oldDep.parent
|
|
372
|
+
|
|
352
373
|
// XXX handle replacing an entire peer group?
|
|
353
374
|
// what about cases where we need to push some other peer groups deeper
|
|
354
375
|
// into the tree? all the tree updating should be done here, and track
|
|
@@ -363,11 +384,51 @@ class PlaceDep {
|
|
|
363
384
|
// later anyway.
|
|
364
385
|
const oldDeps = []
|
|
365
386
|
for (const [name, edge] of this.oldDep.edgesOut.entries()) {
|
|
366
|
-
if (!this.placed.edgesOut.has(name) && edge.to)
|
|
387
|
+
if (!this.placed.edgesOut.has(name) && edge.to) {
|
|
367
388
|
oldDeps.push(...gatherDepSet([edge.to], e => e.to !== edge.to))
|
|
389
|
+
}
|
|
368
390
|
}
|
|
391
|
+
|
|
392
|
+
// gather all peer edgesIn which are at this level, and will not be
|
|
393
|
+
// satisfied by the new dependency. Those are the peer sets that need
|
|
394
|
+
// to be either warned about (if they cannot go deeper), or removed and
|
|
395
|
+
// re-placed (if they can).
|
|
396
|
+
const prunePeerSets = []
|
|
397
|
+
for (const edge of this.oldDep.edgesIn) {
|
|
398
|
+
if (this.placed.satisfies(edge) ||
|
|
399
|
+
!edge.peer ||
|
|
400
|
+
edge.from.parent !== target ||
|
|
401
|
+
edge.overridden) {
|
|
402
|
+
// not a peer dep, not invalid, or not from this level, so it's fine
|
|
403
|
+
// to just let it re-evaluate as a problemEdge later, or let it be
|
|
404
|
+
// satisfied by the new dep being placed.
|
|
405
|
+
continue
|
|
406
|
+
}
|
|
407
|
+
for (const entryEdge of peerEntrySets(edge.from).keys()) {
|
|
408
|
+
// either this one needs to be pruned and re-evaluated, or marked
|
|
409
|
+
// as overridden and warned about. If the entryEdge comes in from
|
|
410
|
+
// the root, then we have to leave it alone, and in that case, it
|
|
411
|
+
// will have already warned or crashed by getting to this point.
|
|
412
|
+
const entryNode = entryEdge.to
|
|
413
|
+
const deepestTarget = deepestNestingTarget(entryNode)
|
|
414
|
+
if (deepestTarget !== target && !entryEdge.from.isRoot) {
|
|
415
|
+
prunePeerSets.push(...gatherDepSet([entryNode], e => {
|
|
416
|
+
return e.to !== entryNode && !e.overridden
|
|
417
|
+
}))
|
|
418
|
+
} else {
|
|
419
|
+
this.warnPeerConflict(edge, this.dep)
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
369
424
|
this.placed.replace(this.oldDep)
|
|
370
425
|
this.pruneForReplacement(this.placed, oldDeps)
|
|
426
|
+
for (const dep of prunePeerSets) {
|
|
427
|
+
for (const edge of dep.edgesIn) {
|
|
428
|
+
this.needEvaluation.add(edge.from)
|
|
429
|
+
}
|
|
430
|
+
dep.root = null
|
|
431
|
+
}
|
|
371
432
|
}
|
|
372
433
|
|
|
373
434
|
pruneForReplacement (node, oldDeps) {
|
|
@@ -377,8 +438,9 @@ class PlaceDep {
|
|
|
377
438
|
.filter(e => e.to && !e.valid).map(e => e.to))
|
|
378
439
|
for (const dep of oldDeps) {
|
|
379
440
|
const set = gatherDepSet([dep], e => e.to !== dep && e.valid)
|
|
380
|
-
for (const dep of set)
|
|
441
|
+
for (const dep of set) {
|
|
381
442
|
invalidDeps.add(dep)
|
|
443
|
+
}
|
|
382
444
|
}
|
|
383
445
|
|
|
384
446
|
// ignore dependency edges from the node being replaced, but
|
|
@@ -388,8 +450,9 @@ class PlaceDep {
|
|
|
388
450
|
edge.from !== node && edge.to !== node && edge.valid)
|
|
389
451
|
|
|
390
452
|
// now just delete whatever's left, because it's junk
|
|
391
|
-
for (const dep of deps)
|
|
453
|
+
for (const dep of deps) {
|
|
392
454
|
dep.root = null
|
|
455
|
+
}
|
|
393
456
|
}
|
|
394
457
|
|
|
395
458
|
// prune all the nodes in a branch of the tree that can be safely removed
|
|
@@ -402,24 +465,27 @@ class PlaceDep {
|
|
|
402
465
|
// the dep set, except for this node we're deduping, so that we
|
|
403
466
|
// also prune deps that would be made extraneous.
|
|
404
467
|
const deps = gatherDepSet([node], e => e.to !== node && e.valid)
|
|
405
|
-
for (const node of deps)
|
|
468
|
+
for (const node of deps) {
|
|
406
469
|
node.root = null
|
|
470
|
+
}
|
|
407
471
|
return
|
|
408
472
|
}
|
|
409
473
|
if (descend) {
|
|
410
474
|
// sort these so that they're deterministically ordered
|
|
411
475
|
// otherwise, resulting tree shape is dependent on the order
|
|
412
476
|
// in which they happened to be resolved.
|
|
413
|
-
const nodeSort = (a, b) => a.location
|
|
477
|
+
const nodeSort = (a, b) => localeCompare(a.location, b.location)
|
|
414
478
|
|
|
415
479
|
const children = [...node.children.values()].sort(nodeSort)
|
|
416
|
-
for (const child of children)
|
|
480
|
+
for (const child of children) {
|
|
417
481
|
this.pruneDedupable(child)
|
|
482
|
+
}
|
|
418
483
|
const fsChildren = [...node.fsChildren].sort(nodeSort)
|
|
419
484
|
for (const topNode of fsChildren) {
|
|
420
485
|
const children = [...topNode.children.values()].sort(nodeSort)
|
|
421
|
-
for (const child of children)
|
|
486
|
+
for (const child of children) {
|
|
422
487
|
this.pruneDedupable(child)
|
|
488
|
+
}
|
|
423
489
|
}
|
|
424
490
|
}
|
|
425
491
|
}
|
|
@@ -432,11 +498,13 @@ class PlaceDep {
|
|
|
432
498
|
const { edge } = this.top
|
|
433
499
|
const { from: node } = edge
|
|
434
500
|
|
|
435
|
-
if (node.isWorkspace || node.isProjectRoot)
|
|
501
|
+
if (node.isWorkspace || node.isProjectRoot) {
|
|
436
502
|
return true
|
|
503
|
+
}
|
|
437
504
|
|
|
438
|
-
if (!edge.peer)
|
|
505
|
+
if (!edge.peer) {
|
|
439
506
|
return false
|
|
507
|
+
}
|
|
440
508
|
|
|
441
509
|
// re-entry case. check if any non-peer edges come from the project,
|
|
442
510
|
// or any entryEdges on peer groups are from the root.
|
|
@@ -446,32 +514,37 @@ class PlaceDep {
|
|
|
446
514
|
hasPeerEdges = true
|
|
447
515
|
continue
|
|
448
516
|
}
|
|
449
|
-
if (edge.from.isWorkspace || edge.from.isProjectRoot)
|
|
517
|
+
if (edge.from.isWorkspace || edge.from.isProjectRoot) {
|
|
450
518
|
return true
|
|
519
|
+
}
|
|
451
520
|
}
|
|
452
521
|
if (hasPeerEdges) {
|
|
453
522
|
for (const edge of peerEntrySets(node).keys()) {
|
|
454
|
-
if (edge.from.isWorkspace || edge.from.isProjectRoot)
|
|
523
|
+
if (edge.from.isWorkspace || edge.from.isProjectRoot) {
|
|
455
524
|
return true
|
|
525
|
+
}
|
|
456
526
|
}
|
|
457
527
|
}
|
|
458
528
|
|
|
459
529
|
return false
|
|
460
530
|
}
|
|
461
531
|
|
|
462
|
-
warnPeerConflict () {
|
|
463
|
-
|
|
464
|
-
|
|
532
|
+
warnPeerConflict (edge, dep) {
|
|
533
|
+
edge = edge || this.edge
|
|
534
|
+
dep = dep || this.dep
|
|
535
|
+
edge.overridden = true
|
|
536
|
+
const expl = this.explainPeerConflict(edge, dep)
|
|
465
537
|
log.warn('ERESOLVE', 'overriding peer dependency', expl)
|
|
466
538
|
}
|
|
467
539
|
|
|
468
|
-
failPeerConflict () {
|
|
469
|
-
|
|
540
|
+
failPeerConflict (edge, dep) {
|
|
541
|
+
edge = edge || this.top.edge
|
|
542
|
+
dep = dep || this.top.dep
|
|
543
|
+
const expl = this.explainPeerConflict(edge, dep)
|
|
470
544
|
throw Object.assign(new Error('could not resolve'), expl)
|
|
471
545
|
}
|
|
472
546
|
|
|
473
|
-
explainPeerConflict () {
|
|
474
|
-
const { edge, dep } = this.top
|
|
547
|
+
explainPeerConflict (edge, dep) {
|
|
475
548
|
const { from: node } = edge
|
|
476
549
|
const curNode = node.resolve(edge.name)
|
|
477
550
|
|
|
@@ -541,8 +614,9 @@ class PlaceDep {
|
|
|
541
614
|
get allChildren () {
|
|
542
615
|
const set = new Set(this.children)
|
|
543
616
|
for (const child of set) {
|
|
544
|
-
for (const grandchild of child.children)
|
|
617
|
+
for (const grandchild of child.children) {
|
|
545
618
|
set.add(grandchild)
|
|
619
|
+
}
|
|
546
620
|
}
|
|
547
621
|
return [...set]
|
|
548
622
|
}
|
package/lib/printable.js
CHANGED
|
@@ -1,63 +1,81 @@
|
|
|
1
1
|
// helper function to output a clearer visualization
|
|
2
2
|
// of the current node and its descendents
|
|
3
3
|
|
|
4
|
+
const localeCompare = require('@isaacs/string-locale-compare')('en')
|
|
4
5
|
const util = require('util')
|
|
5
6
|
const relpath = require('./relpath.js')
|
|
6
7
|
|
|
7
8
|
class ArboristNode {
|
|
8
9
|
constructor (tree, path) {
|
|
9
10
|
this.name = tree.name
|
|
10
|
-
if (tree.packageName && tree.packageName !== this.name)
|
|
11
|
+
if (tree.packageName && tree.packageName !== this.name) {
|
|
11
12
|
this.packageName = tree.packageName
|
|
12
|
-
|
|
13
|
+
}
|
|
14
|
+
if (tree.version) {
|
|
13
15
|
this.version = tree.version
|
|
16
|
+
}
|
|
14
17
|
this.location = tree.location
|
|
15
18
|
this.path = tree.path
|
|
16
|
-
if (tree.realpath !== this.path)
|
|
19
|
+
if (tree.realpath !== this.path) {
|
|
17
20
|
this.realpath = tree.realpath
|
|
18
|
-
|
|
21
|
+
}
|
|
22
|
+
if (tree.resolved !== null) {
|
|
19
23
|
this.resolved = tree.resolved
|
|
20
|
-
|
|
24
|
+
}
|
|
25
|
+
if (tree.extraneous) {
|
|
21
26
|
this.extraneous = true
|
|
22
|
-
|
|
27
|
+
}
|
|
28
|
+
if (tree.dev) {
|
|
23
29
|
this.dev = true
|
|
24
|
-
|
|
30
|
+
}
|
|
31
|
+
if (tree.optional) {
|
|
25
32
|
this.optional = true
|
|
26
|
-
|
|
33
|
+
}
|
|
34
|
+
if (tree.devOptional && !tree.dev && !tree.optional) {
|
|
27
35
|
this.devOptional = true
|
|
28
|
-
|
|
36
|
+
}
|
|
37
|
+
if (tree.peer) {
|
|
29
38
|
this.peer = true
|
|
30
|
-
|
|
39
|
+
}
|
|
40
|
+
if (tree.inBundle) {
|
|
31
41
|
this.bundled = true
|
|
32
|
-
|
|
42
|
+
}
|
|
43
|
+
if (tree.inDepBundle) {
|
|
33
44
|
this.bundler = tree.getBundler().location
|
|
34
|
-
|
|
45
|
+
}
|
|
46
|
+
if (tree.isProjectRoot) {
|
|
35
47
|
this.isProjectRoot = true
|
|
36
|
-
|
|
48
|
+
}
|
|
49
|
+
if (tree.isWorkspace) {
|
|
37
50
|
this.isWorkspace = true
|
|
51
|
+
}
|
|
38
52
|
const bd = tree.package && tree.package.bundleDependencies
|
|
39
|
-
if (bd && bd.length)
|
|
53
|
+
if (bd && bd.length) {
|
|
40
54
|
this.bundleDependencies = bd
|
|
41
|
-
|
|
55
|
+
}
|
|
56
|
+
if (tree.inShrinkwrap) {
|
|
42
57
|
this.inShrinkwrap = true
|
|
43
|
-
else if (tree.hasShrinkwrap)
|
|
58
|
+
} else if (tree.hasShrinkwrap) {
|
|
44
59
|
this.hasShrinkwrap = true
|
|
45
|
-
|
|
60
|
+
}
|
|
61
|
+
if (tree.error) {
|
|
46
62
|
this.error = treeError(tree.error)
|
|
47
|
-
|
|
63
|
+
}
|
|
64
|
+
if (tree.errors && tree.errors.length) {
|
|
48
65
|
this.errors = tree.errors.map(treeError)
|
|
66
|
+
}
|
|
49
67
|
|
|
50
68
|
// edgesOut sorted by name
|
|
51
69
|
if (tree.edgesOut.size) {
|
|
52
70
|
this.edgesOut = new Map([...tree.edgesOut.entries()]
|
|
53
|
-
.sort(([a], [b]) =>
|
|
71
|
+
.sort(([a], [b]) => localeCompare(a, b))
|
|
54
72
|
.map(([name, edge]) => [name, new EdgeOut(edge)]))
|
|
55
73
|
}
|
|
56
74
|
|
|
57
75
|
// edgesIn sorted by location
|
|
58
76
|
if (tree.edgesIn.size) {
|
|
59
77
|
this.edgesIn = new Set([...tree.edgesIn]
|
|
60
|
-
.sort((a, b) => a.from.location
|
|
78
|
+
.sort((a, b) => localeCompare(a.from.location, b.from.location))
|
|
61
79
|
.map(edge => new EdgeIn(edge)))
|
|
62
80
|
}
|
|
63
81
|
|
|
@@ -69,14 +87,14 @@ class ArboristNode {
|
|
|
69
87
|
// fsChildren sorted by path
|
|
70
88
|
if (tree.fsChildren.size) {
|
|
71
89
|
this.fsChildren = new Set([...tree.fsChildren]
|
|
72
|
-
.sort(({path: a}, {path: b}) =>
|
|
90
|
+
.sort(({path: a}, {path: b}) => localeCompare(a, b))
|
|
73
91
|
.map(tree => printableTree(tree, path)))
|
|
74
92
|
}
|
|
75
93
|
|
|
76
94
|
// children sorted by name
|
|
77
95
|
if (tree.children.size) {
|
|
78
96
|
this.children = new Map([...tree.children.entries()]
|
|
79
|
-
.sort(([a], [b]) =>
|
|
97
|
+
.sort(([a], [b]) => localeCompare(a, b))
|
|
80
98
|
.map(([name, tree]) => [name, printableTree(tree, path)]))
|
|
81
99
|
}
|
|
82
100
|
}
|
|
@@ -109,10 +127,12 @@ class Edge {
|
|
|
109
127
|
this.type = edge.type
|
|
110
128
|
this.name = edge.name
|
|
111
129
|
this.spec = edge.spec || '*'
|
|
112
|
-
if (edge.error)
|
|
130
|
+
if (edge.error) {
|
|
113
131
|
this.error = edge.error
|
|
114
|
-
|
|
132
|
+
}
|
|
133
|
+
if (edge.overridden) {
|
|
115
134
|
this.overridden = edge.overridden
|
|
135
|
+
}
|
|
116
136
|
}
|
|
117
137
|
}
|
|
118
138
|
|
|
@@ -151,8 +171,9 @@ class EdgeIn extends Edge {
|
|
|
151
171
|
}
|
|
152
172
|
|
|
153
173
|
const printableTree = (tree, path = []) => {
|
|
154
|
-
if (!tree)
|
|
174
|
+
if (!tree) {
|
|
155
175
|
return tree
|
|
176
|
+
}
|
|
156
177
|
|
|
157
178
|
const Cls = tree.isLink ? ArboristLink
|
|
158
179
|
: tree.sourceReference ? ArboristVirtualNode
|
package/lib/realpath.js
CHANGED
|
@@ -14,18 +14,21 @@ const { resolve, basename, dirname } = require('path')
|
|
|
14
14
|
const realpathCached = (path, rpcache, stcache, depth) => {
|
|
15
15
|
// just a safety against extremely deep eloops
|
|
16
16
|
/* istanbul ignore next */
|
|
17
|
-
if (depth > 2000)
|
|
17
|
+
if (depth > 2000) {
|
|
18
18
|
throw eloop(path)
|
|
19
|
+
}
|
|
19
20
|
|
|
20
21
|
path = resolve(path)
|
|
21
|
-
if (rpcache.has(path))
|
|
22
|
+
if (rpcache.has(path)) {
|
|
22
23
|
return Promise.resolve(rpcache.get(path))
|
|
24
|
+
}
|
|
23
25
|
|
|
24
26
|
const dir = dirname(path)
|
|
25
27
|
const base = basename(path)
|
|
26
28
|
|
|
27
|
-
if (base && rpcache.has(dir))
|
|
29
|
+
if (base && rpcache.has(dir)) {
|
|
28
30
|
return realpathChild(dir, base, rpcache, stcache, depth)
|
|
31
|
+
}
|
|
29
32
|
|
|
30
33
|
// if it's the root, then we know it's real
|
|
31
34
|
if (!base) {
|
|
@@ -40,8 +43,9 @@ const realpathCached = (path, rpcache, stcache, depth) => {
|
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
const lstatCached = (path, stcache) => {
|
|
43
|
-
if (stcache.has(path))
|
|
46
|
+
if (stcache.has(path)) {
|
|
44
47
|
return Promise.resolve(stcache.get(path))
|
|
48
|
+
}
|
|
45
49
|
|
|
46
50
|
const p = lstat(path).then(st => {
|
|
47
51
|
stcache.set(path, st)
|
|
@@ -66,8 +70,9 @@ const realpathChild = (dir, base, rpcache, stcache, depth) => {
|
|
|
66
70
|
const realdir = rpcache.get(dir)
|
|
67
71
|
// that unpossible
|
|
68
72
|
/* istanbul ignore next */
|
|
69
|
-
if (typeof realdir === 'undefined')
|
|
73
|
+
if (typeof realdir === 'undefined') {
|
|
70
74
|
throw new Error('in realpathChild without parent being in realpath cache')
|
|
75
|
+
}
|
|
71
76
|
|
|
72
77
|
const realish = resolve(realdir, base)
|
|
73
78
|
return lstatCached(realish, stcache).then(st => {
|
|
@@ -78,8 +83,9 @@ const realpathChild = (dir, base, rpcache, stcache, depth) => {
|
|
|
78
83
|
|
|
79
84
|
return readlink(realish).then(target => {
|
|
80
85
|
const resolved = resolve(realdir, target)
|
|
81
|
-
if (realish === resolved)
|
|
86
|
+
if (realish === resolved) {
|
|
82
87
|
throw eloop(realish)
|
|
88
|
+
}
|
|
83
89
|
|
|
84
90
|
return realpathCached(resolved, rpcache, stcache, depth + 1)
|
|
85
91
|
}).then(real => {
|