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: Check division operator in astUtils.canTokensBeAdjacent #12879
Conversation
lib/rules/utils/ast-utils.js
Outdated
let leftToken; | ||
|
||
if (typeof leftValue === "string") { | ||
const leftTokens = espree.tokenize(leftValue, { ecmaVersion: 2015 }); | ||
const tokens = espree.tokenize(leftValue, espreeOptions); |
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 you mind adding a test for when a Shebang
comment token is given as the left value? I don't think this could ever be a real world use case (since another token can't be on the same line as the shebang), but I do think we should make sure that this won't crash the process when Espree tries to tokenize this.
For reference, we mutate the text input to make the shebang a regular JS line comment before we parse in lib/linter/linter.js
and then transform the token post-parse to a Shebang
comment token.
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're right, that would crash! Maybe we could already add try-catch
as suggested in #12291 (comment) and also close #12291 with this PR?
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.
canTokensBeAdjacent
also didn't assume it could get a code (as a string argument) without any tokens, so it doesn't support a comment-only code. This isn't changed with this PR, it would still crash, so it isn't possible to call it with e.g.,:
astUtils.canTokensBeAdjacent(someToken, "/* comment */");
Then, it might also make sense to support empty code as well, and maybe even to account for spaces at the start/end of the code (e.g., canTokensBeAdjacent("a ", "b")
would return true
).
Maybe we could do that as well in this PR?
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 sounds good to me! I guess another option (or something we could do additionally) is to short circuit it and add an early return of false
if the left value token is of type Shebang
. That would save the process from having to run the tokenizing at all.
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.
Oh, interesting! Since this is already an improvement over the existing code, I would be fine with splitting these bug fixes over multiple PRs to keep them manageable. 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.
That sounds good to me! I guess another option (or something we could do additionally) is to short circuit it and add an early return of
false
if the left value token is of typeShebang
. That would save the process from having to run the tokenizing at all.
Maybe I didn't understand, but I think it isn't possible to check if the token is Shebang
before tokenizing, because we don't have the token yet?
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.
Oh, I see, I missed that it could be a string or a token. Yes, if the left value is a string that won't work. I think the approach you suggested sounds good 👍
lib/rules/utils/ast-utils.js
Outdated
@@ -1357,17 +1357,43 @@ module.exports = { | |||
* next to each other, behavior is undefined (although it should return `true` in most cases). | |||
*/ | |||
canTokensBeAdjacent(leftValue, rightValue) { | |||
const espreeOptions = { ecmaVersion: 2020, comment: true, range: 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.
Non-blocker for this PR, but it could be nice to add the ability to specify “latest” somehow, so that this never gets out of date.
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 would be great! But, I'm not sure if there is a way to do that at the moment? Does espree
support something like "latest" or provides a list of available versions?
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.
v/_ \ I don't think espree
has such a thing.
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 doesn’t, no! Definitely not a blocker for this - just an idea I had and wanted to write down for posterity 😄
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.
A list of all versions could be also useful for the online demo, it's hard-coded there and has to be updated manually.
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.
PR/proposal here: eslint/espree#430
lib/rules/utils/ast-utils.js
Outdated
let leftToken; | ||
|
||
if (typeof leftValue === "string") { | ||
const leftTokens = espree.tokenize(leftValue, { ecmaVersion: 2015 }); | ||
const tokens = espree.tokenize(leftValue, espreeOptions); |
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.
Oh, interesting! Since this is already an improvement over the existing code, I would be fine with splitting these bug fixes over multiple PRs to keep them manageable. What do you think?
Sorry, meant to submit those two comments yesterday. |
Agreed! Just added This PR is now ready for review since it fixes some issues and (I believe) doesn't add any new ones. |
What are next steps here? Are we waiting for the Espree change? |
I can run an Espree release tomorrow as well. It would be good to get the updated API in before we run the next major release with eslint/espree#429. |
If it would be easier for reviewing, I can add a note in #12291 and update |
espree@6.2.0 has been released. |
Done! |
…12879) * Fix: Check division operator in astUtils.canTokensBeAdjacent * Add try-catch and Shebang check * Upgrade espree, use latestEcmaVersion
Prerequisites checklist
What is the purpose of this pull request? (put an "X" next to an item)
[X] Bug fix
Tell us about your environment
What parser (default, Babel-ESLint, etc.) are you using?
default
Please show your full configuration:
Configuration
What did you do? Please include the actual source code causing the issue.
Online Demo Link (v6.8.0 actual)
What did you expect to happen?
4 errors and auto-fix that would not comment out some code.
What actually happened? Please include the actual, raw output from ESLint.
4 errors and auto-fix to:
In all 4 lines
/
becomes start of a line comment.What changes did you make? (Give an overview)
astUtils.canTokensBeAdjacent
to account for the/
operator on the left side and block comment, line comment or regex on the right side.no-extra-parens
andoperator-assignment
rules to get and pass possible comment tokens as well.astUtils.canTokensBeAdjacent
, had to also add the logic for comments (I believe they can be adjacent with everything except for/
on the left side).astUtils.canTokensBeAdjacent
that deals with string input (usingespree.tokenize
) to handle comments as well. I don't think this will affect the rules that are using this feature at the moment, but it should be a correct change and it also allowed testing this function with comments (all tests actually pass strings, maybe we should add some tests with tokens at some point since it's the most common case).espree
in order to passespree.latestEcmaVersion
instead of a hard-coded version toespree.tokenize()
, and addedtry-catch
aroundespree.tokenize()
. This should fix partially or entirely astUtils.canTokensBeAdjacent hardcoded espree.tokenize #12291 (edited to prevent auto-closing astUtils.canTokensBeAdjacent hardcoded espree.tokenize #12291),Is there anything you'd like reviewers to focus on?
espree.tokenize
?This can also happen in
operator-linebreak
in some edge cases. That rule has its own code to handle adjacent tokens, I'll see if it is possible to switch toastUtils.canTokensBeAdjacent
(or fix the same issue there if it isn't) in a follow-up PR.Marked as accepted since it's an obvious autofix bug.