Repository navigation
Allow parseArgs options to have an optional value #53427
Description
Activity
- addedfeature requestIssues requesting new Node.js features.Issues requesting new Node.js features.
on Jun 12, 2024 Hey team, I'd love to work on this (adding a default / optional param)
I've self-assigned it, but if anyone disagrees, please let me know
Reacted by Daniel Lemire and Benjamin Gruenbaum- addedutilIssues and PRs related to the built-in util module.Issues and PRs related to the built-in util module.
on Jun 12, 2024 The addition of
parseArgs()was controversial, and it was eventually added to Node.js core with the understanding that it would always remain a minimal implementation for the most basic use cases. It is by no means meant to replace more feature-complete argument parsers that exist in the ecosystem.Reacted by Kevin Gibbons, John Gee and Sam AtkinsOptional option-arguments are implemented in various ways and come with complications. My suggestion is don't include them as they complicate the parsing, despite looking attractive.
Let's start with POSIX. The standard says first, don't do it!
Guideline 7:
Option-arguments should not be optional.But then does say:
The Utility Syntax Guidelines in Utility Syntax Guidelines require that the option be a separate argument from its option-argument and that option-arguments not be optional, but there are some exceptions in POSIX.1-2017 to ensure continued operation of historical applications:
It says that an optional option-argument must be in the same argument as the option and not separated by a space.
utility_name -oVALUE utility_name -o POSITIONAL_ARGUMENT_NOT_OPTION_VALUEWith long options (from GNU) this means:
utility_name --optional=VALUE utility_name --optional POSITIONAL_ARGUMENT_NOT_OPTION_VALUE
The way optional option-arguments are implemented in libraries Commander, Yargs, and Python argParse is that optional option-arguments do not consume a space-separated argument that starts with a dash. This works quite nicely for interfaces which do not include positional arguments but is somewhat ambiguous for interfaces with positionals. I found this annoying enough that we eventually wrote it up for Commander to explain the problem and possible work-arounds:
Without positionals works pretty nicely:
utility_name -o utility_name -oVALUE utility_name -o VALUE utility_name -o -s SSSWith positionals, not so good for CLI user. How does user clarify that the following argument is not the option value, if they even realise the ambiguity? Requires more knowledge about conventions and support (especially
--option terminator).utility_name -o WHAT_AM_IThanks folks! I was unaware that the Node implementation was supposed to be minimal, but it makes sense. Commander looks like it solves this and a few other issues I've been having, so I'll give it a try instead. 👍
- addedcommit-queue-squashPRs the Commit Queue should land as one squashed commit.PRs the Commit Queue should land as one squashed commit.wontfixIssues that will not be fixed.Issues that will not be fixed.and removedcommit-queue-squashPRs the Commit Queue should land as one squashed commit.PRs the Commit Queue should land as one squashed commit.
on Aug 15, 2024 I came from #54396 which was closed as duplicated.
I appreciate the information, however this issue showed some information that are missing in the documentation. Would it be possible, at least, to address that? The docs page doesn't warn about this behaviour (or doesn't show it), or it doesn't explain when to use the utility (or when not).
Sure, opened #54431.
Reacted by John GeeI appreciate the information, however this issue showed some information that are missing in the documentation.
I am not sure what is missing in particular?
- a string-type option is used along with a value?
- that it is an exception in strict mode if a string-type option is missing a value?
- that a default value is only used when the option does not appear in the arguments to be parsed?
(I was about to post as @bakkot addressed what I thought might be the most likely confusion.)
What is the problem this feature will solve?
It's not unusual for command-line options to have optional arguments. For example,
githas--color[=<when>]: If an argument is provided, it's used, but if--coloris given without an argument, that argument defaults toalways.parseArgs()does not support this kind of optional argument. Either the option's type isbooleanand any argument throws an error; or it'sstringand a missing argument throws an error.What is the feature you are proposing to solve the problem?
Add a field to the option definition so that a
stringoption is allowed to have no argument, and use a default value in that case. For example, the--color[=<when>]case could look like this:Probably someone can think of a better name for this field.
What alternatives have you considered?
The alternative is to disable strict mode, and manually process the
tokensarray. However, this is a lot of boilerplate, and requires reimplementing the checks for which options are valid, making it error-prone.