mirror of
https://github.com/pnpm/pnpm.git
synced 2026-06-28 09:55:39 -04:00
## What - preserve existing `workspace:` dependency specifiers when `updateProjectManifest` saves updated direct dependencies and `preserveWorkspaceProtocol` is enabled - keep catalog specifiers taking precedence over resolver-normalized specs - add focused coverage for preserved and normalized local spec behavior - add a changeset for the published `@pnpm/installing.deps-resolver` change ### pacquet parity Ported the same fix to pacquet's `update` command. Previously `pacquet update --latest` routed every direct dependency through a registry `latest` lookup, so a `workspace:` local-path dependency (e.g. `workspace:../packages/foo/dist`) was rewritten into a registry version — corrupting the manifest (in the regression test it became `0.0.1-security`). Both `--latest` rewrite sites now skip registry resolution for such specs via `is_workspace_local_path_specifier`, a faithful port of pnpm's `isWorkspaceLocalPathSpecifier`. The gate is unconditional in the `--latest` path because `preserveWorkspaceProtocol` is always on there (its only override derives from `linkWorkspacePackages` under `--workspace`, which cannot be combined with `--latest`). Fixes #3902 --------- Co-authored-by: morning-verlu <258725120+morning-verlu@users.noreply.github.com> Co-authored-by: Zoltan Kochan <z@kochan.io>
101 lines
3.1 KiB
TypeScript
101 lines
3.1 KiB
TypeScript
import { expect, test } from '@jest/globals'
|
|
import type { PkgResolutionId, ProjectId, ProjectRootDir } from '@pnpm/types'
|
|
|
|
import type { ImporterToResolve } from '../lib/index.js'
|
|
import type { ResolvedDirectDependency } from '../lib/resolveDependencyTree.js'
|
|
import { updateProjectManifest } from '../lib/updateProjectManifest.js'
|
|
|
|
test('updateProjectManifest preserves workspace protocol specs when requested', async () => {
|
|
const [manifest] = await updateProjectManifest(createImporter('workspace:../packages/foo/dist'), {
|
|
directDependencies: [createDirectDependency()],
|
|
preserveWorkspaceProtocol: true,
|
|
saveWorkspaceProtocol: 'rolling',
|
|
})
|
|
|
|
expect(manifest?.dependencies?.foo).toBe('workspace:../packages/foo/dist')
|
|
})
|
|
|
|
test('updateProjectManifest saves normalized local specs when workspace protocol is not preserved', async () => {
|
|
const [manifest] = await updateProjectManifest(createImporter('workspace:../packages/foo/dist'), {
|
|
directDependencies: [createDirectDependency()],
|
|
preserveWorkspaceProtocol: false,
|
|
saveWorkspaceProtocol: 'rolling',
|
|
})
|
|
|
|
expect(manifest?.dependencies?.foo).toBe('link:../packages/foo/dist')
|
|
})
|
|
|
|
test('updateProjectManifest saves normalized workspace range specs', async () => {
|
|
const [manifest] = await updateProjectManifest(createImporter('workspace:*'), {
|
|
directDependencies: [
|
|
createDirectDependency({
|
|
normalizedBareSpecifier: 'workspace:^1.0.0',
|
|
}),
|
|
],
|
|
preserveWorkspaceProtocol: true,
|
|
saveWorkspaceProtocol: 'rolling',
|
|
})
|
|
|
|
expect(manifest?.dependencies?.foo).toBe('workspace:^1.0.0')
|
|
})
|
|
|
|
test('updateProjectManifest preserves catalog specifier precedence', async () => {
|
|
const [manifest] = await updateProjectManifest(createImporter('workspace:../packages/foo/dist'), {
|
|
directDependencies: [
|
|
createDirectDependency({
|
|
catalogLookup: {
|
|
catalogName: 'default',
|
|
specifier: '^1.0.0',
|
|
userSpecifiedBareSpecifier: 'catalog:',
|
|
},
|
|
}),
|
|
],
|
|
preserveWorkspaceProtocol: true,
|
|
saveWorkspaceProtocol: 'rolling',
|
|
})
|
|
|
|
expect(manifest?.dependencies?.foo).toBe('catalog:')
|
|
})
|
|
|
|
function createImporter (bareSpecifier: string): ImporterToResolve {
|
|
return {
|
|
binsDir: '/project/node_modules/.bin',
|
|
id: '.' as ProjectId,
|
|
manifest: {
|
|
dependencies: {
|
|
foo: bareSpecifier,
|
|
},
|
|
},
|
|
modulesDir: '/project/node_modules',
|
|
rootDir: '/project' as ProjectRootDir,
|
|
targetDependenciesField: 'dependencies',
|
|
updatePackageManifest: true,
|
|
wantedDependencies: [
|
|
{
|
|
alias: 'foo',
|
|
bareSpecifier,
|
|
dev: false,
|
|
optional: false,
|
|
updateSpec: true,
|
|
},
|
|
],
|
|
}
|
|
}
|
|
|
|
function createDirectDependency (overrides: Partial<ResolvedDirectDependency> = {}): ResolvedDirectDependency {
|
|
return {
|
|
alias: 'foo',
|
|
dev: false,
|
|
name: 'foo',
|
|
normalizedBareSpecifier: 'link:../packages/foo/dist',
|
|
optional: false,
|
|
pkgId: 'link:../packages/foo/dist' as PkgResolutionId,
|
|
resolution: {
|
|
directory: '../packages/foo/dist',
|
|
type: 'directory',
|
|
},
|
|
version: '1.0.0',
|
|
...overrides,
|
|
}
|
|
}
|