-
-
Notifications
You must be signed in to change notification settings - Fork 292
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 CLI's --space
option parsing
#342
Conversation
main.js
Outdated
if (typeof opts.space !== 'number') { | ||
opts.space = true; | ||
} | ||
} |
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.
Relevant meow
issue: sindresorhus/meow#44
main.js
Outdated
@@ -114,6 +114,20 @@ updateNotifier({pkg: cli.pkg}).notify(); | |||
|
|||
const {input, flags: opts} = cli; | |||
|
|||
// Make data types for `opts.space` match those of the API | |||
if (typeof opts.space === 'string') { | |||
if (/^\d+$/.test(opts.space)) { |
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.
You can drop the +
. The number will never be more than 8.
test/main.js
Outdated
const reports = JSON.parse(stdout); | ||
|
||
// Only the specified file was checked (filename was not the value of `space`) | ||
t.true(reports.length === 1); |
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.
Use t.is
here and below.
d232772
to
56bc0de
Compare
Sounds good, I've updated those now. |
main.js
Outdated
@@ -114,6 +114,20 @@ updateNotifier({pkg: cli.pkg}).notify(); | |||
|
|||
const {input, flags: opts} = cli; | |||
|
|||
// Make data types for `opts.space` match those of the API | |||
if (typeof opts.space === 'string') { |
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.
space
is configured as type String
here. So yarg-parser
will always produce a String
.
I tried every possibility I could think of with yargs-parser
and always get either a String
or no space
property at all.
Therefore the test if (typeof opts.space === 'string')
is unnecessary and should be replaced by if (typeof opts.space !== 'undefined')
.
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.
The one exception is if you pass --no-space
, then the value will be false
. Is that an important case or would you still like it to just check against undefined
?
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.
Yes indeed to we can keep (typeof opts.space === 'string')
.
main.js
Outdated
@@ -114,6 +114,20 @@ updateNotifier({pkg: cli.pkg}).notify(); | |||
|
|||
const {input, flags: opts} = cli; | |||
|
|||
// Make data types for `opts.space` match those of the API | |||
if (typeof opts.space === 'string') { | |||
if (/^\d$/.test(opts.space)) { |
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.
/^\d$/
should be /^\d+$/
otherwise all number with multiple digit won't match (for example 10
)
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.
That's actually what I wrote initially and @sindresorhus asked me to remove the +
, saying that the number would never be larger than 8 (see his second comment on this PR). What's the consensus on this?
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 didn't see this comment. The problem if we drop the +
is that xo --space 10
will be considered as trying to lint the file 10
. I'm not sure this is what we want. @sindresorhus did you considered that case?
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.
In addition if we really want to limit that value to 0-8
we should explicitly test it and report the error if it's not valid similarly to https://github.com/xojs/xo/blob/master/main.js#L136
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.
Then I would favor making anything more than 8 an error. It makes no sense to do that and is most likely an error.
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.
Do we want to throw that error here, though, or should that be in options-manager.js so that the limit applies to both the CLI and the API?
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.
Should be in the API.
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.
Just to confirm, I'm hearing that we should checking CLI input using /^\d+$/
(with the +
) so that we don't treat higher numbers as filenames, then enforce the 8-space limit from the API.
Do you want that limit included in this PR, or should that be separate, since its a different scope?
main.js
Outdated
input.push(opts.space); | ||
} | ||
|
||
if (typeof opts.space !== 'number') { |
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 test depends on the fact that a previous branch was executed or not, so it's quite confusing.
Like you have the test (typeof opts.space !== 'number')
within the test (typeof opts.space === 'string')
.
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'm happy to adjust that. Here's my reasoning for doing it this way: in the non-number branch of the first if
statement, I wouldn't want to unconditionally append to input
since the value could be ''
, which wouldn't be useful as a file name. I could absolutely nest this test inside of the first one, though.
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.
It makes sense now that you explain it, but by reading the code the fact you meant to unconditional append to input
since the value could be ''
is really not clear. It not really clear that the value can be ''
unless you know all details of the parser by heart.
The code is locally valid, but most likely if we try to modify it in 6 months we'll never figure that out.
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.
Good point! When I move that condition into the first block I can also add a comment to that effect.
main.js
Outdated
@@ -114,6 +114,20 @@ updateNotifier({pkg: cli.pkg}).notify(); | |||
|
|||
const {input, flags: opts} = cli; | |||
|
|||
// Make data types for `opts.space` match those of the API | |||
if (typeof opts.space === 'string') { |
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.
See my other comments regarding this code.
In addition the cases where yargs-parser
set space
as 'true'
or 'false'
is not handled.
I think would be clearer and cover the 'true'
or 'false'
case:
if (typeof opts.space !== 'undefined') {
if (opts.space === 'true') {
opts.space = true;
} else if (opts.space === 'false') {
opts.space = false;
} else if (/^\d+$/.test(opts.space)) {
opts.space = parseInt(opts.space, 10);
}
if (opts.space) {
input.push(opts.space);
}
opts.space = true;
}
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.
That's a great idea, handling those 'true'
and 'false'
cases! I'll get on that. I'd do a slightly different implementation, though, since that quick example would always set the value to true
and would push numbers and true
to input
.
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.
If we add the +
to the regexp then the numbers wouldn't be parsed as the input
.
Indeed the opts.space = true;
is wrongly positioned. It should probably be something like that:
if (typeof opts.space !== 'undefined') {
if (opts.space === 'true') {
opts.space = true;
} else if (opts.space === 'false') {
opts.space = false;
} else if (/^\d+$/.test(opts.space)) {
opts.space = parseInt(opts.space, 10);
} else {
if (opts.space) {
input.push(opts.space);
}
opts.space = true;
}
}
@sindresorhus that would also be a good idea to fix Travis and the unit test. See #341 |
Ensure that the `space` value, if present, is either a number or a boolean before passing it to the main API. The space option is intended to act as either a boolean or a number option, but it is implemented as a string option out of necessity, which resulted in some bugs. This commit fixes bugs demonstrated by the following invocations: `xo --space=4` Before fix: Expect 2-space indents. * The value of `space` is the *string* '4'. * The value is truthy, resulting in the space option being activated. * The value is not a number, resulting in the default of 2 being used. Now: Expect 4-space indents. * The value of `space` is the *number* 4. `xo --space file.js` Before fix: Check all files in the CWD and expect 2-space indents. * The value of `space` is 'file.js'. * The value is truthy and not a number, so expect 2-space indents. * There are no positional arguments recognized, so check all files. - This is a subtle bug, since the desired file *is* usually checked, it's just not checked exclusively. Now: Check only file.js and expect 2-space indents. `xo --space` Before fix: Expect tab indents. - The value of `space` is the empty string. - The value is falsey, so it is not used, instead defaulting to tabs. Now: Expect 2-space indents.
56bc0de
to
e5cb28d
Compare
I've just updated the PR. Following up on our discussions above:
|
@sindresorhus Any other changes you'd like? |
@noahbrenner Looking good. Thanks for this awesome contribution :) |
Absolutely! And thanks to you two for working with me on it! |
Overview
Ensure that the
space
value, if present, is either a number or a boolean before passing it to the main API. The space option is intended to act as either a boolean or a number option, but it is implemented as a string option out of necessity, which led to a few bugs.Bugs fixed
Here are the results of several invocations before and after applying this PR:
xo --space=4
Before fix:
space
is the string'4'
.Now:
space
is the number4
.xo --space file.js
Before fix:
space
is'file.js'
.Now:
file.js
and expect 2-space indents.xo --space
Before fix:
space
is the empty string.Now:
Edge cases
These are some quirks that are still present after this PR. Some of them may actually be desired, depending on your viewpoint, others perhaps less so. Let me know if there are any that you would like me to address.
xo --space=false
:'false'
is treated as a file name and 2-space indents are expected. It is similar for--space=true
.xo --space=3.0
:'3.0'
is treated as a file name and 2-space indents are expected. The implementation in this PR only recognizes numbers if they contain nothing but digits. This also applies to negative numbers (no-
allowed).10
, even with leading0
s.xo --space=0
: Tabs will be expected, since the value is falsey.Number.MAX_SAFE_INTEGER
, so weird rounding and overflow can happen if someone wants the worst indent ever.xo --space=4 --no-space
: This results in an array of['4', false]
, sospace
will be truthy, 2-space indents will be expected, and this array will be passed to the main API as if it were a positional argument.space
are now assumed to be file names (or globs), it is possible to specify a filename before the end of the command line options:xo --space file.js --quiet another.js
.References
Some relevant lines elsewhere in the code base:
Closes #339
Possibly relevant to #212 when specifying a file directly after
--space