@npmcli/arborist 2.4.1 → 2.4.2

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.
@@ -1,60 +1,60 @@
1
1
  // add and remove dependency specs to/from pkg manifest
2
2
 
3
- const removeFromOthers = (name, type, pkg) => {
4
- const others = new Set([
5
- 'dependencies',
6
- 'optionalDependencies',
7
- 'devDependencies',
8
- 'peerDependenciesMeta',
9
- 'peerDependencies',
10
- ])
11
-
12
- switch (type) {
13
- case 'prod':
14
- others.delete('dependencies')
15
- break
16
- case 'dev':
17
- others.delete('devDependencies')
18
- others.delete('peerDependencies')
19
- others.delete('peerDependenciesMeta')
20
- break
21
- case 'optional':
22
- others.delete('optionalDependencies')
23
- break
24
- case 'peer':
25
- case 'peerOptional':
26
- others.delete('devDependencies')
27
- others.delete('peerDependencies')
28
- others.delete('peerDependenciesMeta')
29
- break
30
- }
31
-
32
- for (const other of others)
33
- deleteSubKey(pkg, other, name)
34
- }
35
-
36
- const add = ({pkg, add, saveBundle, saveType}) => {
3
+ const add = ({pkg, add, saveBundle, saveType, log}) => {
37
4
  for (const spec of add)
38
- addSingle({pkg, spec, saveBundle, saveType})
5
+ addSingle({pkg, spec, saveBundle, saveType, log})
39
6
 
40
7
  return pkg
41
8
  }
42
9
 
43
- const addSingle = ({pkg, spec, saveBundle, saveType}) => {
44
- if (!saveType)
45
- saveType = getSaveType(pkg, spec)
10
+ // Canonical source of both the map between saveType and where it correlates to
11
+ // in the package, and the names of all our dependencies attributes
12
+ const saveTypeMap = new Map([
13
+ ['dev', 'devDependencies'],
14
+ ['optional', 'optionalDependencies'],
15
+ ['prod', 'dependencies'],
16
+ ['peerOptional', 'peerDependencies'],
17
+ ['peer', 'peerDependencies'],
18
+ ])
46
19
 
20
+ const addSingle = ({pkg, spec, saveBundle, saveType, log}) => {
47
21
  const { name, rawSpec } = spec
48
- removeFromOthers(name, saveType, pkg)
49
- const type = saveType === 'prod' ? 'dependencies'
50
- : saveType === 'optional' ? 'optionalDependencies'
51
- : saveType === 'peer' || saveType === 'peerOptional' ? 'peerDependencies'
52
- : saveType === 'dev' ? 'devDependencies'
53
- : /* istanbul ignore next */ null
54
22
 
55
- pkg[type] = pkg[type] || {}
56
- if (rawSpec !== '' || pkg[type][name] === undefined)
57
- pkg[type][name] = rawSpec || '*'
23
+ // if the user does not give us a type, we infer which type(s)
24
+ // to keep based on the same order of priority we do when
25
+ // building the tree as defined in the _loadDeps method of
26
+ // the node class.
27
+ if (!saveType)
28
+ saveType = inferSaveType(pkg, spec.name)
29
+
30
+ if (saveType === 'prod') {
31
+ // a production dependency can only exist as production (rpj ensures it
32
+ // doesn't coexist w/ optional)
33
+ deleteSubKey(pkg, 'devDependencies', name, 'dependencies', log)
34
+ deleteSubKey(pkg, 'peerDependencies', name, 'dependencies', log)
35
+ } else if (saveType === 'dev') {
36
+ // a dev dependency may co-exist as peer, or optional, but not production
37
+ deleteSubKey(pkg, 'dependencies', name, 'devDependencies', log)
38
+ } else if (saveType === 'optional') {
39
+ // an optional dependency may co-exist as dev (rpj ensures it doesn't
40
+ // coexist w/ prod)
41
+ deleteSubKey(pkg, 'peerDependencies', name, 'optionalDependencies', log)
42
+ } else { // peer or peerOptional is all that's left
43
+ // a peer dependency may coexist as dev
44
+ deleteSubKey(pkg, 'dependencies', name, 'peerDependencies', log)
45
+ deleteSubKey(pkg, 'optionalDependencies', name, 'peerDependencies', log)
46
+ }
47
+
48
+ const depType = saveTypeMap.get(saveType)
49
+
50
+ pkg[depType] = pkg[depType] || {}
51
+ if (rawSpec !== '' || pkg[depType][name] === undefined)
52
+ pkg[depType][name] = rawSpec || '*'
53
+ if (saveType === 'optional') {
54
+ // Affordance for previous npm versions that require this behaviour
55
+ pkg.dependencies = pkg.dependencies || {}
56
+ pkg.dependencies[name] = pkg.optionalDependencies[name]
57
+ }
58
58
 
59
59
  if (saveType === 'peer' || saveType === 'peerOptional') {
60
60
  const pdm = pkg.peerDependenciesMeta || {}
@@ -79,47 +79,49 @@ const addSingle = ({pkg, spec, saveBundle, saveType}) => {
79
79
  }
80
80
  }
81
81
 
82
- const getSaveType = (pkg, spec) => {
83
- const {name} = spec
84
- const {
85
- // these names are so lonnnnngggg
86
- devDependencies: devDeps,
87
- optionalDependencies: optDeps,
88
- peerDependencies: peerDeps,
89
- peerDependenciesMeta: peerDepsMeta,
90
- } = pkg
91
-
92
- if (peerDeps && peerDeps[name] !== undefined) {
93
- if (peerDepsMeta && peerDepsMeta[name] && peerDepsMeta[name].optional)
94
- return 'peerOptional'
95
- else
96
- return 'peer'
97
- } else if (devDeps && devDeps[name] !== undefined)
98
- return 'dev'
99
- else if (optDeps && optDeps[name] !== undefined)
100
- return 'optional'
101
- else
102
- return 'prod'
82
+ // Finds where the package is already in the spec and infers saveType from that
83
+ const inferSaveType = (pkg, name) => {
84
+ for (const saveType of saveTypeMap.keys()) {
85
+ if (hasSubKey(pkg, saveTypeMap.get(saveType), name)) {
86
+ if (
87
+ saveType === 'peerOptional' &&
88
+ (!hasSubKey(pkg, 'peerDependenciesMeta', name) ||
89
+ !pkg.peerDependenciesMeta[name].optional)
90
+ )
91
+ return 'peer'
92
+ return saveType
93
+ }
94
+ }
95
+ return 'prod'
103
96
  }
104
97
 
105
- const deleteSubKey = (obj, k, sk) => {
106
- if (obj[k]) {
107
- delete obj[k][sk]
108
- if (!Object.keys(obj[k]).length)
109
- delete obj[k]
98
+ const hasSubKey = (pkg, depType, name) => {
99
+ return pkg[depType] && Object.prototype.hasOwnProperty.call(pkg[depType], name)
100
+ }
101
+
102
+ // Removes a subkey and warns about it if it's being replaced
103
+ const deleteSubKey = (pkg, depType, name, replacedBy, log) => {
104
+ if (hasSubKey(pkg, depType, name)) {
105
+ if (replacedBy && log)
106
+ log.warn('idealTree', `Removing ${depType}.${name} in favor of ${replacedBy}.${name}`)
107
+ delete pkg[depType][name]
108
+
109
+ // clean up peerDependenciesMeta if we are removing something from peerDependencies
110
+ if (depType === 'peerDependencies' && pkg.peerDependenciesMeta) {
111
+ delete pkg.peerDependenciesMeta[name]
112
+ if (!Object.keys(pkg.peerDependenciesMeta).length)
113
+ delete pkg.peerDependenciesMeta
114
+ }
115
+
116
+ if (!Object.keys(pkg[depType]).length)
117
+ delete pkg[depType]
110
118
  }
111
119
  }
112
120
 
113
121
  const rm = (pkg, rm) => {
114
- for (const type of [
115
- 'dependencies',
116
- 'optionalDependencies',
117
- 'peerDependencies',
118
- 'peerDependenciesMeta',
119
- 'devDependencies',
120
- ]) {
122
+ for (const depType of new Set(saveTypeMap.values())) {
121
123
  for (const name of rm)
122
- deleteSubKey(pkg, type, name)
124
+ deleteSubKey(pkg, depType, name)
123
125
  }
124
126
  if (pkg.bundleDependencies) {
125
127
  pkg.bundleDependencies = pkg.bundleDependencies
@@ -130,4 +132,4 @@ const rm = (pkg, rm) => {
130
132
  return pkg
131
133
  }
132
134
 
133
- module.exports = { add, rm }
135
+ module.exports = { add, rm, saveTypeMap, hasSubKey }
@@ -504,6 +504,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
504
504
  saveBundle,
505
505
  saveType,
506
506
  path: this.path,
507
+ log: this.log,
507
508
  })
508
509
  })
509
510
  }
@@ -29,6 +29,7 @@
29
29
  const {resolve} = require('path')
30
30
  const {homedir} = require('os')
31
31
  const procLog = require('../proc-log.js')
32
+ const { saveTypeMap } = require('../add-rm-pkg-deps.js')
32
33
 
33
34
  const mixins = [
34
35
  require('../tracker.js'),
@@ -57,6 +58,8 @@ class Arborist extends Base {
57
58
  packumentCache: options.packumentCache || new Map(),
58
59
  log: options.log || procLog,
59
60
  }
61
+ if (options.saveType && !saveTypeMap.get(options.saveType))
62
+ throw new Error(`Invalid saveType ${options.saveType}`)
60
63
  this.cache = resolve(this.options.cache)
61
64
  this.path = resolve(this.options.path)
62
65
  process.emit('timeEnd', 'arborist:ctor')
@@ -3,9 +3,8 @@
3
3
  const onExit = require('../signal-handling.js')
4
4
  const pacote = require('pacote')
5
5
  const rpj = require('read-package-json-fast')
6
- const { updateDepSpec } = require('../dep-spec.js')
7
6
  const AuditReport = require('../audit-report.js')
8
- const {subset} = require('semver')
7
+ const {subset, intersects} = require('semver')
9
8
  const npa = require('npm-package-arg')
10
9
 
11
10
  const {dirname, resolve, relative} = require('path')
@@ -28,6 +27,7 @@ const promiseAllRejectLate = require('promise-all-reject-late')
28
27
  const optionalSet = require('../optional-set.js')
29
28
  const updateRootPackageJson = require('../update-root-package-json.js')
30
29
  const calcDepFlags = require('../calc-dep-flags.js')
30
+ const { saveTypeMap, hasSubKey } = require('../add-rm-pkg-deps.js')
31
31
 
32
32
  const _retiredPaths = Symbol('retiredPaths')
33
33
  const _retiredUnchanged = Symbol('retiredUnchanged')
@@ -406,11 +406,14 @@ module.exports = cls => class Reifier extends cls {
406
406
  return
407
407
 
408
408
  process.emit('time', 'reify:trashOmits')
409
+ // node.parent is checked to make sure this is a node that's in the tree, and
410
+ // not the parent-less top level nodes
409
411
  const filter = node =>
410
- node.peer && this[_omitPeer] ||
411
- node.dev && this[_omitDev] ||
412
- node.optional && this[_omitOptional] ||
413
- node.devOptional && this[_omitOptional] && this[_omitDev]
412
+ node.isDescendantOf(this.idealTree) &&
413
+ (node.peer && this[_omitPeer] ||
414
+ node.dev && this[_omitDev] ||
415
+ node.optional && this[_omitOptional] ||
416
+ node.devOptional && this[_omitOptional] && this[_omitDev])
414
417
 
415
418
  for (const node of this.idealTree.inventory.filter(filter))
416
419
  this[_addNodeToTrashList](node)
@@ -539,8 +542,8 @@ module.exports = cls => class Reifier extends cls {
539
542
  // Do the best with what we have, or else remove it from the tree
540
543
  // entirely, since we can't possibly reify it.
541
544
  const res = node.resolved ? `${node.name}@${this[_registryResolved](node.resolved)}`
542
- : node.package.name && node.version
543
- ? `${node.package.name}@${node.version}`
545
+ : node.packageName && node.version
546
+ ? `${node.packageName}@${node.version}`
544
547
  : null
545
548
 
546
549
  // no idea what this thing is. remove it from the tree.
@@ -959,6 +962,7 @@ module.exports = cls => class Reifier extends cls {
959
962
  const spec = subSpec ? subSpec.rawSpec : rawSpec
960
963
  const child = root.children.get(name)
961
964
 
965
+ let newSpec
962
966
  if (req.registry) {
963
967
  const version = child.version
964
968
  const prefixRange = version ? this[_savePrefix] + version : '*'
@@ -970,16 +974,17 @@ module.exports = cls => class Reifier extends cls {
970
974
  const isRange = (subSpec || req).type === 'range'
971
975
  const range = !isRange || subset(prefixRange, spec, { loose: true })
972
976
  ? prefixRange : spec
973
- const pname = child.package.name
977
+ const pname = child.packageName
974
978
  const alias = name !== pname
975
- updateDepSpec(pkg, name, (alias ? `npm:${pname}@` : '') + range)
979
+ newSpec = alias ? `npm:${pname}@${range}` : range
976
980
  } else if (req.hosted) {
977
981
  // save the git+https url if it has auth, otherwise shortcut
978
982
  const h = req.hosted
979
983
  const opt = { noCommittish: false }
980
- const save = h.https && h.auth ? `git+${h.https(opt)}`
981
- : h.shortcut(opt)
982
- updateDepSpec(pkg, name, save)
984
+ if (h.https && h.auth)
985
+ newSpec = `git+${h.https(opt)}`
986
+ else
987
+ newSpec = h.shortcut(opt)
983
988
  } else if (req.type === 'directory' || req.type === 'file') {
984
989
  // save the relative path in package.json
985
990
  // Normally saveSpec is updated with the proper relative
@@ -988,9 +993,37 @@ module.exports = cls => class Reifier extends cls {
988
993
  // thing, so just get the ultimate fetchSpec and relativize it.
989
994
  const p = req.fetchSpec.replace(/^file:/, '')
990
995
  const rel = relpath(root.realpath, p)
991
- updateDepSpec(pkg, name, `file:${rel}`)
996
+ newSpec = `file:${rel}`
992
997
  } else
993
- updateDepSpec(pkg, name, req.saveSpec)
998
+ newSpec = req.saveSpec
999
+
1000
+ if (options.saveType) {
1001
+ const depType = saveTypeMap.get(options.saveType)
1002
+ pkg[depType][name] = newSpec
1003
+ // rpj will have moved it here if it was in both
1004
+ // if it is empty it will be deleted later
1005
+ if (options.saveType === 'prod' && pkg.optionalDependencies)
1006
+ delete pkg.optionalDependencies[name]
1007
+ } else {
1008
+ if (hasSubKey(pkg, 'dependencies', name))
1009
+ pkg.dependencies[name] = newSpec
1010
+
1011
+ if (hasSubKey(pkg, 'devDependencies', name)) {
1012
+ pkg.devDependencies[name] = newSpec
1013
+ // don't update peer or optional if we don't have to
1014
+ if (hasSubKey(pkg, 'peerDependencies', name) && !intersects(newSpec, pkg.peerDependencies[name]))
1015
+ pkg.peerDependencies[name] = newSpec
1016
+
1017
+ if (hasSubKey(pkg, 'optionalDependencies', name) && !intersects(newSpec, pkg.optionalDependencies[name]))
1018
+ pkg.optionalDependencies[name] = newSpec
1019
+ } else {
1020
+ if (hasSubKey(pkg, 'peerDependencies', name))
1021
+ pkg.peerDependencies[name] = newSpec
1022
+
1023
+ if (hasSubKey(pkg, 'optionalDependencies', name))
1024
+ pkg.optionalDependencies[name] = newSpec
1025
+ }
1026
+ }
994
1027
  }
995
1028
 
996
1029
  // refresh the edges so they have the correct specs
@@ -101,13 +101,14 @@ class AuditReport extends Map {
101
101
 
102
102
  async run () {
103
103
  this.report = await this[_getReport]()
104
+ this.log.silly('audit report', this.report)
104
105
  if (this.report)
105
106
  await this[_init]()
106
107
  return this
107
108
  }
108
109
 
109
110
  isVulnerable (node) {
110
- const vuln = this.get(node.package.name)
111
+ const vuln = this.get(node.packageName)
111
112
  return !!(vuln && vuln.isVulnerable(node))
112
113
  }
113
114
 
@@ -144,7 +145,7 @@ class AuditReport extends Map {
144
145
  super.set(name, vuln)
145
146
 
146
147
  const p = []
147
- for (const node of this.tree.inventory.query('name', name)) {
148
+ for (const node of this.tree.inventory.query('packageName', name)) {
148
149
  if (shouldOmit(node, this[_omit]))
149
150
  continue
150
151
 
@@ -167,7 +168,7 @@ class AuditReport extends Map {
167
168
  this[_checkTopNode](dep, vuln, spec)
168
169
  else {
169
170
  // calculate a metavuln, if necessary
170
- p.push(this.calculator.calculate(dep.name, advisory).then(meta => {
171
+ p.push(this.calculator.calculate(dep.packageName, advisory).then(meta => {
171
172
  if (meta.testVersion(dep.version, spec))
172
173
  advisories.add(meta)
173
174
  }))
@@ -228,6 +229,9 @@ class AuditReport extends Map {
228
229
  if (!specObj.registry)
229
230
  return false
230
231
 
232
+ if (specObj.subSpec)
233
+ spec = specObj.subSpec.rawSpec
234
+
231
235
  // We don't provide fixes for top nodes other than root, but we
232
236
  // still check to see if the node is fixable with a different version,
233
237
  // and if that is a semver major bump.
@@ -289,6 +293,7 @@ class AuditReport extends Map {
289
293
  try {
290
294
  // first try the super fast bulk advisory listing
291
295
  const body = prepareBulkData(this.tree, this[_omit])
296
+ this.log.silly('audit', 'bulk request', body)
292
297
 
293
298
  // no sense asking if we don't have anything to audit,
294
299
  // we know it'll be empty
@@ -304,7 +309,8 @@ class AuditReport extends Map {
304
309
  })
305
310
 
306
311
  return await res.json()
307
- } catch (_) {
312
+ } catch (er) {
313
+ this.log.silly('audit', 'bulk request failed', String(er.body))
308
314
  // that failed, try the quick audit endpoint
309
315
  const body = prepareData(this.tree, this.options)
310
316
  const res = await fetch('/-/npm/v1/security/audits/quick', {
@@ -330,6 +336,7 @@ class AuditReport extends Map {
330
336
  // return true if we should ignore this one
331
337
  const shouldOmit = (node, omit) =>
332
338
  !node.version ? true
339
+ : node.isRoot ? true
333
340
  : omit.size === 0 ? false
334
341
  : node.dev && omit.has('dev') ||
335
342
  node.optional && omit.has('optional') ||
@@ -338,9 +345,9 @@ const shouldOmit = (node, omit) =>
338
345
 
339
346
  const prepareBulkData = (tree, omit) => {
340
347
  const payload = {}
341
- for (const name of tree.inventory.query('name')) {
348
+ for (const name of tree.inventory.query('packageName')) {
342
349
  const set = new Set()
343
- for (const node of tree.inventory.query('name', name)) {
350
+ for (const node of tree.inventory.query('packageName', name)) {
344
351
  if (shouldOmit(node, omit))
345
352
  continue
346
353
 
package/lib/inventory.js CHANGED
@@ -4,7 +4,7 @@
4
4
  // keys is the set of fields to be able to query.
5
5
  const _primaryKey = Symbol('_primaryKey')
6
6
  const _index = Symbol('_index')
7
- const defaultKeys = ['name', 'license', 'funding', 'realpath']
7
+ const defaultKeys = ['name', 'license', 'funding', 'realpath', 'packageName']
8
8
  const { hasOwnProperty } = Object.prototype
9
9
  const debug = require('./debug.js')
10
10
  class Inventory extends Map {
package/lib/node.js CHANGED
@@ -291,6 +291,10 @@ class Node {
291
291
  return this[_package].version || ''
292
292
  }
293
293
 
294
+ get packageName () {
295
+ return this[_package].name || null
296
+ }
297
+
294
298
  get pkgid () {
295
299
  const { name = '', version = '' } = this.package
296
300
  // root package will prefer package name over folder name,
@@ -350,10 +354,10 @@ class Node {
350
354
  }
351
355
 
352
356
  const why = {
353
- name: this.isProjectRoot ? this.package.name : this.name,
357
+ name: this.isProjectRoot ? this.packageName : this.name,
354
358
  version: this.package.version,
355
359
  }
356
- if (this.errors.length || !this.package.name || !this.package.version) {
360
+ if (this.errors.length || !this.packageName || !this.package.version) {
357
361
  why.errors = this.errors.length ? this.errors : [
358
362
  new Error('invalid package: lacks name and/or version'),
359
363
  ]
@@ -460,7 +464,7 @@ class Node {
460
464
  if (this.isProjectRoot)
461
465
  return false
462
466
  const { root } = this
463
- const { type, to } = root.edgesOut.get(this.package.name) || {}
467
+ const { type, to } = root.edgesOut.get(this.packageName) || {}
464
468
  return type === 'workspace' && to && (to.target === this || to === this)
465
469
  }
466
470
 
@@ -730,20 +734,14 @@ class Node {
730
734
 
731
735
  [_loadDeps] () {
732
736
  // Caveat! Order is relevant!
733
- // packages in optionalDependencies and prod/peer/dev are
734
- // optional. Packages in both deps and devDeps are required.
737
+ // Packages in optionalDependencies are optional.
738
+ // Packages in both deps and devDeps are required.
735
739
  // Note the subtle breaking change from v6: it is no longer possible
736
740
  // to have a different spec for a devDep than production dep.
737
- this[_loadDepType](this.package.optionalDependencies, 'optional')
738
741
 
739
742
  // Linked targets that are disconnected from the tree are tops,
740
743
  // but don't have a 'path' field, only a 'realpath', because we
741
744
  // don't know their canonical location. We don't need their devDeps.
742
- const { isTop, path, sourceReference } = this
743
- const { isTop: srcTop, path: srcPath } = sourceReference || {}
744
- if (isTop && path && (!sourceReference || srcTop && srcPath))
745
- this[_loadDepType](this.package.devDependencies, 'dev')
746
-
747
745
  const pd = this.package.peerDependencies
748
746
  if (pd && typeof pd === 'object' && !this.legacyPeerDeps) {
749
747
  const pm = this.package.peerDependenciesMeta || {}
@@ -760,19 +758,22 @@ class Node {
760
758
  }
761
759
 
762
760
  this[_loadDepType](this.package.dependencies, 'prod')
761
+ this[_loadDepType](this.package.optionalDependencies, 'optional')
762
+
763
+ const { isTop, path, sourceReference } = this
764
+ const { isTop: srcTop, path: srcPath } = sourceReference || {}
765
+ if (isTop && path && (!sourceReference || srcTop && srcPath))
766
+ this[_loadDepType](this.package.devDependencies, 'dev')
763
767
  }
764
768
 
765
- [_loadDepType] (obj, type) {
766
- const from = this
769
+ [_loadDepType] (deps, type) {
767
770
  const ad = this.package.acceptDependencies || {}
768
- for (const [name, spec] of Object.entries(obj || {})) {
769
- const accept = ad[name]
770
- // if it's already set, then we keep the existing edge
771
- // Prod deps should not be marked as dev, however.
772
- // NB: the Edge ctor adds itself to from.edgesOut
771
+ // Because of the order in which _loadDeps runs, we always want to
772
+ // prioritize a new edge over an existing one
773
+ for (const [name, spec] of Object.entries(deps || {})) {
773
774
  const current = this.edgesOut.get(name)
774
- if (!current || current.dev && type === 'prod')
775
- new Edge({ from, name, spec, accept, type })
775
+ if (!current || current.type !== 'workspace')
776
+ new Edge({ from: this, name, spec, accept: ad[name], type })
776
777
  }
777
778
  }
778
779
 
@@ -965,8 +966,8 @@ class Node {
965
966
 
966
967
  // if no resolved, check both package name and version
967
968
  // otherwise, conclude that they are different things
968
- return this.package.name && node.package.name &&
969
- this.package.name === node.package.name &&
969
+ return this.packageName && node.packageName &&
970
+ this.packageName === node.packageName &&
970
971
  this.version && node.version &&
971
972
  this.version === node.version
972
973
  }
package/lib/printable.js CHANGED
@@ -7,8 +7,8 @@ const relpath = require('./relpath.js')
7
7
  class ArboristNode {
8
8
  constructor (tree, path) {
9
9
  this.name = tree.name
10
- if (tree.package.name && tree.package.name !== this.name)
11
- this.packageName = tree.package.name
10
+ if (tree.packageName && tree.packageName !== this.name)
11
+ this.packageName = tree.packageName
12
12
  if (tree.version)
13
13
  this.version = tree.version
14
14
  this.location = tree.location
package/lib/shrinkwrap.js CHANGED
@@ -254,7 +254,7 @@ class Shrinkwrap {
254
254
  meta[key.replace(/^_/, '')] = val
255
255
  })
256
256
  // we only include name if different from the node path name
257
- const pname = node.package.name
257
+ const pname = node.packageName
258
258
  if (pname && pname !== node.name)
259
259
  meta.name = pname
260
260
 
@@ -825,7 +825,7 @@ class Shrinkwrap {
825
825
  [_buildLegacyLockfile] (node, lock, path = []) {
826
826
  if (node === this.tree) {
827
827
  // the root node
828
- lock.name = node.package.name || node.name
828
+ lock.name = node.packageName || node.name
829
829
  if (node.version)
830
830
  lock.version = node.version
831
831
  }
@@ -870,9 +870,9 @@ class Shrinkwrap {
870
870
  lock.from = spec.raw
871
871
  } else if (!node.isRoot &&
872
872
  node.package &&
873
- node.package.name &&
874
- node.package.name !== node.name)
875
- lock.version = `npm:${node.package.name}@${node.version}`
873
+ node.packageName &&
874
+ node.packageName !== node.name)
875
+ lock.version = `npm:${node.packageName}@${node.version}`
876
876
  else if (node.package && node.version)
877
877
  lock.version = node.version
878
878
 
@@ -6,8 +6,6 @@ const {resolve} = require('path')
6
6
 
7
7
  const parseJSON = require('json-parse-even-better-errors')
8
8
 
9
- const { orderDeps } = require('./dep-spec.js')
10
-
11
9
  const depTypes = new Set([
12
10
  'dependencies',
13
11
  'optionalDependencies',
@@ -15,6 +13,20 @@ const depTypes = new Set([
15
13
  'peerDependencies',
16
14
  ])
17
15
 
16
+ // sort alphabetically all types of deps for a given package
17
+ const orderDeps = (pkg) => {
18
+ for (const type of depTypes) {
19
+ if (pkg && pkg[type]) {
20
+ pkg[type] = Object.keys(pkg[type])
21
+ .sort((a, b) => a.localeCompare(b))
22
+ .reduce((res, key) => {
23
+ res[key] = pkg[type][key]
24
+ return res
25
+ }, {})
26
+ }
27
+ }
28
+ return pkg
29
+ }
18
30
  const parseJsonSafe = json => {
19
31
  try {
20
32
  return parseJSON(json)
package/lib/vuln.js CHANGED
@@ -83,6 +83,9 @@ class Vuln {
83
83
  if (!specObj.registry)
84
84
  return true
85
85
 
86
+ if (specObj.subSpec)
87
+ spec = specObj.subSpec.rawSpec
88
+
86
89
  for (const v of this.versions) {
87
90
  if (satisfies(v, spec) && !satisfies(v, this.range, semverOpt))
88
91
  return false
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@npmcli/arborist",
3
- "version": "2.4.1",
3
+ "version": "2.4.2",
4
4
  "description": "Manage node_modules trees",
5
5
  "dependencies": {
6
6
  "@npmcli/installed-package-contents": "^1.0.7",
package/lib/dep-spec.js DELETED
@@ -1,43 +0,0 @@
1
- const types = [
2
- 'peerDependencies',
3
- 'devDependencies',
4
- 'optionalDependencies',
5
- 'dependencies',
6
- ]
7
-
8
- const findType = (pkg, name) => {
9
- for (const t of types) {
10
- if (pkg[t] && typeof pkg[t] === 'object' && pkg[t][name] !== undefined)
11
- return t
12
- }
13
- return 'dependencies'
14
- }
15
-
16
- // given a dep name and spec, update it wherever it exists in
17
- // the manifest, or add the spec to 'dependencies' if not found.
18
- const updateDepSpec = (pkg, name, newSpec) => {
19
- const type = findType(pkg, name)
20
- pkg[type] = pkg[type] || {}
21
- pkg[type][name] = newSpec
22
- return pkg
23
- }
24
-
25
- // sort alphabetically all types of deps for a given package
26
- const orderDeps = (pkg) => {
27
- for (const type of types) {
28
- if (pkg && pkg[type]) {
29
- pkg[type] = Object.keys(pkg[type])
30
- .sort((a, b) => a.localeCompare(b))
31
- .reduce((res, key) => {
32
- res[key] = pkg[type][key]
33
- return res
34
- }, {})
35
- }
36
- }
37
- return pkg
38
- }
39
-
40
- module.exports = {
41
- orderDeps,
42
- updateDepSpec,
43
- }