Skip to content

Executable subcommand does not preserve end-of-options delimiter before option-like operands #2530

Description

@yminod

Description

Related PR: #2531

A stand-alone executable subcommand does not preserve the first end-of-options delimiter (--) when Commander dispatches to the child process.

This means an option-like operand after -- can be reparsed by the child command as an option, rather than as a positional argument.

Reproduction

Parent:

const { Command } = require('commander');

new Command()
  .name('parent')
  .command('child', 'run child', {
    executableFile: 'child.js',
  })
  .parse();

Child:

const { Command } = require('commander');

new Command()
  .name('parent child')
  .argument('[input]')
  .action((input) => console.log({ input }))
  .parse();

Run:

node parent.js child -- --not-an-option

Expected

The child command should receive the end-of-options delimiter and treat the following value as an operand:

{ input: '--not-an-option' }

Actual

The child command reports an unknown option:

error: unknown option '--not-an-option'

Notes

Commander already treats the first -- as an end-of-options delimiter for normal parsing, consistent with POSIX Utility Syntax Guideline 101. The README also documents -- as ending option processing, with remaining arguments used without being interpreted2.

For stand-alone executable subcommands, the README says the executable is responsible for handling its own options, rather than declaring them at the top level3. But in this case the parent consumes the delimiter before spawning the executable, so the child does not receive the same end-of-options boundary from the original command line.

I think the compatible behavior is to keep the existing in-process command behavior unchanged, but restore the first delimiter only when spawning an executable subcommand.

Footnotes

  1. https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap12.html#tag_12_02

  2. https://github.com/tj/commander.js/blob/ba6d13ddb4243e5913367734f8c159089ffe7834/Readme.md?plain=1#L200

  3. https://github.com/tj/commander.js/blob/ba6d13ddb4243e5913367734f8c159089ffe7834/Readme.md?plain=1#L703

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions