-
-
Notifications
You must be signed in to change notification settings - Fork 511
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
aa3d3a5
commit 61dbed6
Showing
15 changed files
with
419 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
136 changes: 136 additions & 0 deletions
136
crates/biome_js_analyze/src/aria_analyzers/nursery/use_valid_aria_role.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
use crate::aria_services::Aria; | ||
use biome_analyze::{context::RuleContext, declare_rule, Rule, RuleDiagnostic}; | ||
use biome_console::markup; | ||
use biome_js_syntax::jsx_ext::AnyJsxElement; | ||
use biome_rowan::AstNode; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
declare_rule! { | ||
/// Elements with ARIA roles must use a valid, non-abstract ARIA role. | ||
/// | ||
/// Source: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/aria-role.md | ||
/// | ||
/// | ||
/// ## Examples | ||
/// | ||
/// ### Invalid | ||
/// | ||
/// ```js,expect_diagnostic | ||
/// <div role="datepicker"></div> | ||
/// ``` | ||
/// | ||
/// ```js,expect_diagnostic | ||
/// <div role="range"></div> | ||
/// ``` | ||
/// | ||
/// ```js,expect_diagnostic | ||
/// <div role=""></div> | ||
/// ``` | ||
/// | ||
/// ```js,expect_diagnostic | ||
/// <Foo role="foo"></Foo> | ||
/// ``` | ||
/// | ||
/// ### Valid | ||
/// | ||
/// ```js | ||
/// <> | ||
/// <div role="button"></div> | ||
/// <div role={role}></div> | ||
/// <div></div> | ||
/// </> | ||
/// ``` | ||
/// | ||
/// ## Accessibility guidelines | ||
/// - [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value) | ||
/// | ||
/// ## Resources | ||
/// - [Chrome Audit Rules, AX_ARIA_01](https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_01) | ||
/// - [DPUB-ARIA roles](https://www.w3.org/TR/dpub-aria-1.0/) | ||
/// - [MDN: Using ARIA: Roles, states, and properties](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques) | ||
/// | ||
pub(crate) UseValidAriaRole { | ||
version: "next", | ||
name: "useValidAriaRole", | ||
recommended: false, | ||
} | ||
} | ||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)] | ||
pub struct UseValidAriaRoleOptions { | ||
allowed_invalid_roles: Vec<String>, | ||
ignore_non_dom: bool, | ||
} | ||
|
||
impl Default for UseValidAriaRoleOptions { | ||
fn default() -> Self { | ||
Self { | ||
allowed_invalid_roles: Vec::new(), | ||
ignore_non_dom: false, | ||
} | ||
} | ||
} | ||
|
||
impl Rule for UseValidAriaRole { | ||
type Query = Aria<AnyJsxElement>; | ||
type State = (); | ||
type Signals = Option<Self::State>; | ||
type Options = UseValidAriaRoleOptions; | ||
|
||
fn run(ctx: &RuleContext<Self>) -> Self::Signals { | ||
let node = ctx.query(); | ||
let options = ctx.options(); | ||
let aria_roles = ctx.aria_roles(); | ||
|
||
let ignore_non_dom = options.ignore_non_dom; | ||
let allowed_invalid_roles = &options.allowed_invalid_roles; | ||
|
||
if ignore_non_dom { | ||
if node.is_custom_component() { | ||
return None; | ||
} | ||
} | ||
|
||
let role_attribute = node.find_attribute_by_name("role")?; | ||
if role_attribute.is_value_null_or_undefined() { | ||
return None; | ||
} | ||
|
||
if node.is_custom_component() { | ||
return Some(()); | ||
} | ||
|
||
let role_attribute_static_value = role_attribute.as_static_value()?; | ||
let role_attribute_value = role_attribute_static_value.text(); | ||
if role_attribute_static_value.is_null_or_undefined() { | ||
return None; | ||
} | ||
|
||
let role_data = aria_roles.get_role(role_attribute_value); | ||
|
||
let is_valid = allowed_invalid_roles.contains(&role_attribute_value.to_string()); | ||
|
||
if is_valid || role_data.is_some() { | ||
return None; | ||
} | ||
|
||
Some(()) | ||
} | ||
|
||
fn diagnostic(ctx: &RuleContext<Self>, _: &Self::State) -> Option<RuleDiagnostic> { | ||
let node = ctx.query(); | ||
|
||
Some( | ||
RuleDiagnostic::new( | ||
rule_category!(), | ||
node.range(), | ||
markup! { | ||
"Enforce that elements with ARIA roles must use a valid, non-abstract ARIA role." | ||
}, | ||
) | ||
.note(markup! { | ||
"Elements with ARIA roles must use a valid, non-abstract ARIA role." | ||
}) | ||
) | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
crates/biome_js_analyze/tests/specs/nursery/useValidAriaRole/invalid.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
<> | ||
<div role="range"></div> | ||
<div role="datepicker"></div> | ||
<div role=""></div> | ||
<Foo role={foo}></Foo> | ||
</> |
82 changes: 82 additions & 0 deletions
82
crates/biome_js_analyze/tests/specs/nursery/useValidAriaRole/invalid.jsx.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
--- | ||
source: crates/biome_js_analyze/tests/spec_tests.rs | ||
expression: invalid.jsx | ||
--- | ||
# Input | ||
```js | ||
<> | ||
<div role="range"></div> | ||
<div role="datepicker"></div> | ||
<div role=""></div> | ||
<Foo role={foo}></Foo> | ||
</> | ||
``` | ||
|
||
# Diagnostics | ||
``` | ||
invalid.jsx:2:3 lint/nursery/useValidAriaRole ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | ||
! Enforce that elements with ARIA roles must use a valid, non-abstract ARIA role. | ||
1 │ <> | ||
> 2 │ <div role="range"></div> | ||
│ ^^^^^^^^^^^^^^^^^^ | ||
3 │ <div role="datepicker"></div> | ||
4 │ <div role=""></div> | ||
i Elements with ARIA roles must use a valid, non-abstract ARIA role. | ||
``` | ||
|
||
``` | ||
invalid.jsx:3:3 lint/nursery/useValidAriaRole ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | ||
! Enforce that elements with ARIA roles must use a valid, non-abstract ARIA role. | ||
1 │ <> | ||
2 │ <div role="range"></div> | ||
> 3 │ <div role="datepicker"></div> | ||
│ ^^^^^^^^^^^^^^^^^^^^^^^ | ||
4 │ <div role=""></div> | ||
5 │ <Foo role={foo}></Foo> | ||
i Elements with ARIA roles must use a valid, non-abstract ARIA role. | ||
``` | ||
|
||
``` | ||
invalid.jsx:4:3 lint/nursery/useValidAriaRole ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | ||
! Enforce that elements with ARIA roles must use a valid, non-abstract ARIA role. | ||
2 │ <div role="range"></div> | ||
3 │ <div role="datepicker"></div> | ||
> 4 │ <div role=""></div> | ||
│ ^^^^^^^^^^^^^ | ||
5 │ <Foo role={foo}></Foo> | ||
6 │ </> | ||
i Elements with ARIA roles must use a valid, non-abstract ARIA role. | ||
``` | ||
|
||
``` | ||
invalid.jsx:5:3 lint/nursery/useValidAriaRole ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | ||
! Enforce that elements with ARIA roles must use a valid, non-abstract ARIA role. | ||
3 │ <div role="datepicker"></div> | ||
4 │ <div role=""></div> | ||
> 5 │ <Foo role={foo}></Foo> | ||
│ ^^^^^^^^^^^^^^^^ | ||
6 │ </> | ||
i Elements with ARIA roles must use a valid, non-abstract ARIA role. | ||
``` | ||
|
||
|
6 changes: 6 additions & 0 deletions
6
crates/biome_js_analyze/tests/specs/nursery/useValidAriaRole/valid.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
<> | ||
<div role="button"></div> | ||
<div role={role}></div> | ||
<div role></div> | ||
<div></div> | ||
</> |
15 changes: 15 additions & 0 deletions
15
crates/biome_js_analyze/tests/specs/nursery/useValidAriaRole/valid.jsx.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
--- | ||
source: crates/biome_js_analyze/tests/spec_tests.rs | ||
expression: valid.jsx | ||
--- | ||
# Input | ||
```js | ||
<> | ||
<div role="button"></div> | ||
<div role={role}></div> | ||
<div role></div> | ||
<div></div> | ||
</> | ||
``` | ||
|
||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
24 changes: 24 additions & 0 deletions
24
crates/biome_service/src/configuration/parse/json/rules.rs
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.