Repository navigation
util: Extended parseArgs validation settings #45062
Description
Activity
Replying to these here to move the discussion.
Previous discussion for reference: #44564 (comment) #44564 (comment)In response to @tniessen #44564 (comment):
I don't see this as added complexity to the API surface since as previously mentioned all of these are 100% optional and do not need to be used, the current simple API would remain usable with no change. As for added complexity to the implementation, yes that's true, but I also see it as an argument in favor of adding it once more, given that if it isn't done by parseArgs, userland code will need to do said complex heavy lifting on its own, which can be prone to mistakes and results in hundreds of different implementations each with their quirks, and having users not need to do such heavy lifting themselves is precisely the goal of utility builtins.
In response to @shadowspawn #44564 (comment):
It is actually a little funny how there is seemingly a paradox here, since as mentioned, there have been arguments in the case of the default values for parseArgs, that it was "too simple" of an addition to be worthwhile to add to the utility since userland code could easily implement such functionality on its own, and now the problem is "too complex", which contradicts the previous, something to think about I suppose...
(There are so many possible additions to argument parsing. I am checking whether proposed changes are a clean addition and widely desired, whether simple or complex to add. No paradox from my point of view, but yes gentle pushback on additions.)
Reacted by Tobias Nießen and Moshe AtlowCommander and Yargs both use
conflicts()as the name for the suggestedincompatible.(The naming is not independent. Commander only recently added
conflicts()after 10 years without any such routines, and I looked at the Yargs naming.)An implementation detail is whether such routines consider just the options from the command-line (or supplied
args), or consider the returned value of the option. The difference is the default values.From the wording referencing
--aI am guessing you are thinking of the command-line option and ignoring the default value.The reason for considering the default value is the author might stick in an environment variable as the default value. This means the option default value may be from the end-user.
Commander and Yargs both use
conflicts()as the name for the suggestedincompatible.(The naming is not independent. Commander only recently added
conflicts()after 10 years without any such routines, and I looked at the Yargs naming.)conflictssounds fine to me aswell, I'd be happy with either, I'll add it as a possible alternative 👍An implementation detail is whether such routines consider just the options from the command-line (or supplied
args), or consider the returned value of the option. The difference is the default values.From the wording referencing
--aI am guessing you are thinking of the command-line option and ignoring the default value.The reason for considering the default value is the author might stick in an environment variable as the default value. This means the option default value may be from the end-user.
I did overlook defining this behavior in the main post, but I think
requires*anddefaultshould simply be incompatible with each other, thinking about it from a JS/TS functions perspective, when you give an argument a default value, it becomes entirely optional and thus cannot be required, so an option with adefaultwould mean explicitly optional at all times and trying to require it should error.Conditionally doing it based on the truthiness of the default value concerns me because there is no guarantee an intended default value will always be a truthy JS value, namely
falseor an empty string.It could maybe be made so that the errors thrown provide sufficient parseable information so that if desired userland code can wrap the parseArgs call in a try catch and implement additional custom behavior for specific errors such as checking environment variable, database or cached data (etc) availability, since this really is one thing that just has too wide range of possibilities to make a good unclogged API for in my opinion, we would probably be talking about stuff like adding callbacks into this to support that in the parseArgs API itself.
- addedutilIssues and PRs related to the built-in util module.Issues and PRs related to the built-in util module.
on Oct 19, 2022 - addedfeature requestIssues requesting new Node.js features.Issues requesting new Node.js features.
on Oct 20, 2022 It is actually a little funny how there is seemingly a paradox here, since as mentioned, there have been arguments in the case of the default values for parseArgs, that it was "too simple" of an addition to be worthwhile to add to the utility since userland code could easily implement such functionality on its own, and now the problem is "too complex", which contradicts the previous, something to think about I suppose...
It's not really a contradiction; complexity can be orthogonal to usefulness, and apparently, enough people saw the usefulness in default values (even though I personally might have preferred not to add default values to
parseArgs). This proposal, on the other hand, appears much more complex and, according to #45062 (comment), commander did not have this feature for an entire decade, so it might not be as desired.(Also, nobody said that this feature would be "too complex" to do in userland.)
In my opinion if people continue importing commander or other third party CLI libraries for these kinds of features that
parseArgsmight not have, it kind of takes away the value of havingparseArgsbuilt-in, which would have been to make argument handling easy without the need of third party libraries. Sure some basic CLI programs may have everything they need fromparseArgsalone, but a standard library should try to account for all (or a majority of) usecases.Sure some basic CLI programs may have everything they need from parseArgs alone, but a standard library should try to account for all (or a majority of) usecases.
I disagree. It's much more important that the standard library be easy to use and reliable, which is directly in tension with having a bunch of options. It's fine if less-common use cases require you to implement a little logic yourself, even if that means some people will reach for a third-party library instead.
Reacted by John Gee and Konstantin ShutkinHere's a draft PR to help move the discussion forward. I don't see these options adding any instability or inconvenience for users who don't need them, other than an extra paragraph to skip over in the docs.
There has been no activity on this feature request for 5 months and it is unlikely to be implemented. It will be closed 6 months after the last non-automated comment.
For more information on how the project manages feature requests, please consult the feature request management document.
- addedstaleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
on Aug 14, 2023 There has been no activity on this feature request and it is being closed. If you feel closing this issue is not the right thing to do, please leave a comment.
For more information on how the project manages feature requests, please consult the feature request management document.
- added a commit that references this issue
on May 5, 2024
On issue #44564, a
requiredsetting was proposed, but frowned upon due to the ideal optional nature of commandline flags and options, in that same linked issue I have made a counter proposal (#44564 (comment)) aboutincompatibleandrequiresfields instead? This is a dedicated followup issue to that proposal for further discussion.The proposal
The addition of 3 new fields to parseArgs'
optionsobjects:incompatible,requiresandrequiresOne.While unconditionally required options are rare and frowned upon, dependent and incompatible options are far more common. These fields would be of type
string[], containing names of other options in the currentparseArgsobject:The above code would result in:
[]. If any of them specify either their own option or a non-existent option it should throw aTypeError.requiresis directional, if--arequires--bbut--bdoesn't require--a,foo --bis valid butfoo --ais not.requiresOneis a variation ofrequireswhere the array is treated as a list of ORs instead of ANDs.requiresandrequiresOnecan be used together without issue, but naturally overlapping options between the two will have higher precedence onrequires.incompatibleis bidirectional, if--adeclared itself incompatible with--b, then--bis also implicitly incompatible with--a. Explicitly marking both incompatible with each other is fine and does nothing extra.requires*andincompatibleof two options or one by itself happens, it should throw aTypeError.Notes
requiresAllmight be considered more consistent withrequiresOnethanrequires.requiresandrequiresOneinto a single option might be a possibility too but I couldn't think of a good way.incompatible->incompatibleWith, slightly longer but more self-explanatory.incompatible->conflicts, compatibility with Commander and Yargs (util: ExtendedparseArgsvalidation settings #45062 (comment))