Skip to content

Commit fbe48a8

Browse files
authored
feat(arborist): add named updates validation (#4307)
* 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 [email protected]` Relates to: #4240
1 parent 1f853f8 commit fbe48a8

File tree

2 files changed

+32
-0
lines changed

2 files changed

+32
-0
lines changed

workspaces/arborist/lib/arborist/build-ideal-tree.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,22 @@ module.exports = cls => class IdealTreeBuilder extends cls {
269269
this[_complete] = !!options.complete
270270
this[_preferDedupe] = !!options.preferDedupe
271271
this[_legacyBundling] = !!options.legacyBundling
272+
273+
// validates list of update names, they must
274+
// be dep names only, no semver ranges are supported
275+
for (const name of update.names) {
276+
const spec = npa(name)
277+
const validationError =
278+
new TypeError(`Update arguments must not contain package version specifiers
279+
280+
Try using the package name instead, e.g:
281+
npm update ${spec.name}`)
282+
validationError.code = 'EUPDATEARGS'
283+
284+
if (spec.fetchSpec !== 'latest') {
285+
throw validationError
286+
}
287+
}
272288
this[_updateNames] = update.names
273289

274290
this[_updateAll] = update.all

workspaces/arborist/test/arborist/build-ideal-tree.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2098,6 +2098,22 @@ t.test('update global', async t => {
20982098

20992099
t.matchSnapshot(await printIdeal(path, { global: true, update: ['wrappy'] }),
21002100
'updating sub-dep has no effect')
2101+
2102+
const invalidArgs = [
2103+
2104+
'once@next',
2105+
'once@^1.0.0',
2106+
'once@>=2.0.0',
2107+
'once@2',
2108+
]
2109+
for (const updateName of invalidArgs) {
2110+
t.rejects(
2111+
printIdeal(path, { global: true, update: [updateName] }),
2112+
{ code: 'EUPDATEARGS' },
2113+
'should throw an error when using semver ranges'
2114+
)
2115+
}
2116+
21012117
t.matchSnapshot(await printIdeal(path, { global: true, update: ['once'] }),
21022118
'update a single dep')
21032119
t.matchSnapshot(await printIdeal(path, { global: true, update: true }),

0 commit comments

Comments
 (0)