mirror of
https://github.com/pnpm/pnpm.git
synced 2025-12-23 23:29:17 -05:00
fix(cli/config): phantom keys (#10323)
* fix(cli/config): phantom keys Fixes https://github.com/pnpm/pnpm/issues/10296 This patch also include other refactors. * test: does not traverse the prototype chain * test: more properties * test: fix other tests * feat: revert unrelated changes
This commit is contained in:
5
.changeset/eighty-clowns-shave.md
Normal file
5
.changeset/eighty-clowns-shave.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/plugin-commands-config": patch
|
||||
---
|
||||
|
||||
Fix phantom keys in `pnpm config get <key>` [#10296](https://github.com/pnpm/pnpm/issues/10296).
|
||||
@@ -444,7 +444,7 @@ export async function getConfig (opts: {
|
||||
// TODO: should we throw some error or print some warning here?
|
||||
if (value === undefined) continue
|
||||
|
||||
if (key in cliOptions || kebabCase(key) in cliOptions) continue
|
||||
if (Object.hasOwn(cliOptions, key) || Object.hasOwn(cliOptions, kebabCase(key))) continue
|
||||
|
||||
// @ts-expect-error
|
||||
pnpmConfig[key] = value
|
||||
|
||||
@@ -35,7 +35,7 @@ function getRcConfig (rawConfig: Record<string, unknown>, key: string, isScopedK
|
||||
return { value }
|
||||
}
|
||||
const rcKey = isCamelCase(key) ? kebabCase(key) : key
|
||||
if (rcKey in types) {
|
||||
if (Object.hasOwn(types, rcKey)) {
|
||||
const value = rawConfig[rcKey]
|
||||
return { value }
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ export class ConfigSetUnsupportedIniConfigKeyError extends PnpmError {
|
||||
*/
|
||||
function validateIniConfigKey (key: string): string {
|
||||
const kebabKey = kebabCase(key)
|
||||
if (kebabKey in types) {
|
||||
if (Object.hasOwn(types, kebabKey)) {
|
||||
return kebabKey
|
||||
}
|
||||
throw new ConfigSetUnsupportedIniConfigKeyError(key)
|
||||
@@ -207,7 +207,7 @@ export class ConfigSetUnsupportedWorkspaceKeyError extends PnpmError {
|
||||
* Return the camelCase of {@link key} if it's valid.
|
||||
*/
|
||||
function validateWorkspaceKey (key: string): string {
|
||||
if (key in types) return camelCase(key)
|
||||
if (Object.hasOwn(types, key)) return camelCase(key)
|
||||
if (!isCamelCase(key)) throw new ConfigSetUnsupportedWorkspaceKeyError(key)
|
||||
return key
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ function normalizeTopLevelConfigName (configName: string | number): string {
|
||||
if (typeof configName === 'number') return configName.toString()
|
||||
|
||||
const kebabKey = kebabCase(configName)
|
||||
if (kebabKey in types) return kebabKey
|
||||
if (Object.hasOwn(types, kebabKey)) return kebabKey
|
||||
|
||||
return configName
|
||||
}
|
||||
|
||||
@@ -302,3 +302,24 @@ test('config get npm-globalconfig', async () => {
|
||||
|
||||
expect(getOutputString(getResult)).toBe(npmGlobalconfigPath)
|
||||
})
|
||||
|
||||
describe('does not traverse the prototype chain (#10296)', () => {
|
||||
test.each([
|
||||
'constructor',
|
||||
'hasOwnProperty',
|
||||
'isPrototypeOf',
|
||||
'toString',
|
||||
'valueOf',
|
||||
'__proto__',
|
||||
])('%s', async key => {
|
||||
const getResult = await config.handler({
|
||||
dir: process.cwd(),
|
||||
cliOptions: {},
|
||||
configDir: process.cwd(),
|
||||
global: true,
|
||||
rawConfig: {},
|
||||
}, ['get', key])
|
||||
|
||||
expect(getOutputString(getResult)).toBe('undefined')
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user