Skip to content

Commit

Permalink
feat(linter): eslint-plugin-jsx-a11y no-access-key (correctness) for (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
yoshi2no authored Dec 18, 2023
1 parent 3cc761d commit 621a943
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 0 deletions.
2 changes: 2 additions & 0 deletions crates/oxc_linter/src/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ mod jsx_a11y {
pub mod html_has_lang;
pub mod iframe_has_title;
pub mod img_redundant_alt;
pub mod no_access_key;
pub mod no_autofocus;
pub mod scope;
pub mod tab_index_no_positive;
Expand Down Expand Up @@ -450,6 +451,7 @@ oxc_macros::declare_all_lint_rules! {
jsx_a11y::html_has_lang,
jsx_a11y::iframe_has_title,
jsx_a11y::img_redundant_alt,
jsx_a11y::no_access_key,
jsx_a11y::no_autofocus,
jsx_a11y::scope,
jsx_a11y::tab_index_no_positive,
Expand Down
87 changes: 87 additions & 0 deletions crates/oxc_linter/src/rules/jsx_a11y/no_access_key.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use oxc_ast::{
ast::{JSXAttributeItem, JSXAttributeValue, JSXExpression, JSXExpressionContainer},
AstKind,
};
use oxc_diagnostics::{
miette::{self, Diagnostic},
thiserror::Error,
};
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;

use crate::{context::LintContext, rule::Rule, utils::has_jsx_prop_lowercase, AstNode};

#[derive(Debug, Error, Diagnostic)]
#[error("eslint-plugin-jsx-a11y(no-access-key): No access key attribute allowed.")]
#[diagnostic(severity(warning), help("Remove the accessKey attribute. Inconsistencies between keyboard shortcuts and keyboard commands used by screenreaders and keyboard-only users create a11y complications."))]
struct NoAccessKeyDiagnostic(#[label] pub Span);

#[derive(Debug, Default, Clone)]
pub struct NoAccessKey;

declare_oxc_lint!(
/// ### What it does
/// Enforces that the `accessKey` prop is not used on any element to avoid complications with keyboard commands used by a screenreader.
///
/// ### Why is this bad?
/// Access keys are HTML attributes that allow web developers to assign keyboard shortcuts to elements.
/// Inconsistencies between keyboard shortcuts and keyboard commands used by screenreaders and keyboard-only users create accessibility complications so to avoid complications, access keys should not be used.
///
/// ### Example
/// ```javascript
/// // Bad
/// <div accessKey="h" />
///
/// // Good
/// <div />
/// ```
NoAccessKey,
correctness
);

impl Rule for NoAccessKey {
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
let AstKind::JSXOpeningElement(jsx_el) = node.kind() else { return };
if let Some(JSXAttributeItem::Attribute(attr)) = has_jsx_prop_lowercase(jsx_el, "accessKey")
{
match attr.value.as_ref() {
Some(JSXAttributeValue::StringLiteral(_)) => {
ctx.diagnostic(NoAccessKeyDiagnostic(attr.span));
}
Some(JSXAttributeValue::ExpressionContainer(JSXExpressionContainer {
expression: JSXExpression::Expression(expr),
..
})) => {
if expr.is_identifier_reference() & expr.is_undefined() {
return;
}
ctx.diagnostic(NoAccessKeyDiagnostic(attr.span));
}
_ => {}
}
}
}
}

#[test]
fn test() {
use crate::tester::Tester;

let pass = vec![r"<div />;", r"<div {...props} />", r"<div accessKey={undefined} />"];

let fail = vec![
r#"<div accesskey="h" />"#,
r#"<div accessKey="h" />"#,
r#"<div accessKey="h" {...props} />"#,
r#"<div acCesSKeY="y" />"#,
r#"<div accessKey={"y"} />"#,
r"<div accessKey={`${y}`} />",
r"<div accessKey={`${undefined}y${undefined}`} />",
r"<div accessKey={`This is ${bad}`} />",
r"<div accessKey={accessKey} />",
r"<div accessKey={`${undefined}`} />",
r"<div accessKey={`${undefined}${undefined}`} />",
];

Tester::new_without_config(NoAccessKey::NAME, pass, fail).test_and_snapshot();
}
82 changes: 82 additions & 0 deletions crates/oxc_linter/src/snapshots/no_access_key.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
source: crates/oxc_linter/src/tester.rs
expression: no_access_key
---
eslint-plugin-jsx-a11y(no-access-key): No access key attribute allowed.
╭─[no_access_key.tsx:1:1]
1<div accesskey="h" />
· ─────────────
╰────
help: Remove the accessKey attribute. Inconsistencies between keyboard shortcuts and keyboard commands used by screenreaders and keyboard-only users create a11y complications.

eslint-plugin-jsx-a11y(no-access-key): No access key attribute allowed.
╭─[no_access_key.tsx:1:1]
1<div accessKey="h" />
· ─────────────
╰────
help: Remove the accessKey attribute. Inconsistencies between keyboard shortcuts and keyboard commands used by screenreaders and keyboard-only users create a11y complications.

eslint-plugin-jsx-a11y(no-access-key): No access key attribute allowed.
╭─[no_access_key.tsx:1:1]
1<div accessKey="h" {...props} />
· ─────────────
╰────
help: Remove the accessKey attribute. Inconsistencies between keyboard shortcuts and keyboard commands used by screenreaders and keyboard-only users create a11y complications.

eslint-plugin-jsx-a11y(no-access-key): No access key attribute allowed.
╭─[no_access_key.tsx:1:1]
1<div acCesSKeY="y" />
· ─────────────
╰────
help: Remove the accessKey attribute. Inconsistencies between keyboard shortcuts and keyboard commands used by screenreaders and keyboard-only users create a11y complications.

eslint-plugin-jsx-a11y(no-access-key): No access key attribute allowed.
╭─[no_access_key.tsx:1:1]
1<div accessKey={"y"} />
· ───────────────
╰────
help: Remove the accessKey attribute. Inconsistencies between keyboard shortcuts and keyboard commands used by screenreaders and keyboard-only users create a11y complications.

eslint-plugin-jsx-a11y(no-access-key): No access key attribute allowed.
╭─[no_access_key.tsx:1:1]
1<div accessKey={`${y}`} />
· ──────────────────
╰────
help: Remove the accessKey attribute. Inconsistencies between keyboard shortcuts and keyboard commands used by screenreaders and keyboard-only users create a11y complications.
⚠ eslint-plugin-jsx-a11y(no-access-key): No access key attribute allowed.
╭─[no_access_key.tsx:1:1]
1 │ <div accessKey={`${undefined}y${undefined}`} />
· ───────────────────────────────────────
╰────
help: Remove the accessKey attribute. Inconsistencies between keyboard shortcuts and keyboard commands used by screenreaders and keyboard-only users create a11y complications.
⚠ eslint-plugin-jsx-a11y(no-access-key): No access key attribute allowed.
╭─[no_access_key.tsx:1:1]
1 │ <div accessKey={`This is ${bad}`} />
· ────────────────────────────
╰────
help: Remove the accessKey attribute. Inconsistencies between keyboard shortcuts and keyboard commands used by screenreaders and keyboard-only users create a11y complications.
⚠ eslint-plugin-jsx-a11y(no-access-key): No access key attribute allowed.
╭─[no_access_key.tsx:1:1]
1 │ <div accessKey={accessKey} />
· ─────────────────────
╰────
help: Remove the accessKey attribute. Inconsistencies between keyboard shortcuts and keyboard commands used by screenreaders and keyboard-only users create a11y complications.
⚠ eslint-plugin-jsx-a11y(no-access-key): No access key attribute allowed.
╭─[no_access_key.tsx:1:1]
1 │ <div accessKey={`${undefined}`} />
· ──────────────────────────
╰────
help: Remove the accessKey attribute. Inconsistencies between keyboard shortcuts and keyboard commands used by screenreaders and keyboard-only users create a11y complications.
⚠ eslint-plugin-jsx-a11y(no-access-key): No access key attribute allowed.
╭─[no_access_key.tsx:1:1]
1 │ <div accessKey={`${undefined}${undefined}`} />
· ──────────────────────────────────────
╰────
help: Remove the accessKey attribute. Inconsistencies between keyboard shortcuts and keyboard commands used by screenreaders and keyboard-only users create a11y complications.

0 comments on commit 621a943

Please sign in to comment.