mirror of
https://github.com/pnpm/pnpm.git
synced 2026-04-28 02:53:15 -04:00
fix: prevent catalog: from leaking into pnpm-workspace.yaml (#10476)
close #10176
This commit is contained in:
6
.changeset/fix-catalog-strict-mode-write.md
Normal file
6
.changeset/fix-catalog-strict-mode-write.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@pnpm/resolve-dependencies": patch
|
||||
"pnpm": patch
|
||||
---
|
||||
|
||||
Fixed a bug where `catalogMode: strict` would write the literal string `"catalog:"` to `pnpm-workspace.yaml` instead of the resolved version specifier when re-adding an existing catalog dependency [#10176](https://github.com/pnpm/pnpm/issues/10176).
|
||||
@@ -1340,6 +1340,65 @@ describe('add', () => {
|
||||
})
|
||||
})
|
||||
|
||||
// Regression test for https://github.com/pnpm/pnpm/issues/10176
|
||||
// When re-adding a dependency that already exists in the catalog with catalogMode: strict,
|
||||
// the catalog entry should preserve the original version specifier, not become 'catalog:'
|
||||
test('re-adding existing catalog dependency with catalogMode: strict preserves catalog specifier', async () => {
|
||||
const { options, projects, readLockfile } = preparePackagesAndReturnObjects([{
|
||||
name: 'project1',
|
||||
dependencies: {
|
||||
'is-positive': 'catalog:',
|
||||
},
|
||||
}])
|
||||
|
||||
// First, install the existing dependency with the catalog
|
||||
const mutateOpts = {
|
||||
...options,
|
||||
lockfileOnly: true,
|
||||
catalogs: {
|
||||
default: { 'is-positive': '^1.0.0' },
|
||||
},
|
||||
catalogMode: 'strict' as const,
|
||||
}
|
||||
|
||||
await mutateModules(installProjects(projects), mutateOpts)
|
||||
|
||||
// Verify initial state
|
||||
expect(readLockfile().catalogs?.default?.['is-positive']).toEqual({
|
||||
specifier: '^1.0.0',
|
||||
version: '1.0.0',
|
||||
})
|
||||
|
||||
// Now re-add the same dependency (simulating 'pnpm add is-positive' from a subpackage)
|
||||
const { updatedManifest, updatedCatalogs } = await addDependenciesToPackage(
|
||||
projects['project1' as ProjectId],
|
||||
['is-positive'],
|
||||
{
|
||||
...mutateOpts,
|
||||
dir: path.join(options.lockfileDir, 'project1'),
|
||||
allowNew: true,
|
||||
})
|
||||
|
||||
// The manifest should still use catalog:
|
||||
expect(updatedManifest).toEqual({
|
||||
name: 'project1',
|
||||
dependencies: {
|
||||
'is-positive': 'catalog:',
|
||||
},
|
||||
})
|
||||
|
||||
// The catalog should preserve the original specifier, NOT become 'catalog:'
|
||||
// This is the bug fix - previously it would incorrectly write 'catalog:' to the catalog
|
||||
if (updatedCatalogs?.default?.['is-positive']) {
|
||||
expect(updatedCatalogs.default['is-positive']).not.toBe('catalog:')
|
||||
expect(updatedCatalogs.default['is-positive']).toMatch(/^\^?\d/)
|
||||
}
|
||||
|
||||
// The lockfile should have the correct catalog specifier
|
||||
const lockfile = readLockfile()
|
||||
expect(lockfile.catalogs?.default?.['is-positive']?.specifier).not.toBe('catalog:')
|
||||
})
|
||||
|
||||
test('adding with catalogMode: prefer will add to or use from catalog', async () => {
|
||||
const { options, projects, readLockfile } = preparePackagesAndReturnObjects([{
|
||||
name: 'project1',
|
||||
|
||||
@@ -289,9 +289,12 @@ export async function resolveDependencies (
|
||||
if (!updateSpec) continue
|
||||
const dep = resolvedImporter.directDependencies[i]
|
||||
if (dep.catalogLookup == null) continue
|
||||
// If normalizedBareSpecifier isn't defined, this catalog entry was resolved from cache.
|
||||
// Avoid updating the updatedCatalogs map since it is likely unchanged.
|
||||
if (dep.normalizedBareSpecifier == null) continue
|
||||
updatedCatalogs ??= {}
|
||||
updatedCatalogs[dep.catalogLookup.catalogName] ??= {}
|
||||
updatedCatalogs[dep.catalogLookup.catalogName][dep.alias] = dep.normalizedBareSpecifier ?? dep.catalogLookup.userSpecifiedBareSpecifier
|
||||
updatedCatalogs[dep.catalogLookup.catalogName][dep.alias] = dep.normalizedBareSpecifier
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user