Skip to content

Commit 66b46ab

Browse files
committed
fix: improve heuristics when dist-tags.latest is in range
Previously, there were two problems. First problem, even though we heuristically choose the version that best suits the stated 'engines' restriction, we were skipping that check when the 'defaultTag' (ie, 'latest', typically) version was a semver match. Second problem, the heuristic was improperly being set for 'staged' and 'restricted' packages, resulting in failure to sort those versions properly. Only choose the defaultTag version if it both a semver match, _and_ passes the engines/staged/restricted heuristics, and apply those heuristics properly in the sort that comes later, if the defaultTag version is not used. Related-to: npm/rfcs#405
1 parent e79d08b commit 66b46ab

File tree

2 files changed

+23
-6
lines changed

2 files changed

+23
-6
lines changed

index.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,15 @@ const pickManifest = (packument, wanted, opts) => {
123123
const defaultVer = distTags[defaultTag]
124124
if (defaultVer &&
125125
(range === '*' || semver.satisfies(defaultVer, range, { loose: true })) &&
126+
!restricted[defaultVer] &&
126127
!shouldAvoid(defaultVer, avoid)) {
127128
const mani = versions[defaultVer]
128-
if (mani && isBefore(verTimes, defaultVer, time)) {
129+
const ok = mani &&
130+
isBefore(verTimes, defaultVer, time) &&
131+
engineOk(mani, npmVersion, nodeVersion) &&
132+
!mani.deprecated &&
133+
!staged[defaultVer]
134+
if (ok) {
129135
return mani
130136
}
131137
}
@@ -155,10 +161,10 @@ const pickManifest = (packument, wanted, opts) => {
155161
const [verb, manib] = b
156162
const notavoida = !shouldAvoid(vera, avoid)
157163
const notavoidb = !shouldAvoid(verb, avoid)
158-
const notrestra = !restricted[a]
159-
const notrestrb = !restricted[b]
160-
const notstagea = !staged[a]
161-
const notstageb = !staged[b]
164+
const notrestra = !restricted[vera]
165+
const notrestrb = !restricted[verb]
166+
const notstagea = !staged[vera]
167+
const notstageb = !staged[verb]
162168
const notdepra = !mania.deprecated
163169
const notdeprb = !manib.deprecated
164170
const enginea = engineOk(mania, npmVersion, nodeVersion)

test/index.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ test('ETARGET if range does not match anything', t => {
130130

131131
test('E403 if version is forbidden', t => {
132132
const metadata = {
133+
'dist-tags': {
134+
latest: '2.1.0' // do not default the latest if restricted
135+
},
133136
policyRestrictions: {
134137
versions: {
135138
'2.1.0': { version: '2.1.0' }
@@ -141,6 +144,9 @@ test('E403 if version is forbidden', t => {
141144
'2.0.5': { version: '2.0.5' }
142145
}
143146
}
147+
t.equal(pickManifest(metadata, '2').version, '2.0.5')
148+
t.equal(pickManifest(metadata, '').version, '2.0.5')
149+
t.equal(pickManifest(metadata, '1 || 2').version, '2.0.5')
144150
t.throws(() => {
145151
pickManifest(metadata, '2.1.0')
146152
}, { code: 'E403' }, 'got correct error on match failure')
@@ -419,13 +425,18 @@ test('accepts opts.before option to do date-based cutoffs', t => {
419425

420426
test('prefers versions that satisfy the engines requirement', t => {
421427
const pack = {
428+
'dist-tags': {
429+
latest: '1.5.0' // do not default latest if engine mismatch
430+
},
422431
versions: {
423432
'1.0.0': { version: '1.0.0', engines: { node: '>=4' } },
424433
'1.1.0': { version: '1.1.0', engines: { node: '>=6' } },
425434
'1.2.0': { version: '1.2.0', engines: { node: '>=8' } },
426435
'1.3.0': { version: '1.3.0', engines: { node: '>=10' } },
427436
'1.4.0': { version: '1.4.0', engines: { node: '>=12' } },
428-
'1.5.0': { version: '1.5.0', engines: { node: '>=14' } }
437+
'1.5.0': { version: '1.5.0', engines: { node: '>=14' } },
438+
// not tagged as latest, won't be chosen by default
439+
'1.5.1': { version: '1.5.0', engines: { node: '>=14' } }
429440
}
430441
}
431442

0 commit comments

Comments
 (0)