From 81c1dfaaaf918229316a975aa8075769ffafdb6d Mon Sep 17 00:00:00 2001 From: Gar Date: Thu, 6 May 2021 10:12:04 -0700 Subject: [PATCH] @npmcli/arborist@2.4.2 * fix(add): save packages in the right place * fix(reify): do not clean up nodes with no parent * fix(audit): support alias specs & root package names --- .../@npmcli/arborist/lib/add-rm-pkg-deps.js | 166 +++++++++--------- .../arborist/lib/arborist/build-ideal-tree.js | 1 + .../@npmcli/arborist/lib/arborist/index.js | 3 + .../@npmcli/arborist/lib/arborist/reify.js | 63 +++++-- .../@npmcli/arborist/lib/audit-report.js | 19 +- node_modules/@npmcli/arborist/lib/dep-spec.js | 43 ----- .../@npmcli/arborist/lib/inventory.js | 2 +- node_modules/@npmcli/arborist/lib/node.js | 45 ++--- .../@npmcli/arborist/lib/printable.js | 4 +- .../@npmcli/arborist/lib/shrinkwrap.js | 10 +- .../arborist/lib/update-root-package-json.js | 16 +- node_modules/@npmcli/arborist/lib/vuln.js | 3 + node_modules/@npmcli/arborist/package.json | 2 +- package-lock.json | 14 +- package.json | 2 +- 15 files changed, 206 insertions(+), 187 deletions(-) delete mode 100644 node_modules/@npmcli/arborist/lib/dep-spec.js diff --git a/node_modules/@npmcli/arborist/lib/add-rm-pkg-deps.js b/node_modules/@npmcli/arborist/lib/add-rm-pkg-deps.js index 9a96fd1b3797..25113cbedff3 100644 --- a/node_modules/@npmcli/arborist/lib/add-rm-pkg-deps.js +++ b/node_modules/@npmcli/arborist/lib/add-rm-pkg-deps.js @@ -1,60 +1,60 @@ // add and remove dependency specs to/from pkg manifest -const removeFromOthers = (name, type, pkg) => { - const others = new Set([ - 'dependencies', - 'optionalDependencies', - 'devDependencies', - 'peerDependenciesMeta', - 'peerDependencies', - ]) - - switch (type) { - case 'prod': - others.delete('dependencies') - break - case 'dev': - others.delete('devDependencies') - others.delete('peerDependencies') - others.delete('peerDependenciesMeta') - break - case 'optional': - others.delete('optionalDependencies') - break - case 'peer': - case 'peerOptional': - others.delete('devDependencies') - others.delete('peerDependencies') - others.delete('peerDependenciesMeta') - break - } - - for (const other of others) - deleteSubKey(pkg, other, name) -} - -const add = ({pkg, add, saveBundle, saveType}) => { +const add = ({pkg, add, saveBundle, saveType, log}) => { for (const spec of add) - addSingle({pkg, spec, saveBundle, saveType}) + addSingle({pkg, spec, saveBundle, saveType, log}) return pkg } -const addSingle = ({pkg, spec, saveBundle, saveType}) => { - if (!saveType) - saveType = getSaveType(pkg, spec) +// Canonical source of both the map between saveType and where it correlates to +// in the package, and the names of all our dependencies attributes +const saveTypeMap = new Map([ + ['dev', 'devDependencies'], + ['optional', 'optionalDependencies'], + ['prod', 'dependencies'], + ['peerOptional', 'peerDependencies'], + ['peer', 'peerDependencies'], +]) +const addSingle = ({pkg, spec, saveBundle, saveType, log}) => { const { name, rawSpec } = spec - removeFromOthers(name, saveType, pkg) - const type = saveType === 'prod' ? 'dependencies' - : saveType === 'optional' ? 'optionalDependencies' - : saveType === 'peer' || saveType === 'peerOptional' ? 'peerDependencies' - : saveType === 'dev' ? 'devDependencies' - : /* istanbul ignore next */ null - pkg[type] = pkg[type] || {} - if (rawSpec !== '' || pkg[type][name] === undefined) - pkg[type][name] = rawSpec || '*' + // if the user does not give us a type, we infer which type(s) + // to keep based on the same order of priority we do when + // building the tree as defined in the _loadDeps method of + // the node class. + if (!saveType) + saveType = inferSaveType(pkg, spec.name) + + if (saveType === 'prod') { + // a production dependency can only exist as production (rpj ensures it + // doesn't coexist w/ optional) + deleteSubKey(pkg, 'devDependencies', name, 'dependencies', log) + deleteSubKey(pkg, 'peerDependencies', name, 'dependencies', log) + } else if (saveType === 'dev') { + // a dev dependency may co-exist as peer, or optional, but not production + deleteSubKey(pkg, 'dependencies', name, 'devDependencies', log) + } else if (saveType === 'optional') { + // an optional dependency may co-exist as dev (rpj ensures it doesn't + // coexist w/ prod) + deleteSubKey(pkg, 'peerDependencies', name, 'optionalDependencies', log) + } else { // peer or peerOptional is all that's left + // a peer dependency may coexist as dev + deleteSubKey(pkg, 'dependencies', name, 'peerDependencies', log) + deleteSubKey(pkg, 'optionalDependencies', name, 'peerDependencies', log) + } + + const depType = saveTypeMap.get(saveType) + + pkg[depType] = pkg[depType] || {} + if (rawSpec !== '' || pkg[depType][name] === undefined) + pkg[depType][name] = rawSpec || '*' + if (saveType === 'optional') { + // Affordance for previous npm versions that require this behaviour + pkg.dependencies = pkg.dependencies || {} + pkg.dependencies[name] = pkg.optionalDependencies[name] + } if (saveType === 'peer' || saveType === 'peerOptional') { const pdm = pkg.peerDependenciesMeta || {} @@ -79,47 +79,49 @@ const addSingle = ({pkg, spec, saveBundle, saveType}) => { } } -const getSaveType = (pkg, spec) => { - const {name} = spec - const { - // these names are so lonnnnngggg - devDependencies: devDeps, - optionalDependencies: optDeps, - peerDependencies: peerDeps, - peerDependenciesMeta: peerDepsMeta, - } = pkg - - if (peerDeps && peerDeps[name] !== undefined) { - if (peerDepsMeta && peerDepsMeta[name] && peerDepsMeta[name].optional) - return 'peerOptional' - else - return 'peer' - } else if (devDeps && devDeps[name] !== undefined) - return 'dev' - else if (optDeps && optDeps[name] !== undefined) - return 'optional' - else - return 'prod' +// Finds where the package is already in the spec and infers saveType from that +const inferSaveType = (pkg, name) => { + for (const saveType of saveTypeMap.keys()) { + if (hasSubKey(pkg, saveTypeMap.get(saveType), name)) { + if ( + saveType === 'peerOptional' && + (!hasSubKey(pkg, 'peerDependenciesMeta', name) || + !pkg.peerDependenciesMeta[name].optional) + ) + return 'peer' + return saveType + } + } + return 'prod' } -const deleteSubKey = (obj, k, sk) => { - if (obj[k]) { - delete obj[k][sk] - if (!Object.keys(obj[k]).length) - delete obj[k] +const hasSubKey = (pkg, depType, name) => { + return pkg[depType] && Object.prototype.hasOwnProperty.call(pkg[depType], name) +} + +// Removes a subkey and warns about it if it's being replaced +const deleteSubKey = (pkg, depType, name, replacedBy, log) => { + if (hasSubKey(pkg, depType, name)) { + if (replacedBy && log) + log.warn('idealTree', `Removing ${depType}.${name} in favor of ${replacedBy}.${name}`) + delete pkg[depType][name] + + // clean up peerDependenciesMeta if we are removing something from peerDependencies + if (depType === 'peerDependencies' && pkg.peerDependenciesMeta) { + delete pkg.peerDependenciesMeta[name] + if (!Object.keys(pkg.peerDependenciesMeta).length) + delete pkg.peerDependenciesMeta + } + + if (!Object.keys(pkg[depType]).length) + delete pkg[depType] } } const rm = (pkg, rm) => { - for (const type of [ - 'dependencies', - 'optionalDependencies', - 'peerDependencies', - 'peerDependenciesMeta', - 'devDependencies', - ]) { + for (const depType of new Set(saveTypeMap.values())) { for (const name of rm) - deleteSubKey(pkg, type, name) + deleteSubKey(pkg, depType, name) } if (pkg.bundleDependencies) { pkg.bundleDependencies = pkg.bundleDependencies @@ -130,4 +132,4 @@ const rm = (pkg, rm) => { return pkg } -module.exports = { add, rm } +module.exports = { add, rm, saveTypeMap, hasSubKey } diff --git a/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js b/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js index 7ee8dae35be1..6176707c3c65 100644 --- a/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js +++ b/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js @@ -504,6 +504,7 @@ module.exports = cls => class IdealTreeBuilder extends cls { saveBundle, saveType, path: this.path, + log: this.log, }) }) } diff --git a/node_modules/@npmcli/arborist/lib/arborist/index.js b/node_modules/@npmcli/arborist/lib/arborist/index.js index 93b9aa382982..3578d50389ea 100644 --- a/node_modules/@npmcli/arborist/lib/arborist/index.js +++ b/node_modules/@npmcli/arborist/lib/arborist/index.js @@ -29,6 +29,7 @@ const {resolve} = require('path') const {homedir} = require('os') const procLog = require('../proc-log.js') +const { saveTypeMap } = require('../add-rm-pkg-deps.js') const mixins = [ require('../tracker.js'), @@ -57,6 +58,8 @@ class Arborist extends Base { packumentCache: options.packumentCache || new Map(), log: options.log || procLog, } + if (options.saveType && !saveTypeMap.get(options.saveType)) + throw new Error(`Invalid saveType ${options.saveType}`) this.cache = resolve(this.options.cache) this.path = resolve(this.options.path) process.emit('timeEnd', 'arborist:ctor') diff --git a/node_modules/@npmcli/arborist/lib/arborist/reify.js b/node_modules/@npmcli/arborist/lib/arborist/reify.js index 64f08756263c..f7731e1c90da 100644 --- a/node_modules/@npmcli/arborist/lib/arborist/reify.js +++ b/node_modules/@npmcli/arborist/lib/arborist/reify.js @@ -3,9 +3,8 @@ const onExit = require('../signal-handling.js') const pacote = require('pacote') const rpj = require('read-package-json-fast') -const { updateDepSpec } = require('../dep-spec.js') const AuditReport = require('../audit-report.js') -const {subset} = require('semver') +const {subset, intersects} = require('semver') const npa = require('npm-package-arg') const {dirname, resolve, relative} = require('path') @@ -28,6 +27,7 @@ const promiseAllRejectLate = require('promise-all-reject-late') const optionalSet = require('../optional-set.js') const updateRootPackageJson = require('../update-root-package-json.js') const calcDepFlags = require('../calc-dep-flags.js') +const { saveTypeMap, hasSubKey } = require('../add-rm-pkg-deps.js') const _retiredPaths = Symbol('retiredPaths') const _retiredUnchanged = Symbol('retiredUnchanged') @@ -406,11 +406,14 @@ module.exports = cls => class Reifier extends cls { return process.emit('time', 'reify:trashOmits') + // node.parent is checked to make sure this is a node that's in the tree, and + // not the parent-less top level nodes const filter = node => - node.peer && this[_omitPeer] || - node.dev && this[_omitDev] || - node.optional && this[_omitOptional] || - node.devOptional && this[_omitOptional] && this[_omitDev] + node.isDescendantOf(this.idealTree) && + (node.peer && this[_omitPeer] || + node.dev && this[_omitDev] || + node.optional && this[_omitOptional] || + node.devOptional && this[_omitOptional] && this[_omitDev]) for (const node of this.idealTree.inventory.filter(filter)) this[_addNodeToTrashList](node) @@ -539,8 +542,8 @@ module.exports = cls => class Reifier extends cls { // Do the best with what we have, or else remove it from the tree // entirely, since we can't possibly reify it. const res = node.resolved ? `${node.name}@${this[_registryResolved](node.resolved)}` - : node.package.name && node.version - ? `${node.package.name}@${node.version}` + : node.packageName && node.version + ? `${node.packageName}@${node.version}` : null // no idea what this thing is. remove it from the tree. @@ -959,6 +962,7 @@ module.exports = cls => class Reifier extends cls { const spec = subSpec ? subSpec.rawSpec : rawSpec const child = root.children.get(name) + let newSpec if (req.registry) { const version = child.version const prefixRange = version ? this[_savePrefix] + version : '*' @@ -970,16 +974,17 @@ module.exports = cls => class Reifier extends cls { const isRange = (subSpec || req).type === 'range' const range = !isRange || subset(prefixRange, spec, { loose: true }) ? prefixRange : spec - const pname = child.package.name + const pname = child.packageName const alias = name !== pname - updateDepSpec(pkg, name, (alias ? `npm:${pname}@` : '') + range) + newSpec = alias ? `npm:${pname}@${range}` : range } else if (req.hosted) { // save the git+https url if it has auth, otherwise shortcut const h = req.hosted const opt = { noCommittish: false } - const save = h.https && h.auth ? `git+${h.https(opt)}` - : h.shortcut(opt) - updateDepSpec(pkg, name, save) + if (h.https && h.auth) + newSpec = `git+${h.https(opt)}` + else + newSpec = h.shortcut(opt) } else if (req.type === 'directory' || req.type === 'file') { // save the relative path in package.json // Normally saveSpec is updated with the proper relative @@ -988,9 +993,37 @@ module.exports = cls => class Reifier extends cls { // thing, so just get the ultimate fetchSpec and relativize it. const p = req.fetchSpec.replace(/^file:/, '') const rel = relpath(root.realpath, p) - updateDepSpec(pkg, name, `file:${rel}`) + newSpec = `file:${rel}` } else - updateDepSpec(pkg, name, req.saveSpec) + newSpec = req.saveSpec + + if (options.saveType) { + const depType = saveTypeMap.get(options.saveType) + pkg[depType][name] = newSpec + // rpj will have moved it here if it was in both + // if it is empty it will be deleted later + if (options.saveType === 'prod' && pkg.optionalDependencies) + delete pkg.optionalDependencies[name] + } else { + if (hasSubKey(pkg, 'dependencies', name)) + pkg.dependencies[name] = newSpec + + if (hasSubKey(pkg, 'devDependencies', name)) { + pkg.devDependencies[name] = newSpec + // don't update peer or optional if we don't have to + if (hasSubKey(pkg, 'peerDependencies', name) && !intersects(newSpec, pkg.peerDependencies[name])) + pkg.peerDependencies[name] = newSpec + + if (hasSubKey(pkg, 'optionalDependencies', name) && !intersects(newSpec, pkg.optionalDependencies[name])) + pkg.optionalDependencies[name] = newSpec + } else { + if (hasSubKey(pkg, 'peerDependencies', name)) + pkg.peerDependencies[name] = newSpec + + if (hasSubKey(pkg, 'optionalDependencies', name)) + pkg.optionalDependencies[name] = newSpec + } + } } // refresh the edges so they have the correct specs diff --git a/node_modules/@npmcli/arborist/lib/audit-report.js b/node_modules/@npmcli/arborist/lib/audit-report.js index 77cd6511aea3..9a0178c59c9e 100644 --- a/node_modules/@npmcli/arborist/lib/audit-report.js +++ b/node_modules/@npmcli/arborist/lib/audit-report.js @@ -101,13 +101,14 @@ class AuditReport extends Map { async run () { this.report = await this[_getReport]() + this.log.silly('audit report', this.report) if (this.report) await this[_init]() return this } isVulnerable (node) { - const vuln = this.get(node.package.name) + const vuln = this.get(node.packageName) return !!(vuln && vuln.isVulnerable(node)) } @@ -144,7 +145,7 @@ class AuditReport extends Map { super.set(name, vuln) const p = [] - for (const node of this.tree.inventory.query('name', name)) { + for (const node of this.tree.inventory.query('packageName', name)) { if (shouldOmit(node, this[_omit])) continue @@ -167,7 +168,7 @@ class AuditReport extends Map { this[_checkTopNode](dep, vuln, spec) else { // calculate a metavuln, if necessary - p.push(this.calculator.calculate(dep.name, advisory).then(meta => { + p.push(this.calculator.calculate(dep.packageName, advisory).then(meta => { if (meta.testVersion(dep.version, spec)) advisories.add(meta) })) @@ -228,6 +229,9 @@ class AuditReport extends Map { if (!specObj.registry) return false + if (specObj.subSpec) + spec = specObj.subSpec.rawSpec + // We don't provide fixes for top nodes other than root, but we // still check to see if the node is fixable with a different version, // and if that is a semver major bump. @@ -289,6 +293,7 @@ class AuditReport extends Map { try { // first try the super fast bulk advisory listing const body = prepareBulkData(this.tree, this[_omit]) + this.log.silly('audit', 'bulk request', body) // no sense asking if we don't have anything to audit, // we know it'll be empty @@ -304,7 +309,8 @@ class AuditReport extends Map { }) return await res.json() - } catch (_) { + } catch (er) { + this.log.silly('audit', 'bulk request failed', String(er.body)) // that failed, try the quick audit endpoint const body = prepareData(this.tree, this.options) const res = await fetch('/-/npm/v1/security/audits/quick', { @@ -330,6 +336,7 @@ class AuditReport extends Map { // return true if we should ignore this one const shouldOmit = (node, omit) => !node.version ? true + : node.isRoot ? true : omit.size === 0 ? false : node.dev && omit.has('dev') || node.optional && omit.has('optional') || @@ -338,9 +345,9 @@ const shouldOmit = (node, omit) => const prepareBulkData = (tree, omit) => { const payload = {} - for (const name of tree.inventory.query('name')) { + for (const name of tree.inventory.query('packageName')) { const set = new Set() - for (const node of tree.inventory.query('name', name)) { + for (const node of tree.inventory.query('packageName', name)) { if (shouldOmit(node, omit)) continue diff --git a/node_modules/@npmcli/arborist/lib/dep-spec.js b/node_modules/@npmcli/arborist/lib/dep-spec.js deleted file mode 100644 index 92911543e168..000000000000 --- a/node_modules/@npmcli/arborist/lib/dep-spec.js +++ /dev/null @@ -1,43 +0,0 @@ -const types = [ - 'peerDependencies', - 'devDependencies', - 'optionalDependencies', - 'dependencies', -] - -const findType = (pkg, name) => { - for (const t of types) { - if (pkg[t] && typeof pkg[t] === 'object' && pkg[t][name] !== undefined) - return t - } - return 'dependencies' -} - -// given a dep name and spec, update it wherever it exists in -// the manifest, or add the spec to 'dependencies' if not found. -const updateDepSpec = (pkg, name, newSpec) => { - const type = findType(pkg, name) - pkg[type] = pkg[type] || {} - pkg[type][name] = newSpec - return pkg -} - -// sort alphabetically all types of deps for a given package -const orderDeps = (pkg) => { - for (const type of types) { - if (pkg && pkg[type]) { - pkg[type] = Object.keys(pkg[type]) - .sort((a, b) => a.localeCompare(b)) - .reduce((res, key) => { - res[key] = pkg[type][key] - return res - }, {}) - } - } - return pkg -} - -module.exports = { - orderDeps, - updateDepSpec, -} diff --git a/node_modules/@npmcli/arborist/lib/inventory.js b/node_modules/@npmcli/arborist/lib/inventory.js index cef0c4e26589..757829188522 100644 --- a/node_modules/@npmcli/arborist/lib/inventory.js +++ b/node_modules/@npmcli/arborist/lib/inventory.js @@ -4,7 +4,7 @@ // keys is the set of fields to be able to query. const _primaryKey = Symbol('_primaryKey') const _index = Symbol('_index') -const defaultKeys = ['name', 'license', 'funding', 'realpath'] +const defaultKeys = ['name', 'license', 'funding', 'realpath', 'packageName'] const { hasOwnProperty } = Object.prototype const debug = require('./debug.js') class Inventory extends Map { diff --git a/node_modules/@npmcli/arborist/lib/node.js b/node_modules/@npmcli/arborist/lib/node.js index a54f76afcdf3..370bfc9567d2 100644 --- a/node_modules/@npmcli/arborist/lib/node.js +++ b/node_modules/@npmcli/arborist/lib/node.js @@ -291,6 +291,10 @@ class Node { return this[_package].version || '' } + get packageName () { + return this[_package].name || null + } + get pkgid () { const { name = '', version = '' } = this.package // root package will prefer package name over folder name, @@ -350,10 +354,10 @@ class Node { } const why = { - name: this.isProjectRoot ? this.package.name : this.name, + name: this.isProjectRoot ? this.packageName : this.name, version: this.package.version, } - if (this.errors.length || !this.package.name || !this.package.version) { + if (this.errors.length || !this.packageName || !this.package.version) { why.errors = this.errors.length ? this.errors : [ new Error('invalid package: lacks name and/or version'), ] @@ -460,7 +464,7 @@ class Node { if (this.isProjectRoot) return false const { root } = this - const { type, to } = root.edgesOut.get(this.package.name) || {} + const { type, to } = root.edgesOut.get(this.packageName) || {} return type === 'workspace' && to && (to.target === this || to === this) } @@ -730,20 +734,14 @@ class Node { [_loadDeps] () { // Caveat! Order is relevant! - // packages in optionalDependencies and prod/peer/dev are - // optional. Packages in both deps and devDeps are required. + // Packages in optionalDependencies are optional. + // Packages in both deps and devDeps are required. // Note the subtle breaking change from v6: it is no longer possible // to have a different spec for a devDep than production dep. - this[_loadDepType](this.package.optionalDependencies, 'optional') // Linked targets that are disconnected from the tree are tops, // but don't have a 'path' field, only a 'realpath', because we // don't know their canonical location. We don't need their devDeps. - const { isTop, path, sourceReference } = this - const { isTop: srcTop, path: srcPath } = sourceReference || {} - if (isTop && path && (!sourceReference || srcTop && srcPath)) - this[_loadDepType](this.package.devDependencies, 'dev') - const pd = this.package.peerDependencies if (pd && typeof pd === 'object' && !this.legacyPeerDeps) { const pm = this.package.peerDependenciesMeta || {} @@ -760,19 +758,22 @@ class Node { } this[_loadDepType](this.package.dependencies, 'prod') + this[_loadDepType](this.package.optionalDependencies, 'optional') + + const { isTop, path, sourceReference } = this + const { isTop: srcTop, path: srcPath } = sourceReference || {} + if (isTop && path && (!sourceReference || srcTop && srcPath)) + this[_loadDepType](this.package.devDependencies, 'dev') } - [_loadDepType] (obj, type) { - const from = this + [_loadDepType] (deps, type) { const ad = this.package.acceptDependencies || {} - for (const [name, spec] of Object.entries(obj || {})) { - const accept = ad[name] - // if it's already set, then we keep the existing edge - // Prod deps should not be marked as dev, however. - // NB: the Edge ctor adds itself to from.edgesOut + // Because of the order in which _loadDeps runs, we always want to + // prioritize a new edge over an existing one + for (const [name, spec] of Object.entries(deps || {})) { const current = this.edgesOut.get(name) - if (!current || current.dev && type === 'prod') - new Edge({ from, name, spec, accept, type }) + if (!current || current.type !== 'workspace') + new Edge({ from: this, name, spec, accept: ad[name], type }) } } @@ -965,8 +966,8 @@ class Node { // if no resolved, check both package name and version // otherwise, conclude that they are different things - return this.package.name && node.package.name && - this.package.name === node.package.name && + return this.packageName && node.packageName && + this.packageName === node.packageName && this.version && node.version && this.version === node.version } diff --git a/node_modules/@npmcli/arborist/lib/printable.js b/node_modules/@npmcli/arborist/lib/printable.js index 79f46a9e93c4..e611f55a4bd6 100644 --- a/node_modules/@npmcli/arborist/lib/printable.js +++ b/node_modules/@npmcli/arborist/lib/printable.js @@ -7,8 +7,8 @@ const relpath = require('./relpath.js') class ArboristNode { constructor (tree, path) { this.name = tree.name - if (tree.package.name && tree.package.name !== this.name) - this.packageName = tree.package.name + if (tree.packageName && tree.packageName !== this.name) + this.packageName = tree.packageName if (tree.version) this.version = tree.version this.location = tree.location diff --git a/node_modules/@npmcli/arborist/lib/shrinkwrap.js b/node_modules/@npmcli/arborist/lib/shrinkwrap.js index 342e78e9e3a7..d9065ffa0258 100644 --- a/node_modules/@npmcli/arborist/lib/shrinkwrap.js +++ b/node_modules/@npmcli/arborist/lib/shrinkwrap.js @@ -254,7 +254,7 @@ class Shrinkwrap { meta[key.replace(/^_/, '')] = val }) // we only include name if different from the node path name - const pname = node.package.name + const pname = node.packageName if (pname && pname !== node.name) meta.name = pname @@ -825,7 +825,7 @@ class Shrinkwrap { [_buildLegacyLockfile] (node, lock, path = []) { if (node === this.tree) { // the root node - lock.name = node.package.name || node.name + lock.name = node.packageName || node.name if (node.version) lock.version = node.version } @@ -870,9 +870,9 @@ class Shrinkwrap { lock.from = spec.raw } else if (!node.isRoot && node.package && - node.package.name && - node.package.name !== node.name) - lock.version = `npm:${node.package.name}@${node.version}` + node.packageName && + node.packageName !== node.name) + lock.version = `npm:${node.packageName}@${node.version}` else if (node.package && node.version) lock.version = node.version diff --git a/node_modules/@npmcli/arborist/lib/update-root-package-json.js b/node_modules/@npmcli/arborist/lib/update-root-package-json.js index aba5614924ec..4a88707b9c47 100644 --- a/node_modules/@npmcli/arborist/lib/update-root-package-json.js +++ b/node_modules/@npmcli/arborist/lib/update-root-package-json.js @@ -6,8 +6,6 @@ const {resolve} = require('path') const parseJSON = require('json-parse-even-better-errors') -const { orderDeps } = require('./dep-spec.js') - const depTypes = new Set([ 'dependencies', 'optionalDependencies', @@ -15,6 +13,20 @@ const depTypes = new Set([ 'peerDependencies', ]) +// sort alphabetically all types of deps for a given package +const orderDeps = (pkg) => { + for (const type of depTypes) { + if (pkg && pkg[type]) { + pkg[type] = Object.keys(pkg[type]) + .sort((a, b) => a.localeCompare(b)) + .reduce((res, key) => { + res[key] = pkg[type][key] + return res + }, {}) + } + } + return pkg +} const parseJsonSafe = json => { try { return parseJSON(json) diff --git a/node_modules/@npmcli/arborist/lib/vuln.js b/node_modules/@npmcli/arborist/lib/vuln.js index 8f887a3fc96c..2561bc80646c 100644 --- a/node_modules/@npmcli/arborist/lib/vuln.js +++ b/node_modules/@npmcli/arborist/lib/vuln.js @@ -83,6 +83,9 @@ class Vuln { if (!specObj.registry) return true + if (specObj.subSpec) + spec = specObj.subSpec.rawSpec + for (const v of this.versions) { if (satisfies(v, spec) && !satisfies(v, this.range, semverOpt)) return false diff --git a/node_modules/@npmcli/arborist/package.json b/node_modules/@npmcli/arborist/package.json index e7ac932e08d8..ebc84f6fc32a 100644 --- a/node_modules/@npmcli/arborist/package.json +++ b/node_modules/@npmcli/arborist/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/arborist", - "version": "2.4.1", + "version": "2.4.2", "description": "Manage node_modules trees", "dependencies": { "@npmcli/installed-package-contents": "^1.0.7", diff --git a/package-lock.json b/package-lock.json index 497fa50ad77c..17cd843bbe6a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -78,7 +78,7 @@ ], "license": "Artistic-2.0", "dependencies": { - "@npmcli/arborist": "^2.4.1", + "@npmcli/arborist": "^2.4.2", "@npmcli/ci-detect": "^1.2.0", "@npmcli/config": "^2.2.0", "@npmcli/run-script": "^1.8.5", @@ -712,9 +712,9 @@ } }, "node_modules/@npmcli/arborist": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-2.4.1.tgz", - "integrity": "sha512-LivXfK+LjtvzFjnwK6E41Pkw1C8+MYrgdXinzqpDc8MDYp7gMT0nvGvnpQd47OV2GhLRyBkbUSEcLk6P1d1s0g==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-2.4.2.tgz", + "integrity": "sha512-QrsMrRWzO1D2EmPQheyPz1yRnnmln6vPe4SujV4cRF0v9qIAQbD8M0dMH6K3y+w/2X3t7vg5lx20LHXsbcu7lw==", "inBundle": true, "dependencies": { "@npmcli/installed-package-contents": "^1.0.7", @@ -10830,9 +10830,9 @@ "dev": true }, "@npmcli/arborist": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-2.4.1.tgz", - "integrity": "sha512-LivXfK+LjtvzFjnwK6E41Pkw1C8+MYrgdXinzqpDc8MDYp7gMT0nvGvnpQd47OV2GhLRyBkbUSEcLk6P1d1s0g==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-2.4.2.tgz", + "integrity": "sha512-QrsMrRWzO1D2EmPQheyPz1yRnnmln6vPe4SujV4cRF0v9qIAQbD8M0dMH6K3y+w/2X3t7vg5lx20LHXsbcu7lw==", "requires": { "@npmcli/installed-package-contents": "^1.0.7", "@npmcli/map-workspaces": "^1.0.2", diff --git a/package.json b/package.json index 3839d3b30142..ea26dd9a3dfd 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "./package.json": "./package.json" }, "dependencies": { - "@npmcli/arborist": "^2.4.1", + "@npmcli/arborist": "^2.4.2", "@npmcli/ci-detect": "^1.2.0", "@npmcli/config": "^2.2.0", "@npmcli/run-script": "^1.8.5",