From e4a09df55bb930d418429a2a3c432d5e9fcd47ab Mon Sep 17 00:00:00 2001 From: ematipico Date: Mon, 28 Nov 2022 14:22:03 +0000 Subject: [PATCH] chore: address code suggestions --- crates/rome_analyze/src/registry.rs | 1 - crates/rome_analyze/src/rule.rs | 5 +- crates/rome_aria/src/constants.rs | 3 - crates/rome_aria/src/generated.rs | 796 +++++++++--------- crates/rome_aria/src/lib.rs | 279 +----- crates/rome_aria/src/properties.rs | 107 +++ crates/rome_aria/src/roles.rs | 192 +++++ .../nursery/use_aria_prop_types.rs | 7 +- .../nursery/use_aria_props_for_role.rs | 7 +- crates/rome_js_analyze/src/aria_services.rs | 2 +- crates/rome_js_analyze/src/lib.rs | 2 - .../src/configuration/linter/rules.rs | 60 +- website/src/pages/lint/rules/index.mdx | 12 + xtask/codegen/src/generate_aria.rs | 20 +- 14 files changed, 749 insertions(+), 744 deletions(-) create mode 100644 crates/rome_aria/src/properties.rs create mode 100644 crates/rome_aria/src/roles.rs diff --git a/crates/rome_analyze/src/registry.rs b/crates/rome_analyze/src/registry.rs index a70a729d32e1..b2e1d8a035c9 100644 --- a/crates/rome_analyze/src/registry.rs +++ b/crates/rome_analyze/src/registry.rs @@ -17,7 +17,6 @@ use std::{borrow, collections::BTreeSet}; pub enum Phases { Syntax = 0, Semantic = 1, - Accessibility = 2, } /// Defines which phase a rule will run. This will be defined diff --git a/crates/rome_analyze/src/rule.rs b/crates/rome_analyze/src/rule.rs index 3ff57ea0a39a..2fc76dec060f 100644 --- a/crates/rome_analyze/src/rule.rs +++ b/crates/rome_analyze/src/rule.rs @@ -507,8 +507,9 @@ impl RuleDiagnostic { self.footer(LogCategory::Info, msg) } - /// - pub fn note_list(mut self, message: impl Display, list: &[impl Display]) -> Self { + /// It creates a new footer note which contains a message and a list of possible suggestions. + /// Useful when there's need to suggest a list of things inside a diagnostic. + pub fn footer_list(mut self, message: impl Display, list: &[impl Display]) -> Self { if !list.is_empty() { self.rule_advice.suggestion_list = Some(SuggestionList { message: markup! { {message} }.to_owned(), diff --git a/crates/rome_aria/src/constants.rs b/crates/rome_aria/src/constants.rs index 4936341576bd..d35e6e83df94 100644 --- a/crates/rome_aria/src/constants.rs +++ b/crates/rome_aria/src/constants.rs @@ -2,9 +2,6 @@ //! - ARIA properties //! - ARIA property types //! - ARIA roles -//! -//! **Note**: the crate relies on `binary_search`, which means that the -//! entries of all these constants must be ordered! pub const ARIA_PROPERTIES: [&str; 48] = [ "aria-activedescendant", diff --git a/crates/rome_aria/src/generated.rs b/crates/rome_aria/src/generated.rs index f8b2ab0c03c2..a9d3b17ad710 100644 --- a/crates/rome_aria/src/generated.rs +++ b/crates/rome_aria/src/generated.rs @@ -1,10 +1,6 @@ //! Generated file, do not edit by hand, see `xtask/codegen` -#![allow(clippy::enum_variant_names)] -use crate::constants::{ - ARIA_ABSTRACT_ROLES, ARIA_DOCUMENT_STRUCTURE_ROLES, ARIA_PROPERTIES, ARIA_PROPERTY_TYPE, - ARIA_WIDGET_ROLES, -}; +use std::str::FromStr; #[derive(Debug, Eq, PartialEq)] pub enum AriaPropertiesEnum { AriaActivedescendant, @@ -59,177 +55,175 @@ pub enum AriaPropertiesEnum { impl From for &str { fn from(property: AriaPropertiesEnum) -> Self { match property { - AriaPropertiesEnum::AriaActivedescendant => ARIA_PROPERTIES[0], - AriaPropertiesEnum::AriaAtomic => ARIA_PROPERTIES[1], - AriaPropertiesEnum::AriaAutocomplete => ARIA_PROPERTIES[2], - AriaPropertiesEnum::AriaBusy => ARIA_PROPERTIES[3], - AriaPropertiesEnum::AriaChecked => ARIA_PROPERTIES[4], - AriaPropertiesEnum::AriaColcount => ARIA_PROPERTIES[5], - AriaPropertiesEnum::AriaColindex => ARIA_PROPERTIES[6], - AriaPropertiesEnum::AriaColspan => ARIA_PROPERTIES[7], - AriaPropertiesEnum::AriaControls => ARIA_PROPERTIES[8], - AriaPropertiesEnum::AriaCurrent => ARIA_PROPERTIES[9], - AriaPropertiesEnum::AriaDescribedby => ARIA_PROPERTIES[10], - AriaPropertiesEnum::AriaDetails => ARIA_PROPERTIES[11], - AriaPropertiesEnum::AriaDisabled => ARIA_PROPERTIES[12], - AriaPropertiesEnum::AriaDropeffect => ARIA_PROPERTIES[13], - AriaPropertiesEnum::AriaErrormessage => ARIA_PROPERTIES[14], - AriaPropertiesEnum::AriaExpanded => ARIA_PROPERTIES[15], - AriaPropertiesEnum::AriaFlowto => ARIA_PROPERTIES[16], - AriaPropertiesEnum::AriaGrabbed => ARIA_PROPERTIES[17], - AriaPropertiesEnum::AriaHaspopup => ARIA_PROPERTIES[18], - AriaPropertiesEnum::AriaHidden => ARIA_PROPERTIES[19], - AriaPropertiesEnum::AriaInvalid => ARIA_PROPERTIES[20], - AriaPropertiesEnum::AriaKeyshortcuts => ARIA_PROPERTIES[21], - AriaPropertiesEnum::AriaLabel => ARIA_PROPERTIES[22], - AriaPropertiesEnum::AriaLabelledby => ARIA_PROPERTIES[23], - AriaPropertiesEnum::AriaLevel => ARIA_PROPERTIES[24], - AriaPropertiesEnum::AriaLive => ARIA_PROPERTIES[25], - AriaPropertiesEnum::AriaModal => ARIA_PROPERTIES[26], - AriaPropertiesEnum::AriaMultiline => ARIA_PROPERTIES[27], - AriaPropertiesEnum::AriaMultiselectable => ARIA_PROPERTIES[28], - AriaPropertiesEnum::AriaOrientation => ARIA_PROPERTIES[29], - AriaPropertiesEnum::AriaOwns => ARIA_PROPERTIES[30], - AriaPropertiesEnum::AriaPlaceholder => ARIA_PROPERTIES[31], - AriaPropertiesEnum::AriaPosinset => ARIA_PROPERTIES[32], - AriaPropertiesEnum::AriaPressed => ARIA_PROPERTIES[33], - AriaPropertiesEnum::AriaReadonly => ARIA_PROPERTIES[34], - AriaPropertiesEnum::AriaRelevant => ARIA_PROPERTIES[35], - AriaPropertiesEnum::AriaRequired => ARIA_PROPERTIES[36], - AriaPropertiesEnum::AriaRoledescription => ARIA_PROPERTIES[37], - AriaPropertiesEnum::AriaRowcount => ARIA_PROPERTIES[38], - AriaPropertiesEnum::AriaRowindex => ARIA_PROPERTIES[39], - AriaPropertiesEnum::AriaRowspan => ARIA_PROPERTIES[40], - AriaPropertiesEnum::AriaSelected => ARIA_PROPERTIES[41], - AriaPropertiesEnum::AriaSetsize => ARIA_PROPERTIES[42], - AriaPropertiesEnum::AriaSort => ARIA_PROPERTIES[43], - AriaPropertiesEnum::AriaValuemax => ARIA_PROPERTIES[44], - AriaPropertiesEnum::AriaValuemin => ARIA_PROPERTIES[45], - AriaPropertiesEnum::AriaValuenow => ARIA_PROPERTIES[46], - AriaPropertiesEnum::AriaValuetext => ARIA_PROPERTIES[47], + AriaPropertiesEnum::AriaActivedescendant => "aria-activedescendant", + AriaPropertiesEnum::AriaAtomic => "aria-atomic", + AriaPropertiesEnum::AriaAutocomplete => "aria-autocomplete", + AriaPropertiesEnum::AriaBusy => "aria-busy", + AriaPropertiesEnum::AriaChecked => "aria-checked", + AriaPropertiesEnum::AriaColcount => "aria-colcount", + AriaPropertiesEnum::AriaColindex => "aria-colindex", + AriaPropertiesEnum::AriaColspan => "aria-colspan", + AriaPropertiesEnum::AriaControls => "aria-controls", + AriaPropertiesEnum::AriaCurrent => "aria-current", + AriaPropertiesEnum::AriaDescribedby => "aria-describedby", + AriaPropertiesEnum::AriaDetails => "aria-details", + AriaPropertiesEnum::AriaDisabled => "aria-disabled", + AriaPropertiesEnum::AriaDropeffect => "aria-dropeffect", + AriaPropertiesEnum::AriaErrormessage => "aria-errormessage", + AriaPropertiesEnum::AriaExpanded => "aria-expanded", + AriaPropertiesEnum::AriaFlowto => "aria-flowto", + AriaPropertiesEnum::AriaGrabbed => "aria-grabbed", + AriaPropertiesEnum::AriaHaspopup => "aria-haspopup", + AriaPropertiesEnum::AriaHidden => "aria-hidden", + AriaPropertiesEnum::AriaInvalid => "aria-invalid", + AriaPropertiesEnum::AriaKeyshortcuts => "aria-keyshortcuts", + AriaPropertiesEnum::AriaLabel => "aria-label", + AriaPropertiesEnum::AriaLabelledby => "aria-labelledby", + AriaPropertiesEnum::AriaLevel => "aria-level", + AriaPropertiesEnum::AriaLive => "aria-live", + AriaPropertiesEnum::AriaModal => "aria-modal", + AriaPropertiesEnum::AriaMultiline => "aria-multiline", + AriaPropertiesEnum::AriaMultiselectable => "aria-multiselectable", + AriaPropertiesEnum::AriaOrientation => "aria-orientation", + AriaPropertiesEnum::AriaOwns => "aria-owns", + AriaPropertiesEnum::AriaPlaceholder => "aria-placeholder", + AriaPropertiesEnum::AriaPosinset => "aria-posinset", + AriaPropertiesEnum::AriaPressed => "aria-pressed", + AriaPropertiesEnum::AriaReadonly => "aria-readonly", + AriaPropertiesEnum::AriaRelevant => "aria-relevant", + AriaPropertiesEnum::AriaRequired => "aria-required", + AriaPropertiesEnum::AriaRoledescription => "aria-roledescription", + AriaPropertiesEnum::AriaRowcount => "aria-rowcount", + AriaPropertiesEnum::AriaRowindex => "aria-rowindex", + AriaPropertiesEnum::AriaRowspan => "aria-rowspan", + AriaPropertiesEnum::AriaSelected => "aria-selected", + AriaPropertiesEnum::AriaSetsize => "aria-setsize", + AriaPropertiesEnum::AriaSort => "aria-sort", + AriaPropertiesEnum::AriaValuemax => "aria-valuemax", + AriaPropertiesEnum::AriaValuemin => "aria-valuemin", + AriaPropertiesEnum::AriaValuenow => "aria-valuenow", + AriaPropertiesEnum::AriaValuetext => "aria-valuetext", } } } -impl From<&str> for AriaPropertiesEnum { - fn from(s: &str) -> Self { - let index = ARIA_PROPERTIES - .binary_search(&s) - .unwrap_or_else(|_| panic!("aria property not implemented {s:?}")); - match index { - 0 => AriaPropertiesEnum::AriaActivedescendant, - 1 => AriaPropertiesEnum::AriaAtomic, - 2 => AriaPropertiesEnum::AriaAutocomplete, - 3 => AriaPropertiesEnum::AriaBusy, - 4 => AriaPropertiesEnum::AriaChecked, - 5 => AriaPropertiesEnum::AriaColcount, - 6 => AriaPropertiesEnum::AriaColindex, - 7 => AriaPropertiesEnum::AriaColspan, - 8 => AriaPropertiesEnum::AriaControls, - 9 => AriaPropertiesEnum::AriaCurrent, - 10 => AriaPropertiesEnum::AriaDescribedby, - 11 => AriaPropertiesEnum::AriaDetails, - 12 => AriaPropertiesEnum::AriaDisabled, - 13 => AriaPropertiesEnum::AriaDropeffect, - 14 => AriaPropertiesEnum::AriaErrormessage, - 15 => AriaPropertiesEnum::AriaExpanded, - 16 => AriaPropertiesEnum::AriaFlowto, - 17 => AriaPropertiesEnum::AriaGrabbed, - 18 => AriaPropertiesEnum::AriaHaspopup, - 19 => AriaPropertiesEnum::AriaHidden, - 20 => AriaPropertiesEnum::AriaInvalid, - 21 => AriaPropertiesEnum::AriaKeyshortcuts, - 22 => AriaPropertiesEnum::AriaLabel, - 23 => AriaPropertiesEnum::AriaLabelledby, - 24 => AriaPropertiesEnum::AriaLevel, - 25 => AriaPropertiesEnum::AriaLive, - 26 => AriaPropertiesEnum::AriaModal, - 27 => AriaPropertiesEnum::AriaMultiline, - 28 => AriaPropertiesEnum::AriaMultiselectable, - 29 => AriaPropertiesEnum::AriaOrientation, - 30 => AriaPropertiesEnum::AriaOwns, - 31 => AriaPropertiesEnum::AriaPlaceholder, - 32 => AriaPropertiesEnum::AriaPosinset, - 33 => AriaPropertiesEnum::AriaPressed, - 34 => AriaPropertiesEnum::AriaReadonly, - 35 => AriaPropertiesEnum::AriaRelevant, - 36 => AriaPropertiesEnum::AriaRequired, - 37 => AriaPropertiesEnum::AriaRoledescription, - 38 => AriaPropertiesEnum::AriaRowcount, - 39 => AriaPropertiesEnum::AriaRowindex, - 40 => AriaPropertiesEnum::AriaRowspan, - 41 => AriaPropertiesEnum::AriaSelected, - 42 => AriaPropertiesEnum::AriaSetsize, - 43 => AriaPropertiesEnum::AriaSort, - 44 => AriaPropertiesEnum::AriaValuemax, - 45 => AriaPropertiesEnum::AriaValuemin, - 46 => AriaPropertiesEnum::AriaValuenow, - 47 => AriaPropertiesEnum::AriaValuetext, - _ => panic!("aria property not implemented"), +impl FromStr for AriaPropertiesEnum { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "aria-activedescendant" => Ok(AriaPropertiesEnum::AriaActivedescendant), + "aria-atomic" => Ok(AriaPropertiesEnum::AriaAtomic), + "aria-autocomplete" => Ok(AriaPropertiesEnum::AriaAutocomplete), + "aria-busy" => Ok(AriaPropertiesEnum::AriaBusy), + "aria-checked" => Ok(AriaPropertiesEnum::AriaChecked), + "aria-colcount" => Ok(AriaPropertiesEnum::AriaColcount), + "aria-colindex" => Ok(AriaPropertiesEnum::AriaColindex), + "aria-colspan" => Ok(AriaPropertiesEnum::AriaColspan), + "aria-controls" => Ok(AriaPropertiesEnum::AriaControls), + "aria-current" => Ok(AriaPropertiesEnum::AriaCurrent), + "aria-describedby" => Ok(AriaPropertiesEnum::AriaDescribedby), + "aria-details" => Ok(AriaPropertiesEnum::AriaDetails), + "aria-disabled" => Ok(AriaPropertiesEnum::AriaDisabled), + "aria-dropeffect" => Ok(AriaPropertiesEnum::AriaDropeffect), + "aria-errormessage" => Ok(AriaPropertiesEnum::AriaErrormessage), + "aria-expanded" => Ok(AriaPropertiesEnum::AriaExpanded), + "aria-flowto" => Ok(AriaPropertiesEnum::AriaFlowto), + "aria-grabbed" => Ok(AriaPropertiesEnum::AriaGrabbed), + "aria-haspopup" => Ok(AriaPropertiesEnum::AriaHaspopup), + "aria-hidden" => Ok(AriaPropertiesEnum::AriaHidden), + "aria-invalid" => Ok(AriaPropertiesEnum::AriaInvalid), + "aria-keyshortcuts" => Ok(AriaPropertiesEnum::AriaKeyshortcuts), + "aria-label" => Ok(AriaPropertiesEnum::AriaLabel), + "aria-labelledby" => Ok(AriaPropertiesEnum::AriaLabelledby), + "aria-level" => Ok(AriaPropertiesEnum::AriaLevel), + "aria-live" => Ok(AriaPropertiesEnum::AriaLive), + "aria-modal" => Ok(AriaPropertiesEnum::AriaModal), + "aria-multiline" => Ok(AriaPropertiesEnum::AriaMultiline), + "aria-multiselectable" => Ok(AriaPropertiesEnum::AriaMultiselectable), + "aria-orientation" => Ok(AriaPropertiesEnum::AriaOrientation), + "aria-owns" => Ok(AriaPropertiesEnum::AriaOwns), + "aria-placeholder" => Ok(AriaPropertiesEnum::AriaPlaceholder), + "aria-posinset" => Ok(AriaPropertiesEnum::AriaPosinset), + "aria-pressed" => Ok(AriaPropertiesEnum::AriaPressed), + "aria-readonly" => Ok(AriaPropertiesEnum::AriaReadonly), + "aria-relevant" => Ok(AriaPropertiesEnum::AriaRelevant), + "aria-required" => Ok(AriaPropertiesEnum::AriaRequired), + "aria-roledescription" => Ok(AriaPropertiesEnum::AriaRoledescription), + "aria-rowcount" => Ok(AriaPropertiesEnum::AriaRowcount), + "aria-rowindex" => Ok(AriaPropertiesEnum::AriaRowindex), + "aria-rowspan" => Ok(AriaPropertiesEnum::AriaRowspan), + "aria-selected" => Ok(AriaPropertiesEnum::AriaSelected), + "aria-setsize" => Ok(AriaPropertiesEnum::AriaSetsize), + "aria-sort" => Ok(AriaPropertiesEnum::AriaSort), + "aria-valuemax" => Ok(AriaPropertiesEnum::AriaValuemax), + "aria-valuemin" => Ok(AriaPropertiesEnum::AriaValuemin), + "aria-valuenow" => Ok(AriaPropertiesEnum::AriaValuenow), + "aria-valuetext" => Ok(AriaPropertiesEnum::AriaValuetext), + _ => Err("aria property not implemented".to_string()), } } } impl AriaPropertiesEnum { pub fn as_str(&self) -> &str { match self { - AriaPropertiesEnum::AriaActivedescendant => ARIA_PROPERTIES[0], - AriaPropertiesEnum::AriaAtomic => ARIA_PROPERTIES[1], - AriaPropertiesEnum::AriaAutocomplete => ARIA_PROPERTIES[2], - AriaPropertiesEnum::AriaBusy => ARIA_PROPERTIES[3], - AriaPropertiesEnum::AriaChecked => ARIA_PROPERTIES[4], - AriaPropertiesEnum::AriaColcount => ARIA_PROPERTIES[5], - AriaPropertiesEnum::AriaColindex => ARIA_PROPERTIES[6], - AriaPropertiesEnum::AriaColspan => ARIA_PROPERTIES[7], - AriaPropertiesEnum::AriaControls => ARIA_PROPERTIES[8], - AriaPropertiesEnum::AriaCurrent => ARIA_PROPERTIES[9], - AriaPropertiesEnum::AriaDescribedby => ARIA_PROPERTIES[10], - AriaPropertiesEnum::AriaDetails => ARIA_PROPERTIES[11], - AriaPropertiesEnum::AriaDisabled => ARIA_PROPERTIES[12], - AriaPropertiesEnum::AriaDropeffect => ARIA_PROPERTIES[13], - AriaPropertiesEnum::AriaErrormessage => ARIA_PROPERTIES[14], - AriaPropertiesEnum::AriaExpanded => ARIA_PROPERTIES[15], - AriaPropertiesEnum::AriaFlowto => ARIA_PROPERTIES[16], - AriaPropertiesEnum::AriaGrabbed => ARIA_PROPERTIES[17], - AriaPropertiesEnum::AriaHaspopup => ARIA_PROPERTIES[18], - AriaPropertiesEnum::AriaHidden => ARIA_PROPERTIES[19], - AriaPropertiesEnum::AriaInvalid => ARIA_PROPERTIES[20], - AriaPropertiesEnum::AriaKeyshortcuts => ARIA_PROPERTIES[21], - AriaPropertiesEnum::AriaLabel => ARIA_PROPERTIES[22], - AriaPropertiesEnum::AriaLabelledby => ARIA_PROPERTIES[23], - AriaPropertiesEnum::AriaLevel => ARIA_PROPERTIES[24], - AriaPropertiesEnum::AriaLive => ARIA_PROPERTIES[25], - AriaPropertiesEnum::AriaModal => ARIA_PROPERTIES[26], - AriaPropertiesEnum::AriaMultiline => ARIA_PROPERTIES[27], - AriaPropertiesEnum::AriaMultiselectable => ARIA_PROPERTIES[28], - AriaPropertiesEnum::AriaOrientation => ARIA_PROPERTIES[29], - AriaPropertiesEnum::AriaOwns => ARIA_PROPERTIES[30], - AriaPropertiesEnum::AriaPlaceholder => ARIA_PROPERTIES[31], - AriaPropertiesEnum::AriaPosinset => ARIA_PROPERTIES[32], - AriaPropertiesEnum::AriaPressed => ARIA_PROPERTIES[33], - AriaPropertiesEnum::AriaReadonly => ARIA_PROPERTIES[34], - AriaPropertiesEnum::AriaRelevant => ARIA_PROPERTIES[35], - AriaPropertiesEnum::AriaRequired => ARIA_PROPERTIES[36], - AriaPropertiesEnum::AriaRoledescription => ARIA_PROPERTIES[37], - AriaPropertiesEnum::AriaRowcount => ARIA_PROPERTIES[38], - AriaPropertiesEnum::AriaRowindex => ARIA_PROPERTIES[39], - AriaPropertiesEnum::AriaRowspan => ARIA_PROPERTIES[40], - AriaPropertiesEnum::AriaSelected => ARIA_PROPERTIES[41], - AriaPropertiesEnum::AriaSetsize => ARIA_PROPERTIES[42], - AriaPropertiesEnum::AriaSort => ARIA_PROPERTIES[43], - AriaPropertiesEnum::AriaValuemax => ARIA_PROPERTIES[44], - AriaPropertiesEnum::AriaValuemin => ARIA_PROPERTIES[45], - AriaPropertiesEnum::AriaValuenow => ARIA_PROPERTIES[46], - AriaPropertiesEnum::AriaValuetext => ARIA_PROPERTIES[47], + AriaPropertiesEnum::AriaActivedescendant => "aria-activedescendant", + AriaPropertiesEnum::AriaAtomic => "aria-atomic", + AriaPropertiesEnum::AriaAutocomplete => "aria-autocomplete", + AriaPropertiesEnum::AriaBusy => "aria-busy", + AriaPropertiesEnum::AriaChecked => "aria-checked", + AriaPropertiesEnum::AriaColcount => "aria-colcount", + AriaPropertiesEnum::AriaColindex => "aria-colindex", + AriaPropertiesEnum::AriaColspan => "aria-colspan", + AriaPropertiesEnum::AriaControls => "aria-controls", + AriaPropertiesEnum::AriaCurrent => "aria-current", + AriaPropertiesEnum::AriaDescribedby => "aria-describedby", + AriaPropertiesEnum::AriaDetails => "aria-details", + AriaPropertiesEnum::AriaDisabled => "aria-disabled", + AriaPropertiesEnum::AriaDropeffect => "aria-dropeffect", + AriaPropertiesEnum::AriaErrormessage => "aria-errormessage", + AriaPropertiesEnum::AriaExpanded => "aria-expanded", + AriaPropertiesEnum::AriaFlowto => "aria-flowto", + AriaPropertiesEnum::AriaGrabbed => "aria-grabbed", + AriaPropertiesEnum::AriaHaspopup => "aria-haspopup", + AriaPropertiesEnum::AriaHidden => "aria-hidden", + AriaPropertiesEnum::AriaInvalid => "aria-invalid", + AriaPropertiesEnum::AriaKeyshortcuts => "aria-keyshortcuts", + AriaPropertiesEnum::AriaLabel => "aria-label", + AriaPropertiesEnum::AriaLabelledby => "aria-labelledby", + AriaPropertiesEnum::AriaLevel => "aria-level", + AriaPropertiesEnum::AriaLive => "aria-live", + AriaPropertiesEnum::AriaModal => "aria-modal", + AriaPropertiesEnum::AriaMultiline => "aria-multiline", + AriaPropertiesEnum::AriaMultiselectable => "aria-multiselectable", + AriaPropertiesEnum::AriaOrientation => "aria-orientation", + AriaPropertiesEnum::AriaOwns => "aria-owns", + AriaPropertiesEnum::AriaPlaceholder => "aria-placeholder", + AriaPropertiesEnum::AriaPosinset => "aria-posinset", + AriaPropertiesEnum::AriaPressed => "aria-pressed", + AriaPropertiesEnum::AriaReadonly => "aria-readonly", + AriaPropertiesEnum::AriaRelevant => "aria-relevant", + AriaPropertiesEnum::AriaRequired => "aria-required", + AriaPropertiesEnum::AriaRoledescription => "aria-roledescription", + AriaPropertiesEnum::AriaRowcount => "aria-rowcount", + AriaPropertiesEnum::AriaRowindex => "aria-rowindex", + AriaPropertiesEnum::AriaRowspan => "aria-rowspan", + AriaPropertiesEnum::AriaSelected => "aria-selected", + AriaPropertiesEnum::AriaSetsize => "aria-setsize", + AriaPropertiesEnum::AriaSort => "aria-sort", + AriaPropertiesEnum::AriaValuemax => "aria-valuemax", + AriaPropertiesEnum::AriaValuemin => "aria-valuemin", + AriaPropertiesEnum::AriaValuenow => "aria-valuenow", + AriaPropertiesEnum::AriaValuetext => "aria-valuetext", } } } #[derive(Debug, Eq, PartialEq)] pub enum AriaPropertyTypeEnum { - String, + Boolean, Id, Idlist, Integer, Number, - Boolean, + String, Token, Tokenlist, Tristate, @@ -237,49 +231,47 @@ pub enum AriaPropertyTypeEnum { impl From for &str { fn from(property: AriaPropertyTypeEnum) -> Self { match property { - AriaPropertyTypeEnum::String => ARIA_PROPERTY_TYPE[0], - AriaPropertyTypeEnum::Id => ARIA_PROPERTY_TYPE[1], - AriaPropertyTypeEnum::Idlist => ARIA_PROPERTY_TYPE[2], - AriaPropertyTypeEnum::Integer => ARIA_PROPERTY_TYPE[3], - AriaPropertyTypeEnum::Number => ARIA_PROPERTY_TYPE[4], - AriaPropertyTypeEnum::Boolean => ARIA_PROPERTY_TYPE[5], - AriaPropertyTypeEnum::Token => ARIA_PROPERTY_TYPE[6], - AriaPropertyTypeEnum::Tokenlist => ARIA_PROPERTY_TYPE[7], - AriaPropertyTypeEnum::Tristate => ARIA_PROPERTY_TYPE[8], + AriaPropertyTypeEnum::Boolean => "boolean", + AriaPropertyTypeEnum::Id => "id", + AriaPropertyTypeEnum::Idlist => "idlist", + AriaPropertyTypeEnum::Integer => "integer", + AriaPropertyTypeEnum::Number => "number", + AriaPropertyTypeEnum::String => "string", + AriaPropertyTypeEnum::Token => "token", + AriaPropertyTypeEnum::Tokenlist => "tokenlist", + AriaPropertyTypeEnum::Tristate => "tristate", } } } -impl From<&str> for AriaPropertyTypeEnum { - fn from(s: &str) -> Self { - let index = ARIA_PROPERTY_TYPE - .binary_search(&s) - .unwrap_or_else(|_| panic!("aria property not implemented {s:?}")); - match index { - 0 => AriaPropertyTypeEnum::String, - 1 => AriaPropertyTypeEnum::Id, - 2 => AriaPropertyTypeEnum::Idlist, - 3 => AriaPropertyTypeEnum::Integer, - 4 => AriaPropertyTypeEnum::Number, - 5 => AriaPropertyTypeEnum::Boolean, - 6 => AriaPropertyTypeEnum::Token, - 7 => AriaPropertyTypeEnum::Tokenlist, - 8 => AriaPropertyTypeEnum::Tristate, - _ => panic!("aria property not implemented"), +impl FromStr for AriaPropertyTypeEnum { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "boolean" => Ok(AriaPropertyTypeEnum::Boolean), + "id" => Ok(AriaPropertyTypeEnum::Id), + "idlist" => Ok(AriaPropertyTypeEnum::Idlist), + "integer" => Ok(AriaPropertyTypeEnum::Integer), + "number" => Ok(AriaPropertyTypeEnum::Number), + "string" => Ok(AriaPropertyTypeEnum::String), + "token" => Ok(AriaPropertyTypeEnum::Token), + "tokenlist" => Ok(AriaPropertyTypeEnum::Tokenlist), + "tristate" => Ok(AriaPropertyTypeEnum::Tristate), + _ => Err("aria property not implemented".to_string()), } } } impl AriaPropertyTypeEnum { pub fn as_str(&self) -> &str { match self { - AriaPropertyTypeEnum::String => ARIA_PROPERTY_TYPE[0], - AriaPropertyTypeEnum::Id => ARIA_PROPERTY_TYPE[1], - AriaPropertyTypeEnum::Idlist => ARIA_PROPERTY_TYPE[2], - AriaPropertyTypeEnum::Integer => ARIA_PROPERTY_TYPE[3], - AriaPropertyTypeEnum::Number => ARIA_PROPERTY_TYPE[4], - AriaPropertyTypeEnum::Boolean => ARIA_PROPERTY_TYPE[5], - AriaPropertyTypeEnum::Token => ARIA_PROPERTY_TYPE[6], - AriaPropertyTypeEnum::Tokenlist => ARIA_PROPERTY_TYPE[7], - AriaPropertyTypeEnum::Tristate => ARIA_PROPERTY_TYPE[8], + AriaPropertyTypeEnum::Boolean => "boolean", + AriaPropertyTypeEnum::Id => "id", + AriaPropertyTypeEnum::Idlist => "idlist", + AriaPropertyTypeEnum::Integer => "integer", + AriaPropertyTypeEnum::Number => "number", + AriaPropertyTypeEnum::String => "string", + AriaPropertyTypeEnum::Token => "token", + AriaPropertyTypeEnum::Tokenlist => "tokenlist", + AriaPropertyTypeEnum::Tristate => "tristate", } } } @@ -316,103 +308,101 @@ pub enum AriaWidgetRolesEnum { impl From for &str { fn from(property: AriaWidgetRolesEnum) -> Self { match property { - AriaWidgetRolesEnum::Alert => ARIA_WIDGET_ROLES[0], - AriaWidgetRolesEnum::Alertdialog => ARIA_WIDGET_ROLES[1], - AriaWidgetRolesEnum::Button => ARIA_WIDGET_ROLES[2], - AriaWidgetRolesEnum::Checkbox => ARIA_WIDGET_ROLES[3], - AriaWidgetRolesEnum::Dialog => ARIA_WIDGET_ROLES[4], - AriaWidgetRolesEnum::Gridcell => ARIA_WIDGET_ROLES[5], - AriaWidgetRolesEnum::Link => ARIA_WIDGET_ROLES[6], - AriaWidgetRolesEnum::Log => ARIA_WIDGET_ROLES[7], - AriaWidgetRolesEnum::Marquee => ARIA_WIDGET_ROLES[8], - AriaWidgetRolesEnum::Menuitem => ARIA_WIDGET_ROLES[9], - AriaWidgetRolesEnum::Menuitemcheckbox => ARIA_WIDGET_ROLES[10], - AriaWidgetRolesEnum::Menuitemradio => ARIA_WIDGET_ROLES[11], - AriaWidgetRolesEnum::Option => ARIA_WIDGET_ROLES[12], - AriaWidgetRolesEnum::Progressbar => ARIA_WIDGET_ROLES[13], - AriaWidgetRolesEnum::Radio => ARIA_WIDGET_ROLES[14], - AriaWidgetRolesEnum::Scrollbar => ARIA_WIDGET_ROLES[15], - AriaWidgetRolesEnum::Searchbox => ARIA_WIDGET_ROLES[16], - AriaWidgetRolesEnum::Slider => ARIA_WIDGET_ROLES[17], - AriaWidgetRolesEnum::Spinbutton => ARIA_WIDGET_ROLES[18], - AriaWidgetRolesEnum::Status => ARIA_WIDGET_ROLES[19], - AriaWidgetRolesEnum::Switch => ARIA_WIDGET_ROLES[20], - AriaWidgetRolesEnum::Tab => ARIA_WIDGET_ROLES[21], - AriaWidgetRolesEnum::Tabpanel => ARIA_WIDGET_ROLES[22], - AriaWidgetRolesEnum::Textbox => ARIA_WIDGET_ROLES[23], - AriaWidgetRolesEnum::Timer => ARIA_WIDGET_ROLES[24], - AriaWidgetRolesEnum::Tooltip => ARIA_WIDGET_ROLES[25], - AriaWidgetRolesEnum::Treeitem => ARIA_WIDGET_ROLES[26], + AriaWidgetRolesEnum::Alert => "alert", + AriaWidgetRolesEnum::Alertdialog => "alertdialog", + AriaWidgetRolesEnum::Button => "button", + AriaWidgetRolesEnum::Checkbox => "checkbox", + AriaWidgetRolesEnum::Dialog => "dialog", + AriaWidgetRolesEnum::Gridcell => "gridcell", + AriaWidgetRolesEnum::Link => "link", + AriaWidgetRolesEnum::Log => "log", + AriaWidgetRolesEnum::Marquee => "marquee", + AriaWidgetRolesEnum::Menuitem => "menuitem", + AriaWidgetRolesEnum::Menuitemcheckbox => "menuitemcheckbox", + AriaWidgetRolesEnum::Menuitemradio => "menuitemradio", + AriaWidgetRolesEnum::Option => "option", + AriaWidgetRolesEnum::Progressbar => "progressbar", + AriaWidgetRolesEnum::Radio => "radio", + AriaWidgetRolesEnum::Scrollbar => "scrollbar", + AriaWidgetRolesEnum::Searchbox => "searchbox", + AriaWidgetRolesEnum::Slider => "slider", + AriaWidgetRolesEnum::Spinbutton => "spinbutton", + AriaWidgetRolesEnum::Status => "status", + AriaWidgetRolesEnum::Switch => "switch", + AriaWidgetRolesEnum::Tab => "tab", + AriaWidgetRolesEnum::Tabpanel => "tabpanel", + AriaWidgetRolesEnum::Textbox => "textbox", + AriaWidgetRolesEnum::Timer => "timer", + AriaWidgetRolesEnum::Tooltip => "tooltip", + AriaWidgetRolesEnum::Treeitem => "treeitem", } } } -impl From<&str> for AriaWidgetRolesEnum { - fn from(s: &str) -> Self { - let index = ARIA_WIDGET_ROLES - .binary_search(&s) - .unwrap_or_else(|_| panic!("aria property not implemented {s:?}")); - match index { - 0 => AriaWidgetRolesEnum::Alert, - 1 => AriaWidgetRolesEnum::Alertdialog, - 2 => AriaWidgetRolesEnum::Button, - 3 => AriaWidgetRolesEnum::Checkbox, - 4 => AriaWidgetRolesEnum::Dialog, - 5 => AriaWidgetRolesEnum::Gridcell, - 6 => AriaWidgetRolesEnum::Link, - 7 => AriaWidgetRolesEnum::Log, - 8 => AriaWidgetRolesEnum::Marquee, - 9 => AriaWidgetRolesEnum::Menuitem, - 10 => AriaWidgetRolesEnum::Menuitemcheckbox, - 11 => AriaWidgetRolesEnum::Menuitemradio, - 12 => AriaWidgetRolesEnum::Option, - 13 => AriaWidgetRolesEnum::Progressbar, - 14 => AriaWidgetRolesEnum::Radio, - 15 => AriaWidgetRolesEnum::Scrollbar, - 16 => AriaWidgetRolesEnum::Searchbox, - 17 => AriaWidgetRolesEnum::Slider, - 18 => AriaWidgetRolesEnum::Spinbutton, - 19 => AriaWidgetRolesEnum::Status, - 20 => AriaWidgetRolesEnum::Switch, - 21 => AriaWidgetRolesEnum::Tab, - 22 => AriaWidgetRolesEnum::Tabpanel, - 23 => AriaWidgetRolesEnum::Textbox, - 24 => AriaWidgetRolesEnum::Timer, - 25 => AriaWidgetRolesEnum::Tooltip, - 26 => AriaWidgetRolesEnum::Treeitem, - _ => panic!("aria property not implemented"), +impl FromStr for AriaWidgetRolesEnum { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "alert" => Ok(AriaWidgetRolesEnum::Alert), + "alertdialog" => Ok(AriaWidgetRolesEnum::Alertdialog), + "button" => Ok(AriaWidgetRolesEnum::Button), + "checkbox" => Ok(AriaWidgetRolesEnum::Checkbox), + "dialog" => Ok(AriaWidgetRolesEnum::Dialog), + "gridcell" => Ok(AriaWidgetRolesEnum::Gridcell), + "link" => Ok(AriaWidgetRolesEnum::Link), + "log" => Ok(AriaWidgetRolesEnum::Log), + "marquee" => Ok(AriaWidgetRolesEnum::Marquee), + "menuitem" => Ok(AriaWidgetRolesEnum::Menuitem), + "menuitemcheckbox" => Ok(AriaWidgetRolesEnum::Menuitemcheckbox), + "menuitemradio" => Ok(AriaWidgetRolesEnum::Menuitemradio), + "option" => Ok(AriaWidgetRolesEnum::Option), + "progressbar" => Ok(AriaWidgetRolesEnum::Progressbar), + "radio" => Ok(AriaWidgetRolesEnum::Radio), + "scrollbar" => Ok(AriaWidgetRolesEnum::Scrollbar), + "searchbox" => Ok(AriaWidgetRolesEnum::Searchbox), + "slider" => Ok(AriaWidgetRolesEnum::Slider), + "spinbutton" => Ok(AriaWidgetRolesEnum::Spinbutton), + "status" => Ok(AriaWidgetRolesEnum::Status), + "switch" => Ok(AriaWidgetRolesEnum::Switch), + "tab" => Ok(AriaWidgetRolesEnum::Tab), + "tabpanel" => Ok(AriaWidgetRolesEnum::Tabpanel), + "textbox" => Ok(AriaWidgetRolesEnum::Textbox), + "timer" => Ok(AriaWidgetRolesEnum::Timer), + "tooltip" => Ok(AriaWidgetRolesEnum::Tooltip), + "treeitem" => Ok(AriaWidgetRolesEnum::Treeitem), + _ => Err("aria property not implemented".to_string()), } } } impl AriaWidgetRolesEnum { pub fn as_str(&self) -> &str { match self { - AriaWidgetRolesEnum::Alert => ARIA_WIDGET_ROLES[0], - AriaWidgetRolesEnum::Alertdialog => ARIA_WIDGET_ROLES[1], - AriaWidgetRolesEnum::Button => ARIA_WIDGET_ROLES[2], - AriaWidgetRolesEnum::Checkbox => ARIA_WIDGET_ROLES[3], - AriaWidgetRolesEnum::Dialog => ARIA_WIDGET_ROLES[4], - AriaWidgetRolesEnum::Gridcell => ARIA_WIDGET_ROLES[5], - AriaWidgetRolesEnum::Link => ARIA_WIDGET_ROLES[6], - AriaWidgetRolesEnum::Log => ARIA_WIDGET_ROLES[7], - AriaWidgetRolesEnum::Marquee => ARIA_WIDGET_ROLES[8], - AriaWidgetRolesEnum::Menuitem => ARIA_WIDGET_ROLES[9], - AriaWidgetRolesEnum::Menuitemcheckbox => ARIA_WIDGET_ROLES[10], - AriaWidgetRolesEnum::Menuitemradio => ARIA_WIDGET_ROLES[11], - AriaWidgetRolesEnum::Option => ARIA_WIDGET_ROLES[12], - AriaWidgetRolesEnum::Progressbar => ARIA_WIDGET_ROLES[13], - AriaWidgetRolesEnum::Radio => ARIA_WIDGET_ROLES[14], - AriaWidgetRolesEnum::Scrollbar => ARIA_WIDGET_ROLES[15], - AriaWidgetRolesEnum::Searchbox => ARIA_WIDGET_ROLES[16], - AriaWidgetRolesEnum::Slider => ARIA_WIDGET_ROLES[17], - AriaWidgetRolesEnum::Spinbutton => ARIA_WIDGET_ROLES[18], - AriaWidgetRolesEnum::Status => ARIA_WIDGET_ROLES[19], - AriaWidgetRolesEnum::Switch => ARIA_WIDGET_ROLES[20], - AriaWidgetRolesEnum::Tab => ARIA_WIDGET_ROLES[21], - AriaWidgetRolesEnum::Tabpanel => ARIA_WIDGET_ROLES[22], - AriaWidgetRolesEnum::Textbox => ARIA_WIDGET_ROLES[23], - AriaWidgetRolesEnum::Timer => ARIA_WIDGET_ROLES[24], - AriaWidgetRolesEnum::Tooltip => ARIA_WIDGET_ROLES[25], - AriaWidgetRolesEnum::Treeitem => ARIA_WIDGET_ROLES[26], + AriaWidgetRolesEnum::Alert => "alert", + AriaWidgetRolesEnum::Alertdialog => "alertdialog", + AriaWidgetRolesEnum::Button => "button", + AriaWidgetRolesEnum::Checkbox => "checkbox", + AriaWidgetRolesEnum::Dialog => "dialog", + AriaWidgetRolesEnum::Gridcell => "gridcell", + AriaWidgetRolesEnum::Link => "link", + AriaWidgetRolesEnum::Log => "log", + AriaWidgetRolesEnum::Marquee => "marquee", + AriaWidgetRolesEnum::Menuitem => "menuitem", + AriaWidgetRolesEnum::Menuitemcheckbox => "menuitemcheckbox", + AriaWidgetRolesEnum::Menuitemradio => "menuitemradio", + AriaWidgetRolesEnum::Option => "option", + AriaWidgetRolesEnum::Progressbar => "progressbar", + AriaWidgetRolesEnum::Radio => "radio", + AriaWidgetRolesEnum::Scrollbar => "scrollbar", + AriaWidgetRolesEnum::Searchbox => "searchbox", + AriaWidgetRolesEnum::Slider => "slider", + AriaWidgetRolesEnum::Spinbutton => "spinbutton", + AriaWidgetRolesEnum::Status => "status", + AriaWidgetRolesEnum::Switch => "switch", + AriaWidgetRolesEnum::Tab => "tab", + AriaWidgetRolesEnum::Tabpanel => "tabpanel", + AriaWidgetRolesEnum::Textbox => "textbox", + AriaWidgetRolesEnum::Timer => "timer", + AriaWidgetRolesEnum::Tooltip => "tooltip", + AriaWidgetRolesEnum::Treeitem => "treeitem", } } } @@ -434,58 +424,56 @@ pub enum AriaAbstractRolesEnum { impl From for &str { fn from(property: AriaAbstractRolesEnum) -> Self { match property { - AriaAbstractRolesEnum::Command => ARIA_ABSTRACT_ROLES[0], - AriaAbstractRolesEnum::Composite => ARIA_ABSTRACT_ROLES[1], - AriaAbstractRolesEnum::Input => ARIA_ABSTRACT_ROLES[2], - AriaAbstractRolesEnum::Landmark => ARIA_ABSTRACT_ROLES[3], - AriaAbstractRolesEnum::Range => ARIA_ABSTRACT_ROLES[4], - AriaAbstractRolesEnum::Roletype => ARIA_ABSTRACT_ROLES[5], - AriaAbstractRolesEnum::Section => ARIA_ABSTRACT_ROLES[6], - AriaAbstractRolesEnum::Sectionhead => ARIA_ABSTRACT_ROLES[7], - AriaAbstractRolesEnum::Select => ARIA_ABSTRACT_ROLES[8], - AriaAbstractRolesEnum::Structure => ARIA_ABSTRACT_ROLES[9], - AriaAbstractRolesEnum::Widget => ARIA_ABSTRACT_ROLES[10], - AriaAbstractRolesEnum::Window => ARIA_ABSTRACT_ROLES[11], + AriaAbstractRolesEnum::Command => "command", + AriaAbstractRolesEnum::Composite => "composite", + AriaAbstractRolesEnum::Input => "input", + AriaAbstractRolesEnum::Landmark => "landmark", + AriaAbstractRolesEnum::Range => "range", + AriaAbstractRolesEnum::Roletype => "roletype", + AriaAbstractRolesEnum::Section => "section", + AriaAbstractRolesEnum::Sectionhead => "sectionhead", + AriaAbstractRolesEnum::Select => "select", + AriaAbstractRolesEnum::Structure => "structure", + AriaAbstractRolesEnum::Widget => "widget", + AriaAbstractRolesEnum::Window => "window", } } } -impl From<&str> for AriaAbstractRolesEnum { - fn from(s: &str) -> Self { - let index = ARIA_ABSTRACT_ROLES - .binary_search(&s) - .unwrap_or_else(|_| panic!("aria property not implemented {s:?}")); - match index { - 0 => AriaAbstractRolesEnum::Command, - 1 => AriaAbstractRolesEnum::Composite, - 2 => AriaAbstractRolesEnum::Input, - 3 => AriaAbstractRolesEnum::Landmark, - 4 => AriaAbstractRolesEnum::Range, - 5 => AriaAbstractRolesEnum::Roletype, - 6 => AriaAbstractRolesEnum::Section, - 7 => AriaAbstractRolesEnum::Sectionhead, - 8 => AriaAbstractRolesEnum::Select, - 9 => AriaAbstractRolesEnum::Structure, - 10 => AriaAbstractRolesEnum::Widget, - 11 => AriaAbstractRolesEnum::Window, - _ => panic!("aria property not implemented"), +impl FromStr for AriaAbstractRolesEnum { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "command" => Ok(AriaAbstractRolesEnum::Command), + "composite" => Ok(AriaAbstractRolesEnum::Composite), + "input" => Ok(AriaAbstractRolesEnum::Input), + "landmark" => Ok(AriaAbstractRolesEnum::Landmark), + "range" => Ok(AriaAbstractRolesEnum::Range), + "roletype" => Ok(AriaAbstractRolesEnum::Roletype), + "section" => Ok(AriaAbstractRolesEnum::Section), + "sectionhead" => Ok(AriaAbstractRolesEnum::Sectionhead), + "select" => Ok(AriaAbstractRolesEnum::Select), + "structure" => Ok(AriaAbstractRolesEnum::Structure), + "widget" => Ok(AriaAbstractRolesEnum::Widget), + "window" => Ok(AriaAbstractRolesEnum::Window), + _ => Err("aria property not implemented".to_string()), } } } impl AriaAbstractRolesEnum { pub fn as_str(&self) -> &str { match self { - AriaAbstractRolesEnum::Command => ARIA_ABSTRACT_ROLES[0], - AriaAbstractRolesEnum::Composite => ARIA_ABSTRACT_ROLES[1], - AriaAbstractRolesEnum::Input => ARIA_ABSTRACT_ROLES[2], - AriaAbstractRolesEnum::Landmark => ARIA_ABSTRACT_ROLES[3], - AriaAbstractRolesEnum::Range => ARIA_ABSTRACT_ROLES[4], - AriaAbstractRolesEnum::Roletype => ARIA_ABSTRACT_ROLES[5], - AriaAbstractRolesEnum::Section => ARIA_ABSTRACT_ROLES[6], - AriaAbstractRolesEnum::Sectionhead => ARIA_ABSTRACT_ROLES[7], - AriaAbstractRolesEnum::Select => ARIA_ABSTRACT_ROLES[8], - AriaAbstractRolesEnum::Structure => ARIA_ABSTRACT_ROLES[9], - AriaAbstractRolesEnum::Widget => ARIA_ABSTRACT_ROLES[10], - AriaAbstractRolesEnum::Window => ARIA_ABSTRACT_ROLES[11], + AriaAbstractRolesEnum::Command => "command", + AriaAbstractRolesEnum::Composite => "composite", + AriaAbstractRolesEnum::Input => "input", + AriaAbstractRolesEnum::Landmark => "landmark", + AriaAbstractRolesEnum::Range => "range", + AriaAbstractRolesEnum::Roletype => "roletype", + AriaAbstractRolesEnum::Section => "section", + AriaAbstractRolesEnum::Sectionhead => "sectionhead", + AriaAbstractRolesEnum::Select => "select", + AriaAbstractRolesEnum::Structure => "structure", + AriaAbstractRolesEnum::Widget => "widget", + AriaAbstractRolesEnum::Window => "window", } } } @@ -520,97 +508,95 @@ pub enum AriaDocumentStructureRolesEnum { impl From for &str { fn from(property: AriaDocumentStructureRolesEnum) -> Self { match property { - AriaDocumentStructureRolesEnum::Article => ARIA_DOCUMENT_STRUCTURE_ROLES[0], - AriaDocumentStructureRolesEnum::Cell => ARIA_DOCUMENT_STRUCTURE_ROLES[1], - AriaDocumentStructureRolesEnum::Columnheader => ARIA_DOCUMENT_STRUCTURE_ROLES[2], - AriaDocumentStructureRolesEnum::Definition => ARIA_DOCUMENT_STRUCTURE_ROLES[3], - AriaDocumentStructureRolesEnum::Directory => ARIA_DOCUMENT_STRUCTURE_ROLES[4], - AriaDocumentStructureRolesEnum::Document => ARIA_DOCUMENT_STRUCTURE_ROLES[5], - AriaDocumentStructureRolesEnum::Feed => ARIA_DOCUMENT_STRUCTURE_ROLES[6], - AriaDocumentStructureRolesEnum::Figure => ARIA_DOCUMENT_STRUCTURE_ROLES[7], - AriaDocumentStructureRolesEnum::Group => ARIA_DOCUMENT_STRUCTURE_ROLES[8], - AriaDocumentStructureRolesEnum::Heading => ARIA_DOCUMENT_STRUCTURE_ROLES[9], - AriaDocumentStructureRolesEnum::Img => ARIA_DOCUMENT_STRUCTURE_ROLES[10], - AriaDocumentStructureRolesEnum::List => ARIA_DOCUMENT_STRUCTURE_ROLES[11], - AriaDocumentStructureRolesEnum::Listitem => ARIA_DOCUMENT_STRUCTURE_ROLES[12], - AriaDocumentStructureRolesEnum::Math => ARIA_DOCUMENT_STRUCTURE_ROLES[13], - AriaDocumentStructureRolesEnum::None => ARIA_DOCUMENT_STRUCTURE_ROLES[14], - AriaDocumentStructureRolesEnum::Note => ARIA_DOCUMENT_STRUCTURE_ROLES[15], - AriaDocumentStructureRolesEnum::Presentation => ARIA_DOCUMENT_STRUCTURE_ROLES[16], - AriaDocumentStructureRolesEnum::Region => ARIA_DOCUMENT_STRUCTURE_ROLES[17], - AriaDocumentStructureRolesEnum::Row => ARIA_DOCUMENT_STRUCTURE_ROLES[18], - AriaDocumentStructureRolesEnum::Rowgroup => ARIA_DOCUMENT_STRUCTURE_ROLES[19], - AriaDocumentStructureRolesEnum::Rowheader => ARIA_DOCUMENT_STRUCTURE_ROLES[20], - AriaDocumentStructureRolesEnum::Separator => ARIA_DOCUMENT_STRUCTURE_ROLES[21], - AriaDocumentStructureRolesEnum::Table => ARIA_DOCUMENT_STRUCTURE_ROLES[22], - AriaDocumentStructureRolesEnum::Term => ARIA_DOCUMENT_STRUCTURE_ROLES[23], - AriaDocumentStructureRolesEnum::Toolbar => ARIA_DOCUMENT_STRUCTURE_ROLES[24], + AriaDocumentStructureRolesEnum::Article => "article", + AriaDocumentStructureRolesEnum::Cell => "cell", + AriaDocumentStructureRolesEnum::Columnheader => "columnheader", + AriaDocumentStructureRolesEnum::Definition => "definition", + AriaDocumentStructureRolesEnum::Directory => "directory", + AriaDocumentStructureRolesEnum::Document => "document", + AriaDocumentStructureRolesEnum::Feed => "feed", + AriaDocumentStructureRolesEnum::Figure => "figure", + AriaDocumentStructureRolesEnum::Group => "group", + AriaDocumentStructureRolesEnum::Heading => "heading", + AriaDocumentStructureRolesEnum::Img => "img", + AriaDocumentStructureRolesEnum::List => "list", + AriaDocumentStructureRolesEnum::Listitem => "listitem", + AriaDocumentStructureRolesEnum::Math => "math", + AriaDocumentStructureRolesEnum::None => "none", + AriaDocumentStructureRolesEnum::Note => "note", + AriaDocumentStructureRolesEnum::Presentation => "presentation", + AriaDocumentStructureRolesEnum::Region => "region", + AriaDocumentStructureRolesEnum::Row => "row", + AriaDocumentStructureRolesEnum::Rowgroup => "rowgroup", + AriaDocumentStructureRolesEnum::Rowheader => "rowheader", + AriaDocumentStructureRolesEnum::Separator => "separator", + AriaDocumentStructureRolesEnum::Table => "table", + AriaDocumentStructureRolesEnum::Term => "term", + AriaDocumentStructureRolesEnum::Toolbar => "toolbar", } } } -impl From<&str> for AriaDocumentStructureRolesEnum { - fn from(s: &str) -> Self { - let index = ARIA_DOCUMENT_STRUCTURE_ROLES - .binary_search(&s) - .unwrap_or_else(|_| panic!("aria property not implemented {s:?}")); - match index { - 0 => AriaDocumentStructureRolesEnum::Article, - 1 => AriaDocumentStructureRolesEnum::Cell, - 2 => AriaDocumentStructureRolesEnum::Columnheader, - 3 => AriaDocumentStructureRolesEnum::Definition, - 4 => AriaDocumentStructureRolesEnum::Directory, - 5 => AriaDocumentStructureRolesEnum::Document, - 6 => AriaDocumentStructureRolesEnum::Feed, - 7 => AriaDocumentStructureRolesEnum::Figure, - 8 => AriaDocumentStructureRolesEnum::Group, - 9 => AriaDocumentStructureRolesEnum::Heading, - 10 => AriaDocumentStructureRolesEnum::Img, - 11 => AriaDocumentStructureRolesEnum::List, - 12 => AriaDocumentStructureRolesEnum::Listitem, - 13 => AriaDocumentStructureRolesEnum::Math, - 14 => AriaDocumentStructureRolesEnum::None, - 15 => AriaDocumentStructureRolesEnum::Note, - 16 => AriaDocumentStructureRolesEnum::Presentation, - 17 => AriaDocumentStructureRolesEnum::Region, - 18 => AriaDocumentStructureRolesEnum::Row, - 19 => AriaDocumentStructureRolesEnum::Rowgroup, - 20 => AriaDocumentStructureRolesEnum::Rowheader, - 21 => AriaDocumentStructureRolesEnum::Separator, - 22 => AriaDocumentStructureRolesEnum::Table, - 23 => AriaDocumentStructureRolesEnum::Term, - 24 => AriaDocumentStructureRolesEnum::Toolbar, - _ => panic!("aria property not implemented"), +impl FromStr for AriaDocumentStructureRolesEnum { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "article" => Ok(AriaDocumentStructureRolesEnum::Article), + "cell" => Ok(AriaDocumentStructureRolesEnum::Cell), + "columnheader" => Ok(AriaDocumentStructureRolesEnum::Columnheader), + "definition" => Ok(AriaDocumentStructureRolesEnum::Definition), + "directory" => Ok(AriaDocumentStructureRolesEnum::Directory), + "document" => Ok(AriaDocumentStructureRolesEnum::Document), + "feed" => Ok(AriaDocumentStructureRolesEnum::Feed), + "figure" => Ok(AriaDocumentStructureRolesEnum::Figure), + "group" => Ok(AriaDocumentStructureRolesEnum::Group), + "heading" => Ok(AriaDocumentStructureRolesEnum::Heading), + "img" => Ok(AriaDocumentStructureRolesEnum::Img), + "list" => Ok(AriaDocumentStructureRolesEnum::List), + "listitem" => Ok(AriaDocumentStructureRolesEnum::Listitem), + "math" => Ok(AriaDocumentStructureRolesEnum::Math), + "none" => Ok(AriaDocumentStructureRolesEnum::None), + "note" => Ok(AriaDocumentStructureRolesEnum::Note), + "presentation" => Ok(AriaDocumentStructureRolesEnum::Presentation), + "region" => Ok(AriaDocumentStructureRolesEnum::Region), + "row" => Ok(AriaDocumentStructureRolesEnum::Row), + "rowgroup" => Ok(AriaDocumentStructureRolesEnum::Rowgroup), + "rowheader" => Ok(AriaDocumentStructureRolesEnum::Rowheader), + "separator" => Ok(AriaDocumentStructureRolesEnum::Separator), + "table" => Ok(AriaDocumentStructureRolesEnum::Table), + "term" => Ok(AriaDocumentStructureRolesEnum::Term), + "toolbar" => Ok(AriaDocumentStructureRolesEnum::Toolbar), + _ => Err("aria property not implemented".to_string()), } } } impl AriaDocumentStructureRolesEnum { pub fn as_str(&self) -> &str { match self { - AriaDocumentStructureRolesEnum::Article => ARIA_DOCUMENT_STRUCTURE_ROLES[0], - AriaDocumentStructureRolesEnum::Cell => ARIA_DOCUMENT_STRUCTURE_ROLES[1], - AriaDocumentStructureRolesEnum::Columnheader => ARIA_DOCUMENT_STRUCTURE_ROLES[2], - AriaDocumentStructureRolesEnum::Definition => ARIA_DOCUMENT_STRUCTURE_ROLES[3], - AriaDocumentStructureRolesEnum::Directory => ARIA_DOCUMENT_STRUCTURE_ROLES[4], - AriaDocumentStructureRolesEnum::Document => ARIA_DOCUMENT_STRUCTURE_ROLES[5], - AriaDocumentStructureRolesEnum::Feed => ARIA_DOCUMENT_STRUCTURE_ROLES[6], - AriaDocumentStructureRolesEnum::Figure => ARIA_DOCUMENT_STRUCTURE_ROLES[7], - AriaDocumentStructureRolesEnum::Group => ARIA_DOCUMENT_STRUCTURE_ROLES[8], - AriaDocumentStructureRolesEnum::Heading => ARIA_DOCUMENT_STRUCTURE_ROLES[9], - AriaDocumentStructureRolesEnum::Img => ARIA_DOCUMENT_STRUCTURE_ROLES[10], - AriaDocumentStructureRolesEnum::List => ARIA_DOCUMENT_STRUCTURE_ROLES[11], - AriaDocumentStructureRolesEnum::Listitem => ARIA_DOCUMENT_STRUCTURE_ROLES[12], - AriaDocumentStructureRolesEnum::Math => ARIA_DOCUMENT_STRUCTURE_ROLES[13], - AriaDocumentStructureRolesEnum::None => ARIA_DOCUMENT_STRUCTURE_ROLES[14], - AriaDocumentStructureRolesEnum::Note => ARIA_DOCUMENT_STRUCTURE_ROLES[15], - AriaDocumentStructureRolesEnum::Presentation => ARIA_DOCUMENT_STRUCTURE_ROLES[16], - AriaDocumentStructureRolesEnum::Region => ARIA_DOCUMENT_STRUCTURE_ROLES[17], - AriaDocumentStructureRolesEnum::Row => ARIA_DOCUMENT_STRUCTURE_ROLES[18], - AriaDocumentStructureRolesEnum::Rowgroup => ARIA_DOCUMENT_STRUCTURE_ROLES[19], - AriaDocumentStructureRolesEnum::Rowheader => ARIA_DOCUMENT_STRUCTURE_ROLES[20], - AriaDocumentStructureRolesEnum::Separator => ARIA_DOCUMENT_STRUCTURE_ROLES[21], - AriaDocumentStructureRolesEnum::Table => ARIA_DOCUMENT_STRUCTURE_ROLES[22], - AriaDocumentStructureRolesEnum::Term => ARIA_DOCUMENT_STRUCTURE_ROLES[23], - AriaDocumentStructureRolesEnum::Toolbar => ARIA_DOCUMENT_STRUCTURE_ROLES[24], + AriaDocumentStructureRolesEnum::Article => "article", + AriaDocumentStructureRolesEnum::Cell => "cell", + AriaDocumentStructureRolesEnum::Columnheader => "columnheader", + AriaDocumentStructureRolesEnum::Definition => "definition", + AriaDocumentStructureRolesEnum::Directory => "directory", + AriaDocumentStructureRolesEnum::Document => "document", + AriaDocumentStructureRolesEnum::Feed => "feed", + AriaDocumentStructureRolesEnum::Figure => "figure", + AriaDocumentStructureRolesEnum::Group => "group", + AriaDocumentStructureRolesEnum::Heading => "heading", + AriaDocumentStructureRolesEnum::Img => "img", + AriaDocumentStructureRolesEnum::List => "list", + AriaDocumentStructureRolesEnum::Listitem => "listitem", + AriaDocumentStructureRolesEnum::Math => "math", + AriaDocumentStructureRolesEnum::None => "none", + AriaDocumentStructureRolesEnum::Note => "note", + AriaDocumentStructureRolesEnum::Presentation => "presentation", + AriaDocumentStructureRolesEnum::Region => "region", + AriaDocumentStructureRolesEnum::Row => "row", + AriaDocumentStructureRolesEnum::Rowgroup => "rowgroup", + AriaDocumentStructureRolesEnum::Rowheader => "rowheader", + AriaDocumentStructureRolesEnum::Separator => "separator", + AriaDocumentStructureRolesEnum::Table => "table", + AriaDocumentStructureRolesEnum::Term => "term", + AriaDocumentStructureRolesEnum::Toolbar => "toolbar", } } } diff --git a/crates/rome_aria/src/lib.rs b/crates/rome_aria/src/lib.rs index fd5e9fc65312..ee221a72c365 100644 --- a/crates/rome_aria/src/lib.rs +++ b/crates/rome_aria/src/lib.rs @@ -1,281 +1,14 @@ -extern crate core; - -use crate::constants::{ - ARIA_ABSTRACT_ROLES, ARIA_DOCUMENT_STRUCTURE_ROLES, ARIA_PROPERTIES, ARIA_PROPERTY_TYPE, - ARIA_WIDGET_ROLES, -}; -use crate::generated::{ - AriaAbstractRolesEnum, AriaDocumentStructureRolesEnum, AriaPropertiesEnum, - AriaPropertyTypeEnum, AriaWidgetRolesEnum, -}; -use rustc_hash::FxHashMap; +use crate::constants::{ARIA_PROPERTIES, ARIA_PROPERTY_TYPE}; #[rustfmt::skip] mod generated; pub mod constants; +pub mod properties; +pub mod roles; -#[derive(Debug)] -pub enum AriaRole { - Widget(AriaWidgetRolesEnum), - Document(AriaDocumentStructureRolesEnum), - Abstract(AriaAbstractRolesEnum), -} - -impl From for &str { - fn from(s: AriaRole) -> Self { - match s { - AriaRole::Widget(widget) => widget.into(), - AriaRole::Document(document) => document.into(), - AriaRole::Abstract(abs) => abs.into(), - } - } -} - -impl From<&str> for AriaRole { - fn from(s: &str) -> Self { - if ARIA_WIDGET_ROLES.binary_search(&s).is_ok() { - Self::Widget(AriaWidgetRolesEnum::from(s)) - } else if ARIA_ABSTRACT_ROLES.binary_search(&s).is_ok() { - Self::Abstract(AriaAbstractRolesEnum::from(s)) - } else if ARIA_DOCUMENT_STRUCTURE_ROLES.binary_search(&s).is_ok() { - Self::Document(AriaDocumentStructureRolesEnum::from(s)) - } else { - unreachable!("Should not come here") - } - } -} - -/// Table reference example: https://www.w3.org/TR/wai-aria-1.1/#checkbox -#[derive(Debug, Default)] -pub struct AriaRoleDefinition { - properties: Vec, - super_class_role: Vec, -} - -#[derive(Debug)] -pub struct AriaRoleProperty { - pub property: AriaPropertiesEnum, - pub required: bool, -} - -impl AriaRoleDefinition { - fn with_prop(mut self, property_name: &str, required: bool) -> Self { - self.properties.push(AriaRoleProperty { - property: AriaPropertiesEnum::from(property_name), - required, - }); - - self - } - - fn with_roles(mut self, roles: &[&str]) -> Self { - for role_name in roles { - self.super_class_role.push(AriaRole::from(*role_name)) - } - - self - } - - /// Given a [aria property](ARIA_PROPERTIES) as input, it checks if it's required - /// for the current role. - /// - /// If the property doesn't exist for the current role, [false] is returned. - /// - /// ## Examples - /// - /// ``` - /// - /// use rome_aria::AriaRoles; - /// let roles = AriaRoles::default(); - /// - /// let checkbox_role = roles.get_role("checkbox").unwrap(); - /// - /// assert_eq!(checkbox_role.is_property_required("aria-readonly"), false); - /// assert_eq!(checkbox_role.is_property_required("aria-checked"), true); - /// - /// ``` - pub fn is_property_required(&self, property_to_check: &str) -> bool { - if is_aria_property_valid(property_to_check) { - let property_to_check = AriaPropertiesEnum::from(property_to_check); - for role_property in &self.properties { - if role_property.property == property_to_check { - return role_property.required; - } - } - } - false - } - - /// It returns an iterator over the properties of the current role - /// - /// ## Examples - /// - /// ``` - /// use rome_aria::AriaRoles; - /// let roles = AriaRoles::default(); - /// - /// let checkbox_role = roles.get_role("checkbox").unwrap(); - /// - /// let properties = checkbox_role.properties(); - /// assert_eq!(properties.len(), 2); - /// ``` - pub fn properties(&self) -> std::slice::Iter { - self.properties.iter() - } -} - -/// A collection of ARIA roles with their metadata, necessary to perform various operations. -#[derive(Debug)] -pub struct AriaRoles(FxHashMap<&'static str, AriaRoleDefinition>); - -impl Default for AriaRoles { - fn default() -> Self { - Self::new() - } -} - -impl AriaRoles { - /// It instantiate the ARIA roles - pub fn new() -> Self { - let mut hash_map = FxHashMap::default(); - // https://www.w3.org/TR/wai-aria-1.1/#button - hash_map.insert( - "button", - AriaRoleDefinition::default() - .with_prop("aria-expanded", false) - .with_prop("aria-pressed", false) - .with_roles(&["roletype", "widget", "command"]), - ); - // https://www.w3.org/TR/wai-aria-1.1/#checkbox - hash_map.insert( - "checkbox", - AriaRoleDefinition::default() - .with_prop("aria-checked", true) - .with_prop("aria-readonly", false) - .with_roles(&["switch", "menuitemcheckbox", "widget"]), - ); - - Self(hash_map) - } - - /// It returns the metadata of a role, if it exits. - /// - /// ## Examples - /// - /// ``` - /// use rome_aria::AriaRoles; - /// let roles = AriaRoles::default(); - /// - /// - /// let button_role = roles.get_role("button"); - /// let made_up_role = roles.get_role("made-up"); - /// - /// assert!(button_role.is_some()); - /// assert!(made_up_role.is_none()); - /// ``` - pub fn get_role(&self, role: &str) -> Option<&AriaRoleDefinition> { - self.0.get(role) - } -} - -/// A collection of ARIA properties with their metadata, necessary to perform various operations. -#[derive(Debug)] -pub struct AriaProperties(FxHashMap<&'static str, AriaPropertyDefinition>); - -impl Default for AriaProperties { - fn default() -> Self { - Self::new() - } -} - -impl AriaProperties { - pub fn new() -> Self { - let mut list = FxHashMap::default(); - - list.insert( - "aria-current", - AriaPropertyDefinition::new("token") - .with_values(&["page", "step", "location", "date", "time", "true", "false"]), - ); - - Self(list) - } - - pub fn get_property(&self, property_name: &str) -> Option<&AriaPropertyDefinition> { - self.0.get(property_name) - } -} - -#[derive(Debug)] -pub struct AriaPropertyDefinition { - property_type: AriaPropertyTypeEnum, - values: Vec, -} - -impl AriaPropertyDefinition { - fn new(property_type: &str) -> Self { - Self { - property_type: AriaPropertyTypeEnum::from(property_type), - values: vec![], - } - } - - fn with_values(mut self, values: &[&str]) -> Self { - self.values = values.iter().map(|value| value.to_string()).collect(); - self - } - - /// It checks if a value is complaint for the current ARIA property. - /// - /// [Source](https://www.w3.org/TR/wai-aria-1.1/#propcharacteristic_value) - /// - /// ## Examples - /// - /// ``` - /// use rome_aria::AriaProperties; - /// - /// let aria_properties = AriaProperties::default(); - /// - /// let aria_current = aria_properties.get_property("aria-current").unwrap(); - /// - /// assert!(aria_current.contains_correct_value("true")); - /// assert!(aria_current.contains_correct_value("false")); - /// assert!(aria_current.contains_correct_value("step")); - /// assert!(!aria_current.contains_correct_value("something_not_allowed")); - /// ``` - pub fn contains_correct_value(&self, input_value: &str) -> bool { - match self.property_type { - AriaPropertyTypeEnum::String | AriaPropertyTypeEnum::Id => { - input_value.parse::().is_err() - } - AriaPropertyTypeEnum::Idlist => input_value - .split(' ') - .any(|piece| piece.parse::().is_err()), - // A numerical value without a fractional component. - AriaPropertyTypeEnum::Integer => input_value.parse::().is_ok(), - AriaPropertyTypeEnum::Number => input_value.parse::().is_ok(), - AriaPropertyTypeEnum::Boolean => { - matches!(input_value, "false" | "true") - } - AriaPropertyTypeEnum::Token => self - .values - .iter() - .any(|allowed_token| allowed_token == input_value), - AriaPropertyTypeEnum::Tokenlist => input_value.split(' ').all(|input_token| { - self.values - .iter() - .any(|allowed_token| allowed_token == input_token) - }), - AriaPropertyTypeEnum::Tristate => { - matches!(input_value, "false" | "true" | "mixed") - } - } - } - pub fn get_allowed_values(&self) -> &Vec { - &self.values - } -} +pub use properties::AriaProperties; +pub use roles::AriaRoles; /// It checks if an ARIA property is valid /// @@ -307,7 +40,7 @@ pub fn is_aria_property_type_valid(property_type: &str) -> bool { #[cfg(test)] mod test { - use crate::AriaRoles; + use crate::roles::AriaRoles; #[test] fn property_is_required() { diff --git a/crates/rome_aria/src/properties.rs b/crates/rome_aria/src/properties.rs new file mode 100644 index 000000000000..3e7b6778704b --- /dev/null +++ b/crates/rome_aria/src/properties.rs @@ -0,0 +1,107 @@ +use crate::generated::AriaPropertyTypeEnum; +use crate::is_aria_property_type_valid; +use rustc_hash::FxHashMap; +use std::fmt::Debug; +use std::slice::Iter; +use std::str::FromStr; + +/// A collection of ARIA properties with their metadata, necessary to perform various operations. +#[derive(Debug)] +pub struct AriaProperties(FxHashMap<&'static str, Box>); + +impl Default for AriaProperties { + fn default() -> Self { + let list = FxHashMap::default(); + Self(list).add("aria-current", AriaCurrent) + } +} + +impl AriaProperties { + fn add( + mut self, + aria_property_name: &'static str, + definition: impl AriaPropertyDefinition + 'static, + ) -> Self { + self.0.insert(aria_property_name, Box::new(definition)); + self + } + + pub fn get_property(&self, property_name: &str) -> Option<&Box> { + self.0.get(property_name) + } +} + +pub trait AriaPropertyDefinition: Debug { + /// Returns the allowed values by this property + fn values<'a>(&self) -> Iter<'a, &str>; + + /// Returns the property type + fn property_type(&self) -> AriaPropertyTypeEnum; + + /// It checks if a value is complaint for the current ARIA property. + /// + /// [Source](https://www.w3.org/TR/wai-aria-1.1/#propcharacteristic_value) + /// + /// ## Examples + /// + /// ``` + /// use rome_aria::AriaProperties; + /// + /// let aria_properties = AriaProperties::default(); + /// + /// let aria_current = aria_properties.get_property("aria-current").unwrap(); + /// + /// assert!(aria_current.contains_correct_value("true")); + /// assert!(aria_current.contains_correct_value("false")); + /// assert!(aria_current.contains_correct_value("step")); + /// assert!(!aria_current.contains_correct_value("something_not_allowed")); + /// ``` + fn contains_correct_value(&self, input_value: &str) -> bool { + if !is_aria_property_type_valid(input_value) { + return false; + } + match self.property_type() { + AriaPropertyTypeEnum::String | AriaPropertyTypeEnum::Id => { + input_value.parse::().is_err() + } + AriaPropertyTypeEnum::Idlist => input_value + .split(' ') + .any(|piece| piece.parse::().is_err()), + // A numerical value without a fractional component. + AriaPropertyTypeEnum::Integer => input_value.parse::().is_ok(), + AriaPropertyTypeEnum::Number => input_value.parse::().is_ok(), + AriaPropertyTypeEnum::Boolean => { + matches!(input_value, "false" | "true") + } + AriaPropertyTypeEnum::Token => self + .values() + .any(|allowed_token| *allowed_token == input_value), + AriaPropertyTypeEnum::Tokenlist => input_value.split(' ').all(|input_token| { + self.values() + .any(|allowed_token| *allowed_token == input_token) + }), + AriaPropertyTypeEnum::Tristate => { + matches!(input_value, "false" | "true" | "mixed") + } + } + } +} + +#[derive(Debug)] +struct AriaCurrent; + +impl AriaCurrent { + const PROPERTY_TYPE: &'static str = "aria-current"; + const VALUES: [&'static str; 7] = ["page", "step", "location", "date", "time", "true", "false"]; +} + +impl AriaPropertyDefinition for AriaCurrent { + fn values<'a>(&self) -> Iter<'a, &str> { + AriaCurrent::VALUES.iter() + } + + fn property_type(&self) -> AriaPropertyTypeEnum { + // SAFETY: PROPERTY_TYPE is internal and should not contain extraneous properties + AriaPropertyTypeEnum::from_str(AriaCurrent::PROPERTY_TYPE).unwrap() + } +} diff --git a/crates/rome_aria/src/roles.rs b/crates/rome_aria/src/roles.rs new file mode 100644 index 000000000000..8bed72197d49 --- /dev/null +++ b/crates/rome_aria/src/roles.rs @@ -0,0 +1,192 @@ +use crate::generated::{ + AriaAbstractRolesEnum, AriaDocumentStructureRolesEnum, AriaPropertiesEnum, AriaWidgetRolesEnum, +}; +use crate::is_aria_property_valid; +use rustc_hash::FxHashMap; +use std::fmt::Debug; +use std::slice::Iter; +use std::str::FromStr; + +#[derive(Debug)] +pub enum AriaRole { + Widget(AriaWidgetRolesEnum), + Document(AriaDocumentStructureRolesEnum), + Abstract(AriaAbstractRolesEnum), +} + +impl From for &str { + fn from(s: AriaRole) -> Self { + match s { + AriaRole::Widget(widget) => widget.into(), + AriaRole::Document(document) => document.into(), + AriaRole::Abstract(abs) => abs.into(), + } + } +} + +impl FromStr for AriaRole { + type Err = String; + + fn from_str(s: &str) -> Result { + AriaWidgetRolesEnum::from_str(s) + .map(Self::Widget) + .or_else(|_| { + AriaAbstractRolesEnum::from_str(s) + .map(Self::Abstract) + .or_else(|_| AriaDocumentStructureRolesEnum::from_str(s).map(Self::Document)) + }) + } +} + +pub trait AriaRoleDefinition: Debug { + /// It returns an iterator over the properties of the current role + /// + /// ## Examples + /// + /// ``` + /// use rome_aria::AriaRoles; + /// let roles = AriaRoles::default(); + /// + /// let checkbox_role = roles.get_role("checkbox").unwrap(); + /// + /// let properties = checkbox_role.properties(); + /// assert_eq!(properties.len(), 2); + /// ``` + fn properties<'a>(&self) -> Iter<'a, (&str, bool)>; + + /// It returns an iterator over the properties of the current role + /// + /// ## Examples + /// + /// ``` + /// use rome_aria::AriaRoles; + /// let roles = AriaRoles::default(); + /// + /// let checkbox_role = roles.get_role("checkbox").unwrap(); + /// + /// let properties = checkbox_role.properties(); + /// assert_eq!(properties.len(), 2); + /// ``` + fn roles<'a>(&self) -> Iter<'a, &str>; + + /// Given a [aria property](ARIA_PROPERTIES) as input, it checks if it's required + /// for the current role. + /// + /// If the property doesn't exist for the current role, [false] is returned. + /// + /// ## Examples + /// + /// ``` + /// + /// use rome_aria::AriaRoles; + /// let roles = AriaRoles::default(); + /// + /// let checkbox_role = roles.get_role("checkbox").unwrap(); + /// + /// assert_eq!(checkbox_role.is_property_required("aria-readonly"), false); + /// assert_eq!(checkbox_role.is_property_required("aria-checked"), true); + /// + /// ``` + fn is_property_required(&self, property_to_check: &str) -> bool { + if is_aria_property_valid(property_to_check) { + let property_to_check = AriaPropertiesEnum::from_str(property_to_check); + if let Ok(property_to_check) = property_to_check { + for (property, required) in self.properties() { + let property = AriaPropertiesEnum::from_str(property).unwrap(); + if property == property_to_check { + return *required; + } + } + } + } + false + } +} + +#[derive(Debug)] +pub struct AriaRoleProperty { + pub property: AriaPropertiesEnum, + pub required: bool, +} + +/// A collection of ARIA roles with their metadata, necessary to perform various operations. +#[derive(Debug)] +pub struct AriaRoles(FxHashMap<&'static str, Box>); + +impl Default for AriaRoles { + fn default() -> Self { + let hash_map = FxHashMap::default(); + Self(hash_map) + // https://www.w3.org/TR/wai-aria-1.1/#button + .add("button", ButtonRole) + // https://www.w3.org/TR/wai-aria-1.1/#checkbox + .add("checkbox", CheckboxRole) + } +} + +#[derive(Debug)] +struct ButtonRole; + +impl ButtonRole { + const PROPS: [(&'static str, bool); 2] = [("aria-expanded", false), ("aria-expanded", false)]; + const ROLES: [&'static str; 3] = ["roletype", "widget", "command"]; +} + +impl AriaRoleDefinition for ButtonRole { + fn properties<'a>(&self) -> Iter<'a, (&str, bool)> { + ButtonRole::PROPS.iter() + } + + fn roles<'a>(&self) -> Iter<'a, &str> { + ButtonRole::ROLES.iter() + } +} + +#[derive(Debug)] +struct CheckboxRole; + +impl CheckboxRole { + const PROPS: [(&'static str, bool); 2] = [("aria-checked", true), ("aria-readonly", false)]; + const ROLES: [&'static str; 3] = ["switch", "menuitemcheckbox", "widget"]; +} + +impl AriaRoleDefinition for CheckboxRole { + fn properties<'a>(&self) -> Iter<'a, (&str, bool)> { + CheckboxRole::PROPS.iter() + } + + fn roles<'a>(&self) -> Iter<'a, &str> { + CheckboxRole::ROLES.iter() + } +} + +impl AriaRoles { + /// It adds a new role + fn add( + mut self, + role_name: &'static str, + definition: impl AriaRoleDefinition + 'static, + ) -> Self { + self.0.insert(role_name, Box::new(definition)); + self + } + + /// It returns the metadata of a role, if it exits. + /// + /// ## Examples + /// + /// ``` + /// use rome_aria::AriaRoles; + /// let roles = AriaRoles::default(); + /// + /// + /// let button_role = roles.get_role("button"); + /// let made_up_role = roles.get_role("made-up"); + /// + /// assert!(button_role.is_some()); + /// assert!(made_up_role.is_none()); + /// ``` + pub fn get_role(&self, role: &str) -> Option<&Box> { + self.0.get(role) + } +} diff --git a/crates/rome_js_analyze/src/aria_analyzers/nursery/use_aria_prop_types.rs b/crates/rome_js_analyze/src/aria_analyzers/nursery/use_aria_prop_types.rs index a929590fe4f2..1aa9ad3f0b61 100644 --- a/crates/rome_js_analyze/src/aria_analyzers/nursery/use_aria_prop_types.rs +++ b/crates/rome_js_analyze/src/aria_analyzers/nursery/use_aria_prop_types.rs @@ -41,7 +41,10 @@ impl Rule for UseAriaPropTypes { if !aria_property.contains_correct_value(attribute_text.text()) { return Some(UseAriaProptypesState { attribute_value_range: attribute_value.range(), - allowed_values: aria_property.get_allowed_values().clone(), + allowed_values: aria_property + .values() + .map(|value| value.to_string()) + .collect::>(), attribute_name, }); } @@ -59,7 +62,7 @@ impl Rule for UseAriaPropTypes { markup! { "The value of the ARIA attribute "{attribute_name}" is not correct." }, - ).note_list( + ).footer_list( markup!{ "The supported values for the "{attribute_name}" attribute are:" }, diff --git a/crates/rome_js_analyze/src/aria_analyzers/nursery/use_aria_props_for_role.rs b/crates/rome_js_analyze/src/aria_analyzers/nursery/use_aria_props_for_role.rs index 6a0d1f4b918c..dfcb116b5cf8 100644 --- a/crates/rome_js_analyze/src/aria_analyzers/nursery/use_aria_props_for_role.rs +++ b/crates/rome_js_analyze/src/aria_analyzers/nursery/use_aria_props_for_role.rs @@ -54,7 +54,7 @@ impl UseAriaPropsForRoleState { }, ) .description(description) - .note_list(markup! { "Missing aria props" }, &self.missing_aria_props) + .footer_list(markup! { "Missing aria props" }, &self.missing_aria_props) }) } } @@ -89,9 +89,8 @@ impl Rule for UseAriaPropsForRole { let mut missing_aria_props = vec![]; if let Some(role) = role { let properties = role.properties(); - for role_property in properties { - if role_property.required { - let property_name = role_property.property.as_str(); + for (property_name, required) in properties { + if *required { let attribute = node.find_by_name(property_name); if attribute.is_none() { missing_aria_props.push(property_name.to_string()); diff --git a/crates/rome_js_analyze/src/aria_services.rs b/crates/rome_js_analyze/src/aria_services.rs index a12714813de1..095c24e4eeef 100644 --- a/crates/rome_js_analyze/src/aria_services.rs +++ b/crates/rome_js_analyze/src/aria_services.rs @@ -37,7 +37,7 @@ impl FromServices for AriaServices { impl Phase for AriaServices { fn phase() -> Phases { - Phases::Accessibility + Phases::Syntax } } diff --git a/crates/rome_js_analyze/src/lib.rs b/crates/rome_js_analyze/src/lib.rs index 6023de2fb790..2561c78f5ca6 100644 --- a/crates/rome_js_analyze/src/lib.rs +++ b/crates/rome_js_analyze/src/lib.rs @@ -100,8 +100,6 @@ where analyzer.add_visitor(Phases::Semantic, SemanticModelVisitor); analyzer.add_visitor(Phases::Semantic, SyntaxVisitor::default()); - analyzer.add_visitor(Phases::Accessibility, SyntaxVisitor::default()); - analyzer.run(AnalyzerContext { file_id, root: root.clone(), diff --git a/crates/rome_service/src/configuration/linter/rules.rs b/crates/rome_service/src/configuration/linter/rules.rs index 0766d4819a4a..0cdde4fa2da9 100644 --- a/crates/rome_service/src/configuration/linter/rules.rs +++ b/crates/rome_service/src/configuration/linter/rules.rs @@ -152,9 +152,7 @@ impl Rules { None } } - pub(crate) fn is_recommended(&self) -> bool { - !matches!(self.recommended, Some(false)) - } + pub(crate) fn is_recommended(&self) -> bool { !matches!(self.recommended, Some(false)) } #[doc = r" It returns a tuple of filters. The first element of the tuple are the enabled rules,"] #[doc = r" while the second element are the disabled rules."] #[doc = r""] @@ -353,9 +351,7 @@ impl A11y { RuleFilter::Rule("a11y", Self::CATEGORY_RULES[7]), RuleFilter::Rule("a11y", Self::CATEGORY_RULES[8]), ]; - pub(crate) fn is_recommended(&self) -> bool { - !matches!(self.recommended, Some(false)) - } + pub(crate) fn is_recommended(&self) -> bool { !matches!(self.recommended, Some(false)) } pub(crate) fn get_enabled_rules(&self) -> IndexSet { IndexSet::from_iter(self.rules.iter().filter_map(|(key, conf)| { if conf.is_enabled() { @@ -375,9 +371,7 @@ impl A11y { })) } #[doc = r" Checks if, given a rule name, matches one of the rules contained in this category"] - pub(crate) fn has_rule(rule_name: &str) -> bool { - Self::CATEGORY_RULES.contains(&rule_name) - } + pub(crate) fn has_rule(rule_name: &str) -> bool { Self::CATEGORY_RULES.contains(&rule_name) } #[doc = r" Checks if, given a rule name, it is marked as recommended"] pub(crate) fn is_recommended_rule(rule_name: &str) -> bool { Self::RECOMMENDED_RULES.contains(&rule_name) @@ -441,9 +435,7 @@ impl Complexity { RuleFilter::Rule("complexity", Self::CATEGORY_RULES[0]), RuleFilter::Rule("complexity", Self::CATEGORY_RULES[1]), ]; - pub(crate) fn is_recommended(&self) -> bool { - !matches!(self.recommended, Some(false)) - } + pub(crate) fn is_recommended(&self) -> bool { !matches!(self.recommended, Some(false)) } pub(crate) fn get_enabled_rules(&self) -> IndexSet { IndexSet::from_iter(self.rules.iter().filter_map(|(key, conf)| { if conf.is_enabled() { @@ -463,9 +455,7 @@ impl Complexity { })) } #[doc = r" Checks if, given a rule name, matches one of the rules contained in this category"] - pub(crate) fn has_rule(rule_name: &str) -> bool { - Self::CATEGORY_RULES.contains(&rule_name) - } + pub(crate) fn has_rule(rule_name: &str) -> bool { Self::CATEGORY_RULES.contains(&rule_name) } #[doc = r" Checks if, given a rule name, it is marked as recommended"] pub(crate) fn is_recommended_rule(rule_name: &str) -> bool { Self::RECOMMENDED_RULES.contains(&rule_name) @@ -670,9 +660,7 @@ impl Correctness { RuleFilter::Rule("correctness", Self::CATEGORY_RULES[29]), RuleFilter::Rule("correctness", Self::CATEGORY_RULES[30]), ]; - pub(crate) fn is_recommended(&self) -> bool { - !matches!(self.recommended, Some(false)) - } + pub(crate) fn is_recommended(&self) -> bool { !matches!(self.recommended, Some(false)) } pub(crate) fn get_enabled_rules(&self) -> IndexSet { IndexSet::from_iter(self.rules.iter().filter_map(|(key, conf)| { if conf.is_enabled() { @@ -692,9 +680,7 @@ impl Correctness { })) } #[doc = r" Checks if, given a rule name, matches one of the rules contained in this category"] - pub(crate) fn has_rule(rule_name: &str) -> bool { - Self::CATEGORY_RULES.contains(&rule_name) - } + pub(crate) fn has_rule(rule_name: &str) -> bool { Self::CATEGORY_RULES.contains(&rule_name) } #[doc = r" Checks if, given a rule name, it is marked as recommended"] pub(crate) fn is_recommended_rule(rule_name: &str) -> bool { Self::RECOMMENDED_RULES.contains(&rule_name) @@ -781,6 +767,10 @@ struct NurserySchema { no_var: Option, #[doc = "Disallow returning a value from a function with the return type 'void'"] no_void_type_return: Option, + #[doc = "Enforce that ARIA state and property values are valid."] + use_aria_prop_types: Option, + #[doc = "Enforce that elements with ARIA roles must have all required attributes for that role"] + use_aria_props_for_role: Option, #[doc = "Enforce camel case naming convention."] use_camel_case: Option, #[doc = "Require const declarations for variables that are never reassigned after declared."] @@ -798,7 +788,7 @@ struct NurserySchema { } impl Nursery { const CATEGORY_NAME: &'static str = "nursery"; - pub(crate) const CATEGORY_RULES: [&'static str; 26] = [ + pub(crate) const CATEGORY_RULES: [&'static str; 28] = [ "noAccessKey", "noBannedTypes", "noConditionalAssignment", @@ -818,6 +808,8 @@ impl Nursery { "noUnsafeFinally", "noVar", "noVoidTypeReturn", + "useAriaPropTypes", + "useAriaPropsForRole", "useCamelCase", "useConst", "useDefaultSwitchClauseLast", @@ -829,9 +821,7 @@ impl Nursery { const RECOMMENDED_RULES: [&'static str; 1] = ["noAccessKey"]; const RECOMMENDED_RULES_AS_FILTERS: [RuleFilter<'static>; 1] = [RuleFilter::Rule("nursery", Self::CATEGORY_RULES[0])]; - pub(crate) fn is_recommended(&self) -> bool { - !matches!(self.recommended, Some(false)) - } + pub(crate) fn is_recommended(&self) -> bool { !matches!(self.recommended, Some(false)) } pub(crate) fn get_enabled_rules(&self) -> IndexSet { IndexSet::from_iter(self.rules.iter().filter_map(|(key, conf)| { if conf.is_enabled() { @@ -851,9 +841,7 @@ impl Nursery { })) } #[doc = r" Checks if, given a rule name, matches one of the rules contained in this category"] - pub(crate) fn has_rule(rule_name: &str) -> bool { - Self::CATEGORY_RULES.contains(&rule_name) - } + pub(crate) fn has_rule(rule_name: &str) -> bool { Self::CATEGORY_RULES.contains(&rule_name) } #[doc = r" Checks if, given a rule name, it is marked as recommended"] pub(crate) fn is_recommended_rule(rule_name: &str) -> bool { Self::RECOMMENDED_RULES.contains(&rule_name) @@ -921,9 +909,7 @@ impl Security { RuleFilter::Rule("security", Self::CATEGORY_RULES[0]), RuleFilter::Rule("security", Self::CATEGORY_RULES[1]), ]; - pub(crate) fn is_recommended(&self) -> bool { - !matches!(self.recommended, Some(false)) - } + pub(crate) fn is_recommended(&self) -> bool { !matches!(self.recommended, Some(false)) } pub(crate) fn get_enabled_rules(&self) -> IndexSet { IndexSet::from_iter(self.rules.iter().filter_map(|(key, conf)| { if conf.is_enabled() { @@ -943,9 +929,7 @@ impl Security { })) } #[doc = r" Checks if, given a rule name, matches one of the rules contained in this category"] - pub(crate) fn has_rule(rule_name: &str) -> bool { - Self::CATEGORY_RULES.contains(&rule_name) - } + pub(crate) fn has_rule(rule_name: &str) -> bool { Self::CATEGORY_RULES.contains(&rule_name) } #[doc = r" Checks if, given a rule name, it is marked as recommended"] pub(crate) fn is_recommended_rule(rule_name: &str) -> bool { Self::RECOMMENDED_RULES.contains(&rule_name) @@ -1056,9 +1040,7 @@ impl Style { RuleFilter::Rule("style", Self::CATEGORY_RULES[9]), RuleFilter::Rule("style", Self::CATEGORY_RULES[10]), ]; - pub(crate) fn is_recommended(&self) -> bool { - !matches!(self.recommended, Some(false)) - } + pub(crate) fn is_recommended(&self) -> bool { !matches!(self.recommended, Some(false)) } pub(crate) fn get_enabled_rules(&self) -> IndexSet { IndexSet::from_iter(self.rules.iter().filter_map(|(key, conf)| { if conf.is_enabled() { @@ -1078,9 +1060,7 @@ impl Style { })) } #[doc = r" Checks if, given a rule name, matches one of the rules contained in this category"] - pub(crate) fn has_rule(rule_name: &str) -> bool { - Self::CATEGORY_RULES.contains(&rule_name) - } + pub(crate) fn has_rule(rule_name: &str) -> bool { Self::CATEGORY_RULES.contains(&rule_name) } #[doc = r" Checks if, given a rule name, it is marked as recommended"] pub(crate) fn is_recommended_rule(rule_name: &str) -> bool { Self::RECOMMENDED_RULES.contains(&rule_name) diff --git a/website/src/pages/lint/rules/index.mdx b/website/src/pages/lint/rules/index.mdx index 0344314dac8d..c52e3b33c9ba 100644 --- a/website/src/pages/lint/rules/index.mdx +++ b/website/src/pages/lint/rules/index.mdx @@ -559,6 +559,18 @@ Disallow the use of var Disallow returning a value from a function with the return type 'void'
+

+ useAriaPropTypes +

+Enforce that ARIA state and property values are valid. +
+
+

+ useAriaPropsForRole +

+Enforce that elements with ARIA roles must have all required attributes for that role +
+

useCamelCase

diff --git a/xtask/codegen/src/generate_aria.rs b/xtask/codegen/src/generate_aria.rs index 683d56719f0e..0f67d5a2c048 100644 --- a/xtask/codegen/src/generate_aria.rs +++ b/xtask/codegen/src/generate_aria.rs @@ -14,7 +14,7 @@ pub(crate) fn generate_aria(mode: Mode) -> Result<()> { let aria_properties = generate_properties(); let aria_roles = generate_roles(); let tokens = quote! { - use crate::constants::{ARIA_PROPERTIES, ARIA_PROPERTY_TYPE, ARIA_WIDGET_ROLES, ARIA_ABSTRACT_ROLES, ARIA_DOCUMENT_STRUCTURE_ROLES}; + use std::str::FromStr; #aria_properties #aria_roles @@ -93,20 +93,20 @@ fn generate_enums<'a>( &property.replace("-", "_").to_camel().to_string(), Span::call_site(), ); - let index = Literal::u16_unsuffixed(index as u16); + let property = Literal::string(property); enum_metadata.push(quote! { #name }); from_enum_metadata.push(quote! { - #enum_name::#name => #const_name[#index] + #enum_name::#name => #property }); from_string_metadata.push(quote! { - #index => #enum_name::#name + #property => Ok(#enum_name::#name) }) } from_string_metadata.push(quote! { - _ => panic!("aria property not implemented") + _ => Err("aria property not implemented".to_string()) }); quote! { @@ -124,12 +124,10 @@ fn generate_enums<'a>( } } - impl From<&str> for #enum_name { - fn from(s: &str) -> Self { - let index = #const_name - .binary_search(&s) - .unwrap_or_else(|_| panic!("aria property not implemented {s:?}")); - match index { + impl FromStr for #enum_name { + type Err = String; + fn from_str(s: &str) -> Result { + match s { #( #from_string_metadata ),* } }