Skip to content
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

Add prefer-event-key rule #226

Merged
merged 33 commits into from May 31, 2019
Merged

Conversation

ankeetmaini
Copy link
Contributor

@ankeetmaini ankeetmaini commented Jan 29, 2019

Fixes #118

  • add fixer code

@ankeetmaini ankeetmaini changed the title [WIP] Adds initial implementation for prefer key. Fixes #118 [WIP] Adds prefer-key-over-key-code rule Jan 29, 2019
@ankeetmaini
Copy link
Contributor Author

I think my approach isn't very good here, trying to first narrow down to addEventListener and then finding all the keyCode bits using SourceCode's getToken API. Because querying under a Node is a little difficult and by doing getTokens I lose the parent-child link. This will make it unusable for destructured elements.

Following up with a better one where in I directly select keyCode identifier and then using context.getAncestors() to assert that they're infact inside an event callback.

@futpib
Copy link
Contributor

futpib commented Jan 30, 2019

One foreseeable gotcha with context.getAncestors() is that a .keyCode that is syntactically inside an addEventListener callback is not exactly the same as a .keyCode on the callback's argument.

const something = undefined;
element.addEventListener('keyup', event => {
  console.log(something.keyCode); // This `.keyCode` is "inside an event callback"
});

I think this can be correctly solved by targeting the callback function in the visitor, then getting it's scope and checking all the references to the first argument to see if they are .keyCode.

@ankeetmaini
Copy link
Contributor Author

ankeetmaini commented Jan 30, 2019

I'll have the CallbackExpression in the ancestors and was in process to do the same thing! I'll double back shortly on how it goes :)

Also I assume we only want to target keyup and keydown events. I'll add that check as well.

@futpib
Copy link
Contributor

futpib commented Jan 30, 2019

Also I assume we only want to target keyup and keydown events. I'll add that check as well.

We might as well target all events, since accessing keyCode (and others) on non-KeyboardEvents makes no sense, as it will always be undefined.

@sindresorhus Any thoughts?

@ankeetmaini If we indeed want to target only KeyboardEvents, there is also keypress.

@sindresorhus
Copy link
Owner

Hey, thanks for the pull request 🙌 I have gotten a huge response on the IssueHunt bounty issues and I now have a very long backlog of pull requests to review, so it might take some time until I will be able to review this. However, you can help move this along by helping out and reviewing the other submissions. If everyone helps everyone we can manage this 👌.

Some things to look for when reviewing:

  • Ensure the rule addition adheres to the instructions.
  • There are never too many tests. Try to find both passing and failing cases, especially obscure cases.
  • Check the docs for typos and whether something could be more clear.
  • Look at the rule code and see if anything could be simplified or done better. If something is unclear in the code, ask the submitter to explain.

@sindresorhus
Copy link
Owner

We might as well target all events, since accessing keyCode (and others) on non-KeyboardEvents makes no sense, as it will always be undefined.

👍

@sindresorhus sindresorhus changed the title [WIP] Adds prefer-key-over-key-code rule [WIP] Add prefer-key-over-key-code rule Jan 30, 2019
@ankeetmaini
Copy link
Contributor Author

@futpib this version shows my current approach. It also takes care of the edge case you suggested. Will poke a bit more before making it final.

@ankeetmaini
Copy link
Contributor Author

I am happy with the current approach and have added a lot of tests for valid/invalid code. The rule also covers the destructuring cases too. Please take a look :)

The thing that I am not convinced on is the fixing part. How do we fix if the case is like

bar.addEventListener('keyup', e => {
  sendThisToAnOtherModule(e.keyCode)
})

In this even if I try to fix it, it'll break the contract as the the receiving party might not accept a string representation of the key. And in other case like

const keys = {
  'enter': 34
}
bar.addEventListener('keyup', e => {
  if (e.keyCode === keys.enter)  return;
})

I am not sure if we should try to fix as we might step over and break things. Please advise!

@futpib
Copy link
Contributor

futpib commented Jan 31, 2019

I think best we can do is fix only comparisons against literals (like event.keyCode === 27 => event.key === 'Escape')

@ankeetmaini
Copy link
Contributor Author

Update: @futpib I've added the fixer code which takes care of direct if conditions.

if (e.keyCode === 27) -> if (e.key === 'Escape')

but the case

const {keyCode} = e;
if (keyCode === 27) // do something

needs to be looked into.

readme.md Outdated Show resolved Hide resolved
rules/prefer-key-over-key-code.js Outdated Show resolved Hide resolved
@futpib
Copy link
Contributor

futpib commented Feb 7, 2019

@ankeetmaini Would be nice to handle destructurings too, but I think we can give it a pass, as other rules like this (prefer-node-remove (with respect to parentNode/parentElement) and prefer-text-content) don't fix it too.

Unless @sindresorhus disagrees.

@ankeetmaini
Copy link
Contributor Author

@futpib I'm planning to give fixing-destructured-variables a try over the weekend. Will come back with an update.

@ankeetmaini
Copy link
Contributor Author

Hi @futpib, this is ready for review now. Also I couldn't figure out a way to fix destructured variables in if conditions.

I tried multiple ways, only one handler for all all keyCode, which etc (currently I target Property for destructured keys) but it threw as it was generating duplicate errors one for the key part and one for value

const {keyCode} = event

Here this generates into two identifiers, where both the key and value of keyCode is same, but the tests couldn't figure out === equality and were failing.

Even if I fix this, when the above variable is referenced again I wasn't able to find out if it is resolved from the destructured variable, as the AST walk function is called separately for them.

I also tried using context.getScope() it returns all the references but I don't get the parent attribute (weird!) and hence wasn't able to assert if it's in an If condition.

index.js Outdated
@@ -56,7 +56,8 @@ module.exports = {
'unicorn/prefer-node-append': 'error',
'unicorn/prefer-query-selector': 'error',
'unicorn/prefer-node-remove': 'error',
'unicorn/prefer-text-content': 'error'
'unicorn/prefer-text-content': 'error',
'unicorn/prefer-key-over-key-code': 'error'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sindresorhus Should this rule be named prefer-key or prefer-event-key, without the "over something else" part, like the other rules, or is the current name fine?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it should be prefer-event-key.

@ankeetmaini ankeetmaini changed the title [WIP] Add prefer-key-over-key-code rule Add prefer-key-over-key-code rule Feb 17, 2019
@futpib
Copy link
Contributor

futpib commented Feb 17, 2019

I also tried using context.getScope() it returns all the references but I don't get the parent attribute (weird!) and hence wasn't able to assert if it's in an If condition.

I guess you were looking for referece.identifier.parent. But fixing destructuring was an optional goal anyway.

rules/prefer-key-over-key-code.js Outdated Show resolved Hide resolved
rules/prefer-key-over-key-code.js Outdated Show resolved Hide resolved
rules/prefer-key-over-key-code.js Outdated Show resolved Hide resolved
rules/prefer-key-over-key-code.js Outdated Show resolved Hide resolved
rules/prefer-key-over-key-code.js Outdated Show resolved Hide resolved
rules/prefer-key-over-key-code.js Outdated Show resolved Hide resolved
@ankeetmaini ankeetmaini changed the title Add prefer-key-over-key-code rule [WIP] Add prefer-key-over-key-code rule Feb 18, 2019
@ankeetmaini
Copy link
Contributor Author

ankeetmaini commented Feb 20, 2019

@futpib thanks a lot for a thorough review! I've fixed and updated the implementation as per your comments. Let me know!


Enforces the use of [`KeyboardEvent#key`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) over [`KeyboardEvent#keyCode`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode) which is deprecated. The `key` property is also more semantic and readable.


Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please describe that it's fixable and what is fixable. See the other docs for how to write it.

@sindresorhus
Copy link
Owner

@ankeetmaini Can you fix the merge conflict and resolve the last feedback?

@ankeetmaini
Copy link
Contributor Author

@sindresorhus I am so sorry for not getting to it I'll update this shortly. Thanks for updating this PR. Will also address @futpib's comment. :)

@ankeetmaini
Copy link
Contributor Author

@sindresorhus all requested changes have been pushed!

@sindresorhus sindresorhus requested a review from futpib May 29, 2019 04:22
@sindresorhus
Copy link
Owner

// @MrHen

@sindresorhus sindresorhus merged commit 9bede78 into sindresorhus:master May 31, 2019
@sindresorhus
Copy link
Owner

Looks good to me now. Thanks for contributing, @ankeetmaini :)

@ankeetmaini
Copy link
Contributor Author

Thanks so much! Yay!

@ankeetmaini ankeetmaini deleted the prefer-key branch May 31, 2019 08:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Prefer event.key over event.keyCode
3 participants