mirror of
https://github.com/pnpm/pnpm.git
synced 2026-03-27 03:21:55 -04:00
* refactor: simplify patchedDependencies lockfile format to map selectors to hashes
Remove the `path` field from patchedDependencies in the lockfile, changing the
format from `Record<string, { path: string, hash: string }>` to
`Record<string, string>` (selector → hash). The path was never consumed from
the lockfile — patch file paths come from user config, not the lockfile.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: migrate old patchedDependencies format when reading lockfile
When reading a lockfile with the old `{ path, hash }` format for
patchedDependencies, extract just the hash string. This ensures
backwards compatibility with existing lockfiles.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: carry patchFilePath through patch groups for runtime patch application
The previous commit removed `path` from the lockfile format but also
accidentally dropped it from the runtime PatchInfo type. This broke
patch application since `applyPatchToDir` needs the file path.
- Add optional `patchFilePath` to `PatchInfo` for runtime use
- Build patch groups with resolved file paths in install
- Fix `build-modules` to use `patchFilePath` instead of `file.path`
- Fix `calcPatchHashes` call site in `checkDepsStatus` (extra arg)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: update remaining references to old PatchFile type
- Update getPatchInfo tests to use { hash, key } instead of { file, key }
- Fix createDeployFiles to handle patchedDependencies as hash strings
- Fix configurationalDependencies test assertion
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: throw when patch exists but patchFilePath is missing
Also guard against undefined patchedDependencies entry when
ignorePackageManifest is true.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: don't join lockfileDir with already-absolute patch file paths
opts.patchedDependencies values are already absolute paths, so
path.join(opts.lockfileDir, absolutePath) created invalid doubled
paths like /project/home/runner/work/pnpm/...
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use path.resolve for patch file paths and address Copilot review
- Use path.resolve instead of path.join to correctly handle both
relative and absolute patch file paths
- Use PnpmError instead of plain Error for missing patch file path
- Only copy patchedDependencies to deploy output when manifest
provides the patch file paths
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: pass rootProjectManifest in deploy patchedDependencies test
The test was missing rootProjectManifest, so createDeployFiles could
not find the manifest's patchedDependencies to propagate to the
deploy output.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
168 lines
5.7 KiB
TypeScript
168 lines
5.7 KiB
TypeScript
import { getPatchInfo } from '../src/getPatchInfo.js'
|
|
import type { PatchGroupRecord } from '../src/index.js'
|
|
|
|
test('getPatchInfo(undefined, ...) returns undefined', () => {
|
|
expect(getPatchInfo(undefined, 'foo', '1.0.0')).toBeUndefined()
|
|
})
|
|
|
|
test('getPatchInfo() returns an exact version patch if the name and version match', () => {
|
|
const patchedDependencies = {
|
|
foo: {
|
|
exact: {
|
|
'1.0.0': {
|
|
hash: '00000000000000000000000000000000',
|
|
key: 'foo@1.0.0',
|
|
},
|
|
},
|
|
range: [],
|
|
all: undefined,
|
|
},
|
|
} satisfies PatchGroupRecord
|
|
expect(getPatchInfo(patchedDependencies, 'foo', '1.0.0')).toStrictEqual(patchedDependencies.foo.exact['1.0.0'])
|
|
expect(getPatchInfo(patchedDependencies, 'foo', '1.1.0')).toBeUndefined()
|
|
expect(getPatchInfo(patchedDependencies, 'foo', '2.0.0')).toBeUndefined()
|
|
expect(getPatchInfo(patchedDependencies, 'bar', '1.0.0')).toBeUndefined()
|
|
})
|
|
|
|
test('getPatchInfo() returns a range version patch if the name matches and the version satisfied', () => {
|
|
const patchedDependencies = {
|
|
foo: {
|
|
exact: {},
|
|
range: [{
|
|
version: '1',
|
|
patch: {
|
|
hash: '00000000000000000000000000000000',
|
|
key: 'foo@1',
|
|
},
|
|
}],
|
|
all: undefined,
|
|
},
|
|
} satisfies PatchGroupRecord
|
|
expect(getPatchInfo(patchedDependencies, 'foo', '1.0.0')).toStrictEqual(patchedDependencies.foo.range[0].patch)
|
|
expect(getPatchInfo(patchedDependencies, 'foo', '1.1.0')).toStrictEqual(patchedDependencies.foo.range[0].patch)
|
|
expect(getPatchInfo(patchedDependencies, 'foo', '2.0.0')).toBeUndefined()
|
|
expect(getPatchInfo(patchedDependencies, 'bar', '1.0.0')).toBeUndefined()
|
|
})
|
|
|
|
test('getPatchInfo() returns name-only patch if the name matches', () => {
|
|
const patchedDependencies = {
|
|
foo: {
|
|
exact: {},
|
|
range: [],
|
|
all: {
|
|
hash: '00000000000000000000000000000000',
|
|
key: 'foo',
|
|
},
|
|
},
|
|
} satisfies PatchGroupRecord
|
|
expect(getPatchInfo(patchedDependencies, 'foo', '1.0.0')).toStrictEqual(patchedDependencies.foo.all)
|
|
expect(getPatchInfo(patchedDependencies, 'foo', '1.1.0')).toStrictEqual(patchedDependencies.foo.all)
|
|
expect(getPatchInfo(patchedDependencies, 'foo', '2.0.0')).toStrictEqual(patchedDependencies.foo.all)
|
|
expect(getPatchInfo(patchedDependencies, 'bar', '1.0.0')).toBeUndefined()
|
|
})
|
|
|
|
test('exact version patches override version range patches, version range patches override name-only patches', () => {
|
|
const patchedDependencies = {
|
|
foo: {
|
|
exact: {
|
|
'1.0.0': {
|
|
hash: '00000000000000000000000000000000',
|
|
key: 'foo@1.0.0',
|
|
},
|
|
'1.1.0': {
|
|
hash: '00000000000000000000000000000000',
|
|
key: 'foo@1.1.0',
|
|
},
|
|
},
|
|
range: [
|
|
{
|
|
version: '1',
|
|
patch: {
|
|
hash: '00000000000000000000000000000000',
|
|
key: 'foo@1',
|
|
},
|
|
},
|
|
{
|
|
version: '2',
|
|
patch: {
|
|
hash: '00000000000000000000000000000000',
|
|
key: 'foo@2',
|
|
},
|
|
},
|
|
],
|
|
all: {
|
|
hash: '00000000000000000000000000000000',
|
|
key: 'foo',
|
|
},
|
|
},
|
|
} satisfies PatchGroupRecord
|
|
expect(getPatchInfo(patchedDependencies, 'foo', '1.0.0')).toStrictEqual(patchedDependencies.foo.exact['1.0.0'])
|
|
expect(getPatchInfo(patchedDependencies, 'foo', '1.1.0')).toStrictEqual(patchedDependencies.foo.exact['1.1.0'])
|
|
expect(getPatchInfo(patchedDependencies, 'foo', '1.1.1')).toStrictEqual(patchedDependencies.foo.range[0].patch)
|
|
expect(getPatchInfo(patchedDependencies, 'foo', '2.0.0')).toStrictEqual(patchedDependencies.foo.range[1].patch)
|
|
expect(getPatchInfo(patchedDependencies, 'foo', '2.1.0')).toStrictEqual(patchedDependencies.foo.range[1].patch)
|
|
expect(getPatchInfo(patchedDependencies, 'foo', '3.0.0')).toStrictEqual(patchedDependencies.foo.all)
|
|
expect(getPatchInfo(patchedDependencies, 'bar', '1.0.0')).toBeUndefined()
|
|
})
|
|
|
|
test('getPatchInfo(_, name, version) throws an error when name@version matches more than one version range patches', () => {
|
|
const patchedDependencies = {
|
|
foo: {
|
|
exact: {},
|
|
range: [
|
|
{
|
|
version: '>=1.0.0 <3.0.0',
|
|
patch: {
|
|
hash: '00000000000000000000000000000000',
|
|
key: 'foo@>=1.0.0 <3.0.0',
|
|
},
|
|
},
|
|
{
|
|
version: '>=2.0.0',
|
|
patch: {
|
|
hash: '00000000000000000000000000000000',
|
|
key: 'foo@>=2.0.0',
|
|
},
|
|
},
|
|
],
|
|
all: undefined,
|
|
},
|
|
} satisfies PatchGroupRecord
|
|
expect(() => getPatchInfo(patchedDependencies, 'foo', '2.1.0')).toThrow(expect.objectContaining({
|
|
code: 'ERR_PNPM_PATCH_KEY_CONFLICT',
|
|
message: 'Unable to choose between 2 version ranges to patch foo@2.1.0: >=1.0.0 <3.0.0, >=2.0.0',
|
|
hint: 'Explicitly set the exact version (foo@2.1.0) to resolve conflict',
|
|
}))
|
|
})
|
|
|
|
test('getPatchInfo(_, name, version) does not throw an error when name@version matches an exact version patch and more than one version range patches', () => {
|
|
const patchedDependencies = {
|
|
foo: {
|
|
exact: {
|
|
'2.1.0': {
|
|
hash: '00000000000000000000000000000000',
|
|
key: 'foo@>=1.0.0 <3.0.0',
|
|
},
|
|
},
|
|
range: [
|
|
{
|
|
version: '>=1.0.0 <3.0.0',
|
|
patch: {
|
|
hash: '00000000000000000000000000000000',
|
|
key: 'foo@>=1.0.0 <3.0.0',
|
|
},
|
|
},
|
|
{
|
|
version: '>=2.0.0',
|
|
patch: {
|
|
hash: '00000000000000000000000000000000',
|
|
key: 'foo@>=2.0.0',
|
|
},
|
|
},
|
|
],
|
|
all: undefined,
|
|
},
|
|
} satisfies PatchGroupRecord
|
|
expect(getPatchInfo(patchedDependencies, 'foo', '2.1.0')).toStrictEqual(patchedDependencies.foo.exact['2.1.0'])
|
|
})
|