fix: incorrect depPath format used in time pruning (#10907)

* fix: depPath format used in time pruning

The local `refToRelative` helper in `lockfileFormatConverters.ts` produced
dependency paths with a leading slash (e.g. `/foo@1.0.0`), while the keys
stored in the `time` field do not have one (e.g. `foo@1.0.0`).

Because of this mismatch, `rootDepPaths.has(depPath)` always returned false
inside `pruneTimeInLockfile`, so `pickBy` filtered out every entry and the
entire `time` field was cleared on every install.

Fix by replacing the local helper with `refToRelative` from
`@pnpm/dependency-path`, which produces the correct format.

* chore: add pnpm to changeset

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
nozaq
2026-03-13 21:01:08 +09:00
committed by GitHub
parent 61f94906ea
commit d458ab318c
3 changed files with 14 additions and 24 deletions

View File

@@ -0,0 +1,6 @@
---
"@pnpm/lockfile.fs": patch
"pnpm": patch
---
Fixed the `time` field in `pnpm-lock.yaml` being entirely wiped on every install. An incorrect dependency path format was used when matching entries to prune, causing all entries to always be removed.

View File

@@ -1,5 +1,5 @@
import { LOCKFILE_VERSION } from '@pnpm/constants'
import { removeSuffix } from '@pnpm/dependency-path'
import { refToRelative, removeSuffix } from '@pnpm/dependency-path'
import type {
LockfileFile,
LockfileFileProjectResolvedDependencies,
@@ -124,22 +124,6 @@ function pruneTimeInLockfile (time: Record<string, string>, importers: Record<st
return pickBy((_, depPath) => rootDepPaths.has(depPath), time)
}
function refToRelative (
reference: string,
pkgName: string
): string | null {
if (reference.startsWith('link:')) {
return null
}
if (reference.startsWith('file:')) {
return reference
}
if (!reference.includes('/') || !reference.replace(/(?:\([^)]+\))+$/, '').includes('/')) {
return `/${pkgName}@${reference}`
}
return reference
}
export function convertToLockfileObject (lockfile: LockfileFile): LockfileObject {
const { importers, ...rest } = lockfile

View File

@@ -57,10 +57,10 @@ test('redundant fields are removed from "time"', () => {
},
},
time: {
'/bar@1.0.0': '2021-02-11T22:54:29.120Z',
'/foo@1.0.0': '2021-02-11T22:54:29.120Z',
'/qar@1.0.0': '2021-02-11T22:54:29.120Z',
'/zoo@1.0.0': '2021-02-11T22:54:29.120Z',
'bar@1.0.0': '2021-02-11T22:54:29.120Z',
'foo@1.0.0': '2021-02-11T22:54:29.120Z',
'qar@1.0.0': '2021-02-11T22:54:29.120Z',
'zoo@1.0.0': '2021-02-11T22:54:29.120Z',
},
})).toStrictEqual({
lockfileVersion: LOCKFILE_VERSION,
@@ -87,9 +87,9 @@ test('redundant fields are removed from "time"', () => {
},
},
time: {
'/bar@1.0.0': '2021-02-11T22:54:29.120Z',
'/foo@1.0.0': '2021-02-11T22:54:29.120Z',
'/qar@1.0.0': '2021-02-11T22:54:29.120Z',
'bar@1.0.0': '2021-02-11T22:54:29.120Z',
'foo@1.0.0': '2021-02-11T22:54:29.120Z',
'qar@1.0.0': '2021-02-11T22:54:29.120Z',
},
})
})