From f2a7d1292daafe478a4872d1d5bea7560ceb75b9 Mon Sep 17 00:00:00 2001 From: Ruy Adorno Date: Fri, 21 Jan 2022 14:56:29 -0500 Subject: [PATCH 1/2] feat(arborist): add named updates validation Arborist update does not support anything other than dependency names, that is confusing to some users that are used to provide semver ranges when using `npm install` and other commands. This changeset adds validation to the values provided as arguments in `npm update` and will throw a `EUPDATEARGS` error in case the user tries to use semver ranges, e.g: `npm update abbrev@1.0.0` Relates to: https://github.com/npm/cli/issues/4240 --- .../arborist/lib/arborist/build-ideal-tree.js | 12 ++++++++++++ .../arborist/test/arborist/build-ideal-tree.js | 16 ++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/workspaces/arborist/lib/arborist/build-ideal-tree.js b/workspaces/arborist/lib/arborist/build-ideal-tree.js index f20a554bd5ee8..7f797d3b4c8a6 100644 --- a/workspaces/arborist/lib/arborist/build-ideal-tree.js +++ b/workspaces/arborist/lib/arborist/build-ideal-tree.js @@ -269,6 +269,18 @@ module.exports = cls => class IdealTreeBuilder extends cls { this[_complete] = !!options.complete this[_preferDedupe] = !!options.preferDedupe this[_legacyBundling] = !!options.legacyBundling + + // validates list of update names, they must + // be dep names only, no semver ranges are supported + const validationError = + new TypeError('Update arguments must not contain semver ranges') + validationError.code = 'EUPDATEARGS' + for (const name of update.names) { + const spec = npa(name) + if (spec.fetchSpec !== 'latest') { + throw validationError + } + } this[_updateNames] = update.names this[_updateAll] = update.all diff --git a/workspaces/arborist/test/arborist/build-ideal-tree.js b/workspaces/arborist/test/arborist/build-ideal-tree.js index 2c058a6a3283e..a07d3b2f6cd15 100644 --- a/workspaces/arborist/test/arborist/build-ideal-tree.js +++ b/workspaces/arborist/test/arborist/build-ideal-tree.js @@ -2094,6 +2094,22 @@ t.test('update global', async t => { }) t.matchSnapshot(await printIdeal(path, { global: true, update: ['wrappy'] }), 'updating sub-dep has no effect') + + const invalidArgs = [ + 'once@1.4.0', + 'once@next', + 'once@^1.0.0', + 'once@>=2.0.0', + 'once@2', + ] + for (const updateName of invalidArgs) { + t.rejects( + printIdeal(path, { global: true, update: [updateName] }), + { code: 'EUPDATEARGS' }, + 'should throw an error when using semver ranges' + ) + } + t.matchSnapshot(await printIdeal(path, { global: true, update: ['once'] }), 'update a single dep') t.matchSnapshot(await printIdeal(path, { global: true, update: true }), From ee78143c2e70dfe4cd95ea7b741dbe825b26b0db Mon Sep 17 00:00:00 2001 From: Ruy Adorno Date: Tue, 25 Jan 2022 19:05:01 -0500 Subject: [PATCH 2/2] fixup! feat(arborist): add named updates validation --- workspaces/arborist/lib/arborist/build-ideal-tree.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/workspaces/arborist/lib/arborist/build-ideal-tree.js b/workspaces/arborist/lib/arborist/build-ideal-tree.js index 7f797d3b4c8a6..ec6933303b3f5 100644 --- a/workspaces/arborist/lib/arborist/build-ideal-tree.js +++ b/workspaces/arborist/lib/arborist/build-ideal-tree.js @@ -272,11 +272,15 @@ module.exports = cls => class IdealTreeBuilder extends cls { // validates list of update names, they must // be dep names only, no semver ranges are supported - const validationError = - new TypeError('Update arguments must not contain semver ranges') - validationError.code = 'EUPDATEARGS' for (const name of update.names) { const spec = npa(name) + const validationError = + new TypeError(`Update arguments must not contain package version specifiers + +Try using the package name instead, e.g: + npm update ${spec.name}`) + validationError.code = 'EUPDATEARGS' + if (spec.fetchSpec !== 'latest') { throw validationError }