feat: deprecate $ version references in overrides (#12262)

Using the "$" syntax in overrides (e.g. "react": "$react") now emits a
deprecation warning. The syntax still resolves as before. Catalogs are the
recommended replacement: reference a catalog entry with the "catalog:"
protocol.

Refs pnpm/pnpm#12160
This commit is contained in:
Zoltan Kochan
2026-06-08 14:00:05 +02:00
committed by GitHub
parent 9777566bf4
commit 894ea6af2c
3 changed files with 66 additions and 2 deletions

View File

@@ -0,0 +1,6 @@
---
"@pnpm/config.reader": patch
"pnpm": patch
---
Using the `$` version reference syntax in `overrides` (e.g. `"react": "$react"`) now prints a deprecation warning. The syntax still works, but [catalogs](https://pnpm.io/catalogs) are the recommended way to keep an overridden version in sync with the rest of the workspace. Reference a catalog entry with the `catalog:` protocol instead.

View File

@@ -2,6 +2,7 @@ import path from 'node:path'
import { envReplace } from '@pnpm/config.env-replace'
import { PnpmError } from '@pnpm/error'
import { globalWarn } from '@pnpm/logger'
import type {
AllowedDeprecatedVersions,
PackageExtension,
@@ -31,8 +32,11 @@ export function getOptionsFromPnpmSettings (manifestDir: string | undefined, pnp
assertValidOverrides(settings.overrides)
if (Object.keys(settings.overrides).length === 0) {
delete settings.overrides
} else if (manifest) {
settings.overrides = mapValues(createVersionReferencesReplacer(manifest), settings.overrides)
} else {
warnAboutDeprecatedVersionReferences(settings.overrides)
if (manifest) {
settings.overrides = mapValues(createVersionReferencesReplacer(manifest), settings.overrides)
}
}
}
if (pnpmSettings.patchedDependencies) {
@@ -92,6 +96,16 @@ function replaceEnvInStringValues (value: unknown): unknown {
return out
}
function warnAboutDeprecatedVersionReferences (overrides: Record<string, string>): void {
const selectors = Object.keys(overrides).filter((selector) => overrides[selector][0] === '$')
if (selectors.length === 0) return
globalWarn(
`The "$" version reference syntax in overrides is deprecated (used by: ${selectors.join(', ')}). ` +
'Define the version in a catalog and reference it with the "catalog:" protocol instead. ' +
'See https://pnpm.io/catalogs'
)
}
function createVersionReferencesReplacer (manifest: ProjectManifest): (spec: string) => string {
const allDeps = {
...manifest.devDependencies,

View File

@@ -0,0 +1,44 @@
import { beforeEach, expect, jest, test } from '@jest/globals'
jest.unstable_mockModule('@pnpm/logger', () => ({
globalWarn: jest.fn(),
}))
const { globalWarn } = await import('@pnpm/logger')
const { getOptionsFromPnpmSettings } = await import('../lib/getOptionsFromRootManifest.js')
beforeEach(() => {
jest.mocked(globalWarn).mockClear()
})
test('getOptionsFromPnpmSettings() warns about deprecated "$" version references and still resolves them', () => {
const options = getOptionsFromPnpmSettings(process.cwd(), {
overrides: {
foo: '$foo',
},
}, {
dependencies: {
foo: '^1.0.0',
},
})
expect(options.overrides).toStrictEqual({ foo: '^1.0.0' })
expect(globalWarn).toHaveBeenCalledTimes(1)
const warning = jest.mocked(globalWarn).mock.calls[0][0]
expect(warning).toContain('deprecated')
expect(warning).toContain('foo')
expect(warning).toContain('catalog:')
})
test('getOptionsFromPnpmSettings() does not warn when no "$" version references are used', () => {
getOptionsFromPnpmSettings(process.cwd(), {
overrides: {
foo: '^1.0.0',
bar: 'catalog:',
},
}, {
dependencies: {
foo: '^1.0.0',
},
})
expect(globalWarn).not.toHaveBeenCalled()
})