diff --git a/crates/biome_html_analyze/src/a11y.rs b/crates/biome_html_analyze/src/a11y.rs index 6629417b88e5..eda027acc8c3 100644 --- a/crates/biome_html_analyze/src/a11y.rs +++ b/crates/biome_html_analyze/src/a11y.rs @@ -1,22 +1,186 @@ +//! Shared accessibility helper functions for HTML lint rules. +//! +//! This module provides reusable utilities for checking accessibility-related +//! attributes and element states. All helpers follow a layered architecture: +//! +//! 1. **Core helpers** (private): Low-level attribute value extraction and checks +//! 2. **Element helpers** (public): Higher-level checks on HTML elements +//! 3. **Type-specific variants** (public): Optimized versions that avoid cloning + use biome_html_syntax::element_ext::AnyHtmlTagElement; +use biome_html_syntax::{AnyHtmlElement, HtmlAttribute}; + +// ============================================================================ +// Core attribute value helpers (private) +// ============================================================================ + +/// Checks if an `aria-hidden` attribute has a truthy value. +/// +/// Per ARIA spec, `aria-hidden` accepts only `"true"` or `"false"` as valid values. +/// Returns `true` only for non-empty values that are not `"false"` (case-insensitive). +/// Missing values, empty strings, and whitespace-only values are considered falsy. +/// +/// Ref: +fn is_aria_hidden_value_truthy(attribute: &HtmlAttribute) -> bool { + attribute.value().is_some_and(|value| { + let trimmed = value.trim(); + !trimmed.is_empty() && !trimmed.eq_ignore_ascii_case("false") + }) +} + +/// Checks if an attribute value equals `"true"` exactly (case-sensitive). +fn is_strict_true_value(attribute: &HtmlAttribute) -> bool { + attribute.value().is_some_and(|value| value == "true") +} + +/// Checks if an attribute has a non-empty value after trimming whitespace. +/// +/// Returns `false` for attributes with no value, empty strings, or whitespace-only values. +fn has_non_empty_value(attribute: &HtmlAttribute) -> bool { + attribute + .value() + .is_some_and(|value| !value.trim().is_empty()) +} -/// Check the element is hidden from screen reader. +/// Checks if an attribute value matches the expected string (case-insensitive). +/// +/// Useful for checking HTML attribute values like `type="hidden"` or `role="button"` +/// where the comparison should be case-insensitive per HTML spec. +pub(crate) fn attribute_value_equals_ignore_case( + attribute: &HtmlAttribute, + expected: &str, +) -> bool { + attribute + .value() + .is_some_and(|value| value.eq_ignore_ascii_case(expected)) +} + +// ============================================================================ +// Element-level helpers (public) +// ============================================================================ + +/// Returns `true` if the element is hidden from assistive technologies. +/// +/// An element is hidden from screen readers when: +/// - It has a truthy `aria-hidden` attribute +/// - It is an `` element /// /// Ref: -/// - https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-hidden -/// - https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/hidden -/// - https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/v6.10.0/src/util/isHiddenFromScreenReader.js +/// - +/// -