@npmcli/arborist 2.2.8 → 2.4.1

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/lib/link.js CHANGED
@@ -23,13 +23,19 @@ class Link extends Node {
23
23
  : null),
24
24
  })
25
25
 
26
- this.target = target || new Node({
27
- ...options,
28
- path: realpath,
29
- parent: null,
30
- fsParent: null,
31
- root: this.root,
32
- })
26
+ if (target)
27
+ this.target = target
28
+ else if (this.realpath === this.root.path)
29
+ this.target = this.root
30
+ else {
31
+ this.target = new Node({
32
+ ...options,
33
+ path: realpath,
34
+ parent: null,
35
+ fsParent: null,
36
+ root: this.root,
37
+ })
38
+ }
33
39
  }
34
40
 
35
41
  get version () {
package/lib/node.js CHANGED
@@ -28,6 +28,7 @@
28
28
  // where we need to quickly find all instances of a given package name within a
29
29
  // tree.
30
30
 
31
+ const semver = require('semver')
31
32
  const nameFromFolder = require('@npmcli/name-from-folder')
32
33
  const Edge = require('./edge.js')
33
34
  const Inventory = require('./inventory.js')
@@ -685,6 +686,7 @@ class Node {
685
686
  ...this.children.values(),
686
687
  ...this.inventory.values(),
687
688
  ].filter(n => n !== this))
689
+
688
690
  for (const child of family) {
689
691
  if (child.root !== root) {
690
692
  child[_delistFromMeta]()
@@ -704,12 +706,14 @@ class Node {
704
706
  }
705
707
 
706
708
  // if we had a target, and didn't find one in the new root, then bring
707
- // it over as well.
708
- if (this.isLink && target && !this.target)
709
+ // it over as well, but only if we're setting the link into a new root,
710
+ // as we don't want to lose the target any time we remove a link.
711
+ if (this.isLink && target && !this.target && root !== this)
709
712
  target.root = root
710
713
 
711
714
  // tree should always be valid upon root setter completion.
712
715
  treeCheck(this)
716
+ treeCheck(root)
713
717
  }
714
718
 
715
719
  get root () {
@@ -882,6 +886,43 @@ class Node {
882
886
  return node.canReplaceWith(this)
883
887
  }
884
888
 
889
+ // return true if it's safe to remove this node, because anything that
890
+ // is depending on it would be fine with the thing that they would resolve
891
+ // to if it was removed, or nothing is depending on it in the first place.
892
+ canDedupe (preferDedupe = false) {
893
+ // not allowed to mess with shrinkwraps or bundles
894
+ if (this.inDepBundle || this.inShrinkwrap)
895
+ return false
896
+
897
+ // it's a top level pkg, or a dep of one
898
+ if (!this.parent || !this.parent.parent)
899
+ return false
900
+
901
+ // no one wants it, remove it
902
+ if (this.edgesIn.size === 0)
903
+ return true
904
+
905
+ const other = this.parent.parent.resolve(this.name)
906
+
907
+ // nothing else, need this one
908
+ if (!other)
909
+ return false
910
+
911
+ // if it's the same thing, then always fine to remove
912
+ if (other.matches(this))
913
+ return true
914
+
915
+ // if the other thing can't replace this, then skip it
916
+ if (!other.canReplace(this))
917
+ return false
918
+
919
+ // if we prefer dedupe, or if the version is greater/equal, take the other
920
+ if (preferDedupe || semver.gte(other.version, this.version))
921
+ return true
922
+
923
+ return false
924
+ }
925
+
885
926
  satisfies (requested) {
886
927
  if (requested instanceof Edge)
887
928
  return this.name === requested.name && requested.satisfiedBy(this)
package/lib/printable.js CHANGED
@@ -2,6 +2,7 @@
2
2
  // of the current node and its descendents
3
3
 
4
4
  const util = require('util')
5
+ const relpath = require('./relpath.js')
5
6
 
6
7
  class ArboristNode {
7
8
  constructor (tree, path) {
@@ -28,6 +29,15 @@ class ArboristNode {
28
29
  this.peer = true
29
30
  if (tree.inBundle)
30
31
  this.bundled = true
32
+ if (tree.inDepBundle)
33
+ this.bundler = tree.getBundler().location
34
+ const bd = tree.package && tree.package.bundleDependencies
35
+ if (bd && bd.length)
36
+ this.bundleDependencies = bd
37
+ if (tree.inShrinkwrap)
38
+ this.inShrinkwrap = true
39
+ else if (tree.hasShrinkwrap)
40
+ this.hasShrinkwrap = true
31
41
  if (tree.error)
32
42
  this.error = treeError(tree.error)
33
43
  if (tree.errors && tree.errors.length)
@@ -47,6 +57,11 @@ class ArboristNode {
47
57
  .map(edge => new EdgeIn(edge)))
48
58
  }
49
59
 
60
+ if (tree.workspaces && tree.workspaces.size) {
61
+ this.workspaces = new Map([...tree.workspaces.entries()]
62
+ .map(([name, path]) => [name, relpath(tree.root.realpath, path)]))
63
+ }
64
+
50
65
  // fsChildren sorted by path
51
66
  if (tree.fsChildren.size) {
52
67
  this.fsChildren = new Set([...tree.fsChildren]
@@ -126,6 +141,9 @@ class EdgeIn extends Edge {
126
141
  }
127
142
 
128
143
  const printableTree = (tree, path = []) => {
144
+ if (!tree)
145
+ return tree
146
+
129
147
  const Cls = tree.isLink ? ArboristLink
130
148
  : tree.sourceReference ? ArboristVirtualNode
131
149
  : ArboristNode
package/lib/tree-check.js CHANGED
@@ -1,6 +1,8 @@
1
1
  const debug = require('./debug.js')
2
2
 
3
3
  const checkTree = (tree, checkUnreachable = true) => {
4
+ const log = [['START TREE CHECK', tree.path]]
5
+
4
6
  // this can only happen in tests where we have a "tree" object
5
7
  // that isn't actually a tree.
6
8
  if (!tree.root || !tree.root.inventory)
@@ -9,8 +11,21 @@ const checkTree = (tree, checkUnreachable = true) => {
9
11
  const { inventory } = tree.root
10
12
  const seen = new Set()
11
13
  const check = (node, via = tree, viaType = 'self') => {
14
+ log.push([
15
+ 'CHECK',
16
+ node && node.location,
17
+ via && via.location,
18
+ viaType,
19
+ 'seen=' + seen.has(node),
20
+ 'promise=' + !!(node && node.then),
21
+ 'root=' + !!(node && node.isRoot),
22
+ ])
23
+
12
24
  if (!node || seen.has(node) || node.then)
13
25
  return
26
+
27
+ seen.add(node)
28
+
14
29
  if (node.isRoot && node !== tree.root) {
15
30
  throw Object.assign(new Error('double root'), {
16
31
  node: node.path,
@@ -19,6 +34,7 @@ const checkTree = (tree, checkUnreachable = true) => {
19
34
  root: tree.root.path,
20
35
  via: via.path,
21
36
  viaType,
37
+ log,
22
38
  })
23
39
  }
24
40
 
@@ -31,6 +47,7 @@ const checkTree = (tree, checkUnreachable = true) => {
31
47
  via: via.path,
32
48
  viaType,
33
49
  otherRoot: node.root && node.root.path,
50
+ log,
34
51
  })
35
52
  }
36
53
 
@@ -43,6 +60,7 @@ const checkTree = (tree, checkUnreachable = true) => {
43
60
  viaType,
44
61
  inventory: [...node.inventory.values()].map(node =>
45
62
  [node.path, node.location]),
63
+ log,
46
64
  })
47
65
  }
48
66
 
@@ -53,6 +71,7 @@ const checkTree = (tree, checkUnreachable = true) => {
53
71
  root: tree.root.path,
54
72
  via: via.path,
55
73
  viaType,
74
+ log,
56
75
  })
57
76
  }
58
77
 
@@ -65,14 +84,38 @@ const checkTree = (tree, checkUnreachable = true) => {
65
84
  via: via.path,
66
85
  viaType,
67
86
  devEdges: devEdges.map(e => [e.type, e.name, e.spec, e.error]),
87
+ log,
88
+ })
89
+ }
90
+
91
+ if (node.path === tree.root.path && node !== tree.root) {
92
+ throw Object.assign(new Error('node with same path as root'), {
93
+ node: node.path,
94
+ tree: tree.path,
95
+ root: tree.root.path,
96
+ via: via.path,
97
+ viaType,
98
+ log,
99
+ })
100
+ }
101
+
102
+ if (!node.isLink && node.path !== node.realpath) {
103
+ throw Object.assign(new Error('non-link with mismatched path/realpath'), {
104
+ node: node.path,
105
+ tree: tree.path,
106
+ realpath: node.realpath,
107
+ root: tree.root.path,
108
+ via: via.path,
109
+ viaType,
110
+ log,
68
111
  })
69
112
  }
70
113
 
71
114
  const { parent, fsParent, target } = node
72
- seen.add(node)
73
115
  check(parent, node, 'parent')
74
116
  check(fsParent, node, 'fsParent')
75
117
  check(target, node, 'target')
118
+ log.push(['CHILDREN', node.location, ...node.children.keys()])
76
119
  for (const kid of node.children.values())
77
120
  check(kid, node, 'children')
78
121
  for (const kid of node.fsChildren)
@@ -81,6 +124,7 @@ const checkTree = (tree, checkUnreachable = true) => {
81
124
  check(link, node, 'linksIn')
82
125
  for (const top of node.tops)
83
126
  check(top, node, 'tops')
127
+ log.push(['DONE', node.location])
84
128
  }
85
129
  check(tree)
86
130
  if (checkUnreachable) {
@@ -92,6 +136,7 @@ const checkTree = (tree, checkUnreachable = true) => {
92
136
  location: node.location,
93
137
  root: tree.root.path,
94
138
  tree: tree.path,
139
+ log,
95
140
  })
96
141
  }
97
142
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@npmcli/arborist",
3
- "version": "2.2.8",
3
+ "version": "2.4.1",
4
4
  "description": "Manage node_modules trees",
5
5
  "dependencies": {
6
6
  "@npmcli/installed-package-contents": "^1.0.7",
@@ -14,19 +14,19 @@
14
14
  "cacache": "^15.0.3",
15
15
  "common-ancestor-path": "^1.0.1",
16
16
  "json-parse-even-better-errors": "^2.3.1",
17
- "json-stringify-nice": "^1.1.1",
17
+ "json-stringify-nice": "^1.1.2",
18
18
  "mkdirp-infer-owner": "^2.0.0",
19
19
  "npm-install-checks": "^4.0.0",
20
20
  "npm-package-arg": "^8.1.0",
21
21
  "npm-pick-manifest": "^6.1.0",
22
- "npm-registry-fetch": "^9.0.0",
22
+ "npm-registry-fetch": "^10.0.0",
23
23
  "pacote": "^11.2.6",
24
24
  "parse-conflict-json": "^1.1.1",
25
25
  "promise-all-reject-late": "^1.0.0",
26
26
  "promise-call-limit": "^1.0.1",
27
27
  "read-package-json-fast": "^2.0.2",
28
28
  "readdir-scoped-modules": "^1.1.0",
29
- "semver": "^7.3.4",
29
+ "semver": "^7.3.5",
30
30
  "tar": "^6.1.0",
31
31
  "treeverse": "^1.0.4",
32
32
  "walk-up-path": "^1.0.0"
@@ -41,8 +41,7 @@
41
41
  "eslint-plugin-standard": "^4.0.1",
42
42
  "minify-registry-metadata": "^2.1.0",
43
43
  "mutate-fs": "^2.1.1",
44
- "require-inject": "^1.4.4",
45
- "tap": "^14.11.0",
44
+ "tap": "^15.0.4",
46
45
  "tcompare": "^3.0.4"
47
46
  },
48
47
  "scripts": {
@@ -76,10 +75,8 @@
76
75
  "arborist": "bin/index.js"
77
76
  },
78
77
  "tap": {
79
- "100": true,
80
78
  "after": "test/fixtures/cleanup.js",
81
79
  "coverage-map": "map.js",
82
- "esm": false,
83
80
  "test-env": [
84
81
  "NODE_OPTIONS=--no-warnings"
85
82
  ],
@@ -87,6 +84,6 @@
87
84
  "--no-warnings",
88
85
  "--no-deprecation"
89
86
  ],
90
- "timeout": "120"
87
+ "timeout": "240"
91
88
  }
92
89
  }