Remix.run Logo
sudahtigabulan 3 days ago

Is there no getopt implementation for Typescript? The input this library tries to handle better looks to me like bad design.

"options that depend on options" should not be a thing. Every option should be optional. Even if you have working code that can handle some complex situation, this doesn't make the situation any less unintuitive for the users.

If you need more complex relationships, consider using arguments as well. Top level, or under an option. Yes, they are not named, but since they are mandatory anyway, you are likely to remember their meaning (spaced repetition and all that). They can still be optional (if they come last). Sometimes an argument may need to have multiple parts, like user@host:port You can still parse it instead of validating, if you want.

> mutually exclusive --json, --xml, --yaml.

Use something like -t TYPE instead, where TYPE can be one of json, xml, or yaml. (Make illegal states unrepresentable.)

> debug: optional(option("--debug")),

Again, I believe it's called "option" because it's meant to be optional already.

  optional(optional(option("--common-sense")))
EOR
dwattttt 3 days ago | parent | next [-]

> options that depend on options

What would you do for "top level option, which can be modified in two other ways"?

  (--option | --option-with-flag1 | --option-with-flag2 | --option-with-flag1-and-flag2)
would solve invalid representation, but is unwieldy.

Something that results in the usage string

  [--option [--flag1 --flag2]]

doesn't seem so bad at that point.
sudahtigabulan 3 days ago | parent [-]

I think I've seen it done like that

  --option flag1,flag2
(Maybe with another separator, as long as it doesn't need to be escaped.)

Another possibility is to make the main option an argument, like the subcommands in git, systemctl, and others:

  command option --flag1 --flag2
This depends on the specifics, though.
dwattttt 3 days ago | parent [-]

> --option flag1,flag2

Embedding a second parse step that the first parser doesn't deal with is done, but it's a rough compromise.

It feels like the difficulty in dealing with

  [--option [--flag1 --flag2]]

Is more to do with its expression in the language parsed to, than CLI elegance.
Spivak 3 days ago | parent | prev [-]

I think ultimately you're trying to tell a river that it's going the wrong way. Programs have had required options for decades at this point. I think they can make sense as alternatives to heterogeneously typed positional arguments. By making the user name them explicitly you remove ambiguity and let the user specify them in whatever order they please.

In Python this was a motivating factor for letting functions demand their arguments be passed as named keywords. Something like send("foo", "bar") is easier to understand and call correctly when you have to say send(channel="foo", message="bar")