示例
commander 13.1.0: Retrieve positional argument default values in Commander via processedArgs or action callbacks rather than program.args when arguments are unset
已验证示例 — npm commander 13.1.0: Retrieve positional argument default values in Commander via processedArgs or action callbacks rather than program.args when…
sha256:3fc59d6ae2df342949bb6f6c09dcdc027cda2183237046c0189f6cabfae569e9
本网络只提供一件事:能构建的样本。它在沙箱中运行并保留签名回执。它不评级、不担保——同样的代码能否在你的环境构建,它没有测量过。
提交了通过的契约回执的不同签名密钥数量。为 1 表示只有作者;大于 1 表示还有其他人构建过。密钥是自行生成的,背后没有注册身份,因此计的是密钥而非人。
MIT-0
执行证据
声明的环境与签名的运行分开呈现,你可以看到这个样本究竟运行了什么、在哪里运行。
- 证据依据
- 签名契约通过
- 验证回执
- 3
- 构建过它的签名密钥
- 3
声明的环境
node linux x64 node node npm
验证运行环境
| 环境 | 契约 | 阶段 | 运行日期 |
|---|---|---|---|
| node 22 · linux alpine/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1 |
2026-08-16 |
| node 22 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1 |
2026-08-18 |
| node 22 · linux alpine/x64 · docker ed25519:c1973797be207ac4 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1node:22-alpine@sha256:c610fcdfb1d5… |
2026-09-08 |
案例
HOW- 目标
- Retrieve positional argument default values in Commander via processedArgs or action callbacks rather than program.args when arguments are unset
- 符号
-
- Command.argument
- Command.args
- Command.processedArgs
- Command.opts
- Option.default
- Argument.default
- 环境
- node
- 创建时间
- 2026-08-16T16:14:22Z
契约
- program.args remains empty when an optional positional argument with a default value is omitted, because default argument values are populated into program.processedArgs and action parameters rather than program.args.
- omitted defaulted argument is absent from program.args when partial arguments are supplied
- variadic omitted argument without an explicit default defaults to an empty Array rather than undefined
- custom coerce parser is bypassed for default values when options or arguments are omitted
- program.opts populates defaults for omitted options while program.args does not populate defaults for omitted arguments
文件
- NOTES.md
- csx.json
- package-lock.json
- package.json
- test/contract.mjs
源代码
# Commander Positional Argument and Option Defaults
## Prior Findings
`search_known_solution` returned existing samples for boolean flag handling (`sha256:e9734b35dd9bf261570327aa6767cba61b29225dbb1b6eebc59d47cb344f1141` regarding dual positive/negative flags in Commander 15, and `sha256:b953db7ef30e702f31dca9192e6ef548a50589157551d3ada4896bd8624d6d8d` regarding boolean environment variables) and subcommand action unpacking (`sha256:05e524cd641f3e66c380604099a1c591c4fbe976012949d4819b1f3ec255ed9f`), but did not cover the omission of positional argument defaults from `program.args` or the bypass of custom coerce parsers on default values.
## How the Wrong Assumption Fails
Fails silently with a green build: reading `program.args[0]` after omitting an argument configured with `.argument('[env]', 'desc', 'dev')` returns `undefined` instead of `'dev'`, causing downstream configurations to silently receive `undefined`, while `program.opts()` simultaneously populates option defaults.
{"case":{"believed":"Configuring an optional argument with a default value populates program.args with the default when the argument is omitted from command line arguments.","caseId":"case:sha256:ceb6c66935c73ad3b8e65ab752af91690ee9f28e300a70a4a3b15723e89d5e22","contract":["program.args remains empty when an optional positional argument with a default value is omitted, because default argument values are populated into program.processedArgs and action parameters rather than program.args.","omitted defaulted argument is absent from program.args when partial arguments are supplied","variadic omitted argument without an explicit default defaults to an empty Array rather than undefined","custom coerce parser is bypassed for default values when options or arguments are omitted","program.opts populates defaults for omitted options while program.args does not populate defaults for omitted arguments"],"goal":"Retrieve positional argument default values in Commander via processedArgs or action callbacks rather than program.args when arguments are unset","kind":"HOW","packages":["pkg:npm/commander@13.1.0"],"schemaVersion":1,"symbols":["Command.argument","Command.args","Command.processedArgs","Command.opts","Option.default","Argument.default"]},"contractCommand":["node","test/contract.mjs"],"environment":{"arch":"x64","ecosystem":"npm","executionContext":"node","language":"node","os":"linux","packageManager":"npm","runtime":"node","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/commander@13.1.0"],"schemaVersion":1,"symbols":["Command.argument","Command.args","Command.processedArgs","Command.opts","Option.default","Argument.default"],"verifierAdapter":"node-typescript@1"}
{
"name": "npm-commander-defaults",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "npm-commander-defaults",
"version": "1.0.0",
"dependencies": {
"commander": "13.1.0"
}
},
"node_modules/commander": {
"version": "13.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz",
"integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==",
"license": "MIT",
"engines": {
"node": ">=18"
}
}
}
}
{
"name": "npm-commander-defaults",
"version": "1.0.0",
"type": "module",
"dependencies": {
"commander": "13.1.0"
}
}
import assert from 'node:assert/strict';
import { Command, Argument, Option } from 'commander';
// ---------------------------------------------------------------------------
// 1. Positional argument defaults are NOT populated in program.args
// ---------------------------------------------------------------------------
// When an optional argument is configured with a default value, callers often
// expect program.args to contain that default value when left unset, mirroring
// how program.opts() populates option defaults.
// In reality, program.args contains ONLY the raw CLI tokens passed by the user.
// Default argument values are populated into program.processedArgs and passed
// to .action() handlers, but program.args remains empty.
{
const program = new Command();
let actionReceivedEnv;
program
.name('deploy')
.argument('[env]', 'target deployment environment', 'development')
.action((env) => {
actionReceivedEnv = env;
});
program.parse([], { from: 'user' });
// Naive expectation: program.args[0] === 'development'
// Actual behavior: program.args is empty []
assert.equal(
program.args.length,
0,
'program.args must remain empty when an optional argument with a default value is omitted',
);
assert.equal(
program.args[0],
undefined,
'program.args[0] is undefined rather than the default value',
);
// Default is correctly available in processedArgs and action parameters
assert.deepEqual(
program.processedArgs,
['development'],
'program.processedArgs contains the resolved default value',
);
assert.equal(
actionReceivedEnv,
'development',
'action handler receives the resolved default value',
);
}
// ---------------------------------------------------------------------------
// 2. Partial arguments: program.args reflects only supplied tokens
// ---------------------------------------------------------------------------
// When a required argument is supplied but a subsequent defaulted argument is
// omitted, program.args has length 1 (only the supplied token), while
// program.processedArgs contains both the supplied value and the default.
{
const program = new Command();
let actionArgs;
program
.argument('<target>', 'deployment target')
.argument('[cluster]', 'target cluster', 'primary-cluster')
.action((target, cluster) => {
actionArgs = { target, cluster };
});
program.parse(['frontend'], { from: 'user' });
assert.deepEqual(
program.args,
['frontend'],
'program.args contains only the explicitly passed CLI argument',
);
assert.equal(
program.args[1],
undefined,
'omitted defaulted argument is absent from program.args',
);
assert.deepEqual(
program.processedArgs,
['frontend', 'primary-cluster'],
'program.processedArgs contains both explicit and default argument values',
);
assert.deepEqual(actionArgs, { target: 'frontend', cluster: 'primary-cluster' });
}
// ---------------------------------------------------------------------------
// 3. Variadic argument defaults to empty Array [] rather than undefined
// ---------------------------------------------------------------------------
// A single optional argument [file] evaluates to undefined when unset.
// A variadic argument [files...] without an explicit default evaluates to []
// (an empty Array) rather than undefined, causing nullish coalescing (files ?? default)
// to retain the empty array.
{
const program = new Command();
let actionFiles;
program
.argument('[single]')
.argument('[files...]')
.action((single, files) => {
actionFiles = { single, files };
});
program.parse([], { from: 'user' });
assert.equal(
actionFiles.single,
undefined,
'single omitted argument without default is undefined',
);
assert.deepEqual(
actionFiles.files,
[],
'variadic omitted argument without default defaults to empty Array [], not undefined',
);
assert.deepEqual(
program.processedArgs,
[undefined, []],
'processedArgs holds undefined for single arg and [] for variadic arg',
);
}
// ---------------------------------------------------------------------------
// 4. Custom coerce parser is bypassed for default values when unset
// ---------------------------------------------------------------------------
// When an option or argument has a custom parse/coerce function and a default value,
// Commander does NOT execute the parse function on the default value.
// When left unset, the raw default value is returned directly without transformation.
{
const program = new Command();
program
.addOption(new Option('-p, --port <number>', 'port number').argParser((v) => parseInt(v, 10)).default('8080'))
.addArgument(new Argument('[retries]', 'retry count').argParser((v) => parseInt(v, 10)).default('3'));
program.parse([], { from: 'user' });
// Unset: raw string defaults are returned, NOT numbers
assert.strictEqual(
typeof program.opts().port,
'string',
'option default value is not passed through custom coerce parser when omitted',
);
assert.strictEqual(program.opts().port, '8080');
assert.strictEqual(
typeof program.processedArgs[0],
'string',
'argument default value is not passed through custom coerce parser when omitted',
);
assert.strictEqual(program.processedArgs[0], '3');
// Explicit CLI value: custom coerce parser is executed
const explicitProgram = new Command();
explicitProgram
.addOption(new Option('-p, --port <number>', 'port number').argParser((v) => parseInt(v, 10)).default('8080'))
.addArgument(new Argument('[retries]', 'retry count').argParser((v) => parseInt(v, 10)).default('3'));
explicitProgram.parse(['-p', '9000', '5'], { from: 'user' });
assert.strictEqual(typeof explicitProgram.opts().port, 'number');
assert.strictEqual(explicitProgram.opts().port, 9000);
assert.strictEqual(typeof explicitProgram.processedArgs[0], 'number');
assert.strictEqual(explicitProgram.processedArgs[0], 5);
}
// ---------------------------------------------------------------------------
// 5. Contrast: program.opts() populates defaults, while program.args does not
// ---------------------------------------------------------------------------
// This fundamental asymmetry is what misleads developers: program.opts()
// returns defaults for omitted options, but program.args stays empty for
// omitted arguments.
{
const program = new Command();
program
.argument('[env]', 'target environment', 'development')
.option('-t, --timeout <ms>', 'timeout in ms', '5000');
program.parse([], { from: 'user' });
assert.equal(program.opts().timeout, '5000', 'opts() contains option default');
assert.equal(program.args[0], undefined, 'args[0] does NOT contain argument default');
}