-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Fix help default values display #1309
Conversation
I like the look of the key code change, nice and small. I haven't tried running it yet, but optimistic enough from reading the code that I jumped straight to suggestions on tuning the PR! |
1ff7d6f
to
7451614
Compare
@shadowspawn I made some updates, let me know if those work! |
index.js
Outdated
|
||
_stringify(value) { | ||
// Use the `toString` method for objects that don't use the default | ||
if (typeof value === 'object' && Object.getPrototypeOf(value).toString !== Object.prototype.toString) { |
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.
Turns out JSON.stringify
is very robust! When I tried putting in some challenging default values, the new code crashed displaying the help. e.g.
.option('--null <value>', 'null', null)
.option('--cleanObject <value>', 'Object.create(null)', Object.create(null))
I did a bit of reading and experimentation and suggest:
if (typeof value === 'object' && value !== null && typeof value.toString === 'function' && value.toString !== Object.prototype.toString) {
For interest, I ran through various standard data types looking for ones that would change display.
|
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 am slightly worried that this will not be an improvement in some cases, but I like the idea in principle of calling toString
rather than JSON.stringify
as closer to the intent — displaying as text.
Needs tightening up for the test whether appropriate to call .toString
, otherwise looking tidy now.
@shadowspawn Oh yes, these are some good cases, I will update. Though, starting to think |
… allows for custom `toString`
7451614
to
25ebd41
Compare
@shadowspawn updated! Let me know your thoughts. |
Hmm, I had noticed the |
@shadowspawn I just feel |
Two work-around approaches for reference: a slightly hacky one taking advantage of const { program } = require('commander');
const ipv4 = require('ip-num').IPv4;
const defaultValue = new ipv4("1.1.1.1");
const customValue = new ipv4("2.2.2.2");
customValue.toJSON = () => { return customValue.toString() }
const manualValue = '3.3.3.3';
program
.option('--plain <value>', 'default Commander behaviour', defaultValue)
.option('--custom <value>', 'custom toJSON', customValue)
.option('--manual <value>', `manual (default: "${manualValue}")`);
program.parse();
const opts = program.opts();
opts.manual = opts.manual || new ipv4(manualValue);
console.log(opts); |
@shadowspawn I know what you are saying, the problem is re-purposing My feeling now is that focus should be instead on fixing problems presented in #400. That way, the default value argument is actually forced to be a string. The user supplies the command line friendly value and it gets processed by the user supplied parse function. Would you be open to closing this and going in the direction of #400 instead? |
Changing the behaviour so that the custom processing (coercion) function is called on the default/starting value is likely to work better with displaying the starting value for rich coercions. I am intrigued with how it might work. I don't think it is as natural for simpler coercions though, say needing to specify "3.4" instead of 3.4. And a big warning in advance, I suspect it will be a very breaking change and not compelling enough to break existing users. I noticed yargs handles this by having a
with a nice example of the function flavour:
This is a simple direct approach to the help problem and separates the value from the representation. There is not anywhere currently to add properties like this, but I have been wondering about how to make options more extensible for the less common things: #518 #1106 |
Thanks @carsonreinke for good discussion. I initially thought
|
Pull Request
Problem
Fixes #1283.
Default values for options that are not either string or boolean display as JSON encoded string.
An example would be using
IPv4
fromip-num
package produces the following as the default value:(default: {"bitSize":32,"maximumBitSize":"4294967295","type":1,"octets":[{"value":1},{"value":1},{"value":1},{"value":1}],"separator":".","value":"16843009"})
This value is not helpful or user friendly.
Solution
Allow for default values that are objects to utilize a custom
toString
method to display for the help. The defaultObject.toString
method will not be used. All other types of default values will continue to useJSON.stringify
.NOTE: This did require a signature change of TypeScript typings to communicate that allows for
defaultValues
to beany
instead of juststring | boolean
.ChangeLog
N/A