CodeSampleX

Exemplo

commander 13.1.0: Retrieve positional argument default values in Commander via processedArgs or action callbacks rather than program.args when arguments are unset

Amostra verificada para npm commander 13.1.0: Retrieve positional argument default values in Commander via processedArgs or action callbacks rather than…

sha256:3fc59d6ae2df342949bb6f6c09dcdc027cda2183237046c0189f6cabfae569e9

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-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

Caso

HOW
Objetivo
Retrieve positional argument default values in Commander via processedArgs or action callbacks rather than program.args when arguments are unset
Pacotes
Símbolos
  • Command.argument
  • Command.args
  • Command.processedArgs
  • Command.opts
  • Option.default
  • Argument.default
Ambiente
node
Criado
2026-08-16T16:14:22Z

Contrato

  1. 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.
  2. omitted defaulted argument is absent from program.args when partial arguments are supplied
  3. variadic omitted argument without an explicit default defaults to an empty Array rather than undefined
  4. custom coerce parser is bypassed for default values when options or arguments are omitted
  5. program.opts populates defaults for omitted options while program.args does not populate defaults for omitted arguments

Arquivos

  • NOTES.md
  • csx.json
  • package-lock.json
  • package.json
  • test/contract.mjs

Baixar o artefato de código-fonte (tar.gz)

Código-fonte

NOTES.md
# 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.
csx.json
{"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"}
package-lock.json
{
  "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"
      }
    }
  }
}
package.json
{
  "name": "npm-commander-defaults",
  "version": "1.0.0",
  "type": "module",
  "dependencies": {
    "commander": "13.1.0"
  }
}
test/contract.mjs
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');
}

Seeder de origem

csx-seed