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