diff --git a/.changeset/shaky-emus-notice.md b/.changeset/shaky-emus-notice.md new file mode 100644 index 0000000000..560399eac4 --- /dev/null +++ b/.changeset/shaky-emus-notice.md @@ -0,0 +1,7 @@ +--- +"@pnpm/cli-utils": patch +"@pnpm/config": patch +"pnpm": patch +--- + +Fix `shamefullyHoist` set via `updateConfig` in `.pnpmfile.cjs` not being converted to `publicHoistPattern` [#10271](https://github.com/pnpm/pnpm/issues/10271). diff --git a/cli/cli-utils/src/getConfig.ts b/cli/cli-utils/src/getConfig.ts index dd2d31cc64..80e511a739 100644 --- a/cli/cli-utils/src/getConfig.ts +++ b/cli/cli-utils/src/getConfig.ts @@ -59,6 +59,7 @@ export async function getConfig ( } } } + applyDerivedConfig(config) if (opts.excludeReporter) { delete config.reporter // This is a silly workaround because @pnpm/core expects a function as opts.reporter @@ -84,3 +85,35 @@ function isPluginName (configDepName: string): boolean { if (configDepName[0] !== '@') return false return configDepName.startsWith('@pnpm/plugin-') || configDepName.includes('/pnpm-plugin-') } + +// Apply derived config settings (hoist, shamefullyHoist, symlink) +function applyDerivedConfig (config: Config): void { + if (config.hoist === false) { + delete config.hoistPattern + } + switch (config.shamefullyHoist) { + case false: + delete config.publicHoistPattern + break + case true: + config.publicHoistPattern = ['*'] + break + default: + if ( + (config.publicHoistPattern == null) || + (config.publicHoistPattern === '') || + ( + Array.isArray(config.publicHoistPattern) && + config.publicHoistPattern.length === 1 && + config.publicHoistPattern[0] === '' + ) + ) { + delete config.publicHoistPattern + } + break + } + if (!config.symlink) { + delete config.hoistPattern + delete config.publicHoistPattern + } +} diff --git a/cli/cli-utils/test/getConfig.test.ts b/cli/cli-utils/test/getConfig.test.ts index d83468fece..6e13af1bd4 100644 --- a/cli/cli-utils/test/getConfig.test.ts +++ b/cli/cli-utils/test/getConfig.test.ts @@ -27,3 +27,18 @@ test('console a warning when the .npmrc has an env variable that does not exist' expect(console.warn).toHaveBeenCalledWith(expect.stringContaining('Failed to replace env in config: ${ENV_VAR_123}')) }) + +test('hoist: false removes hoistPattern', async () => { + prepare() + + const config = await getConfig({ + hoist: false, + }, { + workspaceDir: '.', + excludeReporter: false, + rcOptionsTypes: {}, + }) + + expect(config.hoist).toBe(false) + expect(config.hoistPattern).toBeUndefined() +}) diff --git a/config/config/src/index.ts b/config/config/src/index.ts index d42dfa2758..6113d1c103 100644 --- a/config/config/src/index.ts +++ b/config/config/src/index.ts @@ -524,34 +524,6 @@ export async function getConfig (opts: { if (!pnpmConfig.stateDir) { pnpmConfig.stateDir = getStateDir(process) } - if (pnpmConfig.hoist === false) { - delete pnpmConfig.hoistPattern - } - switch (pnpmConfig.shamefullyHoist) { - case false: - delete pnpmConfig.publicHoistPattern - break - case true: - pnpmConfig.publicHoistPattern = ['*'] - break - default: - if ( - (pnpmConfig.publicHoistPattern == null) || - (pnpmConfig.publicHoistPattern === '') || - ( - Array.isArray(pnpmConfig.publicHoistPattern) && - pnpmConfig.publicHoistPattern.length === 1 && - pnpmConfig.publicHoistPattern[0] === '' - ) - ) { - delete pnpmConfig.publicHoistPattern - } - break - } - if (!pnpmConfig.symlink) { - delete pnpmConfig.hoistPattern - delete pnpmConfig.publicHoistPattern - } if (typeof pnpmConfig['color'] === 'boolean') { switch (pnpmConfig['color']) { case true: diff --git a/config/config/test/index.ts b/config/config/test/index.ts index ac4a6d6320..bfd65cd5ec 100644 --- a/config/config/test/index.ts +++ b/config/config/test/index.ts @@ -502,7 +502,8 @@ test('convert shamefully-flatten to hoist-pattern=* and warn', async () => { ]) }) -test('hoist-pattern is undefined if --no-hoist used', async () => { +// hoist → hoistPattern processing is done in @pnpm/cli-utils +test('hoist-pattern is unchanged if --no-hoist used', async () => { const { config } = await getConfig({ cliOptions: { hoist: false, @@ -513,7 +514,8 @@ test('hoist-pattern is undefined if --no-hoist used', async () => { }, }) - expect(config.hoistPattern).toBeUndefined() + expect(config.hoist).toBe(false) + expect(config.hoistPattern).toStrictEqual(['*']) }) test('throw error if --no-hoist is used with --shamefully-hoist', async () => { @@ -564,6 +566,7 @@ test('throw error if --no-hoist is used with --hoist-pattern', async () => { }) }) +// public-hoist-pattern normalization is done in @pnpm/cli-utils test('normalizing the value of public-hoist-pattern', async () => { { const { config } = await getConfig({ @@ -576,7 +579,7 @@ test('normalizing the value of public-hoist-pattern', async () => { }, }) - expect(config.publicHoistPattern).toBeUndefined() + expect(config.publicHoistPattern).toBe('') } { const { config } = await getConfig({ @@ -589,7 +592,7 @@ test('normalizing the value of public-hoist-pattern', async () => { }, }) - expect(config.publicHoistPattern).toBeUndefined() + expect(config.publicHoistPattern).toStrictEqual(['']) } }) @@ -1247,6 +1250,7 @@ test('settings sharedWorkspaceLockfile in pnpm-workspace.yaml should take effect expect(config.lockfileDir).toBeUndefined() }) +// shamefullyHoist → publicHoistPattern conversion is done in @pnpm/cli-utils test('settings shamefullyHoist in pnpm-workspace.yaml should take effect', async () => { const workspaceDir = f.find('settings-in-workspace-yaml') process.chdir(workspaceDir) @@ -1260,7 +1264,6 @@ test('settings shamefullyHoist in pnpm-workspace.yaml should take effect', async }) expect(config.shamefullyHoist).toBe(true) - expect(config.publicHoistPattern).toStrictEqual(['*']) expect(config.rawConfig['shamefully-hoist']).toBe(true) })