Description
Short version
Making an option with an expected option-argument (i.e. type: string
) always consume the next argument has some benefits:
- simple rule
- consistent with usage description (e.g.
[-c option-argument]
) - no special support needed for negative numbers as option arguments
- consistent with common implementations (e.g.
getopts_long
, Commander) - POSIX compliant
Long version
This is a revisit for a deeper dive into specifically whether a string option should be greedy. Previously raised in #25 and #75 (comment) but not considered in depth.
Given the program:
const { parseArgs } = require('@pkgjs/parseargs');
const options = {
with: { short: 'w', type: 'string'}
};
console.log(parseArgs({ options }));
If there is an argument following the string option, does the parsing result depend on the contents of the argument? (Consider following argument one of: foo
, -x
, --xx
, -5
, true
, -
, --
, ---
, or empty string.)
Some simple examples:
node index.js --with foo
node index.js --with --floating-point-conversion
node index.js --w bar
node index.js --w -5
Let's take a look at the reference specifications and implementations I identified in #76.
POSIX
An option with a mandatory option-argument (our "string" option) should be described in the usage like: [-c option_argument]
Guideline 7 states: Option-arguments should not be optional. This is clarified in the notes to make it clear that the option is greedy:
Guideline 7 allows any string to be an option-argument; an option-argument can begin with any character, can be - or --, and can be an empty string. For example, the commands pr -h -, pr -h --, pr -h -d, pr -h +2, and pr -h " contain the option-arguments -, --, -d, +2, and an empty string, respectively. Conversely, the command pr -h -- -d treats -d as an option, not as an argument, because the -- is an option-argument here, not a delimiter.
GNU
Program Argument Conventions adds long options and does not change the handling of mandatory option-arguments.
getopt_long
Greedy. An option with a mandatory option-argument consumes the next argument.
Commander
Greedy. An option with a mandatory option-argument consumes the next argument.
Minimist
The option-argument is optional. It is not consumed if it is option-like. Negative numbers are not consumed.
(The details actually vary between short and long options, but this may be a historical accident rather than by design! Different behaviours for -
, leading ---
, and empty string.)
Yargs
The option-argument is optional. It is not consumed if it is option-like. There is an exception added for negative numbers, which are consumed.
(The details actually vary between short and long options, but this may be a historical accident rather than by design! Different behaviours for -
and leading ---
.)
Minimist and Yargs likely rationale
Minimist and Yargs using zero-config parsing assume options may take an argument. This allows multiple options which are variously parsed as boolean or string options. For example with Minimist:
$ node index.js -b -w foo
{ _: [], b: true, w: 'foo' }
parseArgs
does not have the same constraints as we are assuming auto-discovered options are boolean.