Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Collect: global option parsing and values #1229

Closed
shadowspawn opened this issue Mar 26, 2020 · 5 comments
Closed

Collect: global option parsing and values #1229

shadowspawn opened this issue Mar 26, 2020 · 5 comments
Milestone

Comments

@shadowspawn
Copy link
Collaborator

shadowspawn commented Mar 26, 2020

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:

Standards

POSIX and GNU differ on how options are parsed relative to operands, but do not mention subcommands as such.

POSIX (Open Group)

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

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.

Examples from Other Implementations

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.

@shadowspawn shadowspawn changed the title Triage: global option parsing and values Group: global option parsing and values Mar 27, 2020
@shadowspawn shadowspawn changed the title Group: global option parsing and values Collect: global option parsing and values Mar 27, 2020
@boulaya66
Copy link

boulaya66 commented May 4, 2020

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

@shadowspawn
Copy link
Collaborator Author

shadowspawn commented Dec 13, 2020

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

program
  .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:

@shadowspawn
Copy link
Collaborator Author

Pull Request opened to add .enablePositionalOptions() and .passThroughOptions(): #1427

@shadowspawn shadowspawn removed their assignment Jan 10, 2021
@shadowspawn shadowspawn added the pending release Merged into a branch for a future release, but not released yet label Jan 10, 2021
@shadowspawn shadowspawn added this to the v7.0.0 milestone Jan 10, 2021
@shadowspawn shadowspawn removed the pending release Merged into a branch for a future release, but not released yet label Jan 15, 2021
@shadowspawn
Copy link
Collaborator Author

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

@shadowspawn
Copy link
Collaborator Author

Opened a draft PR for .addCommonOption() #1670

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants