Skip to content

Commit

Permalink
Rework, and move file
Browse files Browse the repository at this point in the history
  • Loading branch information
shadowspawn committed Sep 4, 2020
1 parent 8113f41 commit 3434f4d
Showing 1 changed file with 59 additions and 104 deletions.
163 changes: 59 additions & 104 deletions optional-options-docs.md → docs/options-taking-varying-arguments.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,18 @@
# More About Options
# Options taking varying numbers of option-arguments

The README covers declaring and using options, and mostly parsing will work the way you and your users expect. This page covers some special cases
and subtle issues in depth.

- [More About Options](#more-about-options)
- [Terminology](#terminology)
- [Options taking varying numbers of option-arguments](#options-taking-varying-numbers-of-option-arguments)
- [Parsing ambiguity](#parsing-ambiguity)
- [Options taking varying numbers of option-arguments](#options-taking-varying-numbers-of-option-arguments)
- [Parsing ambiguity](#parsing-ambiguity)
- [Alternative: Make `--` part of your syntax](#alternative-make----part-of-your-syntax)
- [Alternative: Put options last](#alternative-put-options-last)
- [Alternative: Use options instead of command-arguments](#alternative-use-options-instead-of-command-arguments)
- [Combining short flags with optional values](#combining-short-flags-with-optional-values)
- [Behaviour change from v5 to v6](#behaviour-change-from-v5-to-v6)

## Terminology

_Work in progress: this section may move to the main README, or a page of its own._

The command line arguments are made up of options, option-arguments, commands, and command-arguments.

| Term | Explanation |
| --- | --- |
| option | an argument which begins with a dash and a character, or a double-dash and a string |
| option-argument| some options can take an argument |
| command | a program or command can have subcommands |
| command-argument | argument for the command (and not an option or option-argument) |

For example:

```sh
my-utility command -o --option option-argument command-argument-1 command-argument-2
```

In other references options are sometimes called flags, and command-arguments are sometimes called positional arguments.

## Options taking varying numbers of option-arguments
- [Combining short options, and options taking arguments](#combining-short-options-and-options-taking-arguments)
- [Combining short options as if boolean](#combining-short-options-as-if-boolean)
- [Terminology](#terminology)

Certain options take a varying number of option-arguments:
Certain options take a varying number of arguments:

```js
program
Expand All @@ -45,7 +21,9 @@ program
.option('--test [name...]') // 0 or more
```

### Parsing ambiguity
This page uses examples with options taking 0 or 1 arguments, but the discussions also apply to variadic options taking more arguments.

## Parsing ambiguity

There is a potential downside to be aware of. If a command has both
command-arguments and options with varying option-arguments, this introduces a parsing ambiguity which may affect the user of your program.
Expand Down Expand Up @@ -79,7 +57,7 @@ $ cook -i egg
technique: undefined
ingredient: egg

$ cook -i scrambled # oops
$ cook -i scrambled # oops
technique: undefined
ingredient: scrambled
```
Expand All @@ -99,9 +77,7 @@ If you want to avoid your users needing to learn when to use `--`, there are a f
Rather than trying to teach your users what `--` does, you could just make it part of your syntax.

```js
// ...
program.usage('[options] -- [technique]');
program.parse();
```

```sh
Expand All @@ -123,13 +99,11 @@ ingredient: cheese

### Alternative: Put options last

Commander allows options before or after the command-arguments, or even intermixed (like [GNU program argument conventions](https://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html)).
Commander follows the GNU convention for parsing and allows options before or after the command-arguments, or intermingled.
So by putting the options last, the command-arguments do not get confused with the option-arguments.

```js
// ...
program.usage('[technique] [options]');
program.parse();
```

```sh
Expand Down Expand Up @@ -159,46 +133,48 @@ program
const ingredient = (options.ingredient === true) ? 'cheese' : options.ingredient;
console.log(`ingredient: ${ingredient}`);
});

program.parse();
```

```sh
$ cook -i -t scrambled
technique: scrambled
ingredient: cheese
```
## Combining short options, and options taking arguments

------
_Work in progress: unreviewed from here down._

## Combining short flags with optional values
Multiple boolean short options can be combined after a single `-`, like `ls -al`. You can also include just
a single short option which might take a value, as any following characters will
be taken as the value.

optional options are option(s) which functions as a flag but may also take a value (declared using square brackets).
This means that by default you can not combine short options which may take an argument.

optional values (sometimes called option arguments) are values of these optional flag.

```
```js
program
.option("-o, --others [count]", "others servings")
.option("-v, --vegan [count]", "vegan servings")
.option("-l, --halal [count]", "halal servings");
.name('collect')
.option("-o, --other [count]", "other serving(s)")
.option("-v, --vegan [count]", "vegan serving(s)")
.option("-l, --halal [count]", "halal serving(s)");
program.parse(process.argv);

if (program.others) console.log(`others servings: ${program.others}`);
if (program.vegan) console.log(`vegan servings: ${program.vegan}`);
if (program.halal) console.log(`halal servings: ${program.halal}`);
const opts = program.opts();
if (opts.other) console.log(`other servings: ${opts.other}`);
if (opts.vegan) console.log(`vegan servings: ${opts.vegan}`);
if (opts.halal) console.log(`halal servings: ${opts.halal}`);
```

In this example, you have to take note that optional options consume the value after the short flag.

```
$ collect -avl
any servings: vl
```sh
$ collect -o 3
other servings: 3
$ collect -o3
other servings: 3
$ collect -l -v
vegan servings: true
halal servings: true
$ collect -lv # oops
halal servings: v
```

If you wish to use optional options as boolean options, you need to explicitly list them as individual options.
If you wish to use options taking varying arguments as boolean options, you need to specify them separately.

```
$ collect -a -v -l
Expand All @@ -207,59 +183,38 @@ vegan servings: true
halal servings: true
```

Likewise for variadic options. While options can have a single optional value, variadic options can take in multiple optional values and have the same parsing complications.

```
program
.option("-c, --citizenship <countries...>", "countries you hold passport of") // 1 or more value(s)
.option("-i, --illness [illness...]", "known illness before travel") // 0 or more value(s)
.option("-s, --visa-approved [status]", "status of visa if not approved"); // 0 ir 1 value
program.parse();
### Combining short options as if boolean

console.log(`Citizen of: `, program.citizenship);
console.log(`Known illness(es): `, program.illness);
console.log(`visa approved: ${program.visaApproved}`);
```
Before Commander v5, combining a short option and the value was not supported, and combined short flags were always expanded.
So `-avl` expanded to `-a -v -l`.

Optional options consume the value after the short flag and you will experience the following behaviour:
If you want backwards compatible behaviour, or prefer combining short options as booleans to combining short option and value,
you may change the behavior.

```
$ node opt.js -si
Known illness(es): undefined
visa approved: i
To modify the parsing of options taking an optional value:

$ node opt.js -is
Known illness(es): [ 's' ]
visa approved: undefined
```js
.combineFlagAndOptionalValue(true) // `-v45` is treated like `--vegan=45`, this is the default behaviour
.combineFlagAndOptionalValue(false) // `-vl` is treated like `-v -l`
```

If you wish to use variadic optional options as booleans, you will need to state them explicitly as follows:
## Terminology

```
$ node opt.js -i -s
Known illness(es): true
visa approved: true
```
_Work in progress: this section may move to the main README, or a page of its own._

You should also be careful when you mix variadic optional options with variadic required options. A required option **always** consumes a value and so, you will not get any errors when the first value passed to it contains a '-' like so:
The command line arguments are made up of options, option-arguments, commands, and command-arguments.

```
$ node opt.js -c -si
Citizen of: [ '-si' ] // Does not throw error
```
| Term | Explanation |
| --- | --- |
| option | an argument which is a `-` followed by a character, or `--` followed by a word (or hyphenated words), like `-s` or `--short` |
| option-argument| some options can take an argument |
| command | a program or command can have subcommands |
| command-argument | argument for the command (and not an option or option-argument) |

```
$ node opt.js -c -si -x
error: unknown option '-x'
For example:

$ node opt.js -c -si -i
Citizen of: [ '-si' ]
Known illness(es): true
```sh
my-utility command -o --option option-argument command-argument-1 command-argument-2
```

### Behaviour change from v5 to v6

Before Commander v5, `-ob` expanded to `-o -b`, which is different from the current behaviour in Commander v6 as explained above.

This new behaviour may be an issue for people upgrading from older versions of Commander but we do have plans to prioritise combining flags over combining flag-and-value in the future.
In other references options are sometimes called flags, and command-arguments are sometimes called positional arguments or operands.

0 comments on commit 3434f4d

Please sign in to comment.