diff --git a/Cargo.lock b/Cargo.lock index 7440d548f858..8529d8663a71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -865,6 +865,7 @@ name = "biome_js_syntax" version = "0.5.7" dependencies = [ "biome_aria", + "biome_aria_metadata", "biome_js_factory", "biome_js_parser", "biome_rowan", diff --git a/crates/biome_aria/src/roles.rs b/crates/biome_aria/src/roles.rs index 933b3c7c1007..e2c2bb99a201 100644 --- a/crates/biome_aria/src/roles.rs +++ b/crates/biome_aria/src/roles.rs @@ -238,7 +238,7 @@ impl AriaRoles { /// Given an element name and attributes, it returns the role associated with that element. /// If no explicit role attribute is present, an implicit role is returned. - fn get_role_by_element_name(&self, element: &impl Element) -> Option { + pub fn get_role_by_element_name(&self, element: &impl Element) -> Option { element .find_attribute_by_name(|name| name == "role") .as_ref() diff --git a/crates/biome_aria_metadata/src/lib.rs b/crates/biome_aria_metadata/src/lib.rs index deeb4708c463..3ffacd646013 100644 --- a/crates/biome_aria_metadata/src/lib.rs +++ b/crates/biome_aria_metadata/src/lib.rs @@ -129,7 +129,7 @@ fn is_valid_html_id(id: &str) -> bool { } impl AriaRole { - /// Returns the first valid role from `values`, a space-separated list of roles. + /// Returns the first valid role from `roles`, a space-separated list of roles. /// /// If a role attribute has multiple values, the first valid role (specified role) will be used. /// See diff --git a/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs b/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs index 0e172eed1c2d..d80d70fa886f 100644 --- a/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs +++ b/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs @@ -734,6 +734,16 @@ pub(crate) fn migrate_eslint_any_rule( .get_or_insert(Default::default()); rule.set_level(rule_severity.into()); } + "jsx-a11y/no-noninteractive-element-interactions" => { + if !options.include_nursery { + return false; + } + let group = rules.nursery.get_or_insert_with(Default::default); + let rule = group + .no_noninteractive_element_interactions + .get_or_insert(Default::default()); + rule.set_level(rule_severity.into()); + } "jsx-a11y/no-noninteractive-element-to-interactive-role" => { let group = rules.a11y.get_or_insert_with(Default::default); let rule = group diff --git a/crates/biome_configuration/src/analyzer/linter/rules.rs b/crates/biome_configuration/src/analyzer/linter/rules.rs index 03cf4720e77e..31404f0b2468 100644 --- a/crates/biome_configuration/src/analyzer/linter/rules.rs +++ b/crates/biome_configuration/src/analyzer/linter/rules.rs @@ -3337,6 +3337,10 @@ pub struct Nursery { #[doc = "Disallow nested ternary expressions."] #[serde(skip_serializing_if = "Option::is_none")] pub no_nested_ternary: Option>, + #[doc = "Disallow use event handlers on non-interactive elements."] + #[serde(skip_serializing_if = "Option::is_none")] + pub no_noninteractive_element_interactions: + Option>, #[doc = "Disallow octal escape sequences in string literals"] #[serde(skip_serializing_if = "Option::is_none")] pub no_octal_escape: Option>, @@ -3512,6 +3516,7 @@ impl Nursery { "noIrregularWhitespace", "noMissingVarFunction", "noNestedTernary", + "noNoninteractiveElementInteractions", "noOctalEscape", "noProcessEnv", "noProcessGlobal", @@ -3577,17 +3582,17 @@ impl Nursery { RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[6]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[7]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[16]), - RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[27]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[28]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[29]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[30]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[31]), - RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[36]), - RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[41]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[32]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[37]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[42]), - RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[49]), - RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[51]), - RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[53]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[43]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[50]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[52]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[54]), ]; const ALL_RULES_AS_FILTERS: &'static [RuleFilter<'static>] = &[ RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[0]), @@ -3646,6 +3651,7 @@ impl Nursery { RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[53]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[54]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[55]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[56]), ]; #[doc = r" Retrieves the recommended rules"] pub(crate) fn is_recommended_true(&self) -> bool { @@ -3752,196 +3758,201 @@ impl Nursery { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[17])); } } - if let Some(rule) = self.no_octal_escape.as_ref() { + if let Some(rule) = self.no_noninteractive_element_interactions.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[18])); } } - if let Some(rule) = self.no_process_env.as_ref() { + if let Some(rule) = self.no_octal_escape.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[19])); } } - if let Some(rule) = self.no_process_global.as_ref() { + if let Some(rule) = self.no_process_env.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[20])); } } - if let Some(rule) = self.no_restricted_imports.as_ref() { + if let Some(rule) = self.no_process_global.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[21])); } } - if let Some(rule) = self.no_restricted_types.as_ref() { + if let Some(rule) = self.no_restricted_imports.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[22])); } } - if let Some(rule) = self.no_secrets.as_ref() { + if let Some(rule) = self.no_restricted_types.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[23])); } } - if let Some(rule) = self.no_static_element_interactions.as_ref() { + if let Some(rule) = self.no_secrets.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[24])); } } - if let Some(rule) = self.no_substr.as_ref() { + if let Some(rule) = self.no_static_element_interactions.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[25])); } } - if let Some(rule) = self.no_template_curly_in_string.as_ref() { + if let Some(rule) = self.no_substr.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[26])); } } - if let Some(rule) = self.no_unknown_at_rule.as_ref() { + if let Some(rule) = self.no_template_curly_in_string.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[27])); } } - if let Some(rule) = self.no_unknown_pseudo_class.as_ref() { + if let Some(rule) = self.no_unknown_at_rule.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[28])); } } - if let Some(rule) = self.no_unknown_pseudo_element.as_ref() { + if let Some(rule) = self.no_unknown_pseudo_class.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[29])); } } - if let Some(rule) = self.no_unknown_type_selector.as_ref() { + if let Some(rule) = self.no_unknown_pseudo_element.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[30])); } } - if let Some(rule) = self.no_useless_escape_in_regex.as_ref() { + if let Some(rule) = self.no_unknown_type_selector.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[31])); } } - if let Some(rule) = self.no_useless_string_raw.as_ref() { + if let Some(rule) = self.no_useless_escape_in_regex.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[32])); } } - if let Some(rule) = self.no_useless_undefined.as_ref() { + if let Some(rule) = self.no_useless_string_raw.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[33])); } } - if let Some(rule) = self.no_value_at_rule.as_ref() { + if let Some(rule) = self.no_useless_undefined.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[34])); } } - if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() { + if let Some(rule) = self.no_value_at_rule.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[35])); } } - if let Some(rule) = self.use_aria_props_supported_by_role.as_ref() { + if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[36])); } } - if let Some(rule) = self.use_at_index.as_ref() { + if let Some(rule) = self.use_aria_props_supported_by_role.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[37])); } } - if let Some(rule) = self.use_collapsed_if.as_ref() { + if let Some(rule) = self.use_at_index.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[38])); } } - if let Some(rule) = self.use_component_export_only_modules.as_ref() { + if let Some(rule) = self.use_collapsed_if.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[39])); } } - if let Some(rule) = self.use_consistent_curly_braces.as_ref() { + if let Some(rule) = self.use_component_export_only_modules.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[40])); } } - if let Some(rule) = self.use_consistent_member_accessibility.as_ref() { + if let Some(rule) = self.use_consistent_curly_braces.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[41])); } } - if let Some(rule) = self.use_deprecated_reason.as_ref() { + if let Some(rule) = self.use_consistent_member_accessibility.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[42])); } } - if let Some(rule) = self.use_explicit_type.as_ref() { + if let Some(rule) = self.use_deprecated_reason.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[43])); } } - if let Some(rule) = self.use_exports_last.as_ref() { + if let Some(rule) = self.use_explicit_type.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[44])); } } - if let Some(rule) = self.use_google_font_display.as_ref() { + if let Some(rule) = self.use_exports_last.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[45])); } } - if let Some(rule) = self.use_google_font_preconnect.as_ref() { + if let Some(rule) = self.use_google_font_display.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[46])); } } - if let Some(rule) = self.use_guard_for_in.as_ref() { + if let Some(rule) = self.use_google_font_preconnect.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[47])); } } - if let Some(rule) = self.use_import_restrictions.as_ref() { + if let Some(rule) = self.use_guard_for_in.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[48])); } } - if let Some(rule) = self.use_named_operation.as_ref() { + if let Some(rule) = self.use_import_restrictions.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[49])); } } - if let Some(rule) = self.use_naming_convention.as_ref() { + if let Some(rule) = self.use_named_operation.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[50])); } } - if let Some(rule) = self.use_parse_int_radix.as_ref() { + if let Some(rule) = self.use_naming_convention.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[51])); } } - if let Some(rule) = self.use_sorted_classes.as_ref() { + if let Some(rule) = self.use_parse_int_radix.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[52])); } } - if let Some(rule) = self.use_strict_mode.as_ref() { + if let Some(rule) = self.use_sorted_classes.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[53])); } } - if let Some(rule) = self.use_trim_start_end.as_ref() { + if let Some(rule) = self.use_strict_mode.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[54])); } } - if let Some(rule) = self.use_valid_autocomplete.as_ref() { + if let Some(rule) = self.use_trim_start_end.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[55])); } } + if let Some(rule) = self.use_valid_autocomplete.as_ref() { + if rule.is_enabled() { + index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[56])); + } + } index_set } pub(crate) fn get_disabled_rules(&self) -> FxHashSet> { @@ -4036,196 +4047,201 @@ impl Nursery { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[17])); } } - if let Some(rule) = self.no_octal_escape.as_ref() { + if let Some(rule) = self.no_noninteractive_element_interactions.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[18])); } } - if let Some(rule) = self.no_process_env.as_ref() { + if let Some(rule) = self.no_octal_escape.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[19])); } } - if let Some(rule) = self.no_process_global.as_ref() { + if let Some(rule) = self.no_process_env.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[20])); } } - if let Some(rule) = self.no_restricted_imports.as_ref() { + if let Some(rule) = self.no_process_global.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[21])); } } - if let Some(rule) = self.no_restricted_types.as_ref() { + if let Some(rule) = self.no_restricted_imports.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[22])); } } - if let Some(rule) = self.no_secrets.as_ref() { + if let Some(rule) = self.no_restricted_types.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[23])); } } - if let Some(rule) = self.no_static_element_interactions.as_ref() { + if let Some(rule) = self.no_secrets.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[24])); } } - if let Some(rule) = self.no_substr.as_ref() { + if let Some(rule) = self.no_static_element_interactions.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[25])); } } - if let Some(rule) = self.no_template_curly_in_string.as_ref() { + if let Some(rule) = self.no_substr.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[26])); } } - if let Some(rule) = self.no_unknown_at_rule.as_ref() { + if let Some(rule) = self.no_template_curly_in_string.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[27])); } } - if let Some(rule) = self.no_unknown_pseudo_class.as_ref() { + if let Some(rule) = self.no_unknown_at_rule.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[28])); } } - if let Some(rule) = self.no_unknown_pseudo_element.as_ref() { + if let Some(rule) = self.no_unknown_pseudo_class.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[29])); } } - if let Some(rule) = self.no_unknown_type_selector.as_ref() { + if let Some(rule) = self.no_unknown_pseudo_element.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[30])); } } - if let Some(rule) = self.no_useless_escape_in_regex.as_ref() { + if let Some(rule) = self.no_unknown_type_selector.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[31])); } } - if let Some(rule) = self.no_useless_string_raw.as_ref() { + if let Some(rule) = self.no_useless_escape_in_regex.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[32])); } } - if let Some(rule) = self.no_useless_undefined.as_ref() { + if let Some(rule) = self.no_useless_string_raw.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[33])); } } - if let Some(rule) = self.no_value_at_rule.as_ref() { + if let Some(rule) = self.no_useless_undefined.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[34])); } } - if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() { + if let Some(rule) = self.no_value_at_rule.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[35])); } } - if let Some(rule) = self.use_aria_props_supported_by_role.as_ref() { + if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[36])); } } - if let Some(rule) = self.use_at_index.as_ref() { + if let Some(rule) = self.use_aria_props_supported_by_role.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[37])); } } - if let Some(rule) = self.use_collapsed_if.as_ref() { + if let Some(rule) = self.use_at_index.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[38])); } } - if let Some(rule) = self.use_component_export_only_modules.as_ref() { + if let Some(rule) = self.use_collapsed_if.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[39])); } } - if let Some(rule) = self.use_consistent_curly_braces.as_ref() { + if let Some(rule) = self.use_component_export_only_modules.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[40])); } } - if let Some(rule) = self.use_consistent_member_accessibility.as_ref() { + if let Some(rule) = self.use_consistent_curly_braces.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[41])); } } - if let Some(rule) = self.use_deprecated_reason.as_ref() { + if let Some(rule) = self.use_consistent_member_accessibility.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[42])); } } - if let Some(rule) = self.use_explicit_type.as_ref() { + if let Some(rule) = self.use_deprecated_reason.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[43])); } } - if let Some(rule) = self.use_exports_last.as_ref() { + if let Some(rule) = self.use_explicit_type.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[44])); } } - if let Some(rule) = self.use_google_font_display.as_ref() { + if let Some(rule) = self.use_exports_last.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[45])); } } - if let Some(rule) = self.use_google_font_preconnect.as_ref() { + if let Some(rule) = self.use_google_font_display.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[46])); } } - if let Some(rule) = self.use_guard_for_in.as_ref() { + if let Some(rule) = self.use_google_font_preconnect.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[47])); } } - if let Some(rule) = self.use_import_restrictions.as_ref() { + if let Some(rule) = self.use_guard_for_in.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[48])); } } - if let Some(rule) = self.use_named_operation.as_ref() { + if let Some(rule) = self.use_import_restrictions.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[49])); } } - if let Some(rule) = self.use_naming_convention.as_ref() { + if let Some(rule) = self.use_named_operation.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[50])); } } - if let Some(rule) = self.use_parse_int_radix.as_ref() { + if let Some(rule) = self.use_naming_convention.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[51])); } } - if let Some(rule) = self.use_sorted_classes.as_ref() { + if let Some(rule) = self.use_parse_int_radix.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[52])); } } - if let Some(rule) = self.use_strict_mode.as_ref() { + if let Some(rule) = self.use_sorted_classes.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[53])); } } - if let Some(rule) = self.use_trim_start_end.as_ref() { + if let Some(rule) = self.use_strict_mode.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[54])); } } - if let Some(rule) = self.use_valid_autocomplete.as_ref() { + if let Some(rule) = self.use_trim_start_end.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[55])); } } + if let Some(rule) = self.use_valid_autocomplete.as_ref() { + if rule.is_disabled() { + index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[56])); + } + } index_set } #[doc = r" Checks if, given a rule name, matches one of the rules contained in this category"] @@ -4334,6 +4350,10 @@ impl Nursery { .no_nested_ternary .as_ref() .map(|conf| (conf.level(), conf.get_options())), + "noNoninteractiveElementInteractions" => self + .no_noninteractive_element_interactions + .as_ref() + .map(|conf| (conf.level(), conf.get_options())), "noOctalEscape" => self .no_octal_escape .as_ref() diff --git a/crates/biome_diagnostics_categories/src/categories.rs b/crates/biome_diagnostics_categories/src/categories.rs index 6c9199a53c4c..b3e5cb63c86e 100644 --- a/crates/biome_diagnostics_categories/src/categories.rs +++ b/crates/biome_diagnostics_categories/src/categories.rs @@ -160,6 +160,7 @@ define_categories! { "lint/nursery/noMissingGenericFamilyKeyword": "https://biomejs.dev/linter/rules/no-missing-generic-family-keyword", "lint/nursery/noMissingVarFunction": "https://biomejs.dev/linter/rules/no-missing-var-function", "lint/nursery/noNestedTernary": "https://biomejs.dev/linter/rules/no-nested-ternary", + "lint/nursery/noNoninteractiveElementInteractions": "https://biomejs.dev/linter/rules/no-noninteractive-element-interactions", "lint/nursery/noOctalEscape": "https://biomejs.dev/linter/rules/no-octal-escape", "lint/nursery/noProcessEnv": "https://biomejs.dev/linter/rules/no-process-env", "lint/nursery/noProcessGlobal": "https://biomejs.dev/linter/rules/no-process-global", diff --git a/crates/biome_js_analyze/src/lint/nursery.rs b/crates/biome_js_analyze/src/lint/nursery.rs index f66f4761c1d3..feca74ece6b8 100644 --- a/crates/biome_js_analyze/src/lint/nursery.rs +++ b/crates/biome_js_analyze/src/lint/nursery.rs @@ -15,6 +15,7 @@ pub mod no_head_import_in_document; pub mod no_img_element; pub mod no_irregular_whitespace; pub mod no_nested_ternary; +pub mod no_noninteractive_element_interactions; pub mod no_octal_escape; pub mod no_process_env; pub mod no_process_global; @@ -63,6 +64,7 @@ declare_lint_group! { self :: no_img_element :: NoImgElement , self :: no_irregular_whitespace :: NoIrregularWhitespace , self :: no_nested_ternary :: NoNestedTernary , + self :: no_noninteractive_element_interactions :: NoNoninteractiveElementInteractions , self :: no_octal_escape :: NoOctalEscape , self :: no_process_env :: NoProcessEnv , self :: no_process_global :: NoProcessGlobal , diff --git a/crates/biome_js_analyze/src/lint/nursery/no_noninteractive_element_interactions.rs b/crates/biome_js_analyze/src/lint/nursery/no_noninteractive_element_interactions.rs new file mode 100644 index 000000000000..fbbd43dd80d0 --- /dev/null +++ b/crates/biome_js_analyze/src/lint/nursery/no_noninteractive_element_interactions.rs @@ -0,0 +1,215 @@ +use crate::services::aria::Aria; +use biome_analyze::{context::RuleContext, declare_lint_rule, Rule, RuleDiagnostic, RuleSource}; +use biome_console::markup; +use biome_js_syntax::jsx_ext::AnyJsxElement; +use biome_rowan::AstNode; + +declare_lint_rule! { + /// Disallow use event handlers on non-interactive elements. + /// + /// Non-interactive HTML elements indicate _content_ and _containers_ in the user interface. + /// Non-interactive elements include `
`, ``, `

` (,`

`, etc), ``, `
  • `, `