mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
perf(linter): remove allocations for string comparisons (#4570)
Refactors a lot of case-insensitive comparisons from ```rust a.to_lowercase() == b.to_lowercase() ``` with ```rust a.eq_ignore_ascii_case(b) ``` These mostly happened when checking JSX props, so I'm expecting the most benefit from JSX-related rules.
This commit is contained in:
parent
0914e47660
commit
7585e16beb
27 changed files with 92 additions and 95 deletions
|
|
@ -1267,8 +1267,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for RegExpLiteral<'a> {
|
|||
let last = p.peek_nth(0);
|
||||
// Avoid forming a single-line comment or "</script" sequence
|
||||
if Some('/') == last
|
||||
|| (Some('<') == last
|
||||
&& self.regex.pattern.as_str().to_lowercase().starts_with("script"))
|
||||
|| (Some('<') == last && self.regex.pattern.to_lowercase().starts_with("script"))
|
||||
{
|
||||
p.print_hard_space();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use crate::{
|
|||
context::LintContext,
|
||||
rule::Rule,
|
||||
utils::{
|
||||
get_element_type, get_prop_value, get_string_literal_prop_value, has_jsx_prop_lowercase,
|
||||
get_element_type, get_prop_value, get_string_literal_prop_value, has_jsx_prop_ignore_case,
|
||||
object_has_accessible_child,
|
||||
},
|
||||
AstNode,
|
||||
|
|
@ -205,8 +205,8 @@ impl Rule for AltText {
|
|||
|
||||
// <input type="image">
|
||||
if let Some(custom_tags) = &self.input_type_image {
|
||||
let has_input_with_type_image = name.to_lowercase() == "input"
|
||||
&& has_jsx_prop_lowercase(jsx_el, "type").map_or(false, |v| {
|
||||
let has_input_with_type_image = name.eq_ignore_ascii_case("input")
|
||||
&& has_jsx_prop_ignore_case(jsx_el, "type").map_or(false, |v| {
|
||||
get_string_literal_prop_value(v).map_or(false, |v| v == "image")
|
||||
});
|
||||
if has_input_with_type_image || custom_tags.iter().any(|i| i == name) {
|
||||
|
|
@ -247,26 +247,26 @@ fn aria_label_has_value<'a>(item: &'a JSXAttributeItem<'a>) -> bool {
|
|||
}
|
||||
|
||||
fn img_rule<'a>(node: &'a JSXOpeningElement<'a>, ctx: &LintContext<'a>) {
|
||||
if let Some(alt_prop) = has_jsx_prop_lowercase(node, "alt") {
|
||||
if let Some(alt_prop) = has_jsx_prop_ignore_case(node, "alt") {
|
||||
if !is_valid_alt_prop(alt_prop) {
|
||||
ctx.diagnostic(missing_alt_value(node.span));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if has_jsx_prop_lowercase(node, "role").map_or(false, is_presentation_role) {
|
||||
if has_jsx_prop_ignore_case(node, "role").map_or(false, is_presentation_role) {
|
||||
ctx.diagnostic(prefer_alt(node.span));
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(aria_label_prop) = has_jsx_prop_lowercase(node, "aria-label") {
|
||||
if let Some(aria_label_prop) = has_jsx_prop_ignore_case(node, "aria-label") {
|
||||
if !aria_label_has_value(aria_label_prop) {
|
||||
ctx.diagnostic(aria_label_value(node.span));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(aria_labelledby_prop) = has_jsx_prop_lowercase(node, "aria-labelledby") {
|
||||
if let Some(aria_labelledby_prop) = has_jsx_prop_ignore_case(node, "aria-labelledby") {
|
||||
if !aria_label_has_value(aria_labelledby_prop) {
|
||||
ctx.diagnostic(aria_labelled_by_value(node.span));
|
||||
}
|
||||
|
|
@ -282,11 +282,11 @@ fn object_rule<'a>(
|
|||
ctx: &LintContext<'a>,
|
||||
) {
|
||||
let has_aria_label =
|
||||
has_jsx_prop_lowercase(node, "aria-label").map_or(false, aria_label_has_value);
|
||||
has_jsx_prop_ignore_case(node, "aria-label").map_or(false, aria_label_has_value);
|
||||
let has_aria_labelledby =
|
||||
has_jsx_prop_lowercase(node, "aria-labelledby").map_or(false, aria_label_has_value);
|
||||
has_jsx_prop_ignore_case(node, "aria-labelledby").map_or(false, aria_label_has_value);
|
||||
let has_label = has_aria_label || has_aria_labelledby;
|
||||
let has_title_attr = has_jsx_prop_lowercase(node, "title")
|
||||
let has_title_attr = has_jsx_prop_ignore_case(node, "title")
|
||||
.and_then(get_string_literal_prop_value)
|
||||
.map_or(false, |v| !v.is_empty());
|
||||
|
||||
|
|
@ -298,14 +298,14 @@ fn object_rule<'a>(
|
|||
|
||||
fn area_rule<'a>(node: &'a JSXOpeningElement<'a>, ctx: &LintContext<'a>) {
|
||||
let has_aria_label =
|
||||
has_jsx_prop_lowercase(node, "aria-label").map_or(false, aria_label_has_value);
|
||||
has_jsx_prop_ignore_case(node, "aria-label").map_or(false, aria_label_has_value);
|
||||
let has_aria_labelledby =
|
||||
has_jsx_prop_lowercase(node, "aria-labelledby").map_or(false, aria_label_has_value);
|
||||
has_jsx_prop_ignore_case(node, "aria-labelledby").map_or(false, aria_label_has_value);
|
||||
let has_label = has_aria_label || has_aria_labelledby;
|
||||
if has_label {
|
||||
return;
|
||||
}
|
||||
has_jsx_prop_lowercase(node, "alt").map_or_else(
|
||||
has_jsx_prop_ignore_case(node, "alt").map_or_else(
|
||||
|| {
|
||||
ctx.diagnostic(area(node.span));
|
||||
},
|
||||
|
|
@ -319,14 +319,14 @@ fn area_rule<'a>(node: &'a JSXOpeningElement<'a>, ctx: &LintContext<'a>) {
|
|||
|
||||
fn input_type_image_rule<'a>(node: &'a JSXOpeningElement<'a>, ctx: &LintContext<'a>) {
|
||||
let has_aria_label =
|
||||
has_jsx_prop_lowercase(node, "aria-label").map_or(false, aria_label_has_value);
|
||||
has_jsx_prop_ignore_case(node, "aria-label").map_or(false, aria_label_has_value);
|
||||
let has_aria_labelledby =
|
||||
has_jsx_prop_lowercase(node, "aria-labelledby").map_or(false, aria_label_has_value);
|
||||
has_jsx_prop_ignore_case(node, "aria-labelledby").map_or(false, aria_label_has_value);
|
||||
let has_label = has_aria_label || has_aria_labelledby;
|
||||
if has_label {
|
||||
return;
|
||||
}
|
||||
has_jsx_prop_lowercase(node, "alt").map_or_else(
|
||||
has_jsx_prop_ignore_case(node, "alt").map_or_else(
|
||||
|| {
|
||||
ctx.diagnostic(input_type_image(node.span));
|
||||
},
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
context::LintContext,
|
||||
rule::Rule,
|
||||
utils::{
|
||||
get_element_type, has_jsx_prop_lowercase, is_hidden_from_screen_reader,
|
||||
get_element_type, has_jsx_prop_ignore_case, is_hidden_from_screen_reader,
|
||||
object_has_accessible_child,
|
||||
},
|
||||
AstNode,
|
||||
|
|
@ -79,7 +79,7 @@ impl Rule for AnchorHasContent {
|
|||
}
|
||||
|
||||
for attr in ["title", "aria-label"] {
|
||||
if has_jsx_prop_lowercase(&jsx_el.opening_element, attr).is_some() {
|
||||
if has_jsx_prop_ignore_case(&jsx_el.opening_element, attr).is_some() {
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use oxc_span::Span;
|
|||
use crate::{
|
||||
context::LintContext,
|
||||
rule::Rule,
|
||||
utils::{get_element_type, has_jsx_prop_lowercase},
|
||||
utils::{get_element_type, has_jsx_prop_ignore_case},
|
||||
AstNode,
|
||||
};
|
||||
|
||||
|
|
@ -134,7 +134,7 @@ impl Rule for AnchorIsValid {
|
|||
};
|
||||
if name == "a" {
|
||||
if let Option::Some(herf_attr) =
|
||||
has_jsx_prop_lowercase(&jsx_el.opening_element, "href")
|
||||
has_jsx_prop_ignore_case(&jsx_el.opening_element, "href")
|
||||
{
|
||||
// Check if the 'a' element has a correct href attribute
|
||||
match herf_attr {
|
||||
|
|
@ -142,7 +142,7 @@ impl Rule for AnchorIsValid {
|
|||
Some(value) => {
|
||||
let is_empty = check_value_is_empty(value, &self.0.valid_hrefs);
|
||||
if is_empty {
|
||||
if has_jsx_prop_lowercase(&jsx_el.opening_element, "onclick")
|
||||
if has_jsx_prop_ignore_case(&jsx_el.opening_element, "onclick")
|
||||
.is_some()
|
||||
{
|
||||
ctx.diagnostic(cant_be_anchor(ident.span));
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use crate::{
|
|||
context::LintContext,
|
||||
globals::HTML_TAG,
|
||||
rule::Rule,
|
||||
utils::{get_element_type, has_jsx_prop_lowercase, is_interactive_element, parse_jsx_value},
|
||||
utils::{get_element_type, has_jsx_prop_ignore_case, is_interactive_element, parse_jsx_value},
|
||||
AstNode,
|
||||
};
|
||||
|
||||
|
|
@ -62,7 +62,7 @@ impl Rule for AriaActivedescendantHasTabindex {
|
|||
return;
|
||||
};
|
||||
|
||||
if has_jsx_prop_lowercase(jsx_opening_el, "aria-activedescendant").is_none() {
|
||||
if has_jsx_prop_ignore_case(jsx_opening_el, "aria-activedescendant").is_none() {
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ impl Rule for AriaActivedescendantHasTabindex {
|
|||
};
|
||||
|
||||
if let Some(JSXAttributeItem::Attribute(tab_index_attr)) =
|
||||
has_jsx_prop_lowercase(jsx_opening_el, "tabIndex")
|
||||
has_jsx_prop_ignore_case(jsx_opening_el, "tabIndex")
|
||||
{
|
||||
if !is_valid_tab_index_attr(tab_index_attr) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use phf::{phf_map, phf_set};
|
|||
use crate::{
|
||||
context::LintContext,
|
||||
rule::Rule,
|
||||
utils::{get_element_type, has_jsx_prop_lowercase},
|
||||
utils::{get_element_type, has_jsx_prop_ignore_case},
|
||||
AstNode,
|
||||
};
|
||||
|
||||
|
|
@ -183,7 +183,7 @@ impl Rule for AutocompleteValid {
|
|||
return;
|
||||
}
|
||||
|
||||
let Some(autocomplete_prop) = has_jsx_prop_lowercase(jsx_el, "autocomplete") else {
|
||||
let Some(autocomplete_prop) = has_jsx_prop_ignore_case(jsx_el, "autocomplete") else {
|
||||
return;
|
||||
};
|
||||
let attr = match autocomplete_prop {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use oxc_span::Span;
|
|||
use crate::{
|
||||
context::LintContext,
|
||||
rule::Rule,
|
||||
utils::{get_element_type, get_prop_value, has_jsx_prop_lowercase},
|
||||
utils::{get_element_type, get_prop_value, has_jsx_prop_ignore_case},
|
||||
AstNode,
|
||||
};
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ impl Rule for HtmlHasLang {
|
|||
return;
|
||||
};
|
||||
|
||||
has_jsx_prop_lowercase(jsx_el, "lang").map_or_else(
|
||||
has_jsx_prop_ignore_case(jsx_el, "lang").map_or_else(
|
||||
|| ctx.diagnostic(missing_lang_prop(identifier.span)),
|
||||
|lang_prop| {
|
||||
if !is_valid_lang_prop(lang_prop) {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use oxc_span::Span;
|
|||
use crate::{
|
||||
context::LintContext,
|
||||
rule::Rule,
|
||||
utils::{get_element_type, get_prop_value, has_jsx_prop_lowercase},
|
||||
utils::{get_element_type, get_prop_value, has_jsx_prop_ignore_case},
|
||||
AstNode,
|
||||
};
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ impl Rule for IframeHasTitle {
|
|||
return;
|
||||
}
|
||||
|
||||
let Some(alt_prop) = has_jsx_prop_lowercase(jsx_el, "title") else {
|
||||
let Some(alt_prop) = has_jsx_prop_ignore_case(jsx_el, "title") else {
|
||||
ctx.diagnostic(iframe_has_title_diagnostic(iden.span));
|
||||
return;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use crate::{
|
|||
context::LintContext,
|
||||
rule::Rule,
|
||||
utils::{
|
||||
get_element_type, get_prop_value, has_jsx_prop_lowercase, is_hidden_from_screen_reader,
|
||||
get_element_type, get_prop_value, has_jsx_prop_ignore_case, is_hidden_from_screen_reader,
|
||||
},
|
||||
AstNode,
|
||||
};
|
||||
|
|
@ -120,7 +120,7 @@ impl Rule for ImgRedundantAlt {
|
|||
return;
|
||||
}
|
||||
|
||||
let Some(alt_prop) = has_jsx_prop_lowercase(jsx_el, "alt") else {
|
||||
let Some(alt_prop) = has_jsx_prop_ignore_case(jsx_el, "alt") else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use oxc_span::Span;
|
|||
use crate::{
|
||||
context::LintContext,
|
||||
rule::Rule,
|
||||
utils::{get_element_type, get_prop_value, has_jsx_prop_lowercase},
|
||||
utils::{get_element_type, get_prop_value, has_jsx_prop_ignore_case},
|
||||
AstNode,
|
||||
};
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ impl Rule for Lang {
|
|||
return;
|
||||
};
|
||||
|
||||
has_jsx_prop_lowercase(jsx_el, "lang").map_or_else(
|
||||
has_jsx_prop_ignore_case(jsx_el, "lang").map_or_else(
|
||||
|| ctx.diagnostic(lang_diagnostic(identifier.span)),
|
||||
|lang_prop| {
|
||||
if !is_valid_lang_prop(lang_prop) {
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ impl Rule for MediaHasCaption {
|
|||
if let JSXAttributeName::Identifier(iden) = &attr.name {
|
||||
if let Some(JSXAttributeValue::StringLiteral(s)) = &attr.value {
|
||||
return iden.name == "kind"
|
||||
&& s.value.to_lowercase() == "captions";
|
||||
&& s.value.eq_ignore_ascii_case("captions");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, utils::has_jsx_prop_lowercase, AstNode};
|
||||
use crate::{context::LintContext, rule::Rule, utils::has_jsx_prop_ignore_case, AstNode};
|
||||
|
||||
fn no_access_key_diagnostic(span0: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("No access key attribute allowed.")
|
||||
|
|
@ -42,7 +42,8 @@ impl Rule for NoAccessKey {
|
|||
let AstKind::JSXOpeningElement(jsx_el) = node.kind() else {
|
||||
return;
|
||||
};
|
||||
if let Some(JSXAttributeItem::Attribute(attr)) = has_jsx_prop_lowercase(jsx_el, "accessKey")
|
||||
if let Some(JSXAttributeItem::Attribute(attr)) =
|
||||
has_jsx_prop_ignore_case(jsx_el, "accessKey")
|
||||
{
|
||||
match attr.value.as_ref() {
|
||||
Some(JSXAttributeValue::StringLiteral(_)) => {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use oxc_span::Span;
|
|||
use crate::{
|
||||
context::LintContext,
|
||||
rule::Rule,
|
||||
utils::{get_element_type, has_jsx_prop_lowercase, parse_jsx_value},
|
||||
utils::{get_element_type, has_jsx_prop_ignore_case, parse_jsx_value},
|
||||
AstNode,
|
||||
};
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ impl Rule for NoAriaHiddenOnFocusable {
|
|||
let AstKind::JSXOpeningElement(jsx_el) = node.kind() else {
|
||||
return;
|
||||
};
|
||||
if let Some(aria_hidden_prop) = has_jsx_prop_lowercase(jsx_el, "aria-hidden") {
|
||||
if let Some(aria_hidden_prop) = has_jsx_prop_ignore_case(jsx_el, "aria-hidden") {
|
||||
if is_aria_hidden_true(aria_hidden_prop) && is_focusable(ctx, jsx_el) {
|
||||
if let JSXAttributeItem::Attribute(boxed_attr) = aria_hidden_prop {
|
||||
ctx.diagnostic(no_aria_hidden_on_focusable_diagnostic(boxed_attr.span));
|
||||
|
|
@ -89,16 +89,16 @@ fn is_focusable(ctx: &LintContext, element: &JSXOpeningElement) -> bool {
|
|||
return false;
|
||||
};
|
||||
|
||||
if let Some(JSXAttributeItem::Attribute(attr)) = has_jsx_prop_lowercase(element, "tabIndex") {
|
||||
if let Some(JSXAttributeItem::Attribute(attr)) = has_jsx_prop_ignore_case(element, "tabIndex") {
|
||||
if let Some(attr_value) = &attr.value {
|
||||
return parse_jsx_value(attr_value).map_or(false, |num| num >= 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
match tag_name.as_str() {
|
||||
"a" | "area" => has_jsx_prop_lowercase(element, "href").is_some(),
|
||||
"a" | "area" => has_jsx_prop_ignore_case(element, "href").is_some(),
|
||||
"button" | "input" | "select" | "textarea" => {
|
||||
has_jsx_prop_lowercase(element, "disabled").is_none()
|
||||
has_jsx_prop_ignore_case(element, "disabled").is_none()
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use phf::phf_map;
|
|||
use crate::{
|
||||
context::LintContext,
|
||||
rule::Rule,
|
||||
utils::{get_element_type, has_jsx_prop_lowercase},
|
||||
utils::{get_element_type, has_jsx_prop_ignore_case},
|
||||
AstNode,
|
||||
};
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ impl Rule for NoRedundantRoles {
|
|||
if let AstKind::JSXOpeningElement(jsx_el) = node.kind() {
|
||||
if let Some(component) = get_element_type(ctx, jsx_el) {
|
||||
if let Some(JSXAttributeItem::Attribute(attr)) =
|
||||
has_jsx_prop_lowercase(jsx_el, "role")
|
||||
has_jsx_prop_ignore_case(jsx_el, "role")
|
||||
{
|
||||
if let Some(JSXAttributeValue::StringLiteral(role_values)) = &attr.value {
|
||||
let roles: Vec<String> = role_values
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use phf::phf_map;
|
|||
use crate::{
|
||||
context::LintContext,
|
||||
rule::Rule,
|
||||
utils::{get_element_type, has_jsx_prop_lowercase},
|
||||
utils::{get_element_type, has_jsx_prop_ignore_case},
|
||||
AstNode,
|
||||
};
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ impl Rule for PreferTagOverRole {
|
|||
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
|
||||
if let AstKind::JSXOpeningElement(jsx_el) = node.kind() {
|
||||
if let Some(name) = get_element_type(ctx, jsx_el) {
|
||||
if let Some(role_prop) = has_jsx_prop_lowercase(jsx_el, "role") {
|
||||
if let Some(role_prop) = has_jsx_prop_ignore_case(jsx_el, "role") {
|
||||
Self::check_roles(role_prop, &ROLE_TO_TAG_MAP, &name, ctx);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use oxc_macros::declare_oxc_lint;
|
|||
use oxc_span::Span;
|
||||
use phf::{phf_map, phf_set};
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, utils::has_jsx_prop_lowercase, AstNode};
|
||||
use crate::{context::LintContext, rule::Rule, utils::has_jsx_prop_ignore_case, AstNode};
|
||||
|
||||
fn role_has_required_aria_props_diagnostic(span: Span, role: &str, props: &str) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn(format!("`{role}` role is missing required aria props `{props}`."))
|
||||
|
|
@ -50,7 +50,7 @@ static ROLE_TO_REQUIRED_ARIA_PROPS: phf::Map<&'static str, phf::Set<&'static str
|
|||
impl Rule for RoleHasRequiredAriaProps {
|
||||
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
|
||||
if let AstKind::JSXOpeningElement(jsx_el) = node.kind() {
|
||||
let Some(role_prop) = has_jsx_prop_lowercase(jsx_el, "role") else {
|
||||
let Some(role_prop) = has_jsx_prop_ignore_case(jsx_el, "role") else {
|
||||
return;
|
||||
};
|
||||
let JSXAttributeItem::Attribute(attr) = role_prop else {
|
||||
|
|
@ -63,7 +63,7 @@ impl Rule for RoleHasRequiredAriaProps {
|
|||
for role in roles {
|
||||
if let Some(props) = ROLE_TO_REQUIRED_ARIA_PROPS.get(role) {
|
||||
for prop in props {
|
||||
if has_jsx_prop_lowercase(jsx_el, prop).is_none() {
|
||||
if has_jsx_prop_ignore_case(jsx_el, prop).is_none() {
|
||||
ctx.diagnostic(role_has_required_aria_props_diagnostic(
|
||||
attr.span, role, prop,
|
||||
));
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use crate::{
|
|||
rule::Rule,
|
||||
utils::{
|
||||
get_element_type, get_jsx_attribute_name, get_string_literal_prop_value,
|
||||
has_jsx_prop_lowercase,
|
||||
has_jsx_prop_ignore_case,
|
||||
},
|
||||
AstNode,
|
||||
};
|
||||
|
|
@ -63,7 +63,7 @@ impl Rule for RoleSupportsAriaProps {
|
|||
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
|
||||
if let AstKind::JSXOpeningElement(jsx_el) = node.kind() {
|
||||
if let Some(el_type) = get_element_type(ctx, jsx_el) {
|
||||
let role = has_jsx_prop_lowercase(jsx_el, "role");
|
||||
let role = has_jsx_prop_ignore_case(jsx_el, "role");
|
||||
let role_value = role.map_or_else(
|
||||
|| get_implicit_role(jsx_el, el_type.as_str()),
|
||||
|i| get_string_literal_prop_value(i),
|
||||
|
|
@ -98,7 +98,7 @@ fn get_implicit_role<'a>(
|
|||
element_type: &str,
|
||||
) -> Option<&'static str> {
|
||||
let implicit_role = match element_type {
|
||||
"a" | "area" | "link" => match has_jsx_prop_lowercase(node, "href") {
|
||||
"a" | "area" | "link" => match has_jsx_prop_ignore_case(node, "href") {
|
||||
Some(_) => "link",
|
||||
None => "",
|
||||
},
|
||||
|
|
@ -112,11 +112,11 @@ fn get_implicit_role<'a>(
|
|||
"form" => "form",
|
||||
"h1" | "h2" | "h3" | "h4" | "h5" | "h6" => "heading",
|
||||
"hr" => "separator",
|
||||
"img" => has_jsx_prop_lowercase(node, "alt").map_or("img", |i| {
|
||||
"img" => has_jsx_prop_ignore_case(node, "alt").map_or("img", |i| {
|
||||
get_string_literal_prop_value(i)
|
||||
.map_or("img", |v| if v.is_empty() { "" } else { "img" })
|
||||
}),
|
||||
"input" => has_jsx_prop_lowercase(node, "type").map_or("textbox", |input_type| {
|
||||
"input" => has_jsx_prop_ignore_case(node, "type").map_or("textbox", |input_type| {
|
||||
match get_string_literal_prop_value(input_type) {
|
||||
Some("button" | "image" | "reset" | "submit") => "button",
|
||||
Some("checkbox") => "checkbox",
|
||||
|
|
@ -126,21 +126,18 @@ fn get_implicit_role<'a>(
|
|||
}
|
||||
}),
|
||||
"li" => "listitem",
|
||||
"menu" => has_jsx_prop_lowercase(node, "type").map_or("", |v| {
|
||||
"menu" => has_jsx_prop_ignore_case(node, "type").map_or("", |v| {
|
||||
get_string_literal_prop_value(v)
|
||||
.map_or("", |v| if v == "toolbar" { "toolbar" } else { "" })
|
||||
}),
|
||||
"menuitem" => {
|
||||
has_jsx_prop_lowercase(node, "type").map_or(
|
||||
"",
|
||||
|v| match get_string_literal_prop_value(v) {
|
||||
Some("checkbox") => "menuitemcheckbox",
|
||||
Some("command") => "menuitem",
|
||||
Some("radio") => "menuitemradio",
|
||||
_ => "",
|
||||
},
|
||||
)
|
||||
}
|
||||
"menuitem" => has_jsx_prop_ignore_case(node, "type").map_or("", |v| {
|
||||
match get_string_literal_prop_value(v) {
|
||||
Some("checkbox") => "menuitemcheckbox",
|
||||
Some("command") => "menuitem",
|
||||
Some("radio") => "menuitemradio",
|
||||
_ => "",
|
||||
}
|
||||
}),
|
||||
"meter" | "progress" => "progressbar",
|
||||
"nav" => "navigation",
|
||||
"ol" | "ul" => "list",
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
context::LintContext,
|
||||
globals::HTML_TAG,
|
||||
rule::Rule,
|
||||
utils::{get_element_type, has_jsx_prop_lowercase},
|
||||
utils::{get_element_type, has_jsx_prop_ignore_case},
|
||||
AstNode,
|
||||
};
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ impl Rule for Scope {
|
|||
return;
|
||||
};
|
||||
|
||||
let scope_attribute = match has_jsx_prop_lowercase(jsx_el, "scope") {
|
||||
let scope_attribute = match has_jsx_prop_ignore_case(jsx_el, "scope") {
|
||||
Some(v) => match v {
|
||||
JSXAttributeItem::Attribute(attr) => attr,
|
||||
JSXAttributeItem::SpreadAttribute(_) => {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use oxc_span::Span;
|
|||
use crate::{
|
||||
context::LintContext,
|
||||
rule::Rule,
|
||||
utils::{has_jsx_prop_lowercase, parse_jsx_value},
|
||||
utils::{has_jsx_prop_ignore_case, parse_jsx_value},
|
||||
AstNode,
|
||||
};
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ impl Rule for TabindexNoPositive {
|
|||
let AstKind::JSXOpeningElement(jsx_el) = node.kind() else {
|
||||
return;
|
||||
};
|
||||
if let Some(tab_index_prop) = has_jsx_prop_lowercase(jsx_el, "tabIndex") {
|
||||
if let Some(tab_index_prop) = has_jsx_prop_ignore_case(jsx_el, "tabIndex") {
|
||||
check_and_diagnose(tab_index_prop, ctx);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use oxc_span::{GetSpan, Span};
|
|||
use crate::{
|
||||
context::LintContext,
|
||||
rule::Rule,
|
||||
utils::{get_string_literal_prop_value, has_jsx_prop_lowercase},
|
||||
utils::{get_string_literal_prop_value, has_jsx_prop_ignore_case},
|
||||
AstNode,
|
||||
};
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ impl Rule for GoogleFontDisplay {
|
|||
return;
|
||||
}
|
||||
|
||||
let Some(href_prop) = has_jsx_prop_lowercase(jsx_opening_element, "href") else {
|
||||
let Some(href_prop) = has_jsx_prop_ignore_case(jsx_opening_element, "href") else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use oxc_span::Span;
|
|||
use crate::{
|
||||
context::LintContext,
|
||||
rule::Rule,
|
||||
utils::{get_string_literal_prop_value, has_jsx_prop_lowercase},
|
||||
utils::{get_string_literal_prop_value, has_jsx_prop_ignore_case},
|
||||
AstNode,
|
||||
};
|
||||
|
||||
|
|
@ -47,7 +47,7 @@ impl Rule for GoogleFontPreconnect {
|
|||
return;
|
||||
}
|
||||
|
||||
let Some(href_prop) = has_jsx_prop_lowercase(jsx_opening_element, "href") else {
|
||||
let Some(href_prop) = has_jsx_prop_ignore_case(jsx_opening_element, "href") else {
|
||||
return;
|
||||
};
|
||||
let Some(href_prop_value) = get_string_literal_prop_value(href_prop) else {
|
||||
|
|
@ -55,7 +55,7 @@ impl Rule for GoogleFontPreconnect {
|
|||
};
|
||||
|
||||
let preconnect_missing =
|
||||
has_jsx_prop_lowercase(jsx_opening_element, "rel").map_or(true, |rel_prop| {
|
||||
has_jsx_prop_ignore_case(jsx_opening_element, "rel").map_or(true, |rel_prop| {
|
||||
let rel_prop_value = get_string_literal_prop_value(rel_prop);
|
||||
rel_prop_value != Some("preconnect")
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use oxc_span::Span;
|
|||
use crate::{
|
||||
context::LintContext,
|
||||
rule::Rule,
|
||||
utils::{get_string_literal_prop_value, has_jsx_prop_lowercase},
|
||||
utils::{get_string_literal_prop_value, has_jsx_prop_ignore_case},
|
||||
AstNode,
|
||||
};
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ impl Rule for NextScriptForGa {
|
|||
// Check if the Alternative async tag is being used to add GA.
|
||||
// https://developers.google.com/analytics/devguides/collection/analyticsjs#alternative_async_tag
|
||||
// https://developers.google.com/analytics/devguides/collection/gtagjs
|
||||
if let Some(src_prop) = has_jsx_prop_lowercase(jsx_opening_element, "src") {
|
||||
if let Some(src_prop) = has_jsx_prop_ignore_case(jsx_opening_element, "src") {
|
||||
if let Some(src_prop_value) = get_string_literal_prop_value(src_prop) {
|
||||
if SUPPORTED_SRCS.iter().any(|s| src_prop_value.contains(s)) {
|
||||
ctx.diagnostic(next_script_for_ga_diagnostic(jsx_opening_element_name.span));
|
||||
|
|
@ -92,7 +92,7 @@ fn get_dangerously_set_inner_html_prop_value<'a>(
|
|||
jsx_opening_element: &'a JSXOpeningElement<'a>,
|
||||
) -> Option<&'a ObjectProperty<'a>> {
|
||||
let Some(JSXAttributeItem::Attribute(dangerously_set_inner_html_prop)) =
|
||||
has_jsx_prop_lowercase(jsx_opening_element, "dangerouslysetinnerhtml")
|
||||
has_jsx_prop_ignore_case(jsx_opening_element, "dangerouslysetinnerhtml")
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use oxc_span::{GetSpan, Span};
|
|||
use crate::{
|
||||
context::LintContext,
|
||||
rule::Rule,
|
||||
utils::{get_prop_value, has_jsx_prop_lowercase, is_create_element_call},
|
||||
utils::{get_prop_value, has_jsx_prop_ignore_case, is_create_element_call},
|
||||
AstNode,
|
||||
};
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ impl Rule for ButtonHasType {
|
|||
return;
|
||||
}
|
||||
|
||||
has_jsx_prop_lowercase(jsx_el, "type").map_or_else(
|
||||
has_jsx_prop_ignore_case(jsx_el, "type").map_or_else(
|
||||
|| {
|
||||
ctx.diagnostic(missing_type_prop(identifier.span));
|
||||
},
|
||||
|
|
|
|||
|
|
@ -317,7 +317,7 @@ fn check_rel_val(str: &StringLiteral, allow_referrer: bool) -> bool {
|
|||
false
|
||||
});
|
||||
}
|
||||
splits.any(|str| str.to_lowercase() == "noreferrer")
|
||||
splits.any(|str| str.eq_ignore_ascii_case("noreferrer"))
|
||||
}
|
||||
|
||||
fn match_rel_expression<'a>(
|
||||
|
|
@ -367,7 +367,7 @@ fn match_target_expression<'a>(expr: &'a Expression<'a>) -> (bool, &'a str, bool
|
|||
let default = (false, "", false, false);
|
||||
match expr {
|
||||
Expression::StringLiteral(str) => {
|
||||
(str.value.as_str().to_lowercase() == "_blank", "", false, false)
|
||||
(str.value.eq_ignore_ascii_case("_blank"), "", false, false)
|
||||
}
|
||||
Expression::ConditionalExpression(expr) => {
|
||||
let consequent = match_target_expression(&expr.consequent);
|
||||
|
|
@ -390,7 +390,7 @@ fn check_target<'a>(attribute_value: &'a JSXAttributeValue<'a>) -> (bool, &'a st
|
|||
let default = (false, "", false, false);
|
||||
match attribute_value {
|
||||
JSXAttributeValue::StringLiteral(str) => {
|
||||
(str.value.as_str().to_lowercase() == "_blank", "", false, false)
|
||||
(str.value.eq_ignore_ascii_case("_blank"), "", false, false)
|
||||
}
|
||||
JSXAttributeValue::ExpressionContainer(expr) => {
|
||||
if let Some(expr) = expr.expression.as_expression() {
|
||||
|
|
|
|||
|
|
@ -436,7 +436,7 @@ fn is_valid_data_attr(name: &str) -> bool {
|
|||
fn normalize_attribute_case(name: &str) -> &str {
|
||||
DOM_PROPERTIES_IGNORE_CASE
|
||||
.iter()
|
||||
.find(|camel_name| camel_name.to_lowercase() == name.to_lowercase())
|
||||
.find(|camel_name| camel_name.eq_ignore_ascii_case(name))
|
||||
.unwrap_or(&name)
|
||||
}
|
||||
fn has_uppercase(name: &str) -> bool {
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ fn is_jsx_meta_elem_with_charset_attr(id: AstNodeId, ctx: &LintContext) -> bool
|
|||
let JSXAttributeName::Identifier(ident) = &jsx_attr.name else {
|
||||
return false;
|
||||
};
|
||||
if ident.name.to_lowercase() != "charset" {
|
||||
if !ident.name.eq_ignore_ascii_case("charset") {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -116,7 +116,7 @@ fn is_jsx_meta_elem_with_charset_attr(id: AstNodeId, ctx: &LintContext) -> bool
|
|||
return false;
|
||||
};
|
||||
|
||||
if name.name.to_lowercase() != "meta" {
|
||||
if !name.name.eq_ignore_ascii_case("meta") {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ pub fn has_jsx_prop<'a, 'b>(
|
|||
})
|
||||
}
|
||||
|
||||
pub fn has_jsx_prop_lowercase<'a, 'b>(
|
||||
pub fn has_jsx_prop_ignore_case<'a, 'b>(
|
||||
node: &'b JSXOpeningElement<'a>,
|
||||
target_prop: &'b str,
|
||||
) -> Option<&'b JSXAttributeItem<'a>> {
|
||||
|
|
@ -48,7 +48,7 @@ pub fn has_jsx_prop_lowercase<'a, 'b>(
|
|||
return false;
|
||||
};
|
||||
|
||||
name.name.as_str().to_lowercase() == target_prop.to_lowercase()
|
||||
name.name.as_str().eq_ignore_ascii_case(target_prop)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -84,7 +84,7 @@ pub fn get_string_literal_prop_value<'a>(item: &'a JSXAttributeItem<'_>) -> Opti
|
|||
pub fn is_hidden_from_screen_reader(ctx: &LintContext, node: &JSXOpeningElement) -> bool {
|
||||
if let Some(name) = get_element_type(ctx, node) {
|
||||
if name.as_str().to_uppercase() == "INPUT" {
|
||||
if let Some(item) = has_jsx_prop_lowercase(node, "type") {
|
||||
if let Some(item) = has_jsx_prop_ignore_case(node, "type") {
|
||||
let hidden = get_string_literal_prop_value(item);
|
||||
|
||||
if hidden.is_some_and(|val| val.to_uppercase() == "HIDDEN") {
|
||||
|
|
@ -94,7 +94,7 @@ pub fn is_hidden_from_screen_reader(ctx: &LintContext, node: &JSXOpeningElement)
|
|||
}
|
||||
}
|
||||
|
||||
has_jsx_prop_lowercase(node, "aria-hidden").map_or(false, |v| match get_prop_value(v) {
|
||||
has_jsx_prop_ignore_case(node, "aria-hidden").map_or(false, |v| match get_prop_value(v) {
|
||||
None => true,
|
||||
Some(JSXAttributeValue::StringLiteral(s)) if s.value == "true" => true,
|
||||
Some(JSXAttributeValue::ExpressionContainer(container)) => {
|
||||
|
|
@ -118,8 +118,8 @@ pub fn object_has_accessible_child(ctx: &LintContext, node: &JSXElement<'_>) ->
|
|||
&& !container.expression.is_undefined()
|
||||
}
|
||||
_ => false,
|
||||
}) || has_jsx_prop_lowercase(&node.opening_element, "dangerouslySetInnerHTML").is_some()
|
||||
|| has_jsx_prop_lowercase(&node.opening_element, "children").is_some()
|
||||
}) || has_jsx_prop_ignore_case(&node.opening_element, "dangerouslySetInnerHTML").is_some()
|
||||
|| has_jsx_prop_ignore_case(&node.opening_element, "children").is_some()
|
||||
}
|
||||
|
||||
pub fn is_presentation_role(jsx_opening_el: &JSXOpeningElement) -> bool {
|
||||
|
|
@ -247,7 +247,7 @@ pub fn get_element_type(context: &LintContext, element: &JSXOpeningElement) -> O
|
|||
.polymorphic_prop_name
|
||||
.as_ref()
|
||||
.and_then(|polymorphic_prop_name_value| {
|
||||
has_jsx_prop_lowercase(element, polymorphic_prop_name_value)
|
||||
has_jsx_prop_ignore_case(element, polymorphic_prop_name_value)
|
||||
})
|
||||
.and_then(get_prop_value)
|
||||
.and_then(|prop_value| match prop_value {
|
||||
|
|
|
|||
Loading…
Reference in a new issue