fix: prefer non-deprecated versions when resolving fallback dist-tags (#10004)

close #9987
This commit is contained in:
Zoltan Kochan
2025-09-20 11:03:18 +02:00
committed by GitHub
parent 6633eb3eb0
commit 702ddb9ee8
3 changed files with 71 additions and 1 deletions

View File

@@ -0,0 +1,6 @@
---
"@pnpm/npm-resolver": patch
"pnpm": patch
---
When `minimumReleaseAge` is set and the `latest` tag is not mature enough, prefer a non-deprecated version as the new `latest` [#9987](https://github.com/pnpm/pnpm/issues/9987).

View File

@@ -277,7 +277,12 @@ function filterMetaByPublishedDate (meta: PackageMetaWithTime, publishedBy: Date
bestVersion = candidate
} else {
try {
if (semver.gt(candidate, bestVersion, true)) {
const candidateIsDeprecated = meta.versions[candidate].deprecated != null
const bestVersionIsDeprecated = meta.versions[bestVersion].deprecated != null
if (
(semver.gt(candidate, bestVersion, true) && (bestVersionIsDeprecated === candidateIsDeprecated)) ||
(bestVersionIsDeprecated && !candidateIsDeprecated)
) {
bestVersion = candidate
}
} catch (err) {

View File

@@ -79,6 +79,65 @@ test('repopulate dist-tag to highest same-major version within the date cutoff',
expect(res!.id).toBe(`${name}@3.1.0`)
})
test('repopulate dist-tag to highest same-major version within the date cutoff. Prefer non-deprecated version', async () => {
const name = 'dist-tag-date'
const meta = {
name,
versions: {
'3.0.0': {
name,
version: '3.0.0',
dist: { tarball: `https://registry.npmjs.org/${name}/-/${name}-3.0.0.tgz` },
},
'3.1.0': {
name,
version: '3.1.0',
dist: { tarball: `https://registry.npmjs.org/${name}/-/${name}-3.1.0.tgz` },
deprecated: 'This version is deprecated',
},
'3.2.0': {
name,
version: '3.2.0',
dist: { tarball: `https://registry.npmjs.org/${name}/-/${name}-3.2.0.tgz` },
},
'2.9.9': {
name,
version: '2.9.9',
dist: { tarball: `https://registry.npmjs.org/${name}/-/${name}-2.9.9.tgz` },
},
},
'dist-tags': {
latest: '3.2.0',
},
time: {
'2.9.9': '2020-01-01T00:00:00.000Z',
'3.0.0': '2020-02-01T00:00:00.000Z',
'3.1.0': '2020-03-01T00:00:00.000Z',
'3.2.0': '2020-05-01T00:00:00.000Z',
},
}
// Cutoff before 3.2.0, so latest must be remapped to 3.1.0 (same major 3)
const cutoff = new Date('2020-04-01T00:00:00.000Z')
nock(registries.default)
.get(`/${name}`)
.reply(200, meta)
const cacheDir = tempy.directory()
const { resolveFromNpm } = createResolveFromNpm({
cacheDir,
fullMetadata: true,
registries,
})
const res = await resolveFromNpm({ alias: name, bareSpecifier: 'latest' }, {
publishedBy: cutoff,
})
expect(res!.id).toBe(`${name}@3.0.0`)
})
test('repopulate dist-tag to highest non-prerelease same-major version within the date cutoff', async () => {
const name = 'dist-tag-date'
const meta = {