@npmcli/arborist 2.8.2 → 2.9.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.
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 +28 -15
  14. package/lib/arborist/audit.js +2 -1
  15. package/lib/arborist/build-ideal-tree.js +139 -72
  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 +37 -20
  20. package/lib/arborist/load-workspaces.js +4 -2
  21. package/lib/arborist/rebuild.js +34 -17
  22. package/lib/arborist/reify.js +153 -76
  23. package/lib/audit-report.js +44 -23
  24. package/lib/calc-dep-flags.js +18 -9
  25. package/lib/can-place-dep.js +59 -30
  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 +111 -37
  39. package/lib/printable.js +46 -25
  40. package/lib/realpath.js +12 -6
  41. package/lib/shrinkwrap.js +164 -90
  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 +44 -22
  48. package/lib/yarn-lock.js +34 -21
  49. package/package.json +8 -10
package/bin/actual.js CHANGED
@@ -7,12 +7,14 @@ require('./lib/timers.js')
7
7
  const start = process.hrtime()
8
8
  new Arborist(options).loadActual(options).then(tree => {
9
9
  const end = process.hrtime(start)
10
- if (!process.argv.includes('--quiet'))
10
+ if (!process.argv.includes('--quiet')) {
11
11
  print(tree)
12
+ }
12
13
 
13
14
  console.error(`read ${tree.inventory.size} deps in ${end[0] * 1000 + end[1] / 1e6}ms`)
14
- if (options.save)
15
+ if (options.save) {
15
16
  tree.meta.save()
17
+ }
16
18
  if (options.saveHidden) {
17
19
  tree.meta.hiddenLockfile = true
18
20
  tree.meta.filename = options.path + '/node_modules/.package-lock.json'
package/bin/audit.js CHANGED
@@ -7,12 +7,14 @@ require('./lib/logging.js')
7
7
 
8
8
  const Vuln = require('../lib/vuln.js')
9
9
  const printReport = report => {
10
- for (const vuln of report.values())
10
+ for (const vuln of report.values()) {
11
11
  console.log(printVuln(vuln))
12
+ }
12
13
  if (report.topVulns.size) {
13
14
  console.log('\n# top-level vulnerabilities')
14
- for (const vuln of report.topVulns.values())
15
+ for (const vuln of report.topVulns.values()) {
15
16
  console.log(printVuln(vuln))
17
+ }
16
18
  }
17
19
  }
18
20
 
@@ -37,12 +39,16 @@ const arb = new Arborist(options)
37
39
  arb.audit(options).then(tree => {
38
40
  process.emit('timeEnd', 'audit script')
39
41
  const end = process.hrtime(start)
40
- if (options.fix)
42
+ if (options.fix) {
41
43
  print(tree)
42
- if (!options.quiet)
44
+ }
45
+ if (!options.quiet) {
43
46
  printReport(arb.auditReport)
44
- if (options.fix)
47
+ }
48
+ if (options.fix) {
45
49
  console.error(`resolved ${tree.inventory.size} deps in ${end[0] + end[1] / 1e9}s`)
46
- if (tree.meta && options.save)
50
+ }
51
+ if (tree.meta && options.save) {
47
52
  tree.meta.save()
53
+ }
48
54
  }).catch(er => console.error(er))
package/bin/dedupe.js CHANGED
@@ -10,8 +10,9 @@ const printDiff = diff => {
10
10
  depth({
11
11
  tree: diff,
12
12
  visit: d => {
13
- if (d.location === '')
13
+ if (d.location === '') {
14
14
  return
15
+ }
15
16
  switch (d.action) {
16
17
  case 'REMOVE':
17
18
  console.error('REMOVE', d.actual.location)
@@ -38,9 +39,11 @@ arb.dedupe(options).then(tree => {
38
39
  process.emit('timeEnd', 'install')
39
40
  const end = process.hrtime(start)
40
41
  print(tree)
41
- if (options.dryRun)
42
+ if (options.dryRun) {
42
43
  printDiff(arb.diff)
44
+ }
43
45
  console.error(`resolved ${tree.inventory.size} deps in ${end[0] + end[1] / 1e9}s`)
44
- if (tree.meta && options.save)
46
+ if (tree.meta && options.save) {
45
47
  tree.meta.save()
48
+ }
46
49
  }).catch(er => console.error(require('util').inspect(er, { depth: Infinity })))
package/bin/funding.js CHANGED
@@ -19,13 +19,15 @@ a.loadVirtual().then(tree => {
19
19
  const end = process.hrtime(start)
20
20
  if (!query) {
21
21
  for (const node of tree.inventory.values()) {
22
- if (node.package.funding)
22
+ if (node.package.funding) {
23
23
  console.log(node.name, node.location, node.package.funding)
24
+ }
24
25
  }
25
26
  } else {
26
27
  for (const node of tree.inventory.query('name', query)) {
27
- if (node.package.funding)
28
+ if (node.package.funding) {
28
29
  console.log(node.name, node.location, node.package.funding)
30
+ }
29
31
  }
30
32
  }
31
33
  console.error(`read ${tree.inventory.size} deps in ${end[0] * 1000 + end[1] / 1e6}ms`)
package/bin/ideal.js CHANGED
@@ -11,8 +11,9 @@ new Arborist(options).buildIdealTree(options).then(tree => {
11
11
  const end = process.hrtime(start)
12
12
  print(tree)
13
13
  console.error(`resolved ${tree.inventory.size} deps in ${end[0] + end[1] / 10e9}s`)
14
- if (tree.meta && options.save)
14
+ if (tree.meta && options.save) {
15
15
  tree.meta.save()
16
+ }
16
17
  }).catch(er => {
17
18
  const opt = { depth: Infinity, color: true }
18
19
  console.error(er.code === 'ERESOLVE' ? inspect(er, opt) : er)
@@ -24,12 +24,13 @@ const colors = process.stderr.isTTY
24
24
  const magenta = colors ? msg => `\x1B[35m${msg}\x1B[39m` : m => m
25
25
  if (loglevel !== 'silent') {
26
26
  process.on('log', (level, ...args) => {
27
- if (levelMap.get(level) < levelMap.get(loglevel))
27
+ if (levelMap.get(level) < levelMap.get(loglevel)) {
28
28
  return
29
+ }
29
30
  const pref = `${process.pid} ${magenta(level)} `
30
- if (level === 'warn' && args[0] === 'ERESOLVE')
31
+ if (level === 'warn' && args[0] === 'ERESOLVE') {
31
32
  args[2] = inspect(args[2], { depth: 10, colors })
32
- else {
33
+ } else {
33
34
  args = args.map(a => {
34
35
  return typeof a === 'string' ? a
35
36
  : inspect(a, { depth: 10, colors })
@@ -11,17 +11,17 @@ for (const arg of process.argv.slice(2)) {
11
11
  } else if (/^--rm=/.test(arg)) {
12
12
  options.rm = options.rm || []
13
13
  options.rm.push(arg.substr('--rm='.length))
14
- } else if (arg === '--global')
14
+ } else if (arg === '--global') {
15
15
  options.global = true
16
- else if (arg === '--global-style')
16
+ } else if (arg === '--global-style') {
17
17
  options.globalStyle = true
18
- else if (arg === '--prefer-dedupe')
18
+ } else if (arg === '--prefer-dedupe') {
19
19
  options.preferDedupe = true
20
- else if (arg === '--legacy-peer-deps')
20
+ } else if (arg === '--legacy-peer-deps') {
21
21
  options.legacyPeerDeps = true
22
- else if (arg === '--force')
22
+ } else if (arg === '--force') {
23
23
  options.force = true
24
- else if (arg === '--update-all') {
24
+ } else if (arg === '--update-all') {
25
25
  options.update = options.update || {}
26
26
  options.update.all = true
27
27
  } else if (/^--update=/.test(arg)) {
@@ -31,9 +31,9 @@ for (const arg of process.argv.slice(2)) {
31
31
  } else if (/^--omit=/.test(arg)) {
32
32
  options.omit = options.omit || []
33
33
  options.omit.push(arg.substr('--omit='.length))
34
- } else if (/^--before=/.test(arg))
34
+ } else if (/^--before=/.test(arg)) {
35
35
  options.before = new Date(arg.substr('--before='.length))
36
- else if (/^-w.+/.test(arg)) {
36
+ } else if (/^-w.+/.test(arg)) {
37
37
  options.workspaces = options.workspaces || []
38
38
  options.workspaces.push(arg.replace(/^-w/, ''))
39
39
  } else if (/^--workspace=/.test(arg)) {
@@ -43,15 +43,17 @@ for (const arg of process.argv.slice(2)) {
43
43
  const [key, ...v] = arg.replace(/^--/, '').split('=')
44
44
  const val = v.join('=')
45
45
  options[key] = val === 'false' ? false : val === 'true' ? true : val
46
- } else if (/^--.+/.test(arg))
46
+ } else if (/^--.+/.test(arg)) {
47
47
  options[arg.replace(/^--/, '')] = true
48
- else if (options.path === undefined)
48
+ } else if (options.path === undefined) {
49
49
  options.path = arg
50
- else
50
+ } else {
51
51
  options._.push(arg)
52
+ }
52
53
  }
53
54
 
54
- if (options.path === undefined)
55
+ if (options.path === undefined) {
55
56
  options.path = '.'
57
+ }
56
58
 
57
59
  console.error(options)
package/bin/lib/timers.js CHANGED
@@ -3,21 +3,24 @@ const { format } = require('util')
3
3
  const options = require('./options.js')
4
4
 
5
5
  process.on('time', name => {
6
- if (timers[name])
6
+ if (timers[name]) {
7
7
  throw new Error('conflicting timer! ' + name)
8
+ }
8
9
  timers[name] = process.hrtime()
9
10
  })
10
11
 
11
12
  const dim = process.stderr.isTTY ? msg => `\x1B[2m${msg}\x1B[22m` : m => m
12
13
  const red = process.stderr.isTTY ? msg => `\x1B[31m${msg}\x1B[39m` : m => m
13
14
  process.on('timeEnd', name => {
14
- if (!timers[name])
15
+ if (!timers[name]) {
15
16
  throw new Error('timer not started! ' + name)
17
+ }
16
18
  const res = process.hrtime(timers[name])
17
19
  delete timers[name]
18
20
  const msg = format(`${process.pid} ${name}`, res[0] * 1e3 + res[1] / 1e6)
19
- if (options.timers !== false)
21
+ if (options.timers !== false) {
20
22
  console.error(dim(msg))
23
+ }
21
24
  })
22
25
 
23
26
  process.on('exit', () => {
package/bin/license.js CHANGED
@@ -8,27 +8,31 @@ const query = options._.shift()
8
8
 
9
9
  a.loadVirtual().then(tree => {
10
10
  // only load the actual tree if the virtual one doesn't have modern metadata
11
- if (!tree.meta || !(tree.meta.originalLockfileVersion >= 2))
11
+ if (!tree.meta || !(tree.meta.originalLockfileVersion >= 2)) {
12
12
  throw 'load actual'
13
- else
13
+ } else {
14
14
  return tree
15
+ }
15
16
  }).catch((er) => {
16
17
  console.error('loading actual tree', er)
17
18
  return a.loadActual()
18
19
  }).then(tree => {
19
20
  if (!query) {
20
21
  const set = []
21
- for (const license of tree.inventory.query('license'))
22
+ for (const license of tree.inventory.query('license')) {
22
23
  set.push([tree.inventory.query('license', license).size, license])
24
+ }
23
25
 
24
26
  for (const [count, license] of set.sort((a, b) =>
25
27
  a[1] && b[1] ? b[0] - a[0] || a[1].localeCompare(b[1], 'en')
26
28
  : a[1] ? -1
27
29
  : b[1] ? 1
28
- : 0))
30
+ : 0)) {
29
31
  console.log(count, license)
32
+ }
30
33
  } else {
31
- for (const node of tree.inventory.query('license', query === 'undefined' ? undefined : query))
34
+ for (const node of tree.inventory.query('license', query === 'undefined' ? undefined : query)) {
32
35
  console.log(`${node.name} ${node.location} ${node.package.description || ''}`)
36
+ }
33
37
  }
34
38
  })
package/bin/prune.js CHANGED
@@ -10,8 +10,9 @@ const printDiff = diff => {
10
10
  depth({
11
11
  tree: diff,
12
12
  visit: d => {
13
- if (d.location === '')
13
+ if (d.location === '') {
14
14
  return
15
+ }
15
16
  switch (d.action) {
16
17
  case 'REMOVE':
17
18
  console.error('REMOVE', d.actual.location)
@@ -38,9 +39,11 @@ arb.prune(options).then(tree => {
38
39
  process.emit('timeEnd', 'install')
39
40
  const end = process.hrtime(start)
40
41
  print(tree)
41
- if (options.dryRun)
42
+ if (options.dryRun) {
42
43
  printDiff(arb.diff)
44
+ }
43
45
  console.error(`resolved ${tree.inventory.size} deps in ${end[0] + end[1] / 1e9}s`)
44
- if (tree.meta && options.save)
46
+ if (tree.meta && options.save) {
45
47
  tree.meta.save()
48
+ }
46
49
  }).catch(er => console.error(require('util').inspect(er, { depth: Infinity })))
package/bin/reify.js CHANGED
@@ -10,8 +10,9 @@ const printDiff = diff => {
10
10
  depth({
11
11
  tree: diff,
12
12
  visit: d => {
13
- if (d.location === '')
13
+ if (d.location === '') {
14
14
  return
15
+ }
15
16
  switch (d.action) {
16
17
  case 'REMOVE':
17
18
  console.error('REMOVE', d.actual.location)
@@ -38,9 +39,11 @@ arb.reify(options).then(tree => {
38
39
  process.emit('timeEnd', 'install')
39
40
  const end = process.hrtime(start)
40
41
  print(tree)
41
- if (options.dryRun)
42
+ if (options.dryRun) {
42
43
  printDiff(arb.diff)
44
+ }
43
45
  console.error(`resolved ${tree.inventory.size} deps in ${end[0] + end[1] / 1e9}s`)
44
- if (tree.meta && options.save)
46
+ if (tree.meta && options.save) {
45
47
  tree.meta.save()
48
+ }
46
49
  }).catch(er => console.error(require('util').inspect(er, { depth: Infinity })))
package/bin/virtual.js CHANGED
@@ -8,9 +8,11 @@ require('./lib/timers.js')
8
8
  const start = process.hrtime()
9
9
  new Arborist(options).loadVirtual().then(tree => {
10
10
  const end = process.hrtime(start)
11
- if (!options.quiet)
11
+ if (!options.quiet) {
12
12
  print(tree)
13
- if (options.save)
13
+ }
14
+ if (options.save) {
14
15
  tree.meta.save()
16
+ }
15
17
  console.error(`read ${tree.inventory.size} deps in ${end[0] * 1000 + end[1] / 1e6}ms`)
16
18
  }).catch(er => console.error(er))
@@ -1,8 +1,11 @@
1
1
  // add and remove dependency specs to/from pkg manifest
2
2
 
3
+ const localeCompare = require('@isaacs/string-locale-compare')('en')
4
+
3
5
  const add = ({pkg, add, saveBundle, saveType, log}) => {
4
- for (const spec of add)
6
+ for (const spec of add) {
5
7
  addSingle({pkg, spec, saveBundle, saveType, log})
8
+ }
6
9
 
7
10
  return pkg
8
11
  }
@@ -24,8 +27,9 @@ const addSingle = ({pkg, spec, saveBundle, saveType, log}) => {
24
27
  // to keep based on the same order of priority we do when
25
28
  // building the tree as defined in the _loadDeps method of
26
29
  // the node class.
27
- if (!saveType)
30
+ if (!saveType) {
28
31
  saveType = inferSaveType(pkg, spec.name)
32
+ }
29
33
 
30
34
  if (saveType === 'prod') {
31
35
  // a production dependency can only exist as production (rpj ensures it
@@ -48,8 +52,9 @@ const addSingle = ({pkg, spec, saveBundle, saveType, log}) => {
48
52
  const depType = saveTypeMap.get(saveType)
49
53
 
50
54
  pkg[depType] = pkg[depType] || {}
51
- if (rawSpec !== '' || pkg[depType][name] === undefined)
55
+ if (rawSpec !== '' || pkg[depType][name] === undefined) {
52
56
  pkg[depType][name] = rawSpec || '*'
57
+ }
53
58
  if (saveType === 'optional') {
54
59
  // Affordance for previous npm versions that require this behaviour
55
60
  pkg.dependencies = pkg.dependencies || {}
@@ -58,24 +63,25 @@ const addSingle = ({pkg, spec, saveBundle, saveType, log}) => {
58
63
 
59
64
  if (saveType === 'peer' || saveType === 'peerOptional') {
60
65
  const pdm = pkg.peerDependenciesMeta || {}
61
- if (saveType === 'peer' && pdm[name] && pdm[name].optional)
66
+ if (saveType === 'peer' && pdm[name] && pdm[name].optional) {
62
67
  pdm[name].optional = false
63
- else if (saveType === 'peerOptional') {
68
+ } else if (saveType === 'peerOptional') {
64
69
  pdm[name] = pdm[name] || {}
65
70
  pdm[name].optional = true
66
71
  pkg.peerDependenciesMeta = pdm
67
72
  }
68
73
  // peerDeps are often also a devDep, so that they can be tested when
69
74
  // using package managers that don't auto-install peer deps
70
- if (pkg.devDependencies && pkg.devDependencies[name] !== undefined)
75
+ if (pkg.devDependencies && pkg.devDependencies[name] !== undefined) {
71
76
  pkg.devDependencies[name] = pkg.peerDependencies[name]
77
+ }
72
78
  }
73
79
 
74
80
  if (saveBundle && saveType !== 'peer' && saveType !== 'peerOptional') {
75
81
  // keep it sorted, keep it unique
76
82
  const bd = new Set(pkg.bundleDependencies || [])
77
83
  bd.add(spec.name)
78
- pkg.bundleDependencies = [...bd].sort((a, b) => a.localeCompare(b, 'en'))
84
+ pkg.bundleDependencies = [...bd].sort(localeCompare)
79
85
  }
80
86
  }
81
87
 
@@ -87,47 +93,54 @@ const inferSaveType = (pkg, name) => {
87
93
  saveType === 'peerOptional' &&
88
94
  (!hasSubKey(pkg, 'peerDependenciesMeta', name) ||
89
95
  !pkg.peerDependenciesMeta[name].optional)
90
- )
96
+ ) {
91
97
  return 'peer'
98
+ }
92
99
  return saveType
93
100
  }
94
101
  }
95
102
  return 'prod'
96
103
  }
97
104
 
105
+ const { hasOwnProperty } = Object.prototype
98
106
  const hasSubKey = (pkg, depType, name) => {
99
- return pkg[depType] && Object.prototype.hasOwnProperty.call(pkg[depType], name)
107
+ return pkg[depType] && hasOwnProperty.call(pkg[depType], name)
100
108
  }
101
109
 
102
110
  // Removes a subkey and warns about it if it's being replaced
103
111
  const deleteSubKey = (pkg, depType, name, replacedBy, log) => {
104
112
  if (hasSubKey(pkg, depType, name)) {
105
- if (replacedBy && log)
113
+ if (replacedBy && log) {
106
114
  log.warn('idealTree', `Removing ${depType}.${name} in favor of ${replacedBy}.${name}`)
115
+ }
107
116
  delete pkg[depType][name]
108
117
 
109
- // clean up peerDependenciesMeta if we are removing something from peerDependencies
118
+ // clean up peerDepsMeta if we are removing something from peerDependencies
110
119
  if (depType === 'peerDependencies' && pkg.peerDependenciesMeta) {
111
120
  delete pkg.peerDependenciesMeta[name]
112
- if (!Object.keys(pkg.peerDependenciesMeta).length)
121
+ if (!Object.keys(pkg.peerDependenciesMeta).length) {
113
122
  delete pkg.peerDependenciesMeta
123
+ }
114
124
  }
115
125
 
116
- if (!Object.keys(pkg[depType]).length)
126
+ if (!Object.keys(pkg[depType]).length) {
117
127
  delete pkg[depType]
128
+ }
118
129
  }
119
130
  }
120
131
 
121
132
  const rm = (pkg, rm) => {
122
133
  for (const depType of new Set(saveTypeMap.values())) {
123
- for (const name of rm)
134
+ for (const name of rm) {
124
135
  deleteSubKey(pkg, depType, name)
136
+ }
125
137
  }
126
138
  if (pkg.bundleDependencies) {
127
139
  pkg.bundleDependencies = pkg.bundleDependencies
128
140
  .filter(name => !rm.includes(name))
129
- if (!pkg.bundleDependencies.length)
141
+ if (!pkg.bundleDependencies.length) {
130
142
  delete pkg.bundleDependencies
143
+ }
131
144
  }
132
145
  return pkg
133
146
  }
@@ -22,8 +22,9 @@ module.exports = cls => class Auditor extends cls {
22
22
 
23
23
  process.emit('time', 'audit')
24
24
  const tree = await this.loadVirtual()
25
- if (this[_workspaces] && this[_workspaces].length)
25
+ if (this[_workspaces] && this[_workspaces].length) {
26
26
  options.filterSet = this.workspaceDependencySet(tree, this[_workspaces])
27
+ }
27
28
  this.auditReport = await AuditReport.load(tree, options)
28
29
  const ret = options.fix ? this.reify(options) : this.auditReport
29
30
  process.emit('timeEnd', 'audit')