Skip to content

Allow parseArgs options to have an optional value #53427

Description

@AtkinsSJ

What is the problem this feature will solve?

It's not unusual for command-line options to have optional arguments. For example, git has --color[=<when>]: If an argument is provided, it's used, but if --color is given without an argument, that argument defaults to always.

parseArgs() does not support this kind of optional argument. Either the option's type is boolean and any argument throws an error; or it's string and 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 string option is allowed to have no argument, and use a default value in that case. For example, the --color[=<when>] case could look like this:

{
	color: {
		type: 'string',
		valueIfNoArgument: 'always',
	}
}

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 tokens array. However, this is a lot of boilerplate, and requires reimplementing the checks for which options are valid, making it error-prone.

Activity

  1. self-assigned this
    on Jun 12, 2024
  2. avivkeller commented on Jun 12, 2024

    @avivkeller
    Member

    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

  3. added
    utilIssues and PRs related to the built-in util module.
    on Jun 12, 2024
  4. tniessen commented on Jun 12, 2024

    @tniessen
    Member

    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.

  5. shadowspawn commented on Jun 17, 2024

    @shadowspawn
    Member

    Optional 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_VALUE
    

    With 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 SSS
    

    With 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_I
    
  6. AtkinsSJ commented on Jun 17, 2024

    @AtkinsSJ
    Author

    Thanks 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. 👍

  7. removed their assignment
    on Aug 15, 2024
  8. added
    commit-queue-squashPRs the Commit Queue should land as one squashed commit.
    wontfixIssues that will not be fixed.
    and removed
    commit-queue-squashPRs the Commit Queue should land as one squashed commit.
    on Aug 15, 2024
  9. ematipico commented on Aug 17, 2024

    @ematipico

    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).

  10. bakkot commented on Aug 18, 2024

    @bakkot
    Contributor

    Sure, opened #54431.

  11. shadowspawn commented on Aug 18, 2024

    @shadowspawn
    Member

    I 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.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature requestIssues requesting new Node.js features.utilIssues and PRs related to the built-in util module.wontfixIssues that will not be fixed.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions