mirror of
https://github.com/pnpm/pnpm.git
synced 2026-05-13 02:55:56 -04:00
fix(cli): honor --pm-on-fail when combined with --help / --version (#11489)
The CLI argument parser short-circuits `--help` and `--version` and was discarding every other parsed option in the process — including universal flags like `--pm-on-fail`. So `pnpm audit --pm-on-fail=ignore --help` and `pnpm --pm-on-fail=ignore --version` failed with the strict `packageManager` mismatch error instead of doing what was asked. Users had no documented way out: the suggested escape hatch in the error message itself didn't work. The fix plucks universal options back out of the exploratory `nopt` parse and surfaces them through both short-circuits. They were already typed correctly there; only the regular per-command parse adds command-specific options. Command-specific options (e.g. `--frozen-lockfile`) stay dropped, since the matching command isn't being executed. Closes [#11487](https://github.com/pnpm/pnpm/issues/11487).
This commit is contained in:
@@ -73,6 +73,7 @@ export async function parseCliArgs (
|
||||
argv: noptExploratoryResults.argv,
|
||||
cmd: null,
|
||||
options: {
|
||||
...pickUniversalOptions(),
|
||||
version: true,
|
||||
},
|
||||
params: noptExploratoryResults.argv.remain,
|
||||
@@ -87,13 +88,33 @@ export async function parseCliArgs (
|
||||
return {
|
||||
argv: noptExploratoryResults.argv,
|
||||
cmd: 'help',
|
||||
options: {},
|
||||
options: pickUniversalOptions(),
|
||||
params: noptExploratoryResults.argv.remain,
|
||||
unknownOptions: new Map(),
|
||||
fallbackCommandUsed: false,
|
||||
}
|
||||
}
|
||||
|
||||
// The --help and --version short-circuits skip the per-command nopt
|
||||
// parse, so we still need to surface universal options the user typed
|
||||
// alongside them — most importantly --pm-on-fail, which gates the
|
||||
// packageManager / devEngines.packageManager check (#11487). Universal
|
||||
// options were already typed and parsed by the exploratory nopt call,
|
||||
// so we just pluck them back out and apply the same renamedOptions
|
||||
// mapping the regular parse path uses (e.g. --prefix → dir), so
|
||||
// consumers see consistent option names regardless of which path
|
||||
// produced the result. Command-specific options are intentionally
|
||||
// dropped; they belong to a command we are not running.
|
||||
function pickUniversalOptions (): Record<string, unknown> {
|
||||
const result: Record<string, unknown> = {}
|
||||
for (const key of Object.keys(opts.universalOptionsTypes)) {
|
||||
if (!(key in noptExploratoryResults)) continue
|
||||
const renamed = opts.renamedOptions?.[key] ?? key
|
||||
result[renamed] = (noptExploratoryResults as Record<string, unknown>)[key]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const types = {
|
||||
...opts.universalOptionsTypes,
|
||||
...opts.getTypesByCommandName(commandName),
|
||||
|
||||
Reference in New Issue
Block a user