Commander looks for the program options anywhere on the command line, including after operands (quite common) and after subcommands (less common). When a program option is defined the value is only available from the program options.
The scenarios people have asked about are:
1) only looking for program option before subcommand, so say subcommand could use same option name
2) treating the option as "global" so value available from the subcommand, or even appear in the subcommand help
3) stop parsing at the first operand and and subsequent "options" are included as ordinary arguments, and can be used for calling another program (without needing to use .allowUnknownOptions or --).
(This discussion uses program and subcommand for simplicity as though there were only two levels, but there could be more levels.)
Related issues:
POSIX and GNU differ on how options are parsed relative to operands, but do not mention subcommands as such.
POSIX has options strictly before operands.
https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html
Guideline 9:
All options should precede operands on the command line.
GNU relaxes the order.
https://www.gnu.org/prep/standards/standards.html#Command_002dLine-Interfaces
Note that the GNU version of getopt will normally permit options anywhere among the arguments unless the special argument ‘--’ is used. This is not what POSIX specifies; it is a GNU extension.
https://www.gnu.org/software/coreutils/manual/html_node/Common-options.html
Normally options and operands can appear in any order, and programs act as if all the options appear before any operands. For example, ‘sort -r passwd -t :’ acts like ‘sort -r -t : passwd’, since ‘:’ is an option-argument of -t. However, if the POSIXLY_CORRECT environment variable is set, options must appear before operands, unless otherwise specified for a particular command.
Yargs has halt-at-non-option which defaults to false.
Should parsing stop at the first positional argument?
Cobra has Flags and PersistentFlags for whether flag [value] available to children,
and TraverseChildren for whether to look for local flags of parent in children arguments.
Waiting for a better solution, this is my workaround to have a set of common options for all my subcommands.
import commander from "commander";
import colors from "colors";
class myCommand extends commander.Command {
command(nameAndArgs, actionOptsOrExecDesc, execOpts) {
let cmd = super.command(nameAndArgs, actionOptsOrExecDesc, execOpts);
cmd
.option("-C, --no-color", "remove color", false)
.option("-v, --verbose", "output results", true)
.option("--silent, --no-verbose", "disable output")
.on('option:no-color', () => colors.disable())
.on('command:' + cmd.name(), operands => colors.enable());
return cmd;
}
}
const program = new myCommand()
.version(getCurrentVersion())
.description("my commander test");
program
.command("list")
.alias("l")
.description("list all available commands")
.action(doList);
async function doList(options){
/* ... */
}
async function main() {
if (!process.argv.slice(2).length) {
program.outputHelp();
process.exit();
}
return await program.parseAsync(process.argv);
}
main().catch(error => console.error(error.message));
- treating the option as "global" so value available from the subcommand...
A simple way to do this would be by adding an optional parameter to .opts(). This may mean an extra line of code to access the combined options, but easy and explicit.
.option('--debug');
program
.command('sub')
.option('--mine')
.action((options, command) => { // Commander 7 passes options+command
console.log(command.opts({ includeGlobals: true })); // includes "debug" option
});
Other possible names for the property:
deep: from https://github.com/tj/commander.js/pull/1024#issuecomment-568403615all: similar to "beforeAll" and "afterAll" used with .addHelpText()Pull Request opened to add .enablePositionalOptions() and .passThroughOptions(): #1427
.enablePositionalOptions() and .passThroughOptions() included in Commander 7.0.0.
Not much interest in getting collected options so far, so closing this as covered most of the collected issues.
Most helpful comment
Waiting for a better solution, this is my workaround to have a set of common options for all my subcommands.