Exemplo
commander 15.0.0: Prevent negative number option parsing failures in Commander when registering digit short option flags
Amostra verificada para npm commander 15.0.0: Prevent negative number option parsing failures in Commander when registering digit short option flags. O…
sha256:e84a5f7f9b0e235218dd1ae017a1fdba5fdf2fce9c93b2143bdf8d153a9953fc
Esta rede oferece uma coisa: uma amostra que compila. Ela a executou em um sandbox e guardou o recibo assinado. Não classifica nem garante nada — se o mesmo código compila onde você está, ela não mediu.
Quantas chaves de assinatura distintas enviaram um recibo de contrato aprovado. Uma é só o autor; mais de uma significa que outra pessoa também o compilou. Uma chave é gerada por conta própria e não tem identidade registrada por trás, então conta chaves, não pessoas.
MIT-0
Evidência de execução
O ambiente declarado e as execuções assinadas ficam separados, para você ver exatamente o que esta amostra executou e onde.
- Base da evidência
- Contrato assinado aprovado
- Recibos de verificação
- 3
- Chaves de assinatura que o compilaram
- 3
Ambiente declarado
node linux x64 node node npm
Ambientes das execuções de verificação
| Ambiente | Contrato | Etapas | Execução |
|---|---|---|---|
| node 22 · linux alpine/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1 |
2026-08-17 |
| 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 |
Caso
HOW- Objetivo
- Prevent negative number option parsing failures in Commander when registering digit short option flags
- Pacotes
- Símbolos
-
- Command.option
- Command.parse
- Option
- Ambiente
- node
- Criado
- 2026-08-17T01:48:52Z
Contrato
- Passing -1 after an optional-argument option evaluates that option to boolean true and parses -1 as a distinct flag if any single-digit short option is defined on the command hierarchy, because Commander disables negative number heuristics whenever a digit flag exists.
- Options with required arguments still consume negative number tokens like -1 unconditionally as values regardless of registered digit flags.
- Without any digit flags registered, an optional-argument option consumes -1 as its string value.
- Passing multi-digit negative numbers like -10 after an optional-argument option when a digit flag -1 exists triggers an unknown option error for the remaining digits.
- Positional arguments in leaf commands reject negative numbers and throw unknownOption errors when any digit flag is defined in the command.
Arquivos
- NOTES.md
- csx.json
- package-lock.json
- package.json
- test/contract.mjs
- test1.mjs
- test2.mjs
- test3.mjs
- test4.mjs
- test5.mjs
- test6.mjs
- test_clean.mjs
- test_prototype.mjs
Código-fonte
# Negative Number Option Parsing and Digit Short Flags in Commander
## Known Solutions Search
A search via `search_known_solution` returned existing compatible samples covering:
- Subcommand action argument unpacking and custom coerce radix traps (`sha256:05e524cd641f3e66c380604099a1c591c4fbe976012949d4819b1f3ec255ed9f`)
- Positional argument default value retrieval via `processedArgs` (`sha256:3fc59d6ae2df342949bb6f6c09dcdc027cda2183237046c0189f6cabfae569e9`)
- `Option.preset` vs `Option.default` behavior on optional flags (`sha256:9ed29f29e55e4074676913ca3bb9009038881ff559b26efc27a6df45e0d7e648`)
- Error interception and `CommanderError` wrapping (`sha256:94607693bb374f0a65026f93ee8ff32d6560d2668a0b2e16a5e6ebc40f4ddd52`)
- Boolean negation option default behavior in Commander 15 (`sha256:e9734b35dd9bf261570327aa6767cba61b29225dbb1b6eebc59d47cb344f1141`)
- Boolean environment variable truthiness parsing (`sha256:b953db7ef30e702f31dca9192e6ef548a50589157551d3ada4896bd8624d6d8d`)
None of the existing samples addressed negative number argument parsing interactions with single-digit short flags.
## Failure Mode
The wrong version fails loudly with an unknownOption error when passing multi-digit negative values or positional arguments, and fails silently with a green build when passing single-digit negative arguments to optional options by assigning boolean true and inadvertently activating the digit flag.
{"case":{"believed":"An option configured with an optional value accepts negative numbers like -1 as its argument regardless of what other short option flags are registered on the command.","caseId":"case:sha256:a1a54d8409b0c3eea40222c758c8fd3c05f023431c8ca98a9181518b5f1da0d4","contract":["Passing -1 after an optional-argument option evaluates that option to boolean true and parses -1 as a distinct flag if any single-digit short option is defined on the command hierarchy, because Commander disables negative number heuristics whenever a digit flag exists.","Options with required arguments still consume negative number tokens like -1 unconditionally as values regardless of registered digit flags.","Without any digit flags registered, an optional-argument option consumes -1 as its string value.","Passing multi-digit negative numbers like -10 after an optional-argument option when a digit flag -1 exists triggers an unknown option error for the remaining digits.","Positional arguments in leaf commands reject negative numbers and throw unknownOption errors when any digit flag is defined in the command."],"goal":"Prevent negative number option parsing failures in Commander when registering digit short option flags","kind":"HOW","packages":["pkg:npm/commander@15.0.0"],"schemaVersion":1,"symbols":["Command.option","Command.parse","Option"]},"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@15.0.0"],"schemaVersion":1,"symbols":["Command.option","Command.parse","Option"],"verifierAdapter":"node-typescript@1"}
{
"name": "npm-commander-d8",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "npm-commander-d8",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"commander": "^15.0.0"
}
},
"node_modules/commander": {
"version": "15.0.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz",
"integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==",
"license": "MIT",
"engines": {
"node": ">=22.12.0"
}
}
}
}
{
"name": "npm-commander-d8",
"version": "1.0.0",
"type": "module",
"scripts": {
"test": "node test/contract.mjs"
},
"dependencies": {
"commander": "^15.0.0"
}
}
import assert from 'node:assert/strict';
import { Command, CommanderError } from 'commander';
// 1. Passing -1 after an optional-argument option evaluates that option to boolean true and parses -1 as a distinct flag if any single-digit short option is defined on the command hierarchy, because Commander disables negative number heuristics whenever a digit flag exists.
{
const program = new Command();
program.exitOverride();
program.configureOutput({ writeErr: () => {} });
program.option('-1, --one-line', 'display one line');
program.option('-t, --threshold [val]', 'cutoff threshold');
program.parse(['node', 'cli', '-t', '-1']);
const opts = program.opts();
assert.strictEqual(opts.threshold, true);
assert.strictEqual(opts.oneLine, true);
}
// 2. Options with required arguments still consume negative number tokens like -1 unconditionally as values regardless of registered digit flags.
{
const program = new Command();
program.exitOverride();
program.configureOutput({ writeErr: () => {} });
program.option('-1, --one-line', 'display one line');
program.option('-r, --required <val>', 'required value');
program.parse(['node', 'cli', '-r', '-1']);
const opts = program.opts();
assert.strictEqual(opts.required, '-1');
assert.strictEqual(opts.oneLine, undefined);
}
// 3. Without any digit flags registered, an optional-argument option consumes -1 as its string value.
{
const program = new Command();
program.exitOverride();
program.configureOutput({ writeErr: () => {} });
program.option('-v, --verbose', 'verbose output');
program.option('-t, --threshold [val]', 'cutoff threshold');
program.parse(['node', 'cli', '-t', '-1']);
const opts = program.opts();
assert.strictEqual(opts.threshold, '-1');
assert.strictEqual(opts.verbose, undefined);
}
// 4. Passing multi-digit negative numbers like -10 after an optional-argument option when a digit flag -1 exists triggers an unknown option error for the remaining digits.
{
const program = new Command();
program.exitOverride();
program.configureOutput({ writeErr: () => {} });
program.option('-1, --one-line', 'display one line');
program.option('-t, --threshold [val]', 'cutoff threshold');
assert.throws(
() => program.parse(['node', 'cli', '-t', '-10']),
(err) => {
assert(err instanceof CommanderError);
assert.strictEqual(err.code, 'commander.unknownOption');
assert.match(err.message, /unknown option '-0'/);
return true;
}
);
}
// 5. Positional arguments in leaf commands reject negative numbers and throw unknownOption errors when any digit flag is defined in the command.
{
const program = new Command();
program.exitOverride();
program.configureOutput({ writeErr: () => {} });
program.option('-1, --one-line', 'display one line');
program.argument('[offset]', 'coordinate offset');
assert.throws(
() => program.parse(['node', 'cli', '-5']),
(err) => {
assert(err instanceof CommanderError);
assert.strictEqual(err.code, 'commander.unknownOption');
assert.match(err.message, /unknown option '-5'/);
return true;
}
);
}
import { Command, Option, InvalidArgumentError } from 'commander';
console.log('Testing commander edge cases...');
// Test 1: Negative numbers and digit options
{
const p1 = new Command();
p1.exitOverride();
p1.option('-n, --num <n>');
p1.parse(['node', 'test', '-n', '-5']);
console.log('p1 opts:', p1.opts());
const p2 = new Command();
p2.exitOverride();
p2.option('-1, --one');
p2.option('-n, --num <n>');
try {
p2.parse(['node', 'test', '-n', '-5']);
console.log('p2 opts:', p2.opts());
} catch (e) {
console.log('p2 threw with digit option:', e.code, e.message);
}
}
// Test 2: Optional argument with negative numbers vs flags vs empty string
{
const p3 = new Command();
p3.exitOverride();
p3.option('-o, --optional [val]', 'opt val', 'defaultVal');
p3.parse(['node', 'test', '-o', '-5']);
console.log('p3 with -5:', p3.opts());
const p3b = new Command();
p3b.exitOverride();
p3b.option('-1, --one');
p3b.option('-o, --optional [val]', 'opt val', 'defaultVal');
try {
p3b.parse(['node', 'test', '-o', '-5']);
console.log('p3b with -5:', p3b.opts());
} catch (e) {
console.log('p3b threw:', e.code, e.message);
}
}
// Test 3: Optional argument with empty string or '0' or following operand
{
const p4 = new Command();
p4.exitOverride();
p4.option('-o, --opt [val]');
p4.argument('[target]');
p4.parse(['node', 'test', '-o', 'hello']);
console.log('p4 opts:', p4.opts(), 'args:', p4.args);
const p5 = new Command();
p5.exitOverride();
p5.option('-o, --opt [val]');
p5.argument('[target]');
p5.parse(['node', 'test', '-o', '']);
console.log('p5 opts:', p5.opts(), 'args:', p5.args);
}
import { Command, Option, InvalidArgumentError } from 'commander';
console.log('--- TEST 2 ---');
// Edge 1: Empty string "" as positional argument vs optional argument
{
const p = new Command();
p.exitOverride();
p.argument('<req>');
p.parse(['node', 'test', '']);
console.log('p req with "":', p.processedArgs, p.args);
}
// Edge 2: Variadic argument with empty string or multiple empty strings
{
const p = new Command();
p.exitOverride();
p.argument('<items...>');
p.parse(['node', 'test', '', '']);
console.log('variadic arg with "":', p.processedArgs);
}
// Edge 3: Variadic option with empty string
{
const p = new Command();
p.exitOverride();
p.option('-v, --val <items...>');
p.parse(['node', 'test', '-v', '', '']);
console.log('variadic opt with "":', p.opts());
}
// Edge 4: Option with empty string default vs unset
{
const p = new Command();
p.exitOverride();
p.option('-s, --str <val>', 'string val', '');
p.parse(['node', 'test']);
console.log('opt default "":', p.opts(), 'source:', p.getOptionValueSource('str'));
const p2 = new Command();
p2.exitOverride();
p2.option('-s, --str <val>', 'string val', '');
p2.parse(['node', 'test', '-s', '']);
console.log('opt passed "":', p2.opts(), 'source:', p2.getOptionValueSource('str'));
}
// Edge 5: Negative numbers as positional arguments when subcommands exist vs leaf commands
{
const root = new Command();
root.exitOverride();
root.argument('[pos]');
const sub = root.command('sub');
sub.argument('[pos]');
try {
root.parse(['node', 'test', '-5']);
console.log('root with sub received -5:', root.args);
} catch (e) {
console.log('root with sub threw on -5:', e.code, e.message);
}
}
// Edge 6: Single dash '-' as argument or option value
{
const p = new Command();
p.exitOverride();
p.argument('<file>');
p.option('-o, --output <file>');
p.parse(['node', 'test', '-o', '-', '-']);
console.log('single dash opts:', p.opts(), 'args:', p.args);
}
// Edge 7: Zero value '0' vs false vs empty string in env variables or boolean flags
{
const p = new Command();
p.exitOverride();
p.addOption(new Option('-b, --bool').env('TEST_BOOL'));
process.env.TEST_BOOL = '0';
p.parse(['node', 'test']);
console.log('bool env TEST_BOOL="0":', p.opts());
}
// Edge 8: Option with choices including empty string or negative numbers
{
const p = new Command();
p.exitOverride();
p.addOption(new Option('-c, --choice <val>').choices(['', '0', '-1']));
p.parse(['node', 'test', '-c', '']);
console.log('choices with "":', p.opts());
const p_neg = new Command();
p_neg.exitOverride();
p_neg.addOption(new Option('-c, --choice <val>').choices(['', '0', '-1']));
try {
p_neg.parse(['node', 'test', '-c', '-1']);
console.log('choices with -1:', p_neg.opts());
} catch (e) {
console.log('choices with -1 threw:', e.code, e.message);
}
}
import { Command } from 'commander';
console.log('--- TEST 3: Negative numbers & digit options ---');
// Case A: Leaf command without digit options
const pA = new Command();
pA.exitOverride();
pA.option('-t, --threshold [val]', 'threshold');
pA.option('-v, --verbose', 'verbose');
pA.parse(['node', 'test', '-t', '-10']);
console.log('Case A (no digit options) opts:', pA.opts());
// Case B: Leaf command WITH digit option (-1)
const pB = new Command();
pB.exitOverride();
pB.option('-1, --fast', 'fast mode');
pB.option('-t, --threshold [val]', 'threshold');
pB.parse(['node', 'test', '-t', '-10']);
console.log('Case B (with digit option -1, passing -10):');
import { Command } from 'commander';
console.log('--- TEST 4: Comparing behavior of negative numbers with and without digit options ---');
// Setup 1: No digit option
const p1 = new Command();
p1.exitOverride();
p1.option('-t, --threshold [val]', 'threshold');
p1.parse(['node', 'test', '-t', '-1']);
console.log('p1 (-t -1 without digit option):', p1.opts());
// Output: { threshold: '-1' }
// Setup 2: With digit option -1
const p2 = new Command();
p2.exitOverride();
p2.option('-1, --fast', 'fast mode');
p2.option('-t, --threshold [val]', 'threshold');
p2.parse(['node', 'test', '-t', '-1']);
console.log('p2 (-t -1 with digit option -1):', p2.opts());
// Output: { fast: true, threshold: undefined } or { fast: true }!
// Setup 3: Required argument vs Optional argument
const p3 = new Command();
p3.exitOverride();
p3.option('-1, --fast', 'fast mode');
p3.option('-r, --required <val>', 'required arg');
p3.parse(['node', 'test', '-r', '-1']);
console.log('p3 (-r -1 with digit option -1, required arg):', p3.opts());
// Output: { required: '-1' }!
import { Command } from 'commander';
console.log('--- TEST 5: Variadic options with negative numbers ---');
// Variadic required
const p1 = new Command();
p1.exitOverride();
p1.option('-n, --numbers <vals...>');
p1.parse(['node', 'test', '-n', '-1', '-2', '3']);
console.log('Variadic required without digit opt:', p1.opts());
// Variadic required WITH digit opt
const p2 = new Command();
p2.exitOverride();
p2.option('-1, --one');
p2.option('-n, --numbers <vals...>');
try {
p2.parse(['node', 'test', '-n', '-1', '-2', '3']);
console.log('Variadic required with digit opt:', p2.opts());
} catch (e) {
console.log('Variadic required with digit opt threw:', e.code, e.message);
}
// Variadic optional
const p3 = new Command();
p3.exitOverride();
p3.option('-n, --numbers [vals...]');
p3.parse(['node', 'test', '-n', '-1', '-2', '3']);
console.log('Variadic optional without digit opt:', p3.opts());
// Variadic optional WITH digit opt
const p4 = new Command();
p4.exitOverride();
p4.option('-1, --one');
p4.option('-n, --numbers [vals...]');
try {
p4.parse(['node', 'test', '-n', '-1', '-2', '3']);
console.log('Variadic optional with digit opt:', p4.opts());
} catch (e) {
console.log('Variadic optional with digit opt threw:', e.code, e.message);
}
import { Command } from 'commander';
console.log('--- TEST 6: Positional arguments and negative numbers ---');
// Root with argument only (leaf)
const leaf = new Command();
leaf.exitOverride();
leaf.argument('<target>', 'target position');
leaf.parse(['node', 'test', '-50']);
console.log('Leaf command with -50:', leaf.processedArgs);
// Root with argument AND subcommand
const rootWithSub = new Command();
rootWithSub.exitOverride();
rootWithSub.argument('[target]', 'target position');
rootWithSub.command('build');
try {
rootWithSub.parse(['node', 'test', '-50']);
console.log('Root with sub with -50:', rootWithSub.processedArgs);
} catch (e) {
console.log('Root with sub threw on -50:', e.code, e.message);
}
import assert from 'node:assert/strict';
import { Command, CommanderError } from 'commander';
const program = new Command();
program.exitOverride();
program.configureOutput({ writeErr: () => {} });
program.option('-1, --one-line');
program.argument('[offset]');
assert.throws(
() => program.parse(['node', 'cli', '-5']),
(err) => {
assert(err instanceof CommanderError);
assert.strictEqual(err.code, 'commander.unknownOption');
return true;
}
);
console.log('Clean error handling verified');
import assert from 'node:assert/strict';
import { Command, CommanderError } from 'commander';
// 1. First contract line: With a digit flag (-1), optional option receives `true` instead of '-1', and -1 triggers the digit option
{
const program = new Command();
program.exitOverride();
program.option('-1, --one-line', 'display one line');
program.option('-t, --threshold [val]', 'cutoff threshold');
program.parse(['node', 'cli', '-t', '-1']);
const opts = program.opts();
assert.strictEqual(opts.threshold, true);
assert.strictEqual(opts.oneLine, true);
}
// 2. Without digit flags, optional option consumes -1 as its value string
{
const program = new Command();
program.exitOverride();
program.option('-v, --verbose', 'verbose output');
program.option('-t, --threshold [val]', 'cutoff threshold');
program.parse(['node', 'cli', '-t', '-1']);
const opts = program.opts();
assert.strictEqual(opts.threshold, '-1');
assert.strictEqual(opts.verbose, undefined);
}
// 3. Required argument options unconditionally consume negative numbers as values even when digit flags exist
{
const program = new Command();
program.exitOverride();
program.option('-1, --one-line', 'display one line');
program.option('-r, --required <val>', 'required value');
program.parse(['node', 'cli', '-r', '-1']);
const opts = program.opts();
assert.strictEqual(opts.required, '-1');
assert.strictEqual(opts.oneLine, undefined);
}
// 4. Multi-digit negative number -10 with digit flag -1 parses -1 and throws unknownOption for remaining -0
{
const program = new Command();
program.exitOverride();
program.option('-1, --one-line', 'display one line');
program.option('-t, --threshold [val]', 'cutoff threshold');
assert.throws(
() => program.parse(['node', 'cli', '-t', '-10']),
(err) => {
assert(err instanceof CommanderError);
assert.strictEqual(err.code, 'commander.unknownOption');
assert.match(err.message, /unknown option '-0'/);
return true;
}
);
}
// 5. Leaf command positional arguments reject negative numbers when a digit flag exists
{
const program = new Command();
program.exitOverride();
program.option('-1, --one-line', 'display one line');
program.argument('[offset]', 'coordinate offset');
assert.throws(
() => program.parse(['node', 'cli', '-5']),
(err) => {
assert(err instanceof CommanderError);
assert.strictEqual(err.code, 'commander.unknownOption');
assert.match(err.message, /unknown option '-5'/);
return true;
}
);
}
// 6. Without digit flags, leaf command accepts negative number positional argument
{
const program = new Command();
program.exitOverride();
program.argument('[offset]', 'coordinate offset');
program.parse(['node', 'cli', '-5']);
assert.deepStrictEqual(program.processedArgs, ['-5']);
}
console.log('All prototype contract assertions passed!');