Files
pnpm/installing/deps-resolver/test/linkPathToPeerVersion.test.ts
Zoltan Kochan c86c423bdc fix: preserve pnpm 10 peer suffix encoding for linked paths (#11297)
* fix: preserve pnpm 10 peer suffix encoding for linked paths

The filenamify upgrade from v4 to v7 changed the peer-suffix "version"
token for linked dependency paths: `../packages/b` became `+packages+b`
instead of `packages+b`, causing lockfile churn for workspaces with
packages linked from outside the workspace root.

Replace the filenamify call with a small inline encoder that reproduces
v4's output for link paths, and drop the now-unused dependency.

Closes #11272.

* chore: avoid cspell-flagged word in peer suffix comment

* test: cover linkPathToPeerVersion and clarify its lossy encoding

Address Copilot review feedback on #11297:
- Correct the comment — any leading run of `.` is dropped, not just
  `./` and `../` segments (so `.hidden/pkg` becomes `hidden+pkg`).
- Export the helper and add a focused test that pins the exact token
  output for link paths, so future lockfile-breaking regressions get
  caught by the test suite.

* refactor: extract linkPathToPeerVersion into its own file
2026-04-19 12:57:16 +02:00

33 lines
1.1 KiB
TypeScript

import { linkPathToPeerVersion } from '../lib/linkPathToPeerVersion.js'
// These outputs are lockfile-format: changing any of them breaks existing
// v9 lockfiles. See https://github.com/pnpm/pnpm/issues/11272.
test.each([
// The case from #11272: link target outside the workspace root.
['../packages/b', 'packages+b'],
['./packages/b', 'packages+b'],
['packages/b', 'packages+b'],
['../../a/b', '..+a+b'],
['a/b/c', 'a+b+c'],
['abc', 'abc'],
// Leading dots collapse and are stripped.
['..', '+'],
['...', '+'],
['.hidden/pkg', 'hidden+pkg'],
// Windows-style separators and mixed reserved characters.
['..\\packages\\b', 'packages+b'],
['a/b\\c', 'a+b+c'],
// Literal '+' characters collapse with adjacent separators.
['foo+bar', 'foo+bar'],
['foo++bar', 'foo+bar'],
['+foo', 'foo'],
['foo+', 'foo'],
// Trailing dots are stripped.
['foo.', 'foo'],
['abc...', 'abc'],
// Empty input stays empty.
['', ''],
])('linkPathToPeerVersion(%j) === %j', (input, expected) => {
expect(linkPathToPeerVersion(input)).toBe(expected)
})