@npmcli/arborist 5.4.0 → 5.6.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/bin/index.js CHANGED
@@ -99,6 +99,7 @@ for (const file of commandFiles) {
99
99
  if (bin.loglevel !== 'silent') {
100
100
  console[process.exitCode ? 'error' : 'log'](r)
101
101
  }
102
+ return r
102
103
  })
103
104
  }
104
105
  }
@@ -4,8 +4,67 @@ const log = require('proc-log')
4
4
  const localeCompare = require('@isaacs/string-locale-compare')('en')
5
5
 
6
6
  const add = ({ pkg, add, saveBundle, saveType }) => {
7
- for (const spec of add) {
8
- addSingle({ pkg, spec, saveBundle, saveType })
7
+ for (const { name, rawSpec } of add) {
8
+ // if the user does not give us a type, we infer which type(s)
9
+ // to keep based on the same order of priority we do when
10
+ // building the tree as defined in the _loadDeps method of
11
+ // the node class.
12
+ if (!saveType) {
13
+ saveType = inferSaveType(pkg, name)
14
+ }
15
+
16
+ if (saveType === 'prod') {
17
+ // a production dependency can only exist as production (rpj ensures it
18
+ // doesn't coexist w/ optional)
19
+ deleteSubKey(pkg, 'devDependencies', name, 'dependencies')
20
+ deleteSubKey(pkg, 'peerDependencies', name, 'dependencies')
21
+ } else if (saveType === 'dev') {
22
+ // a dev dependency may co-exist as peer, or optional, but not production
23
+ deleteSubKey(pkg, 'dependencies', name, 'devDependencies')
24
+ } else if (saveType === 'optional') {
25
+ // an optional dependency may co-exist as dev (rpj ensures it doesn't
26
+ // coexist w/ prod)
27
+ deleteSubKey(pkg, 'peerDependencies', name, 'optionalDependencies')
28
+ } else { // peer or peerOptional is all that's left
29
+ // a peer dependency may coexist as dev
30
+ deleteSubKey(pkg, 'dependencies', name, 'peerDependencies')
31
+ deleteSubKey(pkg, 'optionalDependencies', name, 'peerDependencies')
32
+ }
33
+
34
+ const depType = saveTypeMap.get(saveType)
35
+
36
+ pkg[depType] = pkg[depType] || {}
37
+ if (rawSpec !== '' || pkg[depType][name] === undefined) {
38
+ pkg[depType][name] = rawSpec || '*'
39
+ }
40
+ if (saveType === 'optional') {
41
+ // Affordance for previous npm versions that require this behaviour
42
+ pkg.dependencies = pkg.dependencies || {}
43
+ pkg.dependencies[name] = pkg.optionalDependencies[name]
44
+ }
45
+
46
+ if (saveType === 'peer' || saveType === 'peerOptional') {
47
+ const pdm = pkg.peerDependenciesMeta || {}
48
+ if (saveType === 'peer' && pdm[name] && pdm[name].optional) {
49
+ pdm[name].optional = false
50
+ } else if (saveType === 'peerOptional') {
51
+ pdm[name] = pdm[name] || {}
52
+ pdm[name].optional = true
53
+ pkg.peerDependenciesMeta = pdm
54
+ }
55
+ // peerDeps are often also a devDep, so that they can be tested when
56
+ // using package managers that don't auto-install peer deps
57
+ if (pkg.devDependencies && pkg.devDependencies[name] !== undefined) {
58
+ pkg.devDependencies[name] = pkg.peerDependencies[name]
59
+ }
60
+ }
61
+
62
+ if (saveBundle && saveType !== 'peer' && saveType !== 'peerOptional') {
63
+ // keep it sorted, keep it unique
64
+ const bd = new Set(pkg.bundleDependencies || [])
65
+ bd.add(name)
66
+ pkg.bundleDependencies = [...bd].sort(localeCompare)
67
+ }
9
68
  }
10
69
 
11
70
  return pkg
@@ -21,71 +80,6 @@ const saveTypeMap = new Map([
21
80
  ['peer', 'peerDependencies'],
22
81
  ])
23
82
 
24
- const addSingle = ({ pkg, spec, saveBundle, saveType }) => {
25
- const { name, rawSpec } = spec
26
-
27
- // if the user does not give us a type, we infer which type(s)
28
- // to keep based on the same order of priority we do when
29
- // building the tree as defined in the _loadDeps method of
30
- // the node class.
31
- if (!saveType) {
32
- saveType = inferSaveType(pkg, spec.name)
33
- }
34
-
35
- if (saveType === 'prod') {
36
- // a production dependency can only exist as production (rpj ensures it
37
- // doesn't coexist w/ optional)
38
- deleteSubKey(pkg, 'devDependencies', name, 'dependencies')
39
- deleteSubKey(pkg, 'peerDependencies', name, 'dependencies')
40
- } else if (saveType === 'dev') {
41
- // a dev dependency may co-exist as peer, or optional, but not production
42
- deleteSubKey(pkg, 'dependencies', name, 'devDependencies')
43
- } else if (saveType === 'optional') {
44
- // an optional dependency may co-exist as dev (rpj ensures it doesn't
45
- // coexist w/ prod)
46
- deleteSubKey(pkg, 'peerDependencies', name, 'optionalDependencies')
47
- } else { // peer or peerOptional is all that's left
48
- // a peer dependency may coexist as dev
49
- deleteSubKey(pkg, 'dependencies', name, 'peerDependencies')
50
- deleteSubKey(pkg, 'optionalDependencies', name, 'peerDependencies')
51
- }
52
-
53
- const depType = saveTypeMap.get(saveType)
54
-
55
- pkg[depType] = pkg[depType] || {}
56
- if (rawSpec !== '' || pkg[depType][name] === undefined) {
57
- pkg[depType][name] = rawSpec || '*'
58
- }
59
- if (saveType === 'optional') {
60
- // Affordance for previous npm versions that require this behaviour
61
- pkg.dependencies = pkg.dependencies || {}
62
- pkg.dependencies[name] = pkg.optionalDependencies[name]
63
- }
64
-
65
- if (saveType === 'peer' || saveType === 'peerOptional') {
66
- const pdm = pkg.peerDependenciesMeta || {}
67
- if (saveType === 'peer' && pdm[name] && pdm[name].optional) {
68
- pdm[name].optional = false
69
- } else if (saveType === 'peerOptional') {
70
- pdm[name] = pdm[name] || {}
71
- pdm[name].optional = true
72
- pkg.peerDependenciesMeta = pdm
73
- }
74
- // peerDeps are often also a devDep, so that they can be tested when
75
- // using package managers that don't auto-install peer deps
76
- if (pkg.devDependencies && pkg.devDependencies[name] !== undefined) {
77
- pkg.devDependencies[name] = pkg.peerDependencies[name]
78
- }
79
- }
80
-
81
- if (saveBundle && saveType !== 'peer' && saveType !== 'peerOptional') {
82
- // keep it sorted, keep it unique
83
- const bd = new Set(pkg.bundleDependencies || [])
84
- bd.add(spec.name)
85
- pkg.bundleDependencies = [...bd].sort(localeCompare)
86
- }
87
- }
88
-
89
83
  // Finds where the package is already in the spec and infers saveType from that
90
84
  const inferSaveType = (pkg, name) => {
91
85
  for (const saveType of saveTypeMap.keys()) {
@@ -103,9 +97,8 @@ const inferSaveType = (pkg, name) => {
103
97
  return 'prod'
104
98
  }
105
99
 
106
- const { hasOwnProperty } = Object.prototype
107
100
  const hasSubKey = (pkg, depType, name) => {
108
- return pkg[depType] && hasOwnProperty.call(pkg[depType], name)
101
+ return pkg[depType] && Object.prototype.hasOwnProperty.call(pkg[depType], name)
109
102
  }
110
103
 
111
104
  // Removes a subkey and warns about it if it's being replaced
@@ -81,18 +81,11 @@ const _linkNodes = Symbol('linkNodes')
81
81
  const _follow = Symbol('follow')
82
82
  const _globalStyle = Symbol('globalStyle')
83
83
  const _globalRootNode = Symbol('globalRootNode')
84
- const _isVulnerable = Symbol.for('isVulnerable')
85
84
  const _usePackageLock = Symbol.for('usePackageLock')
86
85
  const _rpcache = Symbol.for('realpathCache')
87
86
  const _stcache = Symbol.for('statCache')
88
- const _updateFilePath = Symbol('updateFilePath')
89
- const _followSymlinkPath = Symbol('followSymlinkPath')
90
- const _getRelpathSpec = Symbol('getRelpathSpec')
91
- const _retrieveSpecName = Symbol('retrieveSpecName')
92
87
  const _strictPeerDeps = Symbol('strictPeerDeps')
93
88
  const _checkEngineAndPlatform = Symbol('checkEngineAndPlatform')
94
- const _checkEngine = Symbol('checkEngine')
95
- const _checkPlatform = Symbol('checkPlatform')
96
89
  const _virtualRoots = Symbol('virtualRoots')
97
90
  const _virtualRoot = Symbol('virtualRoot')
98
91
  const _includeWorkspaceRoot = Symbol.for('includeWorkspaceRoot')
@@ -228,34 +221,22 @@ module.exports = cls => class IdealTreeBuilder extends cls {
228
221
  }
229
222
 
230
223
  async [_checkEngineAndPlatform] () {
224
+ const { engineStrict, npmVersion, nodeVersion } = this.options
231
225
  for (const node of this.idealTree.inventory.values()) {
232
226
  if (!node.optional) {
233
- this[_checkEngine](node)
234
- this[_checkPlatform](node)
235
- }
236
- }
237
- }
238
-
239
- [_checkPlatform] (node) {
240
- checkPlatform(node.package, this[_force])
241
- }
242
-
243
- [_checkEngine] (node) {
244
- const { engineStrict, npmVersion, nodeVersion } = this.options
245
- const c = () =>
246
- checkEngine(node.package, npmVersion, nodeVersion, this[_force])
247
-
248
- if (engineStrict) {
249
- c()
250
- } else {
251
- try {
252
- c()
253
- } catch (er) {
254
- log.warn(er.code, er.message, {
255
- package: er.pkgid,
256
- required: er.required,
257
- current: er.current,
258
- })
227
+ try {
228
+ checkEngine(node.package, npmVersion, nodeVersion, this[_force])
229
+ } catch (err) {
230
+ if (engineStrict) {
231
+ throw err
232
+ }
233
+ log.warn(err.code, err.message, {
234
+ package: err.pkgid,
235
+ required: err.required,
236
+ current: err.current,
237
+ })
238
+ }
239
+ checkPlatform(node.package, this[_force])
259
240
  }
260
241
  }
261
242
  }
@@ -378,6 +359,7 @@ Try using the package name instead, e.g:
378
359
  this.idealTree = tree
379
360
  this.virtualTree = null
380
361
  process.emit('timeEnd', 'idealTree:init')
362
+ return tree
381
363
  })
382
364
  }
383
365
 
@@ -529,84 +511,59 @@ Try using the package name instead, e.g:
529
511
  this[_depsQueue].push(tree)
530
512
  }
531
513
 
532
- // This returns a promise because we might not have the name yet,
533
- // and need to call pacote.manifest to find the name.
534
- [_add] (tree, { add, saveType = null, saveBundle = false }) {
535
- // get the name for each of the specs in the list.
536
- // ie, doing `foo@bar` we just return foo
537
- // but if it's a url or git, we don't know the name until we
538
- // fetch it and look in its manifest.
539
- return Promise.all(add.map(async rawSpec => {
540
- // We do NOT provide the path to npa here, because user-additions
541
- // need to be resolved relative to the CWD the user is in.
542
- const spec = await this[_retrieveSpecName](npa(rawSpec))
543
- .then(spec => this[_updateFilePath](spec))
544
- .then(spec => this[_followSymlinkPath](spec))
545
- spec.tree = tree
546
- return spec
547
- })).then(add => {
548
- this[_resolvedAdd].push(...add)
549
- // now add is a list of spec objects with names.
550
- // find a home for each of them!
551
- addRmPkgDeps.add({
552
- pkg: tree.package,
553
- add,
554
- saveBundle,
555
- saveType,
556
- path: this.path,
557
- })
558
- })
559
- }
560
-
561
- async [_retrieveSpecName] (spec) {
562
- // if it's just @'' then we reload whatever's there, or get latest
563
- // if it's an explicit tag, we need to install that specific tag version
564
- const isTag = spec.rawSpec && spec.type === 'tag'
565
-
566
- if (spec.name && !isTag) {
567
- return spec
568
- }
569
-
570
- const mani = await pacote.manifest(spec, { ...this.options })
571
- // if it's a tag type, then we need to run it down to an actual version
572
- if (isTag) {
573
- return npa(`${mani.name}@${mani.version}`)
574
- }
575
-
576
- spec.name = mani.name
577
- return spec
578
- }
579
-
580
- async [_updateFilePath] (spec) {
581
- if (spec.type === 'file') {
582
- return this[_getRelpathSpec](spec, spec.fetchSpec)
583
- }
584
-
585
- return spec
586
- }
587
-
588
- async [_followSymlinkPath] (spec) {
589
- if (spec.type === 'directory') {
590
- const real = await (
591
- realpath(spec.fetchSpec, this[_rpcache], this[_stcache])
592
- // TODO: create synthetic test case to simulate realpath failure
593
- .catch(/* istanbul ignore next */() => null)
594
- )
514
+ // This returns a promise because we might not have the name yet, and need to
515
+ // call pacote.manifest to find the name.
516
+ async [_add] (tree, { add, saveType = null, saveBundle = false }) {
517
+ // If we have a link it will need to be added relative to the target's path
518
+ const path = tree.target.path
595
519
 
596
- return this[_getRelpathSpec](spec, real)
597
- }
598
- return spec
599
- }
520
+ // get the name for each of the specs in the list.
521
+ // ie, doing `foo@bar` we just return foo but if it's a url or git, we
522
+ // don't know the name until we fetch it and look in its manifest.
523
+ await Promise.all(add.map(async rawSpec => {
524
+ // We do NOT provide the path to npa here, because user-additions need to
525
+ // be resolved relative to the tree being added to.
526
+ let spec = npa(rawSpec)
527
+
528
+ // if it's just @'' then we reload whatever's there, or get latest
529
+ // if it's an explicit tag, we need to install that specific tag version
530
+ const isTag = spec.rawSpec && spec.type === 'tag'
531
+
532
+ // look up the names of file/directory/git specs
533
+ if (!spec.name || isTag) {
534
+ const mani = await pacote.manifest(spec, { ...this.options })
535
+ if (isTag) {
536
+ // translate tag to a version
537
+ spec = npa(`${mani.name}@${mani.version}`)
538
+ }
539
+ spec.name = mani.name
540
+ }
600
541
 
601
- [_getRelpathSpec] (spec, filepath) {
602
- /* istanbul ignore else - should also be covered by realpath failure */
603
- if (filepath) {
604
542
  const { name } = spec
605
- const tree = this.idealTree.target
606
- spec = npa(`file:${relpath(tree.path, filepath).replace(/#/g, '%23')}`, tree.path)
607
- spec.name = name
608
- }
609
- return spec
543
+ if (spec.type === 'file') {
544
+ spec = npa(`file:${relpath(path, spec.fetchSpec).replace(/#/g, '%23')}`, path)
545
+ spec.name = name
546
+ } else if (spec.type === 'directory') {
547
+ try {
548
+ const real = await realpath(spec.fetchSpec, this[_rpcache], this[_stcache])
549
+ spec = npa(`file:${relpath(path, real).replace(/#/g, '%23')}`, path)
550
+ spec.name = name
551
+ } catch {
552
+ // TODO: create synthetic test case to simulate realpath failure
553
+ }
554
+ }
555
+ spec.tree = tree
556
+ this[_resolvedAdd].push(spec)
557
+ }))
558
+
559
+ // now this._resolvedAdd is a list of spec objects with names.
560
+ // find a home for each of them!
561
+ addRmPkgDeps.add({
562
+ pkg: tree.package,
563
+ add: this[_resolvedAdd],
564
+ saveBundle,
565
+ saveType,
566
+ })
610
567
  }
611
568
 
612
569
  // TODO: provide a way to fix bundled deps by exposing metadata about
@@ -686,10 +643,6 @@ Try using the package name instead, e.g:
686
643
  }
687
644
  }
688
645
 
689
- [_isVulnerable] (node) {
690
- return this.auditReport && this.auditReport.isVulnerable(node)
691
- }
692
-
693
646
  [_avoidRange] (name) {
694
647
  if (!this.auditReport) {
695
648
  return null
@@ -781,17 +734,18 @@ This is a one-time fix-up, please be patient...
781
734
  const spec = npa.resolve(name, id, dirname(path))
782
735
  const t = `idealTree:inflate:${location}`
783
736
  this.addTracker(t)
784
- await pacote.manifest(spec, {
785
- ...this.options,
786
- resolved: resolved,
787
- integrity: integrity,
788
- fullMetadata: false,
789
- }).then(mani => {
737
+ try {
738
+ const mani = await pacote.manifest(spec, {
739
+ ...this.options,
740
+ resolved: resolved,
741
+ integrity: integrity,
742
+ fullMetadata: false,
743
+ })
790
744
  node.package = { ...mani, _id: `${mani.name}@${mani.version}` }
791
- }).catch((er) => {
745
+ } catch (er) {
792
746
  const warning = `Could not fetch metadata for ${name}@${id}`
793
747
  log.warn(heading, warning, er)
794
- })
748
+ }
795
749
  this.finishTracker(t)
796
750
  })
797
751
  }
@@ -1233,7 +1187,7 @@ This is a one-time fix-up, please be patient...
1233
1187
  }
1234
1188
 
1235
1189
  // fixing a security vulnerability with this package, problem
1236
- if (this[_isVulnerable](edge.to)) {
1190
+ if (this.auditReport && this.auditReport.isVulnerable(edge.to)) {
1237
1191
  return true
1238
1192
  }
1239
1193
 
@@ -134,7 +134,7 @@ class Arborist extends Base {
134
134
  return wsDepSet
135
135
  }
136
136
 
137
- // returns a set of root dependencies, excluding depdencies that are
137
+ // returns a set of root dependencies, excluding dependencies that are
138
138
  // exclusively workspace dependencies
139
139
  excludeWorkspacesDependencySet (tree) {
140
140
  const rootDepSet = new Set()
@@ -115,6 +115,7 @@ module.exports = cls => class ActualLoader extends cls {
115
115
  root = null,
116
116
  transplantFilter = () => true,
117
117
  ignoreMissing = false,
118
+ forceActual = false,
118
119
  } = options
119
120
  this[_filter] = filter
120
121
  this[_transplantFilter] = transplantFilter
@@ -141,26 +142,30 @@ module.exports = cls => class ActualLoader extends cls {
141
142
 
142
143
  this[_actualTree].assertRootOverrides()
143
144
 
144
- // Note: hidden lockfile will be rejected if it's not the latest thing
145
- // in the folder, or if any of the entries in the hidden lockfile are
146
- // missing.
147
- const meta = await Shrinkwrap.load({
148
- path: this[_actualTree].path,
149
- hiddenLockfile: true,
150
- resolveOptions: this.options,
151
- })
152
- if (meta.loadedFromDisk) {
153
- this[_actualTree].meta = meta
154
- return this[_loadActualVirtually]({ root })
155
- } else {
145
+ // if forceActual is set, don't even try the hidden lockfile
146
+ if (!forceActual) {
147
+ // Note: hidden lockfile will be rejected if it's not the latest thing
148
+ // in the folder, or if any of the entries in the hidden lockfile are
149
+ // missing.
156
150
  const meta = await Shrinkwrap.load({
157
151
  path: this[_actualTree].path,
158
- lockfileVersion: this.options.lockfileVersion,
152
+ hiddenLockfile: true,
159
153
  resolveOptions: this.options,
160
154
  })
161
- this[_actualTree].meta = meta
162
- return this[_loadActualActually]({ root, ignoreMissing })
155
+
156
+ if (meta.loadedFromDisk) {
157
+ this[_actualTree].meta = meta
158
+ return this[_loadActualVirtually]({ root })
159
+ }
163
160
  }
161
+
162
+ const meta = await Shrinkwrap.load({
163
+ path: this[_actualTree].path,
164
+ lockfileVersion: this.options.lockfileVersion,
165
+ resolveOptions: this.options,
166
+ })
167
+ this[_actualTree].meta = meta
168
+ return this[_loadActualActually]({ root, ignoreMissing })
164
169
  }
165
170
 
166
171
  async [_loadActualVirtually] ({ root }) {
@@ -342,6 +347,7 @@ module.exports = cls => class ActualLoader extends cls {
342
347
  // node_modules hierarchy, then load that node as well.
343
348
  return this[_loadFSTree](link.target).then(() => link)
344
349
  } else if (target.then) {
350
+ // eslint-disable-next-line promise/catch-or-return
345
351
  target.then(node => link.target = node)
346
352
  }
347
353
 
@@ -359,6 +359,9 @@ module.exports = cls => class Builder extends cls {
359
359
  pkg,
360
360
  path,
361
361
  event,
362
+ // I do not know why this needs to be on THIS line but refactoring
363
+ // this function would be quite a process
364
+ // eslint-disable-next-line promise/always-return
362
365
  cmd: args && args[args.length - 1],
363
366
  env,
364
367
  code,
@@ -69,7 +69,6 @@ const _symlink = Symbol('symlink')
69
69
  const _warnDeprecated = Symbol('warnDeprecated')
70
70
  const _loadBundlesAndUpdateTrees = Symbol.for('loadBundlesAndUpdateTrees')
71
71
  const _submitQuickAudit = Symbol('submitQuickAudit')
72
- const _awaitQuickAudit = Symbol('awaitQuickAudit')
73
72
  const _unpackNewModules = Symbol.for('unpackNewModules')
74
73
  const _moveContents = Symbol.for('moveContents')
75
74
  const _moveBackRetiredUnchanged = Symbol.for('moveBackRetiredUnchanged')
@@ -156,7 +155,8 @@ module.exports = cls => class Reifier extends cls {
156
155
  await this[_reifyPackages]()
157
156
  await this[_saveIdealTree](options)
158
157
  await this[_copyIdealToActual]()
159
- await this[_awaitQuickAudit]()
158
+ // This is a very bad pattern and I can't wait to stop doing it
159
+ this.auditReport = await this.auditReport
160
160
 
161
161
  this.finishTracker('reify')
162
162
  process.emit('timeEnd', 'reify')
@@ -531,12 +531,12 @@ module.exports = cls => class Reifier extends cls {
531
531
  const targets = [...roots, ...Object.keys(this[_retiredPaths])]
532
532
  const unlinks = targets
533
533
  .map(path => rimraf(path).catch(er => failures.push([path, er])))
534
- return promiseAllRejectLate(unlinks)
535
- .then(() => {
536
- if (failures.length) {
537
- log.warn('cleanup', 'Failed to remove some directories', failures)
538
- }
539
- })
534
+ return promiseAllRejectLate(unlinks).then(() => {
535
+ // eslint-disable-next-line promise/always-return
536
+ if (failures.length) {
537
+ log.warn('cleanup', 'Failed to remove some directories', failures)
538
+ }
539
+ })
540
540
  .then(() => process.emit('timeEnd', 'reify:rollback:createSparse'))
541
541
  .then(() => this[_rollbackRetireShallowNodes](er))
542
542
  }
@@ -592,21 +592,21 @@ module.exports = cls => class Reifier extends cls {
592
592
  this.addTracker('reify', node.name, node.location)
593
593
 
594
594
  const { npmVersion, nodeVersion } = this.options
595
- const p = Promise.resolve()
596
- .then(async () => {
597
- // when we reify an optional node, check the engine and platform
598
- // first. be sure to ignore the --force and --engine-strict flags,
599
- // since we always want to skip any optional packages we can't install.
600
- // these checks throwing will result in a rollback and removal
601
- // of the mismatches
602
- if (node.optional) {
603
- checkEngine(node.package, npmVersion, nodeVersion, false)
604
- checkPlatform(node.package, false)
605
- }
606
- await this[_checkBins](node)
607
- await this[_extractOrLink](node)
608
- await this[_warnDeprecated](node)
609
- })
595
+ const p = Promise.resolve().then(async () => {
596
+ // when we reify an optional node, check the engine and platform
597
+ // first. be sure to ignore the --force and --engine-strict flags,
598
+ // since we always want to skip any optional packages we can't install.
599
+ // these checks throwing will result in a rollback and removal
600
+ // of the mismatches
601
+ // eslint-disable-next-line promise/always-return
602
+ if (node.optional) {
603
+ checkEngine(node.package, npmVersion, nodeVersion, false)
604
+ checkPlatform(node.package, false)
605
+ }
606
+ await this[_checkBins](node)
607
+ await this[_extractOrLink](node)
608
+ await this[_warnDeprecated](node)
609
+ })
610
610
 
611
611
  return this[_handleOptionalFailure](node, p)
612
612
  .then(() => {
@@ -916,9 +916,10 @@ module.exports = cls => class Reifier extends cls {
916
916
  }
917
917
  }
918
918
 
919
- [_submitQuickAudit] () {
919
+ async [_submitQuickAudit] () {
920
920
  if (this.options.audit === false) {
921
- return this.auditReport = null
921
+ this.auditReport = null
922
+ return
922
923
  }
923
924
 
924
925
  // we submit the quick audit at this point in the process, as soon as
@@ -940,16 +941,10 @@ module.exports = cls => class Reifier extends cls {
940
941
  )
941
942
  }
942
943
 
943
- this.auditReport = AuditReport.load(tree, options)
944
- .then(res => {
945
- process.emit('timeEnd', 'reify:audit')
946
- this.auditReport = res
947
- })
948
- }
949
-
950
- // return the promise if we're waiting for it, or the replaced result
951
- [_awaitQuickAudit] () {
952
- return this.auditReport
944
+ this.auditReport = AuditReport.load(tree, options).then(res => {
945
+ process.emit('timeEnd', 'reify:audit')
946
+ return res
947
+ })
953
948
  }
954
949
 
955
950
  // ok! actually unpack stuff into their target locations!
@@ -1126,7 +1121,7 @@ module.exports = cls => class Reifier extends cls {
1126
1121
  // remove the retired folders, and any deleted nodes
1127
1122
  // If this fails, there isn't much we can do but tell the user about it.
1128
1123
  // Thankfully, it's pretty unlikely that it'll fail, since rimraf is a tank.
1129
- [_removeTrash] () {
1124
+ async [_removeTrash] () {
1130
1125
  process.emit('time', 'reify:trash')
1131
1126
  const promises = []
1132
1127
  const failures = []
@@ -1136,12 +1131,11 @@ module.exports = cls => class Reifier extends cls {
1136
1131
  promises.push(rm(path))
1137
1132
  }
1138
1133
 
1139
- return promiseAllRejectLate(promises).then(() => {
1140
- if (failures.length) {
1141
- log.warn('cleanup', 'Failed to remove some directories', failures)
1142
- }
1143
- })
1144
- .then(() => process.emit('timeEnd', 'reify:trash'))
1134
+ await promiseAllRejectLate(promises)
1135
+ if (failures.length) {
1136
+ log.warn('cleanup', 'Failed to remove some directories', failures)
1137
+ }
1138
+ process.emit('timeEnd', 'reify:trash')
1145
1139
  }
1146
1140
 
1147
1141
  // last but not least, we save the ideal tree metadata to the package-lock
@@ -1302,7 +1296,9 @@ module.exports = cls => class Reifier extends cls {
1302
1296
  if (semver.subset(edge.spec, node.version)) {
1303
1297
  return false
1304
1298
  }
1305
- } catch {}
1299
+ } catch {
1300
+ // ignore errors
1301
+ }
1306
1302
  }
1307
1303
  return true
1308
1304
  }
@@ -175,7 +175,9 @@ class AuditReport extends Map {
175
175
  } else {
176
176
  // calculate a metavuln, if necessary
177
177
  const calc = this.calculator.calculate(dep.packageName, advisory)
178
+ // eslint-disable-next-line promise/always-return
178
179
  p.push(calc.then(meta => {
180
+ // eslint-disable-next-line promise/always-return
179
181
  if (meta.testVersion(dep.version, spec)) {
180
182
  advisories.add(meta)
181
183
  }
package/lib/link.js CHANGED
@@ -66,6 +66,7 @@ class Link extends Node {
66
66
  // can set to a promise during an async tree build operation
67
67
  // wait until then to assign it.
68
68
  this[_target] = target
69
+ // eslint-disable-next-line promise/always-return, promise/catch-or-return
69
70
  target.then(node => {
70
71
  this[_target] = null
71
72
  this.target = node
package/lib/node.js CHANGED
@@ -334,6 +334,10 @@ class Node {
334
334
  return `${myname}@${alias}${version}`
335
335
  }
336
336
 
337
+ get overridden () {
338
+ return !!(this.overrides && this.overrides.value && this.overrides.name === this.name)
339
+ }
340
+
337
341
  get package () {
338
342
  return this[_package]
339
343
  }
@@ -560,7 +564,8 @@ class Node {
560
564
  // this allows us to do new Node({...}) and then set the root later.
561
565
  // just make the assignment so we don't lose it, and move on.
562
566
  if (!this.path || !root.realpath || !root.path) {
563
- return this[_root] = root
567
+ this[_root] = root
568
+ return
564
569
  }
565
570
 
566
571
  // temporarily become a root node
@@ -262,6 +262,10 @@ class Results {
262
262
  !internalSelector.has(node))
263
263
  }
264
264
 
265
+ overriddenPseudo () {
266
+ return this.initialItems.filter(node => node.overridden)
267
+ }
268
+
265
269
  pathPseudo () {
266
270
  return this.initialItems.filter(node => {
267
271
  if (!this.currentAstNode.pathValue) {
package/lib/shrinkwrap.js CHANGED
@@ -184,34 +184,32 @@ const assertNoNewer = async (path, data, lockTime, dir = path, seen = null) => {
184
184
  ? Promise.resolve([{ name: 'node_modules', isDirectory: () => true }])
185
185
  : readdir(parent, { withFileTypes: true })
186
186
 
187
- return children.catch(() => [])
188
- .then(ents => Promise.all(ents.map(async ent => {
189
- const child = resolve(parent, ent.name)
190
- if (ent.isDirectory() && !/^\./.test(ent.name)) {
191
- await assertNoNewer(path, data, lockTime, child, seen)
192
- } else if (ent.isSymbolicLink()) {
193
- const target = resolve(parent, await readlink(child))
194
- const tstat = await stat(target).catch(
195
- /* istanbul ignore next - windows */ () => null)
196
- seen.add(relpath(path, child))
197
- /* istanbul ignore next - windows cannot do this */
198
- if (tstat && tstat.isDirectory() && !seen.has(relpath(path, target))) {
199
- await assertNoNewer(path, data, lockTime, target, seen)
200
- }
201
- }
202
- })))
203
- .then(() => {
204
- if (dir !== path) {
205
- return
187
+ const ents = await children.catch(() => [])
188
+ await Promise.all(ents.map(async ent => {
189
+ const child = resolve(parent, ent.name)
190
+ if (ent.isDirectory() && !/^\./.test(ent.name)) {
191
+ await assertNoNewer(path, data, lockTime, child, seen)
192
+ } else if (ent.isSymbolicLink()) {
193
+ const target = resolve(parent, await readlink(child))
194
+ const tstat = await stat(target).catch(
195
+ /* istanbul ignore next - windows */ () => null)
196
+ seen.add(relpath(path, child))
197
+ /* istanbul ignore next - windows cannot do this */
198
+ if (tstat && tstat.isDirectory() && !seen.has(relpath(path, target))) {
199
+ await assertNoNewer(path, data, lockTime, target, seen)
206
200
  }
201
+ }
202
+ }))
203
+ if (dir !== path) {
204
+ return
205
+ }
207
206
 
208
- // assert that all the entries in the lockfile were seen
209
- for (const loc of new Set(Object.keys(data.packages))) {
210
- if (!seen.has(loc)) {
211
- throw 'missing from node_modules: ' + loc
212
- }
213
- }
214
- })
207
+ // assert that all the entries in the lockfile were seen
208
+ for (const loc of new Set(Object.keys(data.packages))) {
209
+ if (!seen.has(loc)) {
210
+ throw 'missing from node_modules: ' + loc
211
+ }
212
+ }
215
213
  }
216
214
 
217
215
  const _awaitingUpdate = Symbol('_awaitingUpdate')
@@ -261,7 +259,9 @@ class Shrinkwrap {
261
259
  s.lockfileVersion = json.lockfileVersion
262
260
  }
263
261
  }
264
- } catch (e) {}
262
+ } catch {
263
+ // ignore errors
264
+ }
265
265
 
266
266
  return s
267
267
  }
@@ -442,7 +442,7 @@ class Shrinkwrap {
442
442
  this.newline = newline !== undefined ? newline : this.newline
443
443
  }
444
444
 
445
- load () {
445
+ async load () {
446
446
  // we don't need to load package-lock.json except for top of tree nodes,
447
447
  // only npm-shrinkwrap.json.
448
448
  return this[_maybeRead]().then(([sw, lock, yarn]) => {
@@ -464,7 +464,9 @@ class Shrinkwrap {
464
464
  // ignore invalid yarn data. we'll likely clobber it later anyway.
465
465
  try {
466
466
  this.yarnLock.parse(yarn)
467
- } catch (_) {}
467
+ } catch {
468
+ // ignore errors
469
+ }
468
470
  }
469
471
 
470
472
  return data ? parseJSON(data) : {}
@@ -515,8 +517,10 @@ class Shrinkwrap {
515
517
  !(lock.lockfileVersion >= 2) && !lock.requires
516
518
 
517
519
  // load old lockfile deps into the packages listing
520
+ // eslint-disable-next-line promise/always-return
518
521
  if (lock.dependencies && !lock.packages) {
519
522
  return rpj(this.path + '/package.json').then(pkg => pkg, er => ({}))
523
+ // eslint-disable-next-line promise/always-return
520
524
  .then(pkg => {
521
525
  this[_loadAll]('', null, this.data)
522
526
  this[_fixDependencies](pkg)
@@ -19,7 +19,9 @@ const setup = fn => {
19
19
  for (const sig of signals) {
20
20
  try {
21
21
  process.removeListener(sig, sigListeners[sig])
22
- } catch (er) {}
22
+ } catch {
23
+ // ignore errors
24
+ }
23
25
  }
24
26
  process.removeListener('beforeExit', onBeforeExit)
25
27
  sigListeners.loaded = false
@@ -62,7 +64,9 @@ const setup = fn => {
62
64
  process.setMaxListeners(length + 1)
63
65
  }
64
66
  process.on(sig, sigListeners[sig])
65
- } catch (er) {}
67
+ } catch {
68
+ // ignore errors
69
+ }
66
70
  }
67
71
  sigListeners.loaded = true
68
72
 
@@ -21,10 +21,12 @@ const specFromLock = (name, lock, where) => {
21
21
  if (lock.resolved) {
22
22
  return npa.resolve(name, lock.resolved, where)
23
23
  }
24
- } catch (_) { }
24
+ } catch {
25
+ // ignore errors
26
+ }
25
27
  try {
26
28
  return npa.resolve(name, lock.version, where)
27
- } catch (_) {
29
+ } catch {
28
30
  return {}
29
31
  }
30
32
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@npmcli/arborist",
3
- "version": "5.4.0",
3
+ "version": "5.6.1",
4
4
  "description": "Manage node_modules trees",
5
5
  "dependencies": {
6
6
  "@isaacs/string-locale-compare": "^1.1.0",
@@ -11,20 +11,20 @@
11
11
  "@npmcli/name-from-folder": "^1.0.1",
12
12
  "@npmcli/node-gyp": "^2.0.0",
13
13
  "@npmcli/package-json": "^2.0.0",
14
- "@npmcli/query": "^1.1.1",
14
+ "@npmcli/query": "^1.2.0",
15
15
  "@npmcli/run-script": "^4.1.3",
16
- "bin-links": "^3.0.0",
17
- "cacache": "^16.0.6",
16
+ "bin-links": "^3.0.3",
17
+ "cacache": "^16.1.3",
18
18
  "common-ancestor-path": "^1.0.1",
19
19
  "json-parse-even-better-errors": "^2.3.1",
20
20
  "json-stringify-nice": "^1.1.4",
21
21
  "minimatch": "^5.1.0",
22
22
  "mkdirp": "^1.0.4",
23
23
  "mkdirp-infer-owner": "^2.0.0",
24
- "nopt": "^5.0.0",
24
+ "nopt": "^6.0.0",
25
25
  "npm-install-checks": "^5.0.0",
26
26
  "npm-package-arg": "^9.0.0",
27
- "npm-pick-manifest": "^7.0.0",
27
+ "npm-pick-manifest": "^7.0.2",
28
28
  "npm-registry-fetch": "^13.0.0",
29
29
  "npmlog": "^6.0.2",
30
30
  "pacote": "^13.6.1",
@@ -41,8 +41,8 @@
41
41
  "walk-up-path": "^1.0.0"
42
42
  },
43
43
  "devDependencies": {
44
- "@npmcli/eslint-config": "^3.0.1",
45
- "@npmcli/template-oss": "3.5.0",
44
+ "@npmcli/eslint-config": "^3.1.0",
45
+ "@npmcli/template-oss": "3.8.0",
46
46
  "benchmark": "^2.1.4",
47
47
  "chalk": "^4.1.0",
48
48
  "minify-registry-metadata": "^2.1.0",
@@ -103,6 +103,6 @@
103
103
  },
104
104
  "templateOSS": {
105
105
  "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
106
- "version": "3.5.0"
106
+ "version": "3.8.0"
107
107
  }
108
108
  }