@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/node.js
CHANGED
|
@@ -120,8 +120,9 @@ class Node {
|
|
|
120
120
|
// should be equal if not a link
|
|
121
121
|
this.path = path ? resolve(path) : null
|
|
122
122
|
|
|
123
|
-
if (!this.name && (!this.path || this.path !== dirname(this.path)))
|
|
123
|
+
if (!this.name && (!this.path || this.path !== dirname(this.path))) {
|
|
124
124
|
throw new TypeError('could not detect node name from path or package')
|
|
125
|
+
}
|
|
125
126
|
|
|
126
127
|
this.realpath = !this.isLink ? this.path : resolve(realpath)
|
|
127
128
|
|
|
@@ -142,8 +143,9 @@ class Node {
|
|
|
142
143
|
//
|
|
143
144
|
// Otherwise, hopefully a shrinkwrap will help us out.
|
|
144
145
|
const resolved = consistentResolve(pkg._resolved)
|
|
145
|
-
if (resolved && !(/^file:/.test(resolved) && pkg._where))
|
|
146
|
+
if (resolved && !(/^file:/.test(resolved) && pkg._where)) {
|
|
146
147
|
this.resolved = resolved
|
|
148
|
+
}
|
|
147
149
|
}
|
|
148
150
|
this.integrity = integrity || pkg._integrity || null
|
|
149
151
|
this.hasShrinkwrap = hasShrinkwrap || pkg._hasShrinkwrap || false
|
|
@@ -215,18 +217,21 @@ class Node {
|
|
|
215
217
|
// see parent/root setters below.
|
|
216
218
|
// root is set to parent's root if we have a parent, otherwise if it's
|
|
217
219
|
// null, then it's set to the node itself.
|
|
218
|
-
if (!parent && !fsParent)
|
|
220
|
+
if (!parent && !fsParent) {
|
|
219
221
|
this.root = root || null
|
|
222
|
+
}
|
|
220
223
|
|
|
221
224
|
// mostly a convenience for testing, but also a way to create
|
|
222
225
|
// trees in a more declarative way than setting parent on each
|
|
223
226
|
if (children) {
|
|
224
|
-
for (const c of children)
|
|
227
|
+
for (const c of children) {
|
|
225
228
|
new Node({ ...c, parent: this })
|
|
229
|
+
}
|
|
226
230
|
}
|
|
227
231
|
if (fsChildren) {
|
|
228
|
-
for (const c of fsChildren)
|
|
232
|
+
for (const c of fsChildren) {
|
|
229
233
|
new Node({ ...c, fsParent: this })
|
|
234
|
+
}
|
|
230
235
|
}
|
|
231
236
|
|
|
232
237
|
// now load all the dep edges
|
|
@@ -239,8 +244,9 @@ class Node {
|
|
|
239
244
|
|
|
240
245
|
set meta (meta) {
|
|
241
246
|
this[_meta] = meta
|
|
242
|
-
if (meta)
|
|
247
|
+
if (meta) {
|
|
243
248
|
meta.add(this)
|
|
249
|
+
}
|
|
244
250
|
}
|
|
245
251
|
|
|
246
252
|
get global () {
|
|
@@ -260,8 +266,9 @@ class Node {
|
|
|
260
266
|
// deletes edges if they already exists
|
|
261
267
|
if (this[_workspaces]) {
|
|
262
268
|
for (const name of this[_workspaces].keys()) {
|
|
263
|
-
if (!workspaces.has(name))
|
|
269
|
+
if (!workspaces.has(name)) {
|
|
264
270
|
this.edgesOut.get(name).detach()
|
|
271
|
+
}
|
|
265
272
|
}
|
|
266
273
|
}
|
|
267
274
|
|
|
@@ -271,8 +278,9 @@ class Node {
|
|
|
271
278
|
}
|
|
272
279
|
|
|
273
280
|
get binPaths () {
|
|
274
|
-
if (!this.parent)
|
|
281
|
+
if (!this.parent) {
|
|
275
282
|
return []
|
|
283
|
+
}
|
|
276
284
|
|
|
277
285
|
return getBinPaths({
|
|
278
286
|
pkg: this[_package],
|
|
@@ -319,8 +327,9 @@ class Node {
|
|
|
319
327
|
// only do this more than once at the root level, so the resolve() calls
|
|
320
328
|
// are only one level deep, and there's not much to be saved, anyway.
|
|
321
329
|
// simpler to just toss them all out.
|
|
322
|
-
for (const edge of this.edgesOut.values())
|
|
330
|
+
for (const edge of this.edgesOut.values()) {
|
|
323
331
|
edge.detach()
|
|
332
|
+
}
|
|
324
333
|
|
|
325
334
|
this[_explanation] = null
|
|
326
335
|
/* istanbul ignore next - should be impossible */
|
|
@@ -341,8 +350,9 @@ class Node {
|
|
|
341
350
|
// node.explain(nodes seen already, edge we're trying to satisfy
|
|
342
351
|
// if edge is not specified, it lists every edge into the node.
|
|
343
352
|
explain (edge = null, seen = []) {
|
|
344
|
-
if (this[_explanation])
|
|
353
|
+
if (this[_explanation]) {
|
|
345
354
|
return this[_explanation]
|
|
355
|
+
}
|
|
346
356
|
|
|
347
357
|
return this[_explanation] = this[_explain](edge, seen)
|
|
348
358
|
}
|
|
@@ -374,11 +384,13 @@ class Node {
|
|
|
374
384
|
}
|
|
375
385
|
}
|
|
376
386
|
|
|
377
|
-
if (this.sourceReference)
|
|
387
|
+
if (this.sourceReference) {
|
|
378
388
|
return this.sourceReference.explain(edge, seen)
|
|
389
|
+
}
|
|
379
390
|
|
|
380
|
-
if (seen.includes(this))
|
|
391
|
+
if (seen.includes(this)) {
|
|
381
392
|
return why
|
|
393
|
+
}
|
|
382
394
|
|
|
383
395
|
why.location = this.location
|
|
384
396
|
why.isWorkspace = this.isWorkspace
|
|
@@ -387,56 +399,64 @@ class Node {
|
|
|
387
399
|
seen = seen.concat(this)
|
|
388
400
|
|
|
389
401
|
why.dependents = []
|
|
390
|
-
if (edge)
|
|
402
|
+
if (edge) {
|
|
391
403
|
why.dependents.push(edge.explain(seen))
|
|
392
|
-
else {
|
|
404
|
+
} else {
|
|
393
405
|
// ignore invalid edges, since those aren't satisfied by this thing,
|
|
394
406
|
// and are not keeping it held in this spot anyway.
|
|
395
407
|
const edges = []
|
|
396
408
|
for (const edge of this.edgesIn) {
|
|
397
|
-
if (!edge.valid && !edge.from.isProjectRoot)
|
|
409
|
+
if (!edge.valid && !edge.from.isProjectRoot) {
|
|
398
410
|
continue
|
|
411
|
+
}
|
|
399
412
|
|
|
400
413
|
edges.push(edge)
|
|
401
414
|
}
|
|
402
|
-
for (const edge of edges)
|
|
415
|
+
for (const edge of edges) {
|
|
403
416
|
why.dependents.push(edge.explain(seen))
|
|
417
|
+
}
|
|
404
418
|
}
|
|
405
419
|
|
|
406
|
-
if (this.linksIn.size)
|
|
420
|
+
if (this.linksIn.size) {
|
|
407
421
|
why.linksIn = [...this.linksIn].map(link => link[_explain](edge, seen))
|
|
422
|
+
}
|
|
408
423
|
|
|
409
424
|
return why
|
|
410
425
|
}
|
|
411
426
|
|
|
412
427
|
isDescendantOf (node) {
|
|
413
428
|
for (let p = this; p; p = p.resolveParent) {
|
|
414
|
-
if (p === node)
|
|
429
|
+
if (p === node) {
|
|
415
430
|
return true
|
|
431
|
+
}
|
|
416
432
|
}
|
|
417
433
|
return false
|
|
418
434
|
}
|
|
419
435
|
|
|
420
436
|
getBundler (path = []) {
|
|
421
437
|
// made a cycle, definitely not bundled!
|
|
422
|
-
if (path.includes(this))
|
|
438
|
+
if (path.includes(this)) {
|
|
423
439
|
return null
|
|
440
|
+
}
|
|
424
441
|
|
|
425
442
|
path.push(this)
|
|
426
443
|
|
|
427
444
|
const parent = this[_parent]
|
|
428
|
-
if (!parent)
|
|
445
|
+
if (!parent) {
|
|
429
446
|
return null
|
|
447
|
+
}
|
|
430
448
|
|
|
431
449
|
const pBundler = parent.getBundler(path)
|
|
432
|
-
if (pBundler)
|
|
450
|
+
if (pBundler) {
|
|
433
451
|
return pBundler
|
|
452
|
+
}
|
|
434
453
|
|
|
435
454
|
const ppkg = parent.package
|
|
436
455
|
const bd = ppkg && ppkg.bundleDependencies
|
|
437
456
|
// explicit bundling
|
|
438
|
-
if (Array.isArray(bd) && bd.includes(this.name))
|
|
457
|
+
if (Array.isArray(bd) && bd.includes(this.name)) {
|
|
439
458
|
return parent
|
|
459
|
+
}
|
|
440
460
|
|
|
441
461
|
// deps that are deduped up to the bundling level are bundled.
|
|
442
462
|
// however, if they get their dep met further up than that,
|
|
@@ -444,11 +464,13 @@ class Node {
|
|
|
444
464
|
// unmet bundled deps will not cause your deps to be bundled.
|
|
445
465
|
for (const edge of this.edgesIn) {
|
|
446
466
|
const eBundler = edge.from.getBundler(path)
|
|
447
|
-
if (!eBundler)
|
|
467
|
+
if (!eBundler) {
|
|
448
468
|
continue
|
|
469
|
+
}
|
|
449
470
|
|
|
450
|
-
if (eBundler === parent)
|
|
471
|
+
if (eBundler === parent) {
|
|
451
472
|
return eBundler
|
|
473
|
+
}
|
|
452
474
|
}
|
|
453
475
|
|
|
454
476
|
return null
|
|
@@ -467,8 +489,9 @@ class Node {
|
|
|
467
489
|
}
|
|
468
490
|
|
|
469
491
|
get isWorkspace () {
|
|
470
|
-
if (this.isProjectRoot)
|
|
492
|
+
if (this.isProjectRoot) {
|
|
471
493
|
return false
|
|
494
|
+
}
|
|
472
495
|
const { root } = this
|
|
473
496
|
const { type, to } = root.edgesOut.get(this.packageName) || {}
|
|
474
497
|
return type === 'workspace' && to && (to.target === this || to === this)
|
|
@@ -486,15 +509,17 @@ class Node {
|
|
|
486
509
|
}
|
|
487
510
|
|
|
488
511
|
* ancestry () {
|
|
489
|
-
for (let anc = this; anc; anc = anc.resolveParent)
|
|
512
|
+
for (let anc = this; anc; anc = anc.resolveParent) {
|
|
490
513
|
yield anc
|
|
514
|
+
}
|
|
491
515
|
}
|
|
492
516
|
|
|
493
517
|
set root (root) {
|
|
494
518
|
// setting to null means this is the new root
|
|
495
519
|
// should only ever be one step
|
|
496
|
-
while (root && root.root !== root)
|
|
520
|
+
while (root && root.root !== root) {
|
|
497
521
|
root = root.root
|
|
522
|
+
}
|
|
498
523
|
|
|
499
524
|
root = root || this
|
|
500
525
|
|
|
@@ -504,8 +529,9 @@ class Node {
|
|
|
504
529
|
// can't set the root (yet) if there's no way to determine location
|
|
505
530
|
// this allows us to do new Node({...}) and then set the root later.
|
|
506
531
|
// just make the assignment so we don't lose it, and move on.
|
|
507
|
-
if (!this.path || !root.realpath || !root.path)
|
|
532
|
+
if (!this.path || !root.realpath || !root.path) {
|
|
508
533
|
return this[_root] = root
|
|
534
|
+
}
|
|
509
535
|
|
|
510
536
|
// temporarily become a root node
|
|
511
537
|
this[_root] = this
|
|
@@ -521,8 +547,9 @@ class Node {
|
|
|
521
547
|
if (this.isLink) {
|
|
522
548
|
if (target) {
|
|
523
549
|
target.linksIn.delete(this)
|
|
524
|
-
if (target.root === this)
|
|
550
|
+
if (target.root === this) {
|
|
525
551
|
target[_delistFromMeta]()
|
|
552
|
+
}
|
|
526
553
|
}
|
|
527
554
|
this[_target] = null
|
|
528
555
|
}
|
|
@@ -539,16 +566,17 @@ class Node {
|
|
|
539
566
|
this[_fsParent] = null
|
|
540
567
|
}
|
|
541
568
|
|
|
542
|
-
if (root === this)
|
|
569
|
+
if (root === this) {
|
|
543
570
|
this[_refreshLocation]()
|
|
544
|
-
else {
|
|
571
|
+
} else {
|
|
545
572
|
// setting to some different node.
|
|
546
573
|
const loc = relpath(root.realpath, this.path)
|
|
547
574
|
const current = root.inventory.get(loc)
|
|
548
575
|
|
|
549
576
|
// clobber whatever is there now
|
|
550
|
-
if (current)
|
|
577
|
+
if (current) {
|
|
551
578
|
current.root = null
|
|
579
|
+
}
|
|
552
580
|
|
|
553
581
|
this[_root] = root
|
|
554
582
|
// set this.location and add to inventory
|
|
@@ -556,8 +584,9 @@ class Node {
|
|
|
556
584
|
|
|
557
585
|
// try to find our parent/fsParent in the new root inventory
|
|
558
586
|
for (const p of walkUp(dirname(this.path))) {
|
|
559
|
-
if (p === this.path)
|
|
587
|
+
if (p === this.path) {
|
|
560
588
|
continue
|
|
589
|
+
}
|
|
561
590
|
const ploc = relpath(root.realpath, p)
|
|
562
591
|
const parent = root.inventory.get(ploc)
|
|
563
592
|
if (parent) {
|
|
@@ -576,8 +605,9 @@ class Node {
|
|
|
576
605
|
const isParent = this.location === childLoc
|
|
577
606
|
if (isParent) {
|
|
578
607
|
const oldChild = parent.children.get(this.name)
|
|
579
|
-
if (oldChild && oldChild !== this)
|
|
608
|
+
if (oldChild && oldChild !== this) {
|
|
580
609
|
oldChild.root = null
|
|
610
|
+
}
|
|
581
611
|
if (this.parent) {
|
|
582
612
|
this.parent.children.delete(this.name)
|
|
583
613
|
this.parent[_reloadNamedEdges](this.name)
|
|
@@ -586,13 +616,15 @@ class Node {
|
|
|
586
616
|
this[_parent] = parent
|
|
587
617
|
// don't do it for links, because they don't have a target yet
|
|
588
618
|
// we'll hit them up a bit later on.
|
|
589
|
-
if (!this.isLink)
|
|
619
|
+
if (!this.isLink) {
|
|
590
620
|
parent[_reloadNamedEdges](this.name)
|
|
621
|
+
}
|
|
591
622
|
} else {
|
|
592
623
|
/* istanbul ignore if - should be impossible, since we break
|
|
593
624
|
* all fsParent/child relationships when moving? */
|
|
594
|
-
if (this.fsParent)
|
|
625
|
+
if (this.fsParent) {
|
|
595
626
|
this.fsParent.fsChildren.delete(this)
|
|
627
|
+
}
|
|
596
628
|
parent.fsChildren.add(this)
|
|
597
629
|
this[_fsParent] = parent
|
|
598
630
|
}
|
|
@@ -601,10 +633,11 @@ class Node {
|
|
|
601
633
|
}
|
|
602
634
|
|
|
603
635
|
// if it doesn't have a parent, it's a top node
|
|
604
|
-
if (!this.parent)
|
|
636
|
+
if (!this.parent) {
|
|
605
637
|
root.tops.add(this)
|
|
606
|
-
else
|
|
638
|
+
} else {
|
|
607
639
|
root.tops.delete(this)
|
|
640
|
+
}
|
|
608
641
|
|
|
609
642
|
// assign parentage for any nodes that need to have this as a parent
|
|
610
643
|
// this can happen when we have a node at nm/a/nm/b added *before*
|
|
@@ -614,24 +647,30 @@ class Node {
|
|
|
614
647
|
const nmloc = `${this.location}${this.location ? '/' : ''}node_modules/`
|
|
615
648
|
const isChild = n => n.location === nmloc + n.name
|
|
616
649
|
// check dirname so that /foo isn't treated as the fsparent of /foo-bar
|
|
617
|
-
const isFsChild = n =>
|
|
618
|
-
n
|
|
619
|
-
|
|
620
|
-
|
|
650
|
+
const isFsChild = n => {
|
|
651
|
+
return dirname(n.path).startsWith(this.path) &&
|
|
652
|
+
n !== this &&
|
|
653
|
+
!n.parent &&
|
|
654
|
+
(!n.fsParent ||
|
|
655
|
+
n.fsParent === this ||
|
|
656
|
+
dirname(this.path).startsWith(n.fsParent.path))
|
|
657
|
+
}
|
|
621
658
|
const isKid = n => isChild(n) || isFsChild(n)
|
|
622
659
|
|
|
623
660
|
// only walk top nodes, since anything else already has a parent.
|
|
624
661
|
for (const child of root.tops) {
|
|
625
|
-
if (!isKid(child))
|
|
662
|
+
if (!isKid(child)) {
|
|
626
663
|
continue
|
|
664
|
+
}
|
|
627
665
|
|
|
628
666
|
// set up the internal parentage links
|
|
629
|
-
if (this.isLink)
|
|
667
|
+
if (this.isLink) {
|
|
630
668
|
child.root = null
|
|
631
|
-
else {
|
|
669
|
+
} else {
|
|
632
670
|
// can't possibly have a parent, because it's in tops
|
|
633
|
-
if (child.fsParent)
|
|
671
|
+
if (child.fsParent) {
|
|
634
672
|
child.fsParent.fsChildren.delete(child)
|
|
673
|
+
}
|
|
635
674
|
child[_fsParent] = null
|
|
636
675
|
if (isChild(child)) {
|
|
637
676
|
this.children.set(child.name, child)
|
|
@@ -648,13 +687,15 @@ class Node {
|
|
|
648
687
|
// to that realpath, or a thing at that realpath if we're adding a link
|
|
649
688
|
// (if we're adding a regular node, we already deleted the old one)
|
|
650
689
|
for (const node of root.inventory.query('realpath', this.realpath)) {
|
|
651
|
-
if (node === this)
|
|
690
|
+
if (node === this) {
|
|
652
691
|
continue
|
|
692
|
+
}
|
|
653
693
|
|
|
654
694
|
/* istanbul ignore next - should be impossible */
|
|
655
695
|
debug(() => {
|
|
656
|
-
if (node.root !== root)
|
|
696
|
+
if (node.root !== root) {
|
|
657
697
|
throw new Error('inventory contains node from other root')
|
|
698
|
+
}
|
|
658
699
|
})
|
|
659
700
|
|
|
660
701
|
if (this.isLink) {
|
|
@@ -663,8 +704,9 @@ class Node {
|
|
|
663
704
|
this[_package] = target.package
|
|
664
705
|
target.linksIn.add(this)
|
|
665
706
|
// reload edges here, because now we have a target
|
|
666
|
-
if (this.parent)
|
|
707
|
+
if (this.parent) {
|
|
667
708
|
this.parent[_reloadNamedEdges](this.name)
|
|
709
|
+
}
|
|
668
710
|
break
|
|
669
711
|
} else {
|
|
670
712
|
/* istanbul ignore else - should be impossible */
|
|
@@ -672,8 +714,9 @@ class Node {
|
|
|
672
714
|
node[_target] = this
|
|
673
715
|
node[_package] = this.package
|
|
674
716
|
this.linksIn.add(node)
|
|
675
|
-
if (node.parent)
|
|
717
|
+
if (node.parent) {
|
|
676
718
|
node.parent[_reloadNamedEdges](node.name)
|
|
719
|
+
}
|
|
677
720
|
} else {
|
|
678
721
|
debug(() => {
|
|
679
722
|
throw Object.assign(new Error('duplicate node in root setter'), {
|
|
@@ -690,14 +733,16 @@ class Node {
|
|
|
690
733
|
// reload all edgesIn where the root doesn't match, so we don't have
|
|
691
734
|
// cross-tree dependency graphs
|
|
692
735
|
for (const edge of this.edgesIn) {
|
|
693
|
-
if (edge.from.root !== root)
|
|
736
|
+
if (edge.from.root !== root) {
|
|
694
737
|
edge.reload()
|
|
738
|
+
}
|
|
695
739
|
}
|
|
696
740
|
// reload all edgesOut where root doens't match, or is missing, since
|
|
697
741
|
// it might not be missing in the new tree
|
|
698
742
|
for (const edge of this.edgesOut.values()) {
|
|
699
|
-
if (!edge.to || edge.to.root !== root)
|
|
743
|
+
if (!edge.to || edge.to.root !== root) {
|
|
700
744
|
edge.reload()
|
|
745
|
+
}
|
|
701
746
|
}
|
|
702
747
|
|
|
703
748
|
// now make sure our family comes along for the ride!
|
|
@@ -721,15 +766,17 @@ class Node {
|
|
|
721
766
|
}
|
|
722
767
|
}
|
|
723
768
|
for (const child of family) {
|
|
724
|
-
if (child.root !== root)
|
|
769
|
+
if (child.root !== root) {
|
|
725
770
|
child.root = root
|
|
771
|
+
}
|
|
726
772
|
}
|
|
727
773
|
|
|
728
774
|
// if we had a target, and didn't find one in the new root, then bring
|
|
729
775
|
// it over as well, but only if we're setting the link into a new root,
|
|
730
776
|
// as we don't want to lose the target any time we remove a link.
|
|
731
|
-
if (this.isLink && target && !this.target && root !== this)
|
|
777
|
+
if (this.isLink && target && !this.target && root !== this) {
|
|
732
778
|
target.root = root
|
|
779
|
+
}
|
|
733
780
|
|
|
734
781
|
// tree should always be valid upon root setter completion.
|
|
735
782
|
treeCheck(this)
|
|
@@ -741,11 +788,13 @@ class Node {
|
|
|
741
788
|
}
|
|
742
789
|
|
|
743
790
|
[_loadWorkspaces] () {
|
|
744
|
-
if (!this[_workspaces])
|
|
791
|
+
if (!this[_workspaces]) {
|
|
745
792
|
return
|
|
793
|
+
}
|
|
746
794
|
|
|
747
|
-
for (const [name, path] of this[_workspaces].entries())
|
|
795
|
+
for (const [name, path] of this[_workspaces].entries()) {
|
|
748
796
|
new Edge({ from: this, name, spec: `file:${path}`, type: 'workspace' })
|
|
797
|
+
}
|
|
749
798
|
}
|
|
750
799
|
|
|
751
800
|
[_loadDeps] () {
|
|
@@ -764,10 +813,11 @@ class Node {
|
|
|
764
813
|
const peerDependencies = {}
|
|
765
814
|
const peerOptional = {}
|
|
766
815
|
for (const [name, dep] of Object.entries(pd)) {
|
|
767
|
-
if (pm[name] && pm[name].optional)
|
|
816
|
+
if (pm[name] && pm[name].optional) {
|
|
768
817
|
peerOptional[name] = dep
|
|
769
|
-
else
|
|
818
|
+
} else {
|
|
770
819
|
peerDependencies[name] = dep
|
|
820
|
+
}
|
|
771
821
|
}
|
|
772
822
|
this[_loadDepType](peerDependencies, 'peer')
|
|
773
823
|
this[_loadDepType](peerOptional, 'peerOptional')
|
|
@@ -784,8 +834,9 @@ class Node {
|
|
|
784
834
|
} = sourceReference || {}
|
|
785
835
|
const thisDev = isTop && !globalTop && path
|
|
786
836
|
const srcDev = !sourceReference || srcTop && !srcGlobalTop && srcPath
|
|
787
|
-
if (thisDev && srcDev)
|
|
837
|
+
if (thisDev && srcDev) {
|
|
788
838
|
this[_loadDepType](this.package.devDependencies, 'dev')
|
|
839
|
+
}
|
|
789
840
|
}
|
|
790
841
|
|
|
791
842
|
[_loadDepType] (deps, type) {
|
|
@@ -794,8 +845,9 @@ class Node {
|
|
|
794
845
|
// prioritize a new edge over an existing one
|
|
795
846
|
for (const [name, spec] of Object.entries(deps || {})) {
|
|
796
847
|
const current = this.edgesOut.get(name)
|
|
797
|
-
if (!current || current.type !== 'workspace')
|
|
848
|
+
if (!current || current.type !== 'workspace') {
|
|
798
849
|
new Edge({ from: this, name, spec, accept: ad[name], type })
|
|
850
|
+
}
|
|
799
851
|
}
|
|
800
852
|
}
|
|
801
853
|
|
|
@@ -803,25 +855,29 @@ class Node {
|
|
|
803
855
|
const parent = this[_fsParent]
|
|
804
856
|
/* istanbul ignore next - should be impossible */
|
|
805
857
|
debug(() => {
|
|
806
|
-
if (parent === this)
|
|
858
|
+
if (parent === this) {
|
|
807
859
|
throw new Error('node set to its own fsParent')
|
|
860
|
+
}
|
|
808
861
|
})
|
|
809
862
|
return parent
|
|
810
863
|
}
|
|
811
864
|
|
|
812
865
|
set fsParent (fsParent) {
|
|
813
866
|
if (!fsParent) {
|
|
814
|
-
if (this[_fsParent])
|
|
867
|
+
if (this[_fsParent]) {
|
|
815
868
|
this.root = null
|
|
869
|
+
}
|
|
816
870
|
return
|
|
817
871
|
}
|
|
818
872
|
|
|
819
873
|
debug(() => {
|
|
820
|
-
if (fsParent === this)
|
|
874
|
+
if (fsParent === this) {
|
|
821
875
|
throw new Error('setting node to its own fsParent')
|
|
876
|
+
}
|
|
822
877
|
|
|
823
|
-
if (fsParent.realpath === this.realpath)
|
|
878
|
+
if (fsParent.realpath === this.realpath) {
|
|
824
879
|
throw new Error('setting fsParent to same path')
|
|
880
|
+
}
|
|
825
881
|
|
|
826
882
|
// the initial set MUST be an actual walk-up from the realpath
|
|
827
883
|
// subsequent sets will re-root on the new fsParent's path.
|
|
@@ -837,16 +893,19 @@ class Node {
|
|
|
837
893
|
}
|
|
838
894
|
})
|
|
839
895
|
|
|
840
|
-
if (fsParent.isLink)
|
|
896
|
+
if (fsParent.isLink) {
|
|
841
897
|
fsParent = fsParent.target
|
|
898
|
+
}
|
|
842
899
|
|
|
843
900
|
// setting a thing to its own fsParent is not normal, but no-op for safety
|
|
844
|
-
if (this === fsParent || fsParent.realpath === this.realpath)
|
|
901
|
+
if (this === fsParent || fsParent.realpath === this.realpath) {
|
|
845
902
|
return
|
|
903
|
+
}
|
|
846
904
|
|
|
847
905
|
// nothing to do
|
|
848
|
-
if (this[_fsParent] === fsParent)
|
|
906
|
+
if (this[_fsParent] === fsParent) {
|
|
849
907
|
return
|
|
908
|
+
}
|
|
850
909
|
|
|
851
910
|
const oldFsParent = this[_fsParent]
|
|
852
911
|
const newPath = !oldFsParent ? this.path
|
|
@@ -874,11 +933,13 @@ class Node {
|
|
|
874
933
|
}
|
|
875
934
|
|
|
876
935
|
// update this.path/realpath for this and all children/fsChildren
|
|
877
|
-
if (pathChange)
|
|
936
|
+
if (pathChange) {
|
|
878
937
|
this[_changePath](newPath)
|
|
938
|
+
}
|
|
879
939
|
|
|
880
|
-
if (oldParent)
|
|
940
|
+
if (oldParent) {
|
|
881
941
|
oldParent[_reloadNamedEdges](oldName)
|
|
942
|
+
}
|
|
882
943
|
|
|
883
944
|
// clobbers anything at that path, resets all appropriate references
|
|
884
945
|
this.root = fsParent.root
|
|
@@ -894,11 +955,13 @@ class Node {
|
|
|
894
955
|
// will go ahead and create the invalid state, and then try to resolve
|
|
895
956
|
// it with more tree construction, because it's a user request.
|
|
896
957
|
canReplaceWith (node, ignorePeers = []) {
|
|
897
|
-
if (node.name !== this.name)
|
|
958
|
+
if (node.name !== this.name) {
|
|
898
959
|
return false
|
|
960
|
+
}
|
|
899
961
|
|
|
900
|
-
if (node.packageName !== this.packageName)
|
|
962
|
+
if (node.packageName !== this.packageName) {
|
|
901
963
|
return false
|
|
964
|
+
}
|
|
902
965
|
|
|
903
966
|
ignorePeers = new Set(ignorePeers)
|
|
904
967
|
|
|
@@ -915,12 +978,14 @@ class Node {
|
|
|
915
978
|
edge.from.parent === this.parent &&
|
|
916
979
|
edge.peer &&
|
|
917
980
|
ignorePeers.has(edge.from.name)
|
|
918
|
-
if (ignored)
|
|
981
|
+
if (ignored) {
|
|
919
982
|
continue
|
|
983
|
+
}
|
|
920
984
|
|
|
921
985
|
// only care about edges that don't originate from this node
|
|
922
|
-
if (!depSet.has(edge.from) && !edge.satisfiedBy(node))
|
|
986
|
+
if (!depSet.has(edge.from) && !edge.satisfiedBy(node)) {
|
|
923
987
|
return false
|
|
988
|
+
}
|
|
924
989
|
}
|
|
925
990
|
|
|
926
991
|
return true
|
|
@@ -935,41 +1000,49 @@ class Node {
|
|
|
935
1000
|
// to if it was removed, or nothing is depending on it in the first place.
|
|
936
1001
|
canDedupe (preferDedupe = false) {
|
|
937
1002
|
// not allowed to mess with shrinkwraps or bundles
|
|
938
|
-
if (this.inDepBundle || this.inShrinkwrap)
|
|
1003
|
+
if (this.inDepBundle || this.inShrinkwrap) {
|
|
939
1004
|
return false
|
|
1005
|
+
}
|
|
940
1006
|
|
|
941
1007
|
// it's a top level pkg, or a dep of one
|
|
942
|
-
if (!this.resolveParent || !this.resolveParent.resolveParent)
|
|
1008
|
+
if (!this.resolveParent || !this.resolveParent.resolveParent) {
|
|
943
1009
|
return false
|
|
1010
|
+
}
|
|
944
1011
|
|
|
945
1012
|
// no one wants it, remove it
|
|
946
|
-
if (this.edgesIn.size === 0)
|
|
1013
|
+
if (this.edgesIn.size === 0) {
|
|
947
1014
|
return true
|
|
1015
|
+
}
|
|
948
1016
|
|
|
949
1017
|
const other = this.resolveParent.resolveParent.resolve(this.name)
|
|
950
1018
|
|
|
951
1019
|
// nothing else, need this one
|
|
952
|
-
if (!other)
|
|
1020
|
+
if (!other) {
|
|
953
1021
|
return false
|
|
1022
|
+
}
|
|
954
1023
|
|
|
955
1024
|
// if it's the same thing, then always fine to remove
|
|
956
|
-
if (other.matches(this))
|
|
1025
|
+
if (other.matches(this)) {
|
|
957
1026
|
return true
|
|
1027
|
+
}
|
|
958
1028
|
|
|
959
1029
|
// if the other thing can't replace this, then skip it
|
|
960
|
-
if (!other.canReplace(this))
|
|
1030
|
+
if (!other.canReplace(this)) {
|
|
961
1031
|
return false
|
|
1032
|
+
}
|
|
962
1033
|
|
|
963
1034
|
// if we prefer dedupe, or if the version is greater/equal, take the other
|
|
964
|
-
if (preferDedupe || semver.gte(other.version, this.version))
|
|
1035
|
+
if (preferDedupe || semver.gte(other.version, this.version)) {
|
|
965
1036
|
return true
|
|
1037
|
+
}
|
|
966
1038
|
|
|
967
1039
|
return false
|
|
968
1040
|
}
|
|
969
1041
|
|
|
970
1042
|
satisfies (requested) {
|
|
971
|
-
if (requested instanceof Edge)
|
|
1043
|
+
if (requested instanceof Edge) {
|
|
972
1044
|
return this.name === requested.name && requested.satisfiedBy(this)
|
|
1045
|
+
}
|
|
973
1046
|
|
|
974
1047
|
const parsed = npa(requested)
|
|
975
1048
|
const { name = this.name, rawSpec: spec } = parsed
|
|
@@ -983,29 +1056,35 @@ class Node {
|
|
|
983
1056
|
|
|
984
1057
|
matches (node) {
|
|
985
1058
|
// if the nodes are literally the same object, obviously a match.
|
|
986
|
-
if (node === this)
|
|
1059
|
+
if (node === this) {
|
|
987
1060
|
return true
|
|
1061
|
+
}
|
|
988
1062
|
|
|
989
1063
|
// if the names don't match, they're different things, even if
|
|
990
1064
|
// the package contents are identical.
|
|
991
|
-
if (node.name !== this.name)
|
|
1065
|
+
if (node.name !== this.name) {
|
|
992
1066
|
return false
|
|
1067
|
+
}
|
|
993
1068
|
|
|
994
1069
|
// if they're links, they match if the targets match
|
|
995
|
-
if (this.isLink)
|
|
1070
|
+
if (this.isLink) {
|
|
996
1071
|
return node.isLink && this.target.matches(node.target)
|
|
1072
|
+
}
|
|
997
1073
|
|
|
998
1074
|
// if they're two project root nodes, they're different if the paths differ
|
|
999
|
-
if (this.isProjectRoot && node.isProjectRoot)
|
|
1075
|
+
if (this.isProjectRoot && node.isProjectRoot) {
|
|
1000
1076
|
return this.path === node.path
|
|
1077
|
+
}
|
|
1001
1078
|
|
|
1002
1079
|
// if the integrity matches, then they're the same.
|
|
1003
|
-
if (this.integrity && node.integrity)
|
|
1080
|
+
if (this.integrity && node.integrity) {
|
|
1004
1081
|
return this.integrity === node.integrity
|
|
1082
|
+
}
|
|
1005
1083
|
|
|
1006
1084
|
// if no integrity, check resolved
|
|
1007
|
-
if (this.resolved && node.resolved)
|
|
1085
|
+
if (this.resolved && node.resolved) {
|
|
1008
1086
|
return this.resolved === node.resolved
|
|
1087
|
+
}
|
|
1009
1088
|
|
|
1010
1089
|
// if no resolved, check both package name and version
|
|
1011
1090
|
// otherwise, conclude that they are different things
|
|
@@ -1031,39 +1110,44 @@ class Node {
|
|
|
1031
1110
|
// parent's children map, and leave it at that.
|
|
1032
1111
|
const nameMatch = node.parent &&
|
|
1033
1112
|
node.parent.children.get(this.name) === node
|
|
1034
|
-
if (nameMatch)
|
|
1113
|
+
if (nameMatch) {
|
|
1035
1114
|
this.path = resolve(node.parent.path, 'node_modules', this.name)
|
|
1036
|
-
else {
|
|
1115
|
+
} else {
|
|
1037
1116
|
this.path = node.path
|
|
1038
1117
|
this.name = node.name
|
|
1039
1118
|
}
|
|
1040
1119
|
|
|
1041
|
-
if (!this.isLink)
|
|
1120
|
+
if (!this.isLink) {
|
|
1042
1121
|
this.realpath = this.path
|
|
1122
|
+
}
|
|
1043
1123
|
this[_refreshLocation]()
|
|
1044
1124
|
|
|
1045
1125
|
// keep children when a node replaces another
|
|
1046
1126
|
if (!this.isLink) {
|
|
1047
|
-
for (const kid of node.children.values())
|
|
1127
|
+
for (const kid of node.children.values()) {
|
|
1048
1128
|
kid.parent = this
|
|
1129
|
+
}
|
|
1049
1130
|
}
|
|
1050
1131
|
|
|
1051
|
-
if (!node.isRoot)
|
|
1132
|
+
if (!node.isRoot) {
|
|
1052
1133
|
this.root = node.root
|
|
1134
|
+
}
|
|
1053
1135
|
|
|
1054
1136
|
treeCheck(this)
|
|
1055
1137
|
}
|
|
1056
1138
|
|
|
1057
1139
|
get inShrinkwrap () {
|
|
1058
|
-
return this.parent &&
|
|
1140
|
+
return this.parent &&
|
|
1141
|
+
(this.parent.hasShrinkwrap || this.parent.inShrinkwrap)
|
|
1059
1142
|
}
|
|
1060
1143
|
|
|
1061
1144
|
get parent () {
|
|
1062
1145
|
const parent = this[_parent]
|
|
1063
1146
|
/* istanbul ignore next - should be impossible */
|
|
1064
1147
|
debug(() => {
|
|
1065
|
-
if (parent === this)
|
|
1148
|
+
if (parent === this) {
|
|
1066
1149
|
throw new Error('node set to its own parent')
|
|
1150
|
+
}
|
|
1067
1151
|
})
|
|
1068
1152
|
return parent
|
|
1069
1153
|
}
|
|
@@ -1083,23 +1167,27 @@ class Node {
|
|
|
1083
1167
|
if (!parent) {
|
|
1084
1168
|
// but only delete it if we actually had a parent in the first place
|
|
1085
1169
|
// otherwise it's just setting to null when it's already null
|
|
1086
|
-
if (this[_parent])
|
|
1170
|
+
if (this[_parent]) {
|
|
1087
1171
|
this.root = null
|
|
1172
|
+
}
|
|
1088
1173
|
return
|
|
1089
1174
|
}
|
|
1090
1175
|
|
|
1091
|
-
if (parent.isLink)
|
|
1176
|
+
if (parent.isLink) {
|
|
1092
1177
|
parent = parent.target
|
|
1178
|
+
}
|
|
1093
1179
|
|
|
1094
1180
|
// setting a thing to its own parent is not normal, but no-op for safety
|
|
1095
|
-
if (this === parent)
|
|
1181
|
+
if (this === parent) {
|
|
1096
1182
|
return
|
|
1183
|
+
}
|
|
1097
1184
|
|
|
1098
1185
|
const oldParent = this[_parent]
|
|
1099
1186
|
|
|
1100
1187
|
// nothing to do
|
|
1101
|
-
if (oldParent === parent)
|
|
1188
|
+
if (oldParent === parent) {
|
|
1102
1189
|
return
|
|
1190
|
+
}
|
|
1103
1191
|
|
|
1104
1192
|
// ok now we know something is actually changing, and parent is not a link
|
|
1105
1193
|
const newPath = resolve(parent.path, 'node_modules', this.name)
|
|
@@ -1116,8 +1204,9 @@ class Node {
|
|
|
1116
1204
|
}
|
|
1117
1205
|
|
|
1118
1206
|
// update this.path/realpath for this and all children/fsChildren
|
|
1119
|
-
if (pathChange)
|
|
1207
|
+
if (pathChange) {
|
|
1120
1208
|
this[_changePath](newPath)
|
|
1209
|
+
}
|
|
1121
1210
|
|
|
1122
1211
|
// clobbers anything at that path, resets all appropriate references
|
|
1123
1212
|
this.root = parent.root
|
|
@@ -1127,16 +1216,19 @@ class Node {
|
|
|
1127
1216
|
// Removes the node from its root the metadata and inventory.
|
|
1128
1217
|
[_delistFromMeta] () {
|
|
1129
1218
|
const root = this.root
|
|
1130
|
-
if (!root.realpath || !this.path)
|
|
1219
|
+
if (!root.realpath || !this.path) {
|
|
1131
1220
|
return
|
|
1221
|
+
}
|
|
1132
1222
|
root.inventory.delete(this)
|
|
1133
1223
|
root.tops.delete(this)
|
|
1134
|
-
if (root.meta)
|
|
1224
|
+
if (root.meta) {
|
|
1135
1225
|
root.meta.delete(this.path)
|
|
1226
|
+
}
|
|
1136
1227
|
/* istanbul ignore next - should be impossible */
|
|
1137
1228
|
debug(() => {
|
|
1138
|
-
if ([...root.inventory.values()].includes(this))
|
|
1229
|
+
if ([...root.inventory.values()].includes(this)) {
|
|
1139
1230
|
throw new Error('failed to delist')
|
|
1231
|
+
}
|
|
1140
1232
|
})
|
|
1141
1233
|
}
|
|
1142
1234
|
|
|
@@ -1148,8 +1240,9 @@ class Node {
|
|
|
1148
1240
|
this.path = newPath
|
|
1149
1241
|
const namePattern = /(?:^|\/|\\)node_modules[\\/](@[^/\\]+[\\/][^\\/]+|[^\\/]+)$/
|
|
1150
1242
|
const nameChange = newPath.match(namePattern)
|
|
1151
|
-
if (nameChange && this.name !== nameChange[1])
|
|
1243
|
+
if (nameChange && this.name !== nameChange[1]) {
|
|
1152
1244
|
this.name = nameChange[1].replace(/\\/g, '/')
|
|
1245
|
+
}
|
|
1153
1246
|
|
|
1154
1247
|
// if we move a link target, update link realpaths
|
|
1155
1248
|
if (!this.isLink) {
|
|
@@ -1161,10 +1254,12 @@ class Node {
|
|
|
1161
1254
|
}
|
|
1162
1255
|
}
|
|
1163
1256
|
// if we move /x to /y, then a module at /x/a/b becomes /y/a/b
|
|
1164
|
-
for (const child of this.fsChildren)
|
|
1257
|
+
for (const child of this.fsChildren) {
|
|
1165
1258
|
child[_changePath](resolve(newPath, relative(oldPath, child.path)))
|
|
1166
|
-
|
|
1259
|
+
}
|
|
1260
|
+
for (const [name, child] of this.children.entries()) {
|
|
1167
1261
|
child[_changePath](resolve(newPath, 'node_modules', name))
|
|
1262
|
+
}
|
|
1168
1263
|
|
|
1169
1264
|
this[_refreshLocation]()
|
|
1170
1265
|
}
|
|
@@ -1179,8 +1274,9 @@ class Node {
|
|
|
1179
1274
|
this.location = loc
|
|
1180
1275
|
|
|
1181
1276
|
root.inventory.add(this)
|
|
1182
|
-
if (root.meta)
|
|
1277
|
+
if (root.meta) {
|
|
1183
1278
|
root.meta.add(this)
|
|
1279
|
+
}
|
|
1184
1280
|
}
|
|
1185
1281
|
|
|
1186
1282
|
addEdgeOut (edge) {
|
|
@@ -1191,8 +1287,9 @@ class Node {
|
|
|
1191
1287
|
this.edgesIn.add(edge)
|
|
1192
1288
|
|
|
1193
1289
|
// try to get metadata from the yarn.lock file
|
|
1194
|
-
if (this.root.meta)
|
|
1290
|
+
if (this.root.meta) {
|
|
1195
1291
|
this.root.meta.addEdge(edge)
|
|
1292
|
+
}
|
|
1196
1293
|
}
|
|
1197
1294
|
|
|
1198
1295
|
[_reloadNamedEdges] (name, rootLoc = this.location) {
|
|
@@ -1202,13 +1299,16 @@ class Node {
|
|
|
1202
1299
|
edge.to.location === `${rootLoc}/node_modules/${edge.name}`
|
|
1203
1300
|
const sameResolved = edge && this.resolve(name) === edge.to
|
|
1204
1301
|
const recheck = rootLocResolved || !sameResolved
|
|
1205
|
-
if (edge && recheck)
|
|
1302
|
+
if (edge && recheck) {
|
|
1206
1303
|
edge.reload(true)
|
|
1207
|
-
|
|
1304
|
+
}
|
|
1305
|
+
for (const c of this.children.values()) {
|
|
1208
1306
|
c[_reloadNamedEdges](name, rootLoc)
|
|
1307
|
+
}
|
|
1209
1308
|
|
|
1210
|
-
for (const c of this.fsChildren)
|
|
1309
|
+
for (const c of this.fsChildren) {
|
|
1211
1310
|
c[_reloadNamedEdges](name, rootLoc)
|
|
1311
|
+
}
|
|
1212
1312
|
}
|
|
1213
1313
|
|
|
1214
1314
|
get isLink () {
|
|
@@ -1255,15 +1355,18 @@ class Node {
|
|
|
1255
1355
|
/* istanbul ignore next - should be impossible,
|
|
1256
1356
|
* but I keep doing this mistake in tests */
|
|
1257
1357
|
debug(() => {
|
|
1258
|
-
if (typeof name !== 'string' || !name)
|
|
1358
|
+
if (typeof name !== 'string' || !name) {
|
|
1259
1359
|
throw new Error('non-string passed to Node.resolve')
|
|
1360
|
+
}
|
|
1260
1361
|
})
|
|
1261
1362
|
const mine = this.children.get(name)
|
|
1262
|
-
if (mine)
|
|
1363
|
+
if (mine) {
|
|
1263
1364
|
return mine
|
|
1365
|
+
}
|
|
1264
1366
|
const resolveParent = this.resolveParent
|
|
1265
|
-
if (resolveParent)
|
|
1367
|
+
if (resolveParent) {
|
|
1266
1368
|
return resolveParent.resolve(name)
|
|
1369
|
+
}
|
|
1267
1370
|
return null
|
|
1268
1371
|
}
|
|
1269
1372
|
|