-
-
Notifications
You must be signed in to change notification settings - Fork 387
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
feat(lint/noStaticElementInteractions): add rule #2981
base: main
Are you sure you want to change the base?
feat(lint/noStaticElementInteractions): add rule #2981
Conversation
CodSpeed Performance ReportMerging #2981 will not alter performanceComparing Summary
|
crates/biome_js_analyze/src/lint/nursery/no_static_element_interactions.rs
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_static_element_interactions.rs
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_static_element_interactions.rs
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_static_element_interactions.rs
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_static_element_interactions.rs
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_static_element_interactions.rs
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_static_element_interactions.rs
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_static_element_interactions.rs
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_static_element_interactions.rs
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_static_element_interactions.rs
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_static_element_interactions.rs
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_static_element_interactions.rs
Outdated
Show resolved
Hide resolved
…d move `CATEGORIES_TO_CHECK` to const
As this comment states, the following two methods were created to bridge the gap between eslint-plugin-jsx-a11y and Biome
However, I thought it was necessary to optimize the Biome definition based on the official documentation, rather than discussing the two options of which way to go. Is this an issue that should be addressed in this PR? |
crates/biome_js_analyze/src/lint/nursery/no_static_element_interactions.rs
Outdated
Show resolved
Hide resolved
Let's address that in another PR. |
m.insert("clipboard", vec!["onCopy", "onCut", "onPaste"]); | ||
m.insert("composition", vec!["onCompositionEnd", "onCompositionStart", "onCompositionUpdate"]); | ||
m.insert("keyboard", vec!["onKeyDown", "onKeyPress", "onKeyUp"]); | ||
m.insert("focus", vec!["onFocus", "onBlur"]); | ||
m.insert("form", vec!["onChange", "onInput", "onSubmit"]); | ||
m.insert("mouse", vec![ | ||
"onClick", "onContextMenu", "onDblClick", "onDoubleClick", "onDrag", "onDragEnd", | ||
"onDragEnter", "onDragExit", "onDragLeave", "onDragOver", "onDragStart", "onDrop", | ||
"onMouseDown", "onMouseEnter", "onMouseLeave", "onMouseMove", "onMouseOut", | ||
"onMouseOver", "onMouseUp" | ||
]); | ||
m.insert("selection", vec!["onSelect"]); | ||
m.insert("touch", vec!["onTouchCancel", "onTouchEnd", "onTouchMove", "onTouchStart"]); | ||
m.insert("ui", vec!["onScroll"]); | ||
m.insert("wheel", vec!["onWheel"]); | ||
m.insert("media", vec![ | ||
"onAbort", "onCanPlay", "onCanPlayThrough", "onDurationChange", "onEmptied", | ||
"onEncrypted", "onEnded", "onError", "onLoadedData", "onLoadedMetadata", "onLoadStart", | ||
"onPause", "onPlay", "onPlaying", "onProgress", "onRateChange", "onSeeked", "onSeeking", | ||
"onStalled", "onSuspend", "onTimeUpdate", "onVolumeChange", "onWaiting" | ||
]); | ||
m.insert("image", vec!["onLoad", "onError"]); | ||
m.insert("animation", vec!["onAnimationStart", "onAnimationEnd", "onAnimationIteration"]); | ||
m.insert("transition", vec!["onTransitionEnd"]); |
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 need elements (and handlers) other than in CATEGORIES_TO_CHECK
?
We only use focus
, keyboard
and mouse
.
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.
@unvalley
In ESlint, interactions are managed in independent files named eventHandlersByType
.
ref: https://github.com/jsx-eslint/jsx-ast-utils/blob/main/src/eventHandlers.js
Among them, ESlint uses focus
, keyboard
and mouse
by default.
ref: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/974275353598e9407c76bd4a50c331a953755cee/src/rules/no-static-element-interactions.js#L33-L37
In other words, the EVENT_TO_HANDLERS created in this PR was originally intended to be used for other rules, etc., but since it is currently unclear where to place them, they are implemented this way.
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.
Thanks. So, I guess it means we don't have any other rules that need this CATEGORIES_TO_CHECK
yet.
Alright, we can locate the hashmap here, but I suggest commenting out elements that aren't used here. It may be a waste of overhead. Insertion for focus
, keyboard
, and mouse
is enough.
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.
@unvalley
I see, I understand!
I'll fix 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.
Sorry to barge in during this review. I think this code would benefit from a refactor. I don't think it's a good custom to try to replicate JS code in Rust. For example, this code, while it's created once via lazy_static
, still creates a bunch of vectors that are created at runtime (heap).
Instead, why not create simple arrays?
Also, I think we should explain what this code is. It's copied from another source, which is completely fine, but there's no comment that explains what are the keys and what are the values, how they are used and what they are meant to be.
For example composition
-> [...]
. What's composition
? Where is it coming from? Is it an HTML element? Is it a role? Remember that in Biome, we want to aim for good standards, DX-wise and coding-wise.
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.
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.
@unvalley
Sorry, I didn't address to additional comments, please leave them as they are.
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.
@ematipico @unvalley
Thank you for pointing this out.
As you said, it was causing overhead, so we defined it as a fixed-length array.
Also modified the comment to describe what is stored in this array and added the URL to the MDN reference describing each event handler
fixed in this commit b330131
crates/biome_js_analyze/src/lint/nursery/no_static_element_interactions.rs
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_static_element_interactions.rs
Outdated
Show resolved
Hide resolved
@unvalley |
crates/biome_js_analyze/src/lint/nursery/no_static_element_interactions.rs
Outdated
Show resolved
Hide resolved
crates/biome_js_analyze/src/lint/nursery/no_static_element_interactions.rs
Outdated
Show resolved
Hide resolved
m.insert("clipboard", vec!["onCopy", "onCut", "onPaste"]); | ||
m.insert("composition", vec!["onCompositionEnd", "onCompositionStart", "onCompositionUpdate"]); | ||
m.insert("keyboard", vec!["onKeyDown", "onKeyPress", "onKeyUp"]); | ||
m.insert("focus", vec!["onFocus", "onBlur"]); | ||
m.insert("form", vec!["onChange", "onInput", "onSubmit"]); | ||
m.insert("mouse", vec![ | ||
"onClick", "onContextMenu", "onDblClick", "onDoubleClick", "onDrag", "onDragEnd", | ||
"onDragEnter", "onDragExit", "onDragLeave", "onDragOver", "onDragStart", "onDrop", | ||
"onMouseDown", "onMouseEnter", "onMouseLeave", "onMouseMove", "onMouseOut", | ||
"onMouseOver", "onMouseUp" | ||
]); | ||
m.insert("selection", vec!["onSelect"]); | ||
m.insert("touch", vec!["onTouchCancel", "onTouchEnd", "onTouchMove", "onTouchStart"]); | ||
m.insert("ui", vec!["onScroll"]); | ||
m.insert("wheel", vec!["onWheel"]); | ||
m.insert("media", vec![ | ||
"onAbort", "onCanPlay", "onCanPlayThrough", "onDurationChange", "onEmptied", | ||
"onEncrypted", "onEnded", "onError", "onLoadedData", "onLoadedMetadata", "onLoadStart", | ||
"onPause", "onPlay", "onPlaying", "onProgress", "onRateChange", "onSeeked", "onSeeking", | ||
"onStalled", "onSuspend", "onTimeUpdate", "onVolumeChange", "onWaiting" | ||
]); | ||
m.insert("image", vec!["onLoad", "onError"]); | ||
m.insert("animation", vec!["onAnimationStart", "onAnimationEnd", "onAnimationIteration"]); | ||
m.insert("transition", vec!["onTransitionEnd"]); |
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.
Sorry to barge in during this review. I think this code would benefit from a refactor. I don't think it's a good custom to try to replicate JS code in Rust. For example, this code, while it's created once via lazy_static
, still creates a bunch of vectors that are created at runtime (heap).
Instead, why not create simple arrays?
Also, I think we should explain what this code is. It's copied from another source, which is completely fine, but there's no comment that explains what are the keys and what are the values, how they are used and what they are meant to be.
For example composition
-> [...]
. What's composition
? Where is it coming from? Is it an HTML element? Is it a role? Remember that in Biome, we want to aim for good standards, DX-wise and coding-wise.
crates/biome_js_analyze/src/lint/nursery/no_static_element_interactions.rs
Outdated
Show resolved
Hide resolved
/// Checks if the given element name is considered invalid, inspired by eslint-plugin-jsx-a11y | ||
fn is_invalid_element(element_name: &str) -> bool { | ||
match element_name { | ||
// These cases are interactive with the is_not_interactive_element method, | ||
// but is an invalid test case element for eslint-plugin-jsx-a11y. |
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.
While the mention to the plugin is appreciated, this information doesn't give us enough value. To you and all developers. What you want to do, instead, is to document when and why an element is considered valid. I am sure there's a context here, and it's the developers job to write it down.
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.
@ematipico
Thank you for your comment.
Your comment is correct, but we will hold it in abeyance because the way we respond will depend on the answers to the following questions.
I will address this when this method continues to be needed.
|
||
/// This function ables non-interactive elements. | ||
/// This is because this is an element that is abled by eslint-plugin-jsx-a11y. | ||
fn is_valid_element(element_name: &str) -> bool { |
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.
What does "valid element" mean? Valid for what context? We should document it.
Plus, you would want to move this function inside biome_aria
, as @unvalley suggested. Here's an example:
biome/crates/biome_aria/src/roles.rs
Lines 1131 to 1138 in 9e8addd
pub fn is_role_interactive(&self, role: &str) -> bool { | |
let role = self.get_role(role); | |
if let Some(role) = role { | |
role.is_interactive() | |
} else { | |
false | |
} | |
} |
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.
@ematipico cc @unvalley
Regarding this point, this method includes processing that considers elements generally deemed non-interactive as valid.
These elements were part of valid test cases in eslint-plugin-jsx-a11y.
When considering portability from ESLint, these test cases should be taken into account (meaning that if a project using ESLint transitions to Biome, many lint errors could occur). However, if we are overly concerned with the above point, we will never be able to lint according to Biome's rules.
Therefore, if we align with Biome's interactive criteria and adjust the rules accordingly, this method will become unnecessary. I would appreciate it if you could provide guidance on the direction we should take.
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.
Maybe there was a misunderstanding; I'm sorry about it. I am not asking you to use the link I pasted. The link I pasted was an example. And I didn't ask to remove the logic you're porting from the plugin.
What I asked was to properly document the function. The phrase "This function ables non-interactive elements."
doesn't provide any value to the function name, because it doesn't explain what is a valid element (or when it is valid).
I understand that English is not your first language, so I am willing to help if you explain a bit the logic of this function
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 think we can merge this PR after addressing this point.
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.
@ematipico cc @unvalley
Okay, thank you.
Then I need to see why Eslint is enabling these elements, but we have not yet found a clear reason.
So it may take a little time, but I may ask for your help in documenting it. Thank you in advance for your help at that time.
…added explanatory comments for better clarity and performance.
…attributes function
Summary
Enforce that non-interactive, visible elements (such as
<div>
) that have click handlers use the role attribute.Implements #527
Test Plan
Added snaps for valid/invalid cases.
Basically, it conforms to the test cases of eslint-plugin-jsx-a11y/no-static-element-interactions, and test cases that cannot be handled by the resources within Biome are handled individually.
ref:
https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/__tests__/src/rules/no-static-element-interactions-test.js