diff --git a/crates/oxc_linter/src/rules/jsx_a11y/alt_text.rs b/crates/oxc_linter/src/rules/jsx_a11y/alt_text.rs index 627f0f37f..de1e88090 100644 --- a/crates/oxc_linter/src/rules/jsx_a11y/alt_text.rs +++ b/crates/oxc_linter/src/rules/jsx_a11y/alt_text.rs @@ -1,6 +1,6 @@ use oxc_ast::{ ast::{ - JSXAttributeItem, JSXAttributeValue, JSXChild, JSXElement, JSXElementName, JSXExpression, + JSXAttributeItem, JSXAttributeValue, JSXChild, JSXElement, JSXExpression, JSXExpressionContainer, JSXOpeningElement, }, AstKind, @@ -12,7 +12,9 @@ use oxc_diagnostics::{ use oxc_macros::declare_oxc_lint; use oxc_span::Span; -use crate::utils::{get_prop_value, get_string_literal_prop_value, has_jsx_prop_lowercase}; +use crate::utils::{ + get_element_type, get_prop_value, get_string_literal_prop_value, has_jsx_prop_lowercase, +}; use crate::{context::LintContext, rule::Rule, AstNode}; #[derive(Debug, Error, Diagnostic)] @@ -163,8 +165,7 @@ impl Rule for AltText { fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { let AstKind::JSXOpeningElement(jsx_el) = node.kind() else { return }; - let JSXElementName::Identifier(iden) = &jsx_el.name else { return }; - let name = iden.name.as_str(); + let Some(name) = &get_element_type(ctx, jsx_el) else { return }; // if let Some(custom_tags) = &self.img { @@ -356,7 +357,7 @@ fn input_type_image_rule<'a>(node: &'a JSXOpeningElement<'a>, ctx: &LintContext< fn test() { use crate::tester::Tester; - fn array() -> serde_json::Value { + fn config() -> serde_json::Value { serde_json::json!([{ "img": ["Thumbnail", "Image"], "object": ["Object"], @@ -366,177 +367,179 @@ fn test() { } let pass = vec![ - (r#"foo;"#, None), - (r#"{"foo"};"#, None), - (r"{alt};", None), - (r#"foo;"#, None), - (r"{`This;", None), - (r#"foo;"#, None), - (r#"foo;"#, None), - (r#"foo"#, None), - (r"", None), - (r"
", None), - (r"{function(e)", None), - (r"
", None), - (r"{() void 0} />", None), - (r"", None), - (r"test", None), - (r#"{alt"#, None), - (r"{photo.caption};", None), - (r"{bar()};", None), - (r#"{foo.bar"#, None), - (r#"{bar()"#, None), - (r#"{foo.bar()"#, None), - (r#""#, None), - (r"{`${undefined}`}", None), - (r#" "#, None), - (r#""#, None), - (r#""#, None), - (r#""#, None), - (r#""#, None), - (r#"this is lit..."#, None), - (r#"{error"#, None), - (r#"{undefined"#, None), - (r#"{plugin.name"#, None), - (r#""#, None), - (r#""#, None), - (r#""#, None), - (r#""#, None), - (r"Foo", None), - (r"

This is descriptive!

", None), - (r"", None), - (r#""#, None), - (r#""#, None), - (r#""#, None), - (r#""#, None), - (r#"This is descriptive!"#, None), - (r"{altText}", None), - (r"", None), - (r"", None), - (r#""#, None), - (r#""#, None), - (r#""#, None), - (r#""#, None), - (r#""#, None), - (r#""#, None), - (r"", None), - (r#""#, None), - // TODO: When polymorphic components are supported - // (r#""#, None), - (r#";"#, Some(array())), - (r#";"#, Some(array())), - (r";", Some(array())), - (r#";"#, Some(array())), - (r";", Some(array())), - (r#";"#, Some(array())), - (r#";"#, Some(array())), - (r#""#, Some(array())), - (r"", Some(array())), - (r"", Some(array())), - (r"
", Some(array())), - (r" void 0} />", Some(array())), - (r"", Some(array())), - (r#""#, Some(array())), - (r#"foo;"#, Some(array())), - (r#"{"foo"};"#, Some(array())), - (r"{alt};", Some(array())), - (r#"foo;"#, Some(array())), - (r"{`This;", Some(array())), - (r#"foo;"#, Some(array())), - (r#"foo;"#, Some(array())), - (r#"foo"#, Some(array())), - (r"", Some(array())), - (r"{function(e)", Some(array())), - (r"
", Some(array())), - (r"{() void 0} />", Some(array())), - (r"", Some(array())), - (r#"{alt"#, Some(array())), - (r#""#, Some(array())), - (r#""#, Some(array())), - (r"Foo", Some(array())), - (r"

This is descriptive!

", Some(array())), - (r#""#, Some(array())), - (r#""#, Some(array())), - (r#""#, Some(array())), - (r#""#, Some(array())), - (r#"This is descriptive!"#, Some(array())), - (r"{altText}", Some(array())), - (r#""#, Some(array())), - (r#""#, Some(array())), - (r#""#, Some(array())), - (r#""#, Some(array())), - (r"", Some(array())), + (r#"foo;"#, None, None), + (r#"{"foo"};"#, None, None), + (r"{alt};", None, None), + (r#"foo;"#, None, None), + (r"{`This;", None, None), + (r#"foo;"#, None, None), + (r#"foo;"#, None, None), + (r#"foo"#, None, None), + (r"", None, None), + (r"
", None, None), + (r"{function(e)", None, None), + (r"
", None, None), + (r"{() void 0} />", None, None), + (r"", None, None), + (r"test", None, None), + (r#"{alt"#, None, None), + (r"{photo.caption};", None, None), + (r"{bar()};", None, None), + (r#"{foo.bar"#, None, None), + (r#"{bar()"#, None, None), + (r#"{foo.bar()"#, None, None), + (r#""#, None, None), + (r"{`${undefined}`}", None, None), + (r#" "#, None, None), + (r#""#, None, None), + (r#""#, None, None), + (r#""#, None, None), + (r#""#, None, None), + (r#"this is lit..."#, None, None), + (r#"{error"#, None, None), + (r#"{undefined"#, None, None), + (r#"{plugin.name"#, None, None), + (r#""#, None, None), + (r#""#, None, None), + (r#""#, None, None), + (r#""#, None, None), + (r"Foo", None, None), + (r"

This is descriptive!

", None, None), + (r"", None, None), + (r#""#, None, None), + (r#""#, None, None), + (r#""#, None, None), + (r#""#, None, None), + (r#"This is descriptive!"#, None, None), + (r"{altText}", None, None), + (r"", None, None), + (r"", None, None), + (r#""#, None, None), + (r#""#, None, None), + (r#""#, None, None), + (r#""#, None, None), + (r#""#, None, None), + (r#""#, None, None), + (r"", None, None), + (r#""#, None, None), + (r#""#, None, None), + (r#";"#, Some(config()), None), + (r#";"#, Some(config()), None), + (r";", Some(config()), None), + (r#";"#, Some(config()), None), + (r";", Some(config()), None), + (r#";"#, Some(config()), None), + (r#";"#, Some(config()), None), + (r#""#, Some(config()), None), + (r"", Some(config()), None), + (r"", Some(config()), None), + (r"
", Some(config()), None), + (r" void 0} />", Some(config()), None), + (r"", Some(config()), None), + (r#""#, Some(config()), None), + (r#"foo;"#, Some(config()), None), + (r#"{"foo"};"#, Some(config()), None), + (r"{alt};", Some(config()), None), + (r#"foo;"#, Some(config()), None), + (r"{`This;", Some(config()), None), + (r#"foo;"#, Some(config()), None), + (r#"foo;"#, Some(config()), None), + (r#"foo"#, Some(config()), None), + (r"", Some(config()), None), + (r"{function(e)", Some(config()), None), + (r"
", Some(config()), None), + (r"{() void 0} />", Some(config()), None), + (r"", Some(config()), None), + (r#"{alt"#, Some(config()), None), + (r#""#, Some(config()), None), + (r#""#, Some(config()), None), + (r"Foo", Some(config()), None), + (r"

This is descriptive!

", Some(config()), None), + (r#""#, Some(config()), None), + (r#""#, Some(config()), None), + (r#""#, Some(config()), None), + (r#""#, Some(config()), None), + (r#"This is descriptive!"#, Some(config()), None), + (r"{altText}", Some(config()), None), + (r#""#, Some(config()), None), + (r#""#, Some(config()), None), + (r#""#, Some(config()), None), + (r#""#, Some(config()), None), + (r"", Some(config()), None), ]; let fail = vec![ - (r";", None), - (r";", None), - (r"{undefined};", None), - (r#""#, None), - (r"", None), - (r"", None), + (r";", None, None), + (r";", None, None), + (r"{undefined};", None, None), + (r#""#, None, None), + (r"", None, None), + (r"", None, None), // TODO: Could support if get_prop_value could evaluate // some logical expressions - // (r#"{false"#, None), - (r#"{undefined};"#, None), - (r#";"#, None), - (r#";"#, None), - (r#";"#, None), - (r"", None), - (r"", None), - (r#""#, None), - (r#""#, None), - // TODO: When polymorphic components are supported - // (r#""#, None), - (r"", None), - (r"
", None), - (r"", None), - (r#""#, None), - (r#""#, None), - (r"", None), - (r"", None), - (r"", None), - (r"", None), - (r"{undefined}", None), - (r#""#, None), - (r"", None), - (r#""#, None), - (r"", None), - (r#""#, None), - (r"", None), - (r#""#, None), - (r#""#, None), - (r#""#, None), - (r#"Foo"#, None), - (r#""#, None), - (r#""#, None), - (r#""#, None), - (r#""#, None), - (r#""#, None), - (r";", Some(array())), - (r";", Some(array())), - (r";", Some(array())), - (r#""#, Some(array())), - (r"", Some(array())), - (r";", Some(array())), - (r";", Some(array())), - (r"{undefined};", Some(array())), - (r#""#, Some(array())), - (r"", Some(array())), - (r"", Some(array())), - (r"
", Some(array())), - (r"", Some(array())), - (r"", Some(array())), - (r"", Some(array())), - (r"{undefined}", Some(array())), - (r#""#, Some(array())), - (r"", Some(array())), - (r"", Some(array())), - (r"", Some(array())), - (r"", Some(array())), - (r"Foo", Some(array())), - (r"", Some(array())), - (r#""#, None), + // (r#"{false"#, None, None), + (r#"{undefined};"#, None, None), + (r#";"#, None, None), + (r#";"#, None, None), + (r#";"#, None, None), + (r"", None, None), + (r"", None, None), + (r#""#, None, None), + (r#""#, None, None), + ( + r#""#, + None, + Some(serde_json::json!({ "jsx-a11y": { "polymorphicPropName": "as" } })), + ), + (r"", None, None), + (r"
", None, None), + (r"", None, None), + (r#""#, None, None), + (r#""#, None, None), + (r"", None, None), + (r"", None, None), + (r"", None, None), + (r"", None, None), + (r"{undefined}", None, None), + (r#""#, None, None), + (r"", None, None), + (r#""#, None, None), + (r"", None, None), + (r#""#, None, None), + (r"", None, None), + (r#""#, None, None), + (r#""#, None, None), + (r#""#, None, None), + (r#"Foo"#, None, None), + (r#""#, None, None), + (r#""#, None, None), + (r#""#, None, None), + (r#""#, None, None), + (r#""#, None, None), + (r";", Some(config()), None), + (r";", Some(config()), None), + (r";", Some(config()), None), + (r#""#, Some(config()), None), + (r"", Some(config()), None), + (r";", Some(config()), None), + (r";", Some(config()), None), + (r"{undefined};", Some(config()), None), + (r#""#, Some(config()), None), + (r"", Some(config()), None), + (r"", Some(config()), None), + (r"
", Some(config()), None), + (r"", Some(config()), None), + (r"", Some(config()), None), + (r"", Some(config()), None), + (r"{undefined}", Some(config()), None), + (r#""#, Some(config()), None), + (r"", Some(config()), None), + (r"", Some(config()), None), + (r"", Some(config()), None), + (r"", Some(config()), None), + (r"Foo", Some(config()), None), + (r"", Some(config()), None), + (r#""#, None, None), ]; Tester::new(AltText::NAME, pass, fail).with_jsx_a11y_plugin(true).test_and_snapshot(); diff --git a/crates/oxc_linter/src/rules/jsx_a11y/anchor_has_content.rs b/crates/oxc_linter/src/rules/jsx_a11y/anchor_has_content.rs index b3435ee47..65c9a5b1a 100644 --- a/crates/oxc_linter/src/rules/jsx_a11y/anchor_has_content.rs +++ b/crates/oxc_linter/src/rules/jsx_a11y/anchor_has_content.rs @@ -17,7 +17,7 @@ use oxc_allocator::Vec; use crate::{ context::LintContext, rule::Rule, - utils::{get_prop_value, has_jsx_prop_lowercase}, + utils::{get_element_type, get_prop_value, has_jsx_prop_lowercase}, AstNode, }; @@ -75,8 +75,7 @@ declare_oxc_lint!( impl Rule for AnchorHasContent { fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { if let AstKind::JSXElement(jsx_el) = node.kind() { - let JSXElementName::Identifier(iden) = &jsx_el.opening_element.name else { return }; - let name = iden.name.as_str(); + let Some(name) = &get_element_type(ctx, &jsx_el.opening_element) else { return }; if name == "a" { // check self attr if has_jsx_prop_lowercase(&jsx_el.opening_element, "aria-hidden").is_some() { @@ -163,30 +162,36 @@ fn test() { // https://raw.githubusercontent.com/jsx-eslint/eslint-plugin-jsx-a11y/main/__tests__/src/rules/anchor-has-content-test.js let pass = vec![ - (r"
;", None), - (r"Foo", None), - (r"", None), - (r"{foo}", None), - (r"{foo.bar}", None), - (r#""#, None), - (r"", None), - // TODO: - // { code: 'foo', settings: { 'jsx-a11y': { components: { Link: 'a' } } }, }, - (r"", None), - (r"", None), - (r"", None), - (r"Foo", None), + (r"
;", None, None), + (r"Foo", None, None), + (r"", None, None), + (r"{foo}", None, None), + (r"{foo.bar}", None, None), + (r#""#, None, None), + (r"", None, None), + ( + r"foo", + None, + Some(serde_json::json!({ "jsx-a11y": { "components": { "Link": "a" } } })), + ), + (r"", None, None), + (r"", None, None), + (r"", None, None), + (r"Foo", None, None), ]; let fail = vec![ - (r"", None), - (r"", None), - (r"{undefined}", None), - // TODO: - // { code: '', errors: [expectedError], settings: { 'jsx-a11y': { components: { Link: 'a' } } }, }, - (r"", None), - (r"{null}", None), - (r"", None), + (r"", None, None), + (r"", None, None), + (r"{undefined}", None, None), + ( + r"", + None, + Some(serde_json::json!({ "jsx-a11y": { "components": { "Link": "a" } } })), + ), + (r"", None, None), + (r"{null}", None, None), + (r"", None, None), ]; Tester::new(AnchorHasContent::NAME, pass, fail).test_and_snapshot(); diff --git a/crates/oxc_linter/src/rules/jsx_a11y/anchor_is_valid.rs b/crates/oxc_linter/src/rules/jsx_a11y/anchor_is_valid.rs index 9e572b31c..2699a52b4 100644 --- a/crates/oxc_linter/src/rules/jsx_a11y/anchor_is_valid.rs +++ b/crates/oxc_linter/src/rules/jsx_a11y/anchor_is_valid.rs @@ -9,7 +9,12 @@ use oxc_diagnostics::{ use oxc_macros::declare_oxc_lint; use oxc_span::Span; -use crate::{context::LintContext, rule::Rule, utils::has_jsx_prop_lowercase, AstNode}; +use crate::{ + context::LintContext, + rule::Rule, + utils::{get_element_type, has_jsx_prop_lowercase}, + AstNode, +}; #[derive(Debug, Error, Diagnostic)] enum AnchorIsValidDiagnostic { @@ -108,10 +113,12 @@ declare_oxc_lint!( ); impl Rule for AnchorIsValid { + // TODO: Implement from_configuration() and test it + fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { if let AstKind::JSXElement(jsx_el) = node.kind() { let JSXElementName::Identifier(ident) = &jsx_el.opening_element.name else { return }; - let name = ident.name.as_str(); + let Some(name) = &get_element_type(ctx, &jsx_el.opening_element) else { return }; if name == "a" { if let Option::Some(herf_attr) = has_jsx_prop_lowercase(&jsx_el.opening_element, "href") @@ -212,24 +219,24 @@ fn test() { // https://raw.githubusercontent.com/jsx-eslint/eslint-plugin-jsx-a11y/main/__tests__/src/rules/anchor-is-valid-test.js let pass = vec![ - (r"", None), - (r"", None), - (r"", None), - (r"", None), - (r"", None), - (r"", None), - (r"
", None), - (r"", None), - (r"", None), - (r"", None), - (r"", None), - (r"", None), - (r"", None), - (r"", None), - (r"", None), - (r"", None), - (r"test", None), - (r"", None), + (r"", None, None), + (r"", None, None), + (r"", None, None), + (r"", None, None), + (r"", None, None), + (r"", None, None), + (r"
", None, None), + (r"", None, None), + (r"", None, None), + (r"", None, None), + (r"", None, None), + (r"", None, None), + (r"", None, None), + (r"", None, None), + (r"", None, None), + (r"", None, None), + (r"test", None, None), + (r"", None, None), // (r#""#, Some(serde_json::json!(components))), // (r#""#, Some(serde_json::json!(components))), // (r#""#, Some(serde_json::json!(components))), @@ -248,7 +255,13 @@ fn test() { // (r#""#, Some(serde_json::json!(components))), // (r#""#, Some(serde_json::json!(components))), // (r#""#, Some(serde_json::json!(components))), - (r"", None), + ( + r"", + None, + Some( + serde_json::json!({ "jsx-a11y": { "components": { "Anchor": "a", "Link": "a" } } }), + ), + ), // (r#""#, Some(serde_json::json!(specialLink))), // (r#""#, Some(serde_json::json!(specialLink))), // (r#""#, Some(serde_json::json!(specialLink))), @@ -284,16 +297,16 @@ fn test() { // (r#""#, Some(serde_json::json!(componentsAndSpecialLink))), // (r#""#, Some(serde_json::json!(componentsAndSpecialLink))), // (r#"test"#, Some(serde_json::json!(componentsAndSpecialLink))), - (r" void 0} />", None), - (r" void 0} />", None), - (r" void 0} />", None), - (r" void 0} />", None), - (r" void 0} />", None), - (r"
void 0} />", None), - (r" void 0} />", None), - (r" void 0} />", None), - (r" void 0} />", None), - (r" void 0} />", None), + (r" void 0} />", None, None), + (r" void 0} />", None, None), + (r" void 0} />", None, None), + (r" void 0} />", None, None), + (r" void 0} />", None, None), + (r"
void 0} />", None, None), + (r" void 0} />", None, None), + (r" void 0} />", None, None), + (r" void 0} />", None, None), + (r" void 0} />", None, None), // (r#" void 0} />"#, Some(serde_json::json!(components))), // (r#" void 0} />"#, Some(serde_json::json!(components))), // (r#" void 0} />"#, Some(serde_json::json!(components))), @@ -460,18 +473,18 @@ fn test() { ]; let fail = vec![ - (r"", None), - (r"", None), - (r"", None), - (r"", None), - (r"", None), - (r"", None), - (r"", None), - (r" void 0} />", None), - (r" void 0} />", None), - (r" void 0} />", None), - (r" void 0} />", None), + (r"", None, None), + (r"", None, None), + (r"", None, None), + (r"", None, None), + (r"", None, None), + (r"", None, None), + (r"", None, None), + (r" void 0} />", None, None), + (r" void 0} />", None, None), + (r" void 0} />", None, None), + (r" void 0} />", None, None), // (r#""#, Some(serde_json::json!(components))), // (r#""#, Some(serde_json::json!(components))), // (r#""#, Some(serde_json::json!(components))), @@ -505,7 +518,13 @@ fn test() { // r#" void 0} />"#, // Some(serde_json::json!(components)), // ), - // (r#" void 0} />"#, None), + ( + r" void 0} />", + None, + Some( + serde_json::json!({ "jsx-a11y": { "components": { "Anchor": "a", "Link": "a" } } }), + ), + ), // (r#""#, Some(serde_json::json!(specialLink))), // (r#""#, Some(serde_json::json!(specialLink))), // (r#"", None), - (r"