@npmcli/arborist 7.4.1 → 7.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  const fs = require('fs')
4
4
  const path = require('path')
5
+ const { time } = require('proc-log')
5
6
 
6
7
  const { bin, arb: options } = require('./lib/options')
7
8
  const version = require('../package.json').version
@@ -72,11 +73,11 @@ for (const file of commandFiles) {
72
73
 
73
74
  log.info(name, options)
74
75
 
75
- process.emit('time', totalTime)
76
- process.emit('time', scriptTime)
76
+ const timeEnd = time.start(totalTime)
77
+ const scriptEnd = time.start(scriptTime)
77
78
 
78
79
  return command(options, (result) => {
79
- process.emit('timeEnd', scriptTime)
80
+ scriptEnd()
80
81
  return {
81
82
  result,
82
83
  timing: {
@@ -95,7 +96,7 @@ for (const file of commandFiles) {
95
96
  return err
96
97
  })
97
98
  .then((r) => {
98
- process.emit('timeEnd', totalTime)
99
+ timeEnd()
99
100
  if (bin.loglevel !== 'silent') {
100
101
  console[process.exitCode ? 'error' : 'log'](r)
101
102
  }
@@ -1,4 +1,4 @@
1
- const log = require('proc-log')
1
+ const { log } = require('proc-log')
2
2
  const fs = require('fs')
3
3
  const { dirname } = require('path')
4
4
  const os = require('os')
package/bin/lib/timers.js CHANGED
@@ -4,22 +4,22 @@ const log = require('./logging.js')
4
4
  const timers = new Map()
5
5
  const finished = new Map()
6
6
 
7
- process.on('time', name => {
8
- if (timers.has(name)) {
9
- throw new Error('conflicting timer! ' + name)
10
- }
11
- timers.set(name, process.hrtime.bigint())
12
- })
13
-
14
- process.on('timeEnd', name => {
15
- if (!timers.has(name)) {
16
- throw new Error('timer not started! ' + name)
17
- }
18
- const elapsed = Number(process.hrtime.bigint() - timers.get(name))
19
- timers.delete(name)
20
- finished.set(name, elapsed)
21
- if (options.timing) {
22
- log.info('timeEnd', `${name} ${elapsed / 1e9}s`, log.meta({ force: options.timing === 'always' }))
7
+ process.on('time', (level, name) => {
8
+ if (level === 'start') {
9
+ if (timers.has(name)) {
10
+ throw new Error('conflicting timer! ' + name)
11
+ }
12
+ timers.set(name, process.hrtime.bigint())
13
+ } else if (level === 'end') {
14
+ if (!timers.has(name)) {
15
+ throw new Error('timer not started! ' + name)
16
+ }
17
+ const elapsed = Number(process.hrtime.bigint() - timers.get(name))
18
+ timers.delete(name)
19
+ finished.set(name, elapsed)
20
+ if (options.timing) {
21
+ log.info('timeEnd', `${name} ${elapsed / 1e9}s`, log.meta({ force: options.timing === 'always' }))
22
+ }
23
23
  }
24
24
  })
25
25
 
@@ -1,6 +1,6 @@
1
1
  // add and remove dependency specs to/from pkg manifest
2
2
 
3
- const log = require('proc-log')
3
+ 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 }) => {
@@ -11,8 +11,8 @@ const treeCheck = require('../tree-check.js')
11
11
  const { readdirScoped } = require('@npmcli/fs')
12
12
  const { lstat, readlink } = require('fs/promises')
13
13
  const { depth } = require('treeverse')
14
- const log = require('proc-log')
15
- const { cleanUrl } = require('npm-registry-fetch')
14
+ const { log, time } = require('proc-log')
15
+ const { redact } = require('@npmcli/redact')
16
16
 
17
17
  const {
18
18
  OK,
@@ -179,7 +179,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
179
179
  options.rm = null
180
180
  }
181
181
 
182
- process.emit('time', 'idealTree')
182
+ const timeEnd = time.start('idealTree')
183
183
 
184
184
  if (!options.add && !options.rm && !options.update && this.options.global) {
185
185
  throw new Error('global requires add, rm, or update option')
@@ -205,7 +205,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
205
205
  await this.#pruneFailedOptional()
206
206
  await this.#checkEngineAndPlatform()
207
207
  } finally {
208
- process.emit('timeEnd', 'idealTree')
208
+ timeEnd()
209
209
  this.finishTracker('idealTree')
210
210
  }
211
211
 
@@ -278,7 +278,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
278
278
  // load the initial tree, either the virtualTree from a shrinkwrap,
279
279
  // or just the root node from a package.json
280
280
  async #initTree () {
281
- process.emit('time', 'idealTree:init')
281
+ const timeEnd = time.start('idealTree:init')
282
282
  let root
283
283
  if (this.options.global) {
284
284
  root = await this.#globalRootNode()
@@ -356,7 +356,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
356
356
  // if you want another one, load another copy.
357
357
  this.idealTree = tree
358
358
  this.virtualTree = null
359
- process.emit('timeEnd', 'idealTree:init')
359
+ timeEnd()
360
360
  return tree
361
361
  })
362
362
  }
@@ -420,7 +420,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
420
420
  // process the add/rm requests by modifying the root node, and the
421
421
  // update.names request by queueing nodes dependent on those named.
422
422
  async #applyUserRequests (options) {
423
- process.emit('time', 'idealTree:userRequests')
423
+ const timeEnd = time.start('idealTree:userRequests')
424
424
  const tree = this.idealTree.target
425
425
 
426
426
  if (!this.options.workspaces.length) {
@@ -436,7 +436,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
436
436
  await Promise.all(appliedRequests)
437
437
  }
438
438
 
439
- process.emit('timeEnd', 'idealTree:userRequests')
439
+ timeEnd()
440
440
  }
441
441
 
442
442
  async #applyUserRequestsToNode (tree, options) {
@@ -691,7 +691,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
691
691
  // if the lockfile is from node v5 or earlier, then we'll have to reload
692
692
  // all the manifests of everything we encounter. this is costly, but at
693
693
  // least it's just a one-time hit.
694
- process.emit('time', 'idealTree:inflate')
694
+ const timeEnd = time.start('idealTree:inflate')
695
695
 
696
696
  // don't warn if we're not gonna actually write it back anyway.
697
697
  const heading = ancient ? 'ancient lockfile' : 'old lockfile'
@@ -758,14 +758,14 @@ This is a one-time fix-up, please be patient...
758
758
  meta.originalLockfileVersion = defaultLockfileVersion
759
759
  }
760
760
  this.finishTracker('idealTree:inflate')
761
- process.emit('timeEnd', 'idealTree:inflate')
761
+ timeEnd()
762
762
  }
763
763
 
764
764
  // at this point we have a virtual tree with the actual root node's
765
765
  // package deps, which may be partly or entirely incomplete, invalid
766
766
  // or extraneous.
767
767
  #buildDeps () {
768
- process.emit('time', 'idealTree:buildDeps')
768
+ const timeEnd = time.start('idealTree:buildDeps')
769
769
  const tree = this.idealTree.target
770
770
  tree.assertRootOverrides()
771
771
  this.#depsQueue.push(tree)
@@ -773,15 +773,14 @@ This is a one-time fix-up, please be patient...
773
773
  // in the override list
774
774
  log.silly('idealTree', 'buildDeps')
775
775
  this.addTracker('idealTree', tree.name, '')
776
- return this.#buildDepStep()
777
- .then(() => process.emit('timeEnd', 'idealTree:buildDeps'))
776
+ return this.#buildDepStep().then(timeEnd)
778
777
  }
779
778
 
780
779
  async #buildDepStep () {
781
780
  // removes tracker of previous dependency in the queue
782
781
  if (this.#currentDep) {
783
782
  const { location, name } = this.#currentDep
784
- process.emit('timeEnd', `idealTree:${location || '#root'}`)
783
+ time.end(`idealTree:${location || '#root'}`)
785
784
  this.finishTracker('idealTree', name, location)
786
785
  this.#currentDep = null
787
786
  }
@@ -807,7 +806,7 @@ This is a one-time fix-up, please be patient...
807
806
 
808
807
  this.#depsSeen.add(node)
809
808
  this.#currentDep = node
810
- process.emit('time', `idealTree:${node.location || '#root'}`)
809
+ time.start(`idealTree:${node.location || '#root'}`)
811
810
 
812
811
  // if we're loading a _complete_ ideal tree, for a --package-lock-only
813
812
  // installation for example, we have to crack open the tarball and
@@ -1213,7 +1212,7 @@ This is a one-time fix-up, please be patient...
1213
1212
  if (this.#manifests.has(spec.raw)) {
1214
1213
  return this.#manifests.get(spec.raw)
1215
1214
  } else {
1216
- const cleanRawSpec = cleanUrl(spec.rawSpec)
1215
+ const cleanRawSpec = redact(spec.rawSpec)
1217
1216
  log.silly('fetch manifest', spec.raw.replace(spec.rawSpec, cleanRawSpec))
1218
1217
  const o = {
1219
1218
  ...options,
@@ -1449,7 +1448,7 @@ This is a one-time fix-up, please be patient...
1449
1448
  }
1450
1449
 
1451
1450
  #fixDepFlags () {
1452
- process.emit('time', 'idealTree:fixDepFlags')
1451
+ const timeEnd = time.start('idealTree:fixDepFlags')
1453
1452
  const metaFromDisk = this.idealTree.meta.loadedFromDisk
1454
1453
  const flagsSuspect = this[_flagsSuspect]
1455
1454
  const mutateTree = this.#mutateTree
@@ -1496,7 +1495,7 @@ This is a one-time fix-up, please be patient...
1496
1495
  }
1497
1496
  }
1498
1497
 
1499
- process.emit('timeEnd', 'idealTree:fixDepFlags')
1498
+ timeEnd()
1500
1499
  }
1501
1500
 
1502
1501
  #idealTreePrune () {
@@ -30,7 +30,7 @@ const { resolve } = require('path')
30
30
  const { homedir } = require('os')
31
31
  const { depth } = require('treeverse')
32
32
  const mapWorkspaces = require('@npmcli/map-workspaces')
33
- const log = require('proc-log')
33
+ const { log, time } = require('proc-log')
34
34
 
35
35
  const { saveTypeMap } = require('../add-rm-pkg-deps.js')
36
36
  const AuditReport = require('../audit-report.js')
@@ -66,7 +66,7 @@ const lockfileVersion = lfv => {
66
66
 
67
67
  class Arborist extends Base {
68
68
  constructor (options = {}) {
69
- process.emit('time', 'arborist:ctor')
69
+ const timeEnd = time.start('arborist:ctor')
70
70
  super(options)
71
71
  this.options = {
72
72
  nodeVersion: process.version,
@@ -97,7 +97,7 @@ class Arborist extends Base {
97
97
  }
98
98
  this.cache = resolve(this.options.cache)
99
99
  this.path = resolve(this.options.path)
100
- process.emit('timeEnd', 'arborist:ctor')
100
+ timeEnd()
101
101
  }
102
102
 
103
103
  // TODO: We should change these to static functions instead
@@ -223,7 +223,7 @@ class Arborist extends Base {
223
223
  // XXX: deprecate separate method options objects.
224
224
  options = { ...this.options, ...options }
225
225
 
226
- process.emit('time', 'audit')
226
+ const timeEnd = time.start('audit')
227
227
  let tree
228
228
  if (options.packageLock === false) {
229
229
  // build ideal tree
@@ -246,7 +246,7 @@ class Arborist extends Base {
246
246
  }
247
247
  this.auditReport = await AuditReport.load(tree, options)
248
248
  const ret = options.fix ? this.reify(options) : this.auditReport
249
- process.emit('timeEnd', 'audit')
249
+ timeEnd()
250
250
  this.finishTracker('audit')
251
251
  return ret
252
252
  }
@@ -1,7 +1,7 @@
1
1
  const _makeIdealGraph = Symbol('makeIdealGraph')
2
2
  const _createIsolatedTree = Symbol.for('createIsolatedTree')
3
3
  const _createBundledTree = Symbol('createBundledTree')
4
- const fs = require('fs')
4
+ const { mkdirSync } = require('fs')
5
5
  const pacote = require('pacote')
6
6
  const { join } = require('path')
7
7
  const { depth } = require('treeverse')
@@ -108,7 +108,7 @@ module.exports = cls => class IsolatedReifier extends cls {
108
108
  '.store',
109
109
  `${node.name}@${node.version}`
110
110
  )
111
- fs.mkdirSync(dir, { recursive: true })
111
+ mkdirSync(dir, { recursive: true })
112
112
  // TODO this approach feels wrong
113
113
  // and shouldn't be necessary for shrinkwraps
114
114
  await pacote.extract(node.resolved, dir, {
@@ -9,11 +9,8 @@ const binLinks = require('bin-links')
9
9
  const runScript = require('@npmcli/run-script')
10
10
  const { callLimit: promiseCallLimit } = require('promise-call-limit')
11
11
  const { resolve } = require('path')
12
- const {
13
- isNodeGypPackage,
14
- defaultGypInstallScript,
15
- } = require('@npmcli/node-gyp')
16
- const log = require('proc-log')
12
+ const { isNodeGypPackage, defaultGypInstallScript } = require('@npmcli/node-gyp')
13
+ const { log, time } = require('proc-log')
17
14
 
18
15
  const boolEnv = b => b ? '1' : ''
19
16
  const sortNodes = (a, b) =>
@@ -54,7 +51,7 @@ module.exports = cls => class Builder extends cls {
54
51
 
55
52
  // separates links nodes so that it can run
56
53
  // prepare scripts and link bins in the expected order
57
- process.emit('time', 'build')
54
+ const timeEnd = time.start('build')
58
55
 
59
56
  const {
60
57
  depNodes,
@@ -70,7 +67,7 @@ module.exports = cls => class Builder extends cls {
70
67
  await this.#build(linkNodes, { type: 'links' })
71
68
  }
72
69
 
73
- process.emit('timeEnd', 'build')
70
+ timeEnd()
74
71
  }
75
72
 
76
73
  // if we don't have a set of nodes, then just rebuild
@@ -147,7 +144,7 @@ module.exports = cls => class Builder extends cls {
147
144
  }
148
145
 
149
146
  async #build (nodes, { type = 'deps' }) {
150
- process.emit('time', `build:${type}`)
147
+ const timeEnd = time.start(`build:${type}`)
151
148
 
152
149
  await this.#buildQueues(nodes)
153
150
 
@@ -168,11 +165,11 @@ module.exports = cls => class Builder extends cls {
168
165
  await this.#runScripts('postinstall')
169
166
  }
170
167
 
171
- process.emit('timeEnd', `build:${type}`)
168
+ timeEnd()
172
169
  }
173
170
 
174
171
  async #buildQueues (nodes) {
175
- process.emit('time', 'build:queue')
172
+ const timeEnd = time.start('build:queue')
176
173
  const set = new Set()
177
174
 
178
175
  const promises = []
@@ -210,7 +207,7 @@ module.exports = cls => class Builder extends cls {
210
207
  }
211
208
  }
212
209
  }
213
- process.emit('timeEnd', 'build:queue')
210
+ timeEnd()
214
211
  }
215
212
 
216
213
  async [_checkBins] (node) {
@@ -286,7 +283,7 @@ module.exports = cls => class Builder extends cls {
286
283
  return
287
284
  }
288
285
 
289
- process.emit('time', `build:run:${event}`)
286
+ const timeEnd = time.start(`build:run:${event}`)
290
287
  const stdio = this.options.foregroundScripts ? 'inherit' : 'pipe'
291
288
  const limit = this.options.foregroundScripts ? 1 : undefined
292
289
  await promiseCallLimit(queue.map(node => async () => {
@@ -309,8 +306,7 @@ module.exports = cls => class Builder extends cls {
309
306
  return
310
307
  }
311
308
 
312
- const timer = `build:run:${event}:${location}`
313
- process.emit('time', timer)
309
+ const timeEndLocation = time.start(`build:run:${event}:${location}`)
314
310
  log.info('run', pkg._id, event, location, pkg.scripts[event])
315
311
  const env = {
316
312
  npm_package_resolved: resolved,
@@ -356,9 +352,9 @@ module.exports = cls => class Builder extends cls {
356
352
  ? this[_handleOptionalFailure](node, p)
357
353
  : p)
358
354
 
359
- process.emit('timeEnd', timer)
355
+ timeEndLocation()
360
356
  }), { limit })
361
- process.emit('timeEnd', `build:run:${event}`)
357
+ timeEnd()
362
358
  }
363
359
 
364
360
  async #linkAllBins () {
@@ -367,7 +363,7 @@ module.exports = cls => class Builder extends cls {
367
363
  return
368
364
  }
369
365
 
370
- process.emit('time', 'build:link')
366
+ const timeEnd = time.start('build:link')
371
367
  const promises = []
372
368
  // sort the queue by node path, so that the module-local collision
373
369
  // detector in bin-links will always resolve the same way.
@@ -377,7 +373,7 @@ module.exports = cls => class Builder extends cls {
377
373
  }
378
374
 
379
375
  await promiseAllRejectLate(promises)
380
- process.emit('timeEnd', 'build:link')
376
+ timeEnd()
381
377
  }
382
378
 
383
379
  async #createBinLinks (node) {
@@ -385,7 +381,7 @@ module.exports = cls => class Builder extends cls {
385
381
  return
386
382
  }
387
383
 
388
- process.emit('time', `build:link:${node.location}`)
384
+ const timeEnd = time.start(`build:link:${node.location}`)
389
385
 
390
386
  const p = binLinks({
391
387
  pkg: node.package,
@@ -399,6 +395,6 @@ module.exports = cls => class Builder extends cls {
399
395
  ? this[_handleOptionalFailure](node, p)
400
396
  : p)
401
397
 
402
- process.emit('timeEnd', `build:link:${node.location}`)
398
+ timeEnd()
403
399
  }
404
400
  }
@@ -7,7 +7,7 @@ const npa = require('npm-package-arg')
7
7
  const semver = require('semver')
8
8
  const debug = require('../debug.js')
9
9
  const { walkUp } = require('walk-up-path')
10
- const log = require('proc-log')
10
+ const { log, time } = require('proc-log')
11
11
  const hgi = require('hosted-git-info')
12
12
  const rpj = require('read-package-json-fast')
13
13
 
@@ -149,7 +149,7 @@ module.exports = cls => class Reifier extends cls {
149
149
 
150
150
  // start tracker block
151
151
  this.addTracker('reify')
152
- process.emit('time', 'reify')
152
+ const timeEnd = time.start('reify')
153
153
  await this[_validatePath]()
154
154
  await this[_loadTrees](options)
155
155
 
@@ -174,7 +174,7 @@ module.exports = cls => class Reifier extends cls {
174
174
  this.auditReport = await this.auditReport
175
175
 
176
176
  this.finishTracker('reify')
177
- process.emit('timeEnd', 'reify')
177
+ timeEnd()
178
178
  return treeCheck(this.actualTree)
179
179
  }
180
180
 
@@ -269,7 +269,7 @@ module.exports = cls => class Reifier extends cls {
269
269
  // when doing a local install, we load everything and figure it all out.
270
270
  // when doing a global install, we *only* care about the explicit requests.
271
271
  [_loadTrees] (options) {
272
- process.emit('time', 'reify:loadTrees')
272
+ const timeEnd = time.start('reify:loadTrees')
273
273
  const bitOpt = {
274
274
  ...options,
275
275
  complete: this[_packageLockOnly] || this[_dryRun],
@@ -277,8 +277,7 @@ module.exports = cls => class Reifier extends cls {
277
277
 
278
278
  // if we're only writing a package lock, then it doesn't matter what's here
279
279
  if (this[_packageLockOnly]) {
280
- return this.buildIdealTree(bitOpt)
281
- .then(() => process.emit('timeEnd', 'reify:loadTrees'))
280
+ return this.buildIdealTree(bitOpt).then(timeEnd)
282
281
  }
283
282
 
284
283
  const actualOpt = this.options.global ? {
@@ -312,7 +311,7 @@ module.exports = cls => class Reifier extends cls {
312
311
  return Promise.all([
313
312
  this.loadActual(actualOpt),
314
313
  this.buildIdealTree(bitOpt),
315
- ]).then(() => process.emit('timeEnd', 'reify:loadTrees'))
314
+ ]).then(timeEnd)
316
315
  }
317
316
 
318
317
  // the global install space tends to have a lot of stuff in it. don't
@@ -322,7 +321,7 @@ module.exports = cls => class Reifier extends cls {
322
321
  // explicitRequests which is set during buildIdealTree
323
322
  return this.buildIdealTree(bitOpt)
324
323
  .then(() => this.loadActual(actualOpt))
325
- .then(() => process.emit('timeEnd', 'reify:loadTrees'))
324
+ .then(timeEnd)
326
325
  }
327
326
 
328
327
  [_diffTrees] () {
@@ -330,7 +329,7 @@ module.exports = cls => class Reifier extends cls {
330
329
  return
331
330
  }
332
331
 
333
- process.emit('time', 'reify:diffTrees')
332
+ const timeEnd = time.start('reify:diffTrees')
334
333
  // XXX if we have an existing diff already, there should be a way
335
334
  // to just invalidate the parts that changed, but avoid walking the
336
335
  // whole tree again.
@@ -397,7 +396,7 @@ module.exports = cls => class Reifier extends cls {
397
396
  // because if we remove node_modules/FOO on case-insensitive systems,
398
397
  // it will remove the dep that we *want* at node_modules/foo.
399
398
 
400
- process.emit('timeEnd', 'reify:diffTrees')
399
+ timeEnd()
401
400
  }
402
401
 
403
402
  // add the node and all its bins to the list of things to be
@@ -422,7 +421,7 @@ module.exports = cls => class Reifier extends cls {
422
421
  // move aside the shallowest nodes in the tree that have to be
423
422
  // changed or removed, so that we can rollback if necessary.
424
423
  [_retireShallowNodes] () {
425
- process.emit('time', 'reify:retireShallow')
424
+ const timeEnd = time.start('reify:retireShallow')
426
425
  const moves = this[_retiredPaths] = {}
427
426
  for (const diff of this.diff.children) {
428
427
  if (diff.action === 'CHANGE' || diff.action === 'REMOVE') {
@@ -433,8 +432,7 @@ module.exports = cls => class Reifier extends cls {
433
432
  log.silly('reify', 'moves', moves)
434
433
  const movePromises = Object.entries(moves)
435
434
  .map(([from, to]) => this[_renamePath](from, to))
436
- return promiseAllRejectLate(movePromises)
437
- .then(() => process.emit('timeEnd', 'reify:retireShallow'))
435
+ return promiseAllRejectLate(movePromises).then(timeEnd)
438
436
  }
439
437
 
440
438
  [_renamePath] (from, to, didMkdirp = false) {
@@ -456,14 +454,14 @@ module.exports = cls => class Reifier extends cls {
456
454
  }
457
455
 
458
456
  [_rollbackRetireShallowNodes] (er) {
459
- process.emit('time', 'reify:rollback:retireShallow')
457
+ const timeEnd = time.start('reify:rollback:retireShallow')
460
458
  const moves = this[_retiredPaths]
461
459
  const movePromises = Object.entries(moves)
462
460
  .map(([from, to]) => this[_renamePath](to, from))
463
461
  return promiseAllRejectLate(movePromises)
464
462
  // ignore subsequent rollback errors
465
463
  .catch(er => {})
466
- .then(() => process.emit('timeEnd', 'reify:rollback:retireShallow'))
464
+ .then(timeEnd)
467
465
  .then(() => {
468
466
  throw er
469
467
  })
@@ -476,7 +474,7 @@ module.exports = cls => class Reifier extends cls {
476
474
  return
477
475
  }
478
476
 
479
- process.emit('time', 'reify:trashOmits')
477
+ const timeEnd = time.start('reify:trashOmits')
480
478
 
481
479
  for (const node of this.idealTree.inventory.values()) {
482
480
  const { top } = node
@@ -503,11 +501,11 @@ module.exports = cls => class Reifier extends cls {
503
501
  }
504
502
  }
505
503
 
506
- process.emit('timeEnd', 'reify:trashOmits')
504
+ timeEnd()
507
505
  }
508
506
 
509
507
  [_createSparseTree] () {
510
- process.emit('time', 'reify:createSparse')
508
+ const timeEnd = time.start('reify:createSparse')
511
509
  // if we call this fn again, we look for the previous list
512
510
  // so that we can avoid making the same directory multiple times
513
511
  const leaves = this.diff.leaves
@@ -550,12 +548,11 @@ module.exports = cls => class Reifier extends cls {
550
548
  if (made) {
551
549
  this[_sparseTreeRoots].add(made)
552
550
  }
553
- }))
554
- .then(() => process.emit('timeEnd', 'reify:createSparse'))
551
+ })).then(timeEnd)
555
552
  }
556
553
 
557
554
  [_rollbackCreateSparseTree] (er) {
558
- process.emit('time', 'reify:rollback:createSparse')
555
+ const timeEnd = time.start('reify:rollback:createSparse')
559
556
  // cut the roots of the sparse tree that were created, not the leaves
560
557
  const roots = this[_sparseTreeRoots]
561
558
  // also delete the moves that we retired, so that we can move them back
@@ -569,7 +566,7 @@ module.exports = cls => class Reifier extends cls {
569
566
  log.warn('cleanup', 'Failed to remove some directories', failures)
570
567
  }
571
568
  })
572
- .then(() => process.emit('timeEnd', 'reify:rollback:createSparse'))
569
+ .then(timeEnd)
573
570
  .then(() => this[_rollbackRetireShallowNodes](er))
574
571
  }
575
572
 
@@ -587,7 +584,7 @@ module.exports = cls => class Reifier extends cls {
587
584
  return
588
585
  }
589
586
 
590
- process.emit('time', 'reify:loadShrinkwraps')
587
+ const timeEnd = time.start('reify:loadShrinkwraps')
591
588
 
592
589
  const Arborist = this.constructor
593
590
  return promiseAllRejectLate(shrinkwraps.map(diff => {
@@ -604,7 +601,7 @@ module.exports = cls => class Reifier extends cls {
604
601
  .then(() => this[_createSparseTree]())
605
602
  .then(() => this[_addOmitsToTrashList]())
606
603
  .then(() => this[_loadShrinkwrapsAndUpdateTrees]())
607
- .then(() => process.emit('timeEnd', 'reify:loadShrinkwraps'))
604
+ .then(timeEnd)
608
605
  }
609
606
 
610
607
  // create a symlink for Links, extract for Nodes
@@ -619,8 +616,7 @@ module.exports = cls => class Reifier extends cls {
619
616
  return node
620
617
  }
621
618
 
622
- const timer = `reifyNode:${node.location}`
623
- process.emit('time', timer)
619
+ const timeEnd = time.start(`reifyNode:${node.location}`)
624
620
  this.addTracker('reify', node.name, node.location)
625
621
 
626
622
  const { npmVersion, nodeVersion, cpu, os, libc } = this.options
@@ -643,7 +639,7 @@ module.exports = cls => class Reifier extends cls {
643
639
  return this[_handleOptionalFailure](node, p)
644
640
  .then(() => {
645
641
  this.finishTracker('reify', node.name, node.location)
646
- process.emit('timeEnd', timer)
642
+ timeEnd()
647
643
  return node
648
644
  })
649
645
  }
@@ -786,7 +782,7 @@ module.exports = cls => class Reifier extends cls {
786
782
  depth = 0, bundlesByDepth = this[_getBundlesByDepth]()
787
783
  ) {
788
784
  if (depth === 0) {
789
- process.emit('time', 'reify:loadBundles')
785
+ time.start('reify:loadBundles')
790
786
  }
791
787
 
792
788
  const maxBundleDepth = bundlesByDepth.get('maxBundleDepth')
@@ -796,7 +792,7 @@ module.exports = cls => class Reifier extends cls {
796
792
  this[_pruneBundledMetadeps](bundlesByDepth)
797
793
  this[_diffTrees]()
798
794
  }
799
- process.emit('timeEnd', 'reify:loadBundles')
795
+ time.end('reify:loadBundles')
800
796
  return
801
797
  }
802
798
 
@@ -981,7 +977,7 @@ module.exports = cls => class Reifier extends cls {
981
977
  // before finishing the reify() and returning the tree. Thus, we do
982
978
  // NOT return the promise, as the intent is for this to run in parallel
983
979
  // with the reification, and be resolved at a later time.
984
- process.emit('time', 'reify:audit')
980
+ const timeEnd = time.start('reify:audit')
985
981
  const options = { ...this.options }
986
982
  const tree = this.idealTree
987
983
 
@@ -995,7 +991,7 @@ module.exports = cls => class Reifier extends cls {
995
991
  }
996
992
 
997
993
  this.auditReport = AuditReport.load(tree, options).then(res => {
998
- process.emit('timeEnd', 'reify:audit')
994
+ timeEnd()
999
995
  return res
1000
996
  })
1001
997
  }
@@ -1005,7 +1001,7 @@ module.exports = cls => class Reifier extends cls {
1005
1001
  // kicking off each unpack job. If any fail, we rm the sparse
1006
1002
  // tree entirely and try to put everything back where it was.
1007
1003
  [_unpackNewModules] () {
1008
- process.emit('time', 'reify:unpack')
1004
+ const timeEnd = time.start('reify:unpack')
1009
1005
  const unpacks = []
1010
1006
  dfwalk({
1011
1007
  tree: this.diff,
@@ -1038,8 +1034,7 @@ module.exports = cls => class Reifier extends cls {
1038
1034
  },
1039
1035
  getChildren: diff => diff.children,
1040
1036
  })
1041
- return promiseAllRejectLate(unpacks)
1042
- .then(() => process.emit('timeEnd', 'reify:unpack'))
1037
+ return promiseAllRejectLate(unpacks).then(timeEnd)
1043
1038
  }
1044
1039
 
1045
1040
  // This is the part where we move back the unchanging nodes that were
@@ -1054,7 +1049,7 @@ module.exports = cls => class Reifier extends cls {
1054
1049
  // This is sort of an inverse diff tree, of all the nodes where
1055
1050
  // the actualTree and idealTree _don't_ differ, starting from the
1056
1051
  // shallowest nodes that we moved aside in the first place.
1057
- process.emit('time', 'reify:unretire')
1052
+ const timeEnd = time.start('reify:unretire')
1058
1053
  const moves = this[_retiredPaths]
1059
1054
  this[_retiredUnchanged] = {}
1060
1055
  return promiseAllRejectLate(this.diff.children.map(diff => {
@@ -1102,8 +1097,7 @@ module.exports = cls => class Reifier extends cls {
1102
1097
  const dir = bd && bd.length ? node.path + '/node_modules' : node.path
1103
1098
  return mkdir(dir, { recursive: true }).then(() => this[_moveContents](node, fromPath))
1104
1099
  }))
1105
- }))
1106
- .then(() => process.emit('timeEnd', 'reify:unretire'))
1100
+ })).then(timeEnd)
1107
1101
  }
1108
1102
 
1109
1103
  // move the contents from the fromPath to the node.path
@@ -1135,7 +1129,7 @@ module.exports = cls => class Reifier extends cls {
1135
1129
  }
1136
1130
 
1137
1131
  [_build] () {
1138
- process.emit('time', 'reify:build')
1132
+ const timeEnd = time.start('reify:build')
1139
1133
 
1140
1134
  // for all the things being installed, run their appropriate scripts
1141
1135
  // run in tip->root order, so as to be more likely to build a node's
@@ -1167,8 +1161,7 @@ module.exports = cls => class Reifier extends cls {
1167
1161
  }
1168
1162
  }
1169
1163
 
1170
- return this.rebuild({ nodes, handleOptionalFailure: true })
1171
- .then(() => process.emit('timeEnd', 'reify:build'))
1164
+ return this.rebuild({ nodes, handleOptionalFailure: true }).then(timeEnd)
1172
1165
  }
1173
1166
 
1174
1167
  // the tree is pretty much built now, so it's cleanup time.
@@ -1176,7 +1169,7 @@ module.exports = cls => class Reifier extends cls {
1176
1169
  // If this fails, there isn't much we can do but tell the user about it.
1177
1170
  // Thankfully, it's pretty unlikely that it'll fail, since rm is a node builtin.
1178
1171
  async [_removeTrash] () {
1179
- process.emit('time', 'reify:trash')
1172
+ const timeEnd = time.start('reify:trash')
1180
1173
  const promises = []
1181
1174
  const failures = []
1182
1175
  const _rm = path => rm(path, { recursive: true, force: true }).catch(er => failures.push([path, er]))
@@ -1189,7 +1182,8 @@ module.exports = cls => class Reifier extends cls {
1189
1182
  if (failures.length) {
1190
1183
  log.warn('cleanup', 'Failed to remove some directories', failures)
1191
1184
  }
1192
- process.emit('timeEnd', 'reify:trash')
1185
+
1186
+ timeEnd()
1193
1187
  }
1194
1188
 
1195
1189
  // last but not least, we save the ideal tree metadata to the package-lock
@@ -1222,7 +1216,7 @@ module.exports = cls => class Reifier extends cls {
1222
1216
  return false
1223
1217
  }
1224
1218
 
1225
- process.emit('time', 'reify:save')
1219
+ const timeEnd = time.start('reify:save')
1226
1220
 
1227
1221
  const updatedTrees = new Set()
1228
1222
  const updateNodes = nodes => {
@@ -1460,7 +1454,7 @@ module.exports = cls => class Reifier extends cls {
1460
1454
  })
1461
1455
  }
1462
1456
 
1463
- process.emit('timeEnd', 'reify:save')
1457
+ timeEnd()
1464
1458
  return true
1465
1459
  }
1466
1460
 
@@ -1571,17 +1565,14 @@ module.exports = cls => class Reifier extends cls {
1571
1565
  const { scripts = {} } = pkg
1572
1566
  for (const event of ['predependencies', 'dependencies', 'postdependencies']) {
1573
1567
  if (Object.prototype.hasOwnProperty.call(scripts, event)) {
1574
- const timer = `reify:run:${event}`
1575
- process.emit('time', timer)
1576
1568
  log.info('run', pkg._id, event, scripts[event])
1577
- await runScript({
1569
+ await time.start(`reify:run:${event}`, () => runScript({
1578
1570
  event,
1579
1571
  path,
1580
1572
  pkg,
1581
1573
  stdio,
1582
1574
  scriptShell: this.options.scriptShell,
1583
- })
1584
- process.emit('timeEnd', timer)
1575
+ }))
1585
1576
  }
1586
1577
  }
1587
1578
  }
@@ -13,7 +13,7 @@ const _fixAvailable = Symbol('fixAvailable')
13
13
  const _checkTopNode = Symbol('checkTopNode')
14
14
  const _init = Symbol('init')
15
15
  const _omit = Symbol('omit')
16
- const log = require('proc-log')
16
+ const { log, time } = require('proc-log')
17
17
 
18
18
  const fetch = require('npm-registry-fetch')
19
19
 
@@ -117,7 +117,7 @@ class AuditReport extends Map {
117
117
  }
118
118
 
119
119
  async [_init] () {
120
- process.emit('time', 'auditReport:init')
120
+ const timeEnd = time.start('auditReport:init')
121
121
 
122
122
  const promises = []
123
123
  for (const [name, advisories] of Object.entries(this.report)) {
@@ -210,7 +210,8 @@ class AuditReport extends Map {
210
210
  }
211
211
  }
212
212
  }
213
- process.emit('timeEnd', 'auditReport:init')
213
+
214
+ timeEnd()
214
215
  }
215
216
 
216
217
  [_checkTopNode] (topNode, vuln, spec) {
@@ -306,7 +307,7 @@ class AuditReport extends Map {
306
307
  return null
307
308
  }
308
309
 
309
- process.emit('time', 'auditReport:getReport')
310
+ const timeEnd = time.start('auditReport:getReport')
310
311
  try {
311
312
  try {
312
313
  // first try the super fast bulk advisory listing
@@ -347,7 +348,7 @@ class AuditReport extends Map {
347
348
  this.error = er
348
349
  return null
349
350
  } finally {
350
- process.emit('timeEnd', 'auditReport:getReport')
351
+ timeEnd()
351
352
  }
352
353
  }
353
354
  }
package/lib/place-dep.js CHANGED
@@ -8,8 +8,8 @@
8
8
  // a result.
9
9
 
10
10
  const localeCompare = require('@isaacs/string-locale-compare')('en')
11
- const log = require('proc-log')
12
- const { cleanUrl } = require('npm-registry-fetch')
11
+ const { log } = require('proc-log')
12
+ const { redact } = require('@npmcli/redact')
13
13
  const deepestNestingTarget = require('./deepest-nesting-target.js')
14
14
  const CanPlaceDep = require('./can-place-dep.js')
15
15
  const {
@@ -188,7 +188,7 @@ class PlaceDep {
188
188
  `${this.dep.name}@${this.dep.version}`,
189
189
  this.canPlace.description,
190
190
  `for: ${this.edge.from.package._id || this.edge.from.location}`,
191
- `want: ${cleanUrl(this.edge.spec || '*')}`
191
+ `want: ${redact(this.edge.spec || '*')}`
192
192
  )
193
193
 
194
194
  const placementType = this.canPlace.canPlace === CONFLICT
@@ -3,7 +3,7 @@
3
3
  const { resolve } = require('path')
4
4
  const { parser, arrayDelimiter } = require('@npmcli/query')
5
5
  const localeCompare = require('@isaacs/string-locale-compare')('en')
6
- const log = require('proc-log')
6
+ const { log } = require('proc-log')
7
7
  const { minimatch } = require('minimatch')
8
8
  const npa = require('npm-package-arg')
9
9
  const pacote = require('pacote')
package/lib/shrinkwrap.js CHANGED
@@ -33,7 +33,7 @@ const mismatch = (a, b) => a && b && a !== b
33
33
  // After calling this.commit(), any nodes not present in the tree will have
34
34
  // been removed from the shrinkwrap data as well.
35
35
 
36
- const log = require('proc-log')
36
+ const { log } = require('proc-log')
37
37
  const YarnLock = require('./yarn-lock.js')
38
38
  const {
39
39
  readFile,
@@ -1145,6 +1145,7 @@ class Shrinkwrap {
1145
1145
  throw new Error('run load() before saving data')
1146
1146
  }
1147
1147
 
1148
+ // This must be called before the lockfile conversion check below since it sets properties as part of `commit()`
1148
1149
  const json = this.toString(options)
1149
1150
  if (
1150
1151
  !this.hiddenLockfile
@@ -1155,6 +1156,7 @@ class Shrinkwrap {
1155
1156
  `Converting lock file (${relative(process.cwd(), this.filename)}) from v${this.originalLockfileVersion} -> v${this.lockfileVersion}`
1156
1157
  )
1157
1158
  }
1159
+
1158
1160
  return Promise.all([
1159
1161
  writeFile(this.filename, json).catch(er => {
1160
1162
  if (this.hiddenLockfile) {
package/lib/tracker.js CHANGED
@@ -1,12 +1,12 @@
1
- const npmlog = require('npmlog')
1
+ const proggy = require('proggy')
2
2
 
3
3
  module.exports = cls => class Tracker extends cls {
4
4
  #progress = new Map()
5
- #setProgress
6
5
 
7
- constructor (options = {}) {
8
- super(options)
9
- this.#setProgress = !!options.progress
6
+ #createTracker (key, name) {
7
+ const tracker = new proggy.Tracker(name ?? key)
8
+ tracker.on('done', () => this.#progress.delete(key))
9
+ this.#progress.set(key, tracker)
10
10
  }
11
11
 
12
12
  addTracker (section, subsection = null, key = null) {
@@ -26,22 +26,17 @@ module.exports = cls => class Tracker extends cls {
26
26
  this.#onError(`Tracker "${section}" already exists`)
27
27
  } else if (!hasTracker && subsection === null) {
28
28
  // 1. no existing tracker, no subsection
29
- // Create a new tracker from npmlog
30
- // starts progress bar
31
- if (this.#setProgress && this.#progress.size === 0) {
32
- npmlog.enableProgress()
33
- }
34
-
35
- this.#progress.set(section, npmlog.newGroup(section))
29
+ // Create a new progress tracker
30
+ this.#createTracker(section)
36
31
  } else if (!hasTracker && subsection !== null) {
37
32
  // 2. no parent tracker and subsection
38
33
  this.#onError(`Parent tracker "${section}" does not exist`)
39
34
  } else if (!hasTracker || !hasSubtracker) {
40
35
  // 3. existing parent tracker, no subsection tracker
41
- // Create a new subtracker in this.#progress from parent tracker
42
- this.#progress.set(`${section}:${key}`,
43
- this.#progress.get(section).newGroup(`${section}:${subsection}`)
44
- )
36
+ // Create a new subtracker and update parents
37
+ const parentTracker = this.#progress.get(section)
38
+ parentTracker.update(parentTracker.value, parentTracker.total + 1)
39
+ this.#createTracker(`${section}:${key}`, `${section}:${subsection}`)
45
40
  }
46
41
  // 4. existing parent tracker, existing subsection tracker
47
42
  // skip it
@@ -70,32 +65,22 @@ module.exports = cls => class Tracker extends cls {
70
65
  this.finishTracker(section, key)
71
66
  }
72
67
  }
73
-
74
68
  // remove parent tracker
75
69
  this.#progress.get(section).finish()
76
- this.#progress.delete(section)
77
-
78
- // remove progress bar if all
79
- // trackers are finished
80
- if (this.#setProgress && this.#progress.size === 0) {
81
- npmlog.disableProgress()
82
- }
83
70
  } else if (!hasTracker && subsection === null) {
84
71
  // 1. no existing parent tracker, no subsection
85
72
  this.#onError(`Tracker "${section}" does not exist`)
86
73
  } else if (!hasTracker || hasSubtracker) {
87
74
  // 2. subtracker exists
88
75
  // Finish subtracker and remove from this.#progress
76
+ const parentTracker = this.#progress.get(section)
77
+ parentTracker.update(parentTracker.value + 1)
89
78
  this.#progress.get(`${section}:${key}`).finish()
90
- this.#progress.delete(`${section}:${key}`)
91
79
  }
92
80
  // 3. existing parent tracker, no subsection
93
81
  }
94
82
 
95
83
  #onError (msg) {
96
- if (this.#setProgress) {
97
- npmlog.disableProgress()
98
- }
99
84
  throw new Error(msg)
100
85
  }
101
86
  }
package/package.json CHANGED
@@ -1,18 +1,19 @@
1
1
  {
2
2
  "name": "@npmcli/arborist",
3
- "version": "7.4.1",
3
+ "version": "7.5.0",
4
4
  "description": "Manage node_modules trees",
5
5
  "dependencies": {
6
6
  "@isaacs/string-locale-compare": "^1.1.0",
7
7
  "@npmcli/fs": "^3.1.0",
8
- "@npmcli/installed-package-contents": "^2.0.2",
8
+ "@npmcli/installed-package-contents": "^2.1.0",
9
9
  "@npmcli/map-workspaces": "^3.0.2",
10
- "@npmcli/metavuln-calculator": "^7.0.0",
10
+ "@npmcli/metavuln-calculator": "^7.1.0",
11
11
  "@npmcli/name-from-folder": "^2.0.0",
12
12
  "@npmcli/node-gyp": "^3.0.0",
13
- "@npmcli/package-json": "^5.0.0",
13
+ "@npmcli/package-json": "^5.1.0",
14
14
  "@npmcli/query": "^3.1.0",
15
- "@npmcli/run-script": "^7.0.2",
15
+ "@npmcli/redact": "^1.1.0",
16
+ "@npmcli/run-script": "^8.0.0",
16
17
  "bin-links": "^4.0.1",
17
18
  "cacache": "^18.0.0",
18
19
  "common-ancestor-path": "^1.0.1",
@@ -22,13 +23,13 @@
22
23
  "minimatch": "^9.0.4",
23
24
  "nopt": "^7.0.0",
24
25
  "npm-install-checks": "^6.2.0",
25
- "npm-package-arg": "^11.0.1",
26
+ "npm-package-arg": "^11.0.2",
26
27
  "npm-pick-manifest": "^9.0.0",
27
- "npm-registry-fetch": "^16.2.0",
28
- "npmlog": "^7.0.1",
29
- "pacote": "^17.0.4",
28
+ "npm-registry-fetch": "^16.2.1",
29
+ "pacote": "^18.0.1",
30
30
  "parse-conflict-json": "^3.0.0",
31
- "proc-log": "^3.0.0",
31
+ "proc-log": "^4.2.0",
32
+ "proggy": "^2.0.0",
32
33
  "promise-all-reject-late": "^1.0.0",
33
34
  "promise-call-limit": "^3.0.1",
34
35
  "read-package-json-fast": "^3.0.2",