-
Notifications
You must be signed in to change notification settings - Fork 583
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
feat(flags): infer argument types, names and defaults #2180
Conversation
flags/test.ts
Outdated
import { | ||
assert, | ||
IsExact, | ||
} from "https://deno.land/x/conditional_type_checks@1.0.5/mod.ts"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We prefer to avoid depending on deno.land/x/
from std
. Can you copy the necessary part of the module in std as test utility?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep i know, it was only temporarily 😉 will do 👍
|
||
/** ---------------------- TYPE TESTS ---------------------- */ | ||
|
||
Deno.test("typesOfAllBoolean", function (): void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice test cases! These illustrate what's done in this change very well
@c4spar Can you fix the type error in CI?
|
Oops, I assumed dashed parameters are camelcased 😅 is there a reason why we don't do that? |
flags/mod.ts
Outdated
|
||
/** Same as `Record` but also supports dotted and negatable options. */ | ||
type MapTypes<T extends ArgType, V> = undefined extends T ? Record<never, never> | ||
: T extends `no-${infer Name}` ? MapTypes<Name, V | false> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the last thing that is missing is the handling of negatable options. How do we want to proceed with them? do we want to make them configurable by prefixing them with no-
or with a separate option?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@c4spar
Sorry for the delay in response.
do we want to make them configurable by prefixing them with no- or with a separate option?
I don't think we should change it optional. That feels like an unnecessary breaking change to me. In my view --no-foo
shorthand is always useful for boolean args. So I suggest we just keep the existing behavior
For negation of non-boolean args, I can't think of reasonable usages of it. So I'd suggest we should leave it undefined behavior and let's ignore it in typings. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think we should keep support for negation of non boolean args.
A good example is deno run --no-config
😉 It's a string arg with a default behavior that can be disabled.
But if we don't make it configurable than all string and collectable args can be also false
, which is a bit annoying.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. --no-config
looks like a useful example.
But if we don't make it configurable than all string and collectable args can be also false, which is a bit annoying.
I agree with this. What API do you suggest for configurable negatable args?
Is the following example what you suggest for configurable negatable args? (I think this is not implemented though)
boolean: ["foo", "no-bar", "no-dotted.tick", "dotted.tock"],
string: ["beep", "no-boop", "no-dotted.zig", "dotted.zag"],
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the following example what you suggest for configurable negatable args? (I think this is not implemented though)
This would be the easiest solution and the typings for this are already implemented in this PR. I have also implemented the logic but only locally, i can open another PR for this.
Another solution would be to add a new negate
option, same like the collect
option. But the typings would be more complex for this solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would be the easiest solution and the typings for this are already implemented in this PR. I have also implemented the logic but only locally, i can open another PR for this.
Thank you for your efforts on this, but this syntax (boolean: ["no-bar"]
) for indicating negatable arg looks confusing/too implicit to me.
Another solution would be to add a new negate option, same like the collect option. But the typings would be more complex for this solution.
This solution looks much better to me as it's more explicit and probably easier to document. Also this feels consistent with collect
option for configuring arg behaviors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your efforts on this, but this syntax (boolean: ["no-bar"]) for indicating negatable arg looks confusing/too implicit to me.
I agree with you, I also don't really like it to activate --foo
and --no-foo
only with no-foo
.
I would like it more if you could explicitly activate both separately like this string: ["foo", "no-foo"]
. foo
would add the type string
and no-foo
would add the type false
. But this doesn't really work if only no-foo
is defined, because foo
is always a valid argument. A workaround could be to set foo
to unknown if only no-foo
is defined.
But i'm also fine with a new option to align with the collect
option.
I tried both solutions already, but with both solutions I had some issues with union types, but I can give it a second try.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok i got the types for the negatable
option working now 😉
flags/mod.ts
Outdated
|
||
type CollectType = string | undefined; | ||
|
||
type NoTypes<B, S, C> = undefined extends ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of this being a negative name ("No"), maybe instead use a positive name ("UseTypes" maybe?).
flags/mod.ts
Outdated
|
||
type CollectType = string | undefined; | ||
|
||
type NoTypes<B, S, C> = undefined extends ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe also add the type parameter constraints here to make it a little more clear what these type parameters could possibly be.
Though not necessary, it actually might be good to move away from single letter type parameter names and instead use longer more descriptive names because of how complex this is (I usually prefix type parameter names with a T
to distinguish them from other types)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great improvement of the usability of flags
. Nice work!
LGTM
I think this PR is ready to land now. @bartlomieju Do you have any concern about landing this? |
flags/mod.ts
Outdated
|
||
/** When `true`, populate the result `_` with everything after the first | ||
* non-option. */ | ||
stopEarly?: boolean; | ||
|
||
/** A string or array of strings argument names to always treat as strings. */ | ||
string?: string | string[]; | ||
string?: S | ReadonlyArray<Extract<S, string>>; | ||
|
||
/** A string or array of strings argument names to always treat as arrays. | ||
* Collectable options can be used multiple times. All values will be | ||
* colelcted into one array. If a non-collectable option is used multiple |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a typo here: colelcted
to collected
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed. Thx @dcdunkan 👍
No, this looks good to me! |
Ok. Let's land now! Thanks again for the series of works for landing this PR @c4spar! |
close #1898