@npmcli/arborist 2.8.2 → 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.
Files changed (49) hide show
  1. package/bin/actual.js +4 -2
  2. package/bin/audit.js +12 -6
  3. package/bin/dedupe.js +6 -3
  4. package/bin/funding.js +4 -2
  5. package/bin/ideal.js +2 -1
  6. package/bin/lib/logging.js +4 -3
  7. package/bin/lib/options.js +14 -12
  8. package/bin/lib/timers.js +6 -3
  9. package/bin/license.js +9 -5
  10. package/bin/prune.js +6 -3
  11. package/bin/reify.js +6 -3
  12. package/bin/virtual.js +4 -2
  13. package/lib/add-rm-pkg-deps.js +25 -14
  14. package/lib/arborist/audit.js +2 -1
  15. package/lib/arborist/build-ideal-tree.js +129 -68
  16. package/lib/arborist/deduper.js +2 -1
  17. package/lib/arborist/index.js +8 -4
  18. package/lib/arborist/load-actual.js +28 -13
  19. package/lib/arborist/load-virtual.js +34 -18
  20. package/lib/arborist/load-workspaces.js +4 -2
  21. package/lib/arborist/rebuild.js +31 -16
  22. package/lib/arborist/reify.js +153 -76
  23. package/lib/audit-report.js +42 -22
  24. package/lib/calc-dep-flags.js +18 -9
  25. package/lib/can-place-dep.js +56 -28
  26. package/lib/case-insensitive-map.js +4 -2
  27. package/lib/consistent-resolve.js +2 -1
  28. package/lib/deepest-nesting-target.js +4 -2
  29. package/lib/dep-valid.js +8 -4
  30. package/lib/diff.js +74 -22
  31. package/lib/edge.js +26 -13
  32. package/lib/gather-dep-set.js +2 -1
  33. package/lib/inventory.js +12 -6
  34. package/lib/link.js +14 -9
  35. package/lib/node.js +216 -113
  36. package/lib/optional-set.js +4 -2
  37. package/lib/peer-entry-sets.js +10 -5
  38. package/lib/place-dep.js +56 -29
  39. package/lib/printable.js +41 -21
  40. package/lib/realpath.js +12 -6
  41. package/lib/shrinkwrap.js +162 -89
  42. package/lib/signal-handling.js +6 -3
  43. package/lib/spec-from-lock.js +7 -4
  44. package/lib/tracker.js +24 -18
  45. package/lib/tree-check.js +12 -6
  46. package/lib/version-from-tgz.js +4 -2
  47. package/lib/vuln.js +28 -16
  48. package/lib/yarn-lock.js +27 -15
  49. package/package.json +7 -10
@@ -78,8 +78,9 @@ module.exports = cls => class ActualLoader extends cls {
78
78
  [_resetDepFlags] (tree, root) {
79
79
  // reset all deps to extraneous prior to recalc
80
80
  if (!root) {
81
- for (const node of tree.inventory.values())
81
+ for (const node of tree.inventory.values()) {
82
82
  node.extraneous = true
83
+ }
83
84
  }
84
85
 
85
86
  // only reset root flags if we're not re-rooting,
@@ -176,8 +177,9 @@ module.exports = cls => class ActualLoader extends cls {
176
177
  await this[_loadFSTree](this[_actualTree])
177
178
  await this[_loadWorkspaces](this[_actualTree])
178
179
  await this[_loadWorkspaceTargets](this[_actualTree])
179
- if (!ignoreMissing)
180
+ if (!ignoreMissing) {
180
181
  await this[_findMissingEdges]()
182
+ }
181
183
  this[_findFSParents]()
182
184
  this[_transplant](root)
183
185
 
@@ -200,8 +202,9 @@ module.exports = cls => class ActualLoader extends cls {
200
202
  // if there are workspace targets without Link nodes created, load
201
203
  // the targets, so that we know what they are.
202
204
  async [_loadWorkspaceTargets] (tree) {
203
- if (!tree.workspaces || !tree.workspaces.size)
205
+ if (!tree.workspaces || !tree.workspaces.size) {
204
206
  return
207
+ }
205
208
 
206
209
  const promises = []
207
210
  for (const path of tree.workspaces.values()) {
@@ -215,18 +218,21 @@ module.exports = cls => class ActualLoader extends cls {
215
218
  }
216
219
 
217
220
  [_transplant] (root) {
218
- if (!root || root === this[_actualTree])
221
+ if (!root || root === this[_actualTree]) {
219
222
  return
223
+ }
220
224
 
221
225
  this[_actualTree][_changePath](root.path)
222
226
  for (const node of this[_actualTree].children.values()) {
223
- if (!this[_transplantFilter](node))
227
+ if (!this[_transplantFilter](node)) {
224
228
  node.root = null
229
+ }
225
230
  }
226
231
 
227
232
  root.replace(this[_actualTree])
228
- for (const node of this[_actualTree].fsChildren)
233
+ for (const node of this[_actualTree].fsChildren) {
229
234
  node.root = this[_transplantFilter](node) ? root : null
235
+ }
230
236
 
231
237
  this[_actualTree] = root
232
238
  }
@@ -291,8 +297,9 @@ module.exports = cls => class ActualLoader extends cls {
291
297
  // it'll get parented later, making the fsParent scan a no-op, but better
292
298
  // safe than sorry, since it's cheap.
293
299
  const { parent, realpath } = options
294
- if (!parent)
300
+ if (!parent) {
295
301
  this[_topNodes].add(realpath)
302
+ }
296
303
  return process.env._TEST_ARBORIST_SLOW_LINK_TARGET_ === '1'
297
304
  ? new Promise(res => setTimeout(() => res(new Node(options)), 100))
298
305
  : new Node(options)
@@ -309,8 +316,9 @@ module.exports = cls => class ActualLoader extends cls {
309
316
  // if a link target points at a node outside of the root tree's
310
317
  // node_modules hierarchy, then load that node as well.
311
318
  return this[_loadFSTree](link.target).then(() => link)
312
- } else if (target.then)
319
+ } else if (target.then) {
313
320
  target.then(node => link.target = node)
321
+ }
314
322
 
315
323
  return link
316
324
  }
@@ -321,13 +329,15 @@ module.exports = cls => class ActualLoader extends cls {
321
329
 
322
330
  // if a Link target has started, but not completed, then
323
331
  // a Promise will be in the cache to indicate this.
324
- if (node.then)
332
+ if (node.then) {
325
333
  return node.then(node => this[_loadFSTree](node))
334
+ }
326
335
 
327
336
  // impossible except in pathological ELOOP cases
328
337
  /* istanbul ignore if */
329
- if (did.has(node.realpath))
338
+ if (did.has(node.realpath)) {
330
339
  return Promise.resolve(node)
340
+ }
331
341
 
332
342
  did.add(node.realpath)
333
343
  return this[_loadFSChildren](node)
@@ -371,8 +381,11 @@ module.exports = cls => class ActualLoader extends cls {
371
381
 
372
382
  const depPromises = []
373
383
  for (const [name, edge] of node.edgesOut.entries()) {
374
- if (!edge.missing && !(edge.to && (edge.to.dummy || edge.to.parent !== node)))
384
+ const notMissing = !edge.missing &&
385
+ !(edge.to && (edge.to.dummy || edge.to.parent !== node))
386
+ if (notMissing) {
375
387
  continue
388
+ }
376
389
 
377
390
  // start the walk from the dirname, because we would have found
378
391
  // the dep in the loadFSTree step already if it was local.
@@ -383,14 +396,16 @@ module.exports = cls => class ActualLoader extends cls {
383
396
  // allows for finding the transitive deps of link targets.
384
397
  // ie, if it has to go up and back out to get to the path
385
398
  // from the nearest common ancestor, we've gone too far.
386
- if (ancestor && /^\.\.(?:[\\/]|$)/.test(relative(ancestor, p)))
399
+ if (ancestor && /^\.\.(?:[\\/]|$)/.test(relative(ancestor, p))) {
387
400
  break
401
+ }
388
402
 
389
403
  const entries = nmContents.get(p) ||
390
404
  await readdir(p + '/node_modules').catch(() => [])
391
405
  nmContents.set(p, entries)
392
- if (!entries.includes(name))
406
+ if (!entries.includes(name)) {
393
407
  continue
408
+ }
394
409
 
395
410
  const d = this[_cache].has(p) ? await this[_cache].get(p)
396
411
  : new Node({ path: p, root: node.root, dummy: true })
@@ -40,8 +40,9 @@ module.exports = cls => class VirtualLoader extends cls {
40
40
 
41
41
  // public method
42
42
  async loadVirtual (options = {}) {
43
- if (this.virtualTree)
43
+ if (this.virtualTree) {
44
44
  return this.virtualTree
45
+ }
45
46
 
46
47
  // allow the user to set reify options on the ctor as well.
47
48
  // XXX: deprecate separate reify() options object.
@@ -85,18 +86,21 @@ module.exports = cls => class VirtualLoader extends cls {
85
86
  root.optional = false
86
87
  root.devOptional = false
87
88
  root.peer = false
88
- } else
89
+ } else {
89
90
  this[flagsSuspect] = true
91
+ }
90
92
 
91
93
  this[checkRootEdges](s, root)
92
94
  root.meta = s
93
95
  this.virtualTree = root
94
96
  const {links, nodes} = this[resolveNodes](s, root)
95
97
  await this[resolveLinks](links, nodes)
96
- if (!(s.originalLockfileVersion >= 2))
98
+ if (!(s.originalLockfileVersion >= 2)) {
97
99
  this[assignBundles](nodes)
98
- if (this[flagsSuspect])
100
+ }
101
+ if (this[flagsSuspect]) {
99
102
  this[reCalcDepFlags](nodes.values())
103
+ }
100
104
  return root
101
105
  }
102
106
 
@@ -104,8 +108,9 @@ module.exports = cls => class VirtualLoader extends cls {
104
108
  // reset all dep flags
105
109
  // can't use inventory here, because virtualTree might not be root
106
110
  for (const node of nodes) {
107
- if (node.isRoot || node === this[rootOptionProvided])
111
+ if (node.isRoot || node === this[rootOptionProvided]) {
108
112
  continue
113
+ }
109
114
  node.extraneous = true
110
115
  node.dev = true
111
116
  node.optional = true
@@ -123,8 +128,9 @@ module.exports = cls => class VirtualLoader extends cls {
123
128
  // loaded virtually from tree, no chance of being out of sync
124
129
  // ancient lockfiles are critically damaged by this process,
125
130
  // so we need to just hope for the best in those cases.
126
- if (!s.loadedFromDisk || s.ancientLockfile)
131
+ if (!s.loadedFromDisk || s.ancientLockfile) {
127
132
  return
133
+ }
128
134
 
129
135
  const lock = s.get('')
130
136
  const prod = lock.dependencies || {}
@@ -140,16 +146,18 @@ module.exports = cls => class VirtualLoader extends cls {
140
146
  }
141
147
  }
142
148
  }
143
- for (const name of Object.keys(optional))
149
+ for (const name of Object.keys(optional)) {
144
150
  delete prod[name]
151
+ }
145
152
 
146
153
  const lockWS = []
147
154
  const workspaces = this[loadWorkspacesVirtual]({
148
155
  cwd: this.path,
149
156
  lockfile: s.data,
150
157
  })
151
- for (const [name, path] of workspaces.entries())
158
+ for (const [name, path] of workspaces.entries()) {
152
159
  lockWS.push(['workspace', name, `file:${path}`])
160
+ }
153
161
 
154
162
  const lockEdges = [
155
163
  ...depsToEdges('prod', prod),
@@ -174,8 +182,9 @@ module.exports = cls => class VirtualLoader extends cls {
174
182
  for (let i = 0; i < lockEdges.length; i++) {
175
183
  if (rootEdges[i][0] !== lockEdges[i][0] ||
176
184
  rootEdges[i][1] !== lockEdges[i][1] ||
177
- rootEdges[i][2] !== lockEdges[i][2])
185
+ rootEdges[i][2] !== lockEdges[i][2]) {
178
186
  return this[flagsSuspect] = true
187
+ }
179
188
  }
180
189
  }
181
190
 
@@ -185,13 +194,15 @@ module.exports = cls => class VirtualLoader extends cls {
185
194
  const nodes = new Map([['', root]])
186
195
  for (const [location, meta] of Object.entries(s.data.packages)) {
187
196
  // skip the root because we already got it
188
- if (!location)
197
+ if (!location) {
189
198
  continue
199
+ }
190
200
 
191
- if (meta.link)
201
+ if (meta.link) {
192
202
  links.set(location, meta)
193
- else
203
+ } else {
194
204
  nodes.set(location, this[loadNode](location, meta))
205
+ }
195
206
  }
196
207
  return {links, nodes}
197
208
  }
@@ -212,8 +223,9 @@ module.exports = cls => class VirtualLoader extends cls {
212
223
  if (!link.target.parent) {
213
224
  const pj = link.realpath + '/package.json'
214
225
  const pkg = await rpj(pj).catch(() => null)
215
- if (pkg)
226
+ if (pkg) {
216
227
  link.target.package = pkg
228
+ }
217
229
  }
218
230
  }
219
231
  }
@@ -221,12 +233,14 @@ module.exports = cls => class VirtualLoader extends cls {
221
233
  [assignBundles] (nodes) {
222
234
  for (const [location, node] of nodes) {
223
235
  // Skip assignment of parentage for the root package
224
- if (!location || node.isLink && !node.target.location)
236
+ if (!location || node.isLink && !node.target.location) {
225
237
  continue
238
+ }
226
239
  const { name, parent, package: { inBundle }} = node
227
240
 
228
- if (!parent)
241
+ if (!parent) {
229
242
  continue
243
+ }
230
244
 
231
245
  // read inBundle from package because 'package' here is
232
246
  // actually a v2 lockfile metadata entry.
@@ -236,10 +250,11 @@ module.exports = cls => class VirtualLoader extends cls {
236
250
  const { package: ppkg } = parent
237
251
  const { inBundle: parentBundled } = ppkg
238
252
  if (inBundle && !parentBundled && parent.edgesOut.has(node.name)) {
239
- if (!ppkg.bundleDependencies)
253
+ if (!ppkg.bundleDependencies) {
240
254
  ppkg.bundleDependencies = [name]
241
- else
255
+ } else {
242
256
  ppkg.bundleDependencies.push(name)
257
+ }
243
258
  }
244
259
  }
245
260
  }
@@ -248,8 +263,9 @@ module.exports = cls => class VirtualLoader extends cls {
248
263
  const p = this.virtualTree ? this.virtualTree.realpath : this.path
249
264
  const path = resolve(p, location)
250
265
  // shrinkwrap doesn't include package name unless necessary
251
- if (!sw.name)
266
+ if (!sw.name) {
252
267
  sw.name = nameFromFolder(path)
268
+ }
253
269
 
254
270
  const dev = sw.dev
255
271
  const optional = sw.optional
@@ -7,15 +7,17 @@ const _loadWorkspacesVirtual = Symbol.for('loadWorkspacesVirtual')
7
7
 
8
8
  module.exports = cls => class MapWorkspaces extends cls {
9
9
  [_appendWorkspaces] (node, workspaces) {
10
- if (node && workspaces.size)
10
+ if (node && workspaces.size) {
11
11
  node.workspaces = workspaces
12
+ }
12
13
 
13
14
  return node
14
15
  }
15
16
 
16
17
  async [_loadWorkspaces] (node) {
17
- if (node.workspaces)
18
+ if (node.workspaces) {
18
19
  return node
20
+ }
19
21
 
20
22
  const workspaces = await mapWorkspaces({
21
23
  cwd: node.path,
@@ -61,8 +61,9 @@ module.exports = cls => class Builder extends cls {
61
61
 
62
62
  async rebuild ({ nodes, handleOptionalFailure = false } = {}) {
63
63
  // nothing to do if we're not building anything!
64
- if (this[_ignoreScripts] && !this[_binLinks])
64
+ if (this[_ignoreScripts] && !this[_binLinks]) {
65
65
  return
66
+ }
66
67
 
67
68
  // when building for the first time, as part of reify, we ignore
68
69
  // failures in optional nodes, and just delete them. however, when
@@ -76,8 +77,9 @@ module.exports = cls => class Builder extends cls {
76
77
  if (this[_workspaces] && this[_workspaces].length) {
77
78
  const filterSet = this.workspaceDependencySet(tree, this[_workspaces])
78
79
  nodes = tree.inventory.filter(node => filterSet.has(node))
79
- } else
80
+ } else {
80
81
  nodes = tree.inventory.values()
82
+ }
81
83
  }
82
84
 
83
85
  // separates links nodes so that it can run
@@ -88,10 +90,11 @@ module.exports = cls => class Builder extends cls {
88
90
  for (const node of nodes) {
89
91
  // we skip the target nodes to that workspace in order to make sure
90
92
  // we only run lifecycle scripts / place bin links once per workspace
91
- if (node.isLink)
93
+ if (node.isLink) {
92
94
  linkNodes.add(node)
93
- else
95
+ } else {
94
96
  depNodes.add(node)
97
+ }
95
98
  }
96
99
 
97
100
  await this[_build](depNodes, {})
@@ -118,17 +121,20 @@ module.exports = cls => class Builder extends cls {
118
121
  process.emit('time', `build:${type}`)
119
122
 
120
123
  await this[_buildQueues](nodes)
121
- if (!this[_ignoreScripts])
124
+ if (!this[_ignoreScripts]) {
122
125
  await this[_runScripts]('preinstall')
123
- if (this[_binLinks] && type !== 'links')
126
+ }
127
+ if (this[_binLinks] && type !== 'links') {
124
128
  await this[_linkAllBins]()
129
+ }
125
130
 
126
131
  // links should also run prepare scripts and only link bins after that
127
132
  if (type === 'links') {
128
133
  await this[_runScripts]('prepare')
129
134
 
130
- if (this[_binLinks])
135
+ if (this[_binLinks]) {
131
136
  await this[_linkAllBins]()
137
+ }
132
138
  }
133
139
 
134
140
  if (!this[_ignoreScripts]) {
@@ -173,8 +179,9 @@ module.exports = cls => class Builder extends cls {
173
179
  const { preinstall, install, postinstall, prepare } = scripts
174
180
  const tests = { bin, preinstall, install, postinstall, prepare }
175
181
  for (const [key, has] of Object.entries(tests)) {
176
- if (has)
182
+ if (has) {
177
183
  this[_queues][key].push(node)
184
+ }
178
185
  }
179
186
  }
180
187
  process.emit('timeEnd', 'build:queue')
@@ -186,15 +193,17 @@ module.exports = cls => class Builder extends cls {
186
193
  // the node path. Otherwise a package can have a preinstall script
187
194
  // that unlinks something, to allow them to silently overwrite system
188
195
  // binaries, which is unsafe and insecure.
189
- if (!node.globalTop || this[_force])
196
+ if (!node.globalTop || this[_force]) {
190
197
  return
198
+ }
191
199
  const { path, package: pkg } = node
192
200
  await binLinks.checkBins({ pkg, path, top: true, global: true })
193
201
  }
194
202
 
195
203
  async [_addToBuildSet] (node, set, refreshed = false) {
196
- if (set.has(node))
204
+ if (set.has(node)) {
197
205
  return
206
+ }
198
207
 
199
208
  if (this[_oldMeta] === null) {
200
209
  const {root: {meta}} = node
@@ -233,8 +242,9 @@ module.exports = cls => class Builder extends cls {
233
242
  await isNodeGypPackage(node.path)
234
243
 
235
244
  if (bin || preinstall || install || postinstall || prepare || isGyp) {
236
- if (bin)
245
+ if (bin) {
237
246
  await this[_checkBins](node)
247
+ }
238
248
  if (isGyp) {
239
249
  scripts.install = defaultGypInstallScript
240
250
  node.package.scripts = scripts
@@ -246,8 +256,9 @@ module.exports = cls => class Builder extends cls {
246
256
  async [_runScripts] (event) {
247
257
  const queue = this[_queues][event]
248
258
 
249
- if (!queue.length)
259
+ if (!queue.length) {
250
260
  return
261
+ }
251
262
 
252
263
  process.emit('time', `build:run:${event}`)
253
264
  const stdio = this.options.foregroundScripts ? 'inherit' : 'pipe'
@@ -266,8 +277,9 @@ module.exports = cls => class Builder extends cls {
266
277
  } = node.target
267
278
 
268
279
  // skip any that we know we'll be deleting
269
- if (this[_trashList].has(path))
280
+ if (this[_trashList].has(path)) {
270
281
  return
282
+ }
271
283
 
272
284
  const timer = `build:run:${event}:${location}`
273
285
  process.emit('time', timer)
@@ -321,23 +333,26 @@ module.exports = cls => class Builder extends cls {
321
333
 
322
334
  async [_linkAllBins] () {
323
335
  const queue = this[_queues].bin
324
- if (!queue.length)
336
+ if (!queue.length) {
325
337
  return
338
+ }
326
339
 
327
340
  process.emit('time', 'build:link')
328
341
  const promises = []
329
342
  // sort the queue by node path, so that the module-local collision
330
343
  // detector in bin-links will always resolve the same way.
331
- for (const node of queue.sort(sortNodes))
344
+ for (const node of queue.sort(sortNodes)) {
332
345
  promises.push(this[_createBinLinks](node))
346
+ }
333
347
 
334
348
  await promiseAllRejectLate(promises)
335
349
  process.emit('timeEnd', 'build:link')
336
350
  }
337
351
 
338
352
  async [_createBinLinks] (node) {
339
- if (this[_trashList].has(node.path))
353
+ if (this[_trashList].has(node.path)) {
340
354
  return
355
+ }
341
356
 
342
357
  process.emit('time', `build:link:${node.location}`)
343
358