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

Conflict with global options and command specific options #1033

Closed
dennisdupont opened this issue Aug 29, 2019 · 3 comments
Closed

Conflict with global options and command specific options #1033

dennisdupont opened this issue Aug 29, 2019 · 3 comments

Comments

@dennisdupont
Copy link

dennisdupont commented Aug 29, 2019

When .command() is called with options that are the same as the global options (aka top level options), then command specific option is parsed as if it were the top level option instead and the command specific option value is never defined.

commander
    .version(version)
    .description('tool')
    .option('-f, --format <format>', 'output format')

commander
    .command('fetch [version]')
    .alias('f')
    .description('fetch things')
    .option("-f, --file <destFile>", "file name to save output")
    .option("-d, --dir <destDir>", "destination directory for output")
    .action(function(version, options) {
    	// looking for something in destFile fails *always*
    	if (options.destFile) {
    		...
    	}
    }

If the above is invoked (assume linked or globally installed) as
> app f -f someFile
then I would expect options.destFile to have the value "someFile", but it is always null and instead format has the value "someFile".
If invoked as
> app -f someFormat f -f someFile
then I would expect options.destFile to have the value "someFile" and format to have the value "someFormat", but the behavior is the same again.

NOTE: does not matter whether the alias or the full command is used

This is due to code in parseOptions that tries to match all options instead of stopping at a command and allowing the child object to parse its own options.

There is an easy fix, although it may cause side effect due to my ignorance of the design and other features. That is in parseOptions, once a arg is not matched to an option and does not look like an option, simply stop processing and add the remainder to the unknown list:



    // option is defined
    if (option) {
    	...
      continue;
    }

    // looks like an option
    if (arg.length > 1 && arg[0] === '-') {
    	...
      continue;
    }

    // arg
    args.push(arg);

    // ============= Uninformed neophyte change starts here  ===================
    // not an option and doesn't look like one, must be a subcommand 
    // 		- stop collecting options at this level
    for (var u = i + 1; u < len; ++u) {
      unknownOptions.push(argv[u]);
    }
    break;
    // ============= Uninformed neophyte change ends here  ===================

  }
@shadowspawn
Copy link
Collaborator

Global options are not positional, and are processed before checking the command options. This could be thought of as similar to options coming before or after arguments.

So these are effectively the same:

app --format=short fetch
app fetch --format=short

and

app fetch --dir=build 1.2.3
app fetch build --dir=1.2.3

There is not currently support for positional global options.

@shadowspawn
Copy link
Collaborator

An answer was provided, and no further activity in a month. Closing this as resolved.

Feel free to open a new issue if it comes up again, with new information and renewed interest.

Having support for positional vs global options is a possible enhancement. There are not any open issues raising that possibility.

@shadowspawn
Copy link
Collaborator

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

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