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

Extra documentation: tricks and traps with options with optional values #1315

Closed
shadowspawn opened this issue Jul 27, 2020 · 15 comments
Closed
Labels
docs README (or other docs) could be improved

Comments

@shadowspawn
Copy link
Collaborator

shadowspawn commented Jul 27, 2020

We could add a separate page, outside the README, going into details about potential challenges using options with optional values. They seem quite attractive and the README used to use them more than options with require values! In practice, they are a bit tricky and aren't a free choice.

  • parsing ambiguity when use option as boolean flag but also operands and subcommands
  • possible work-arounds
    • dash-dash (for expert users)
    • tell users always dash-dash before operands
    • tell users options come after operands
    • convert arguments into options! Options work pretty nicely together.
  • conflict between short flag with value, and combined short flags with optional values. Work-around code to restore pre-Commander v5.0 parsing for people who prefer short-flag combining to short-flag+value.
@shadowspawn shadowspawn added the docs README (or other docs) could be improved label Jul 27, 2020
@heyjiawei
Copy link
Contributor

Hi @shadowspawn I would like to help out with this, is it alright?

@shadowspawn
Copy link
Collaborator Author

@heyjiawei happy to have someone else involved. Would you like to make a start on writing the page, or are you wanting to provide feedback/help with something I write?

@heyjiawei
Copy link
Contributor

heyjiawei commented Aug 16, 2020

If you have started on this I could help provide feedback. I can also start writing a section on this.

Could you elaborate on the following points:

  • parsing ambiguity when also option as boolean flag but also operands and subcommands
  • conflict between short flag with value, and combined short flags with optional values. Work-around code to restore pre-Commander v5.0 parsing for people who prefer short-flag combining to short-flag+value.

@shadowspawn
Copy link
Collaborator Author

shadowspawn commented Aug 16, 2020

parsing ambiguity when also option as boolean flag but also operands and subcommands

I had a typo there, "when also" should be "when use" (fixed in original post now).

If there is an option with an optional value -o

example -o
example -o optionalValue
example index.js
example -o whatIsThis

In the last example, the user might be intending whatIsThis as an argument or a subcommand but it will be read as the value for -o.

conflict between short flag with value, and combined short flags with optional values.

Suppose there is a plain flag -b and an option with an optional value -o.

example -b -o
example -oValue   => same as -o Value
example -bo   => same as -b -o
example -ob   ???

Before Commander v5, -ob expanded to -o -b. After Commander v5 the b is read as the value for -o.

Work-around code to restore pre-Commander v5.0 parsing for people who prefer short-flag combining to short-flag+value.

I was thinking of showing some example code to restore the old behaviour, but when I tried it was trickier than I expected to do it well, so I added configuration to build into Commander to switch the behaviour. #1326

@shadowspawn
Copy link
Collaborator Author

(I have been thinking about documenting complications with optional values for a long time, but have not started writing it down yet.)

@heyjiawei
Copy link
Contributor

Ah I see. Here is a rough draft (sorry its not complete but do comment!):

Tricks and traps with options with optional values

There potential challenges using options with optional values. They seem quite attractive and the README used to use them more than options with require values! In practice, they are a bit tricky and aren't a free choice.

Parsing ambiguity when also option as boolean flag but also operands and subcommands

program.command('example')
      .option("-o, --option [optionalValue]")
      .command('brew')
      .action(() => {
        console.log("example brew");
      })

program.parse(process.argv);

if (program.option) console.log(`option: ${program.option}`);
$ example -o
option: true
$ example -o thisValueIsPassedToOption
option: thisValueIsPassedToOption
$ example -o brew
option: brew
$ example -o nextArg
option: nextArg

For example, the user might be intending brew as the subcommand but it will be read as the value for -o. Likewise, the user might be intending nextArg as an argument but it too, will be read as the value for -o

Conflict between short flag with value, and combined short flags with optional values.

program
  .option("-a, --any [count]", "any servings")
  .option("-v, --vegan [count]", "vegan servings")
  .option("-l, --halal [count]", "halal servings");
program.parse(process.argv);

if (program.any) console.log(`any servings: ${program.any}`);
if (program.vegan) console.log(`vegan servings: ${program.vegan}`);
if (program.halal) console.log(`halal servings: ${program.halal}`);

In this example, it is ambiguous as to whether the user is trying to use optional options as boolean options, or pass the value vl to option -a

$ collect -avl
any servings: vl

If you wish to use optional options as boolean options, you need explicity list them as options

$ collect -a -v -l
any servings: true
vegan servings: true
halal servings: true

Possible workarounds

// TODO

@heyjiawei
Copy link
Contributor

conflict between short flag with value, and combined short flags with optional values.

I'm not quite sure what's the conflict here.

From your example:

example -ob   ???

It seems like this can be misleading instead of conflicting for users. I assume users may expect either:

  1. example -ob => -o b
  2. example -ob => -o -b

I think this is clearer if we show an example of combined short flags with optional values, using the servings type code example above. What do you think @shadowspawn ?

Before Commander v5, -ob expanded to -o -b

Are we pointing out this difference? Or are we adding a short explanation on why things became like that? @shadowspawn

@shadowspawn
Copy link
Collaborator Author

Great comments and questions. I'll write up a long reply when I have a bit more time.

@shadowspawn
Copy link
Collaborator Author

I'm not quite sure what's the conflict here.
...
It seems like this can be misleading instead of conflicting for users.

Very good point. This is not a conflict. This is not an error. But this will trip up some users the first time they encounter it, when it works differently than they expected (they won't notice when it does work the way they expected!).

The high level issue that that the end user will sometimes need to adjust the command-line to get the result they want, effectively so Commander understands what they intend.

@shadowspawn
Copy link
Collaborator Author

I think this is clearer if we show an example of combined short flags with optional values, using the servings type code example above.

I am not sure it will be clearer, but it is certainly the situation that is more likely to trip people up! I agree use an example of combined short flags with optional values.

@shadowspawn
Copy link
Collaborator Author

I like the vegan and halal example. I am not so keen on .option("-a, --any [count]", "any servings") I think because I associate -a with --all. Maybe "-o, --other"?

@shadowspawn
Copy link
Collaborator Author

Before Commander v5, -ob expanded to -o -b
Q: Are we pointing out this difference? Or are we adding a short explanation on why things became like that?

I was mainly giving you the back context in that comment. Hmmm, what do I want to say...

Like with the other issue, the (current) behaviour is not wrong or a conflict. But this may trip up some users. So again we want to help people understand enough to adjust the command-line if needed to get the result they want

The addition in this case is the new behaviour may be an issue for people upgrading from old versions of Commander, who are relying on the "other" (old) behaviour . So I want to cover that there is (will be) a routine to prioritise combining flags over combining flag-and-value.

Ask again if that does not make enough sense!

@heyjiawei
Copy link
Contributor

@shadowspawn I've created a PR for this #1332 , perhaps you can take a look

@shadowspawn
Copy link
Collaborator Author

shadowspawn commented Aug 21, 2020

(Will do.)

@shadowspawn shadowspawn added the pending release Merged into a branch for a future release, but not released yet label Sep 13, 2020
@shadowspawn shadowspawn removed the pending release Merged into a branch for a future release, but not released yet label Oct 25, 2020
@shadowspawn
Copy link
Collaborator Author

Released in Commander v6.2.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs README (or other docs) could be improved
Projects
None yet
Development

No branches or pull requests

2 participants