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.
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:
Child:
Run:
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
https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap12.html#tag_12_02 ↩
https://github.com/tj/commander.js/blob/ba6d13ddb4243e5913367734f8c159089ffe7834/Readme.md?plain=1#L200 ↩
https://github.com/tj/commander.js/blob/ba6d13ddb4243e5913367734f8c159089ffe7834/Readme.md?plain=1#L703 ↩