Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implying a value or conditional on a value #2340

Open
DavidEdell opened this issue Jun 26, 2023 · 4 comments
Open

Implying a value or conditional on a value #2340

DavidEdell opened this issue Jun 26, 2023 · 4 comments

Comments

@DavidEdell
Copy link

I'm looking at ways of simplifying my logic in an application, but I'm not seeing a clean way to do what I want. If I'm missing an existing easy way to do this, please enlighten me. I can certainly implement this manually in a check function or main application logic, but it would be cleaner (especially if there are a large number of such arguments) if it could be specified as part of 'implies'.

Let's say I have an option "type" that is defined with choices of "local","remote" or "other". If the value is set to "remote", I want to require the field "host" to be defined with a value. A slightly more complex corollary is if "host" is defined, then the default "type" should become "remote (possibly skipping that check if type was explicitly set).

I think the cleanest way of achieving this would be implementing an advanced version of the "implies" argument, triggered when arguments are an object instead of a string.

For example, in the above case the type field may specify: implies: [{field: "host", condition: (val)=>(val=="remote")}].

Correspondingly the "host" field may specify: implies: [{field: "type", default: "ssh"}]. This would set type=ssh if the user has not explicitly specified another value [ie: to allow for the 'other' field allowing this option], though evaluating that rule may require more complex multi-pass parsing of the arguments. Using a key of "value" instead of default would provide the simpler case of unconditionally setting the host field value. If neither default nor value is specified, it would imply the original behavior of setting the field to true (now contingent on the optional condition evaluation).

To avoid implication loops, such conditions would have to be evaluated in order and not re-evaluated if one implies rule changes a value that affects another. The existing syntax (ie: implies:["foo"]) would be interpreted as equivalent to implies: [{field: "foo", value: true}]

There are probably some subtleties that I'm not thinking of, but I believe this would be useful if/when someone has time to implement it.

@shadowspawn
Copy link
Member

shadowspawn commented Jun 26, 2023

A heads-up that the existing implies has what has proved a somewhat unfortunate name. See #1322 for discussion.

If I read your suggestions correctly, your first suggestion is a conditional requirement that another option must have a value, and the second suggestion is for setting an implied value on another option. I think the first fits into the historical implies while the second does not. So I suspect they might go through different APIs rather than the same API.

A side note from looking for related issues, I think some people use .check() for manually setting missing options based on known options. (Edit: and you mentioned .check() in your introduction.)

@shadowspawn
Copy link
Member

(Thanks for the detailed description, and suggestions.)

@shadowspawn
Copy link
Member

I am aware of one argument parsing library with fancy conditionals, Oclif has relationships: https://oclif.io/docs/flags

@jly36963
Copy link
Contributor

jly36963 commented Jul 1, 2023

A workaround might be to use pre-validation middleware to conditionally check and fill in values. Unfortunately, I don't think this middleware solution would reflect in usage output the way other yargs methods would, so it would be on the developer to document these well in the option descriptions.

Because implies can be specified both on yargs directly (ie: yargs.implies(x, y)) and in the shorthand option declarations (ie: yargs.option('my-opt', { /* ... */ })), overloading implies to do handle more complex use cases might make the api more confusing

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

No branches or pull requests

3 participants