Skip to content

Commit

Permalink
perf(linter): use aho-corasick instead of regex for string matchi…
Browse files Browse the repository at this point in the history
…ng in `jsx-a11y/img-redundant-alt` (#5892)

hypothesis: profiling shows that Regex creation takes a decent amount of time. the `regex` crate uses `aho-corasick` internally for string matching, which is all we need in some cases. in theory, we could save time by using the lib directly and not needing the full regex syntax.
  • Loading branch information
camchenry committed Sep 19, 2024
1 parent 66b4688 commit 608d637
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 10 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ napi = "3.0.0-alpha.8"
napi-build = "2.1.3"
napi-derive = "3.0.0-alpha.7"

aho-corasick = "1.1.3"
allocator-api2 = "0.2.18"
assert-unchecked = "0.1.2"
base64 = "0.22.1"
Expand Down
1 change: 1 addition & 0 deletions crates/oxc_linter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ oxc_semantic = { workspace = true }
oxc_span = { workspace = true, features = ["schemars", "serialize"] }
oxc_syntax = { workspace = true }

aho-corasick = { workspace = true }
bitflags = { workspace = true }
convert_case = { workspace = true }
cow-utils = { workspace = true }
Expand Down
30 changes: 20 additions & 10 deletions crates/oxc_linter/src/rules/jsx_a11y/img_redundant_alt.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use aho_corasick::AhoCorasick;
use oxc_ast::{
ast::{JSXAttributeItem, JSXAttributeName, JSXAttributeValue, JSXExpression},
AstKind,
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{CompactStr, Span};
use regex::{Regex, RegexBuilder};
use serde_json::Value;

use crate::{
Expand All @@ -28,7 +28,7 @@ pub struct ImgRedundantAlt(Box<ImgRedundantAltConfig>);
#[derive(Debug, Clone)]
pub struct ImgRedundantAltConfig {
types_to_validate: Vec<CompactStr>,
redundant_words: Regex,
redundant_words: AhoCorasick,
}

impl std::ops::Deref for ImgRedundantAlt {
Expand All @@ -45,21 +45,25 @@ impl Default for ImgRedundantAltConfig {
fn default() -> Self {
Self {
types_to_validate: vec![CompactStr::new("img")],
redundant_words: Self::union(&REDUNDANT_WORDS).unwrap(),
redundant_words: AhoCorasick::builder()
.ascii_case_insensitive(true)
.build(REDUNDANT_WORDS)
.expect("Could not build AhoCorasick"),
}
}
}
impl ImgRedundantAltConfig {
fn new(types_to_validate: Vec<&str>, redundant_words: &[&str]) -> Result<Self, regex::Error> {
fn new(
types_to_validate: Vec<&str>,
redundant_words: &[&str],
) -> Result<Self, aho_corasick::BuildError> {
Ok(Self {
types_to_validate: types_to_validate.into_iter().map(Into::into).collect(),
redundant_words: Self::union(redundant_words)?,
redundant_words: AhoCorasick::builder()
.ascii_case_insensitive(true)
.build(redundant_words)?,
})
}

fn union(strs: &[&str]) -> Result<Regex, regex::Error> {
RegexBuilder::new(&format!(r"(?i)\b({})\b", strs.join("|"))).case_insensitive(true).build()
}
}

declare_oxc_lint!(
Expand Down Expand Up @@ -191,7 +195,13 @@ impl Rule for ImgRedundantAlt {
impl ImgRedundantAlt {
#[inline]
fn is_redundant_alt_text(&self, alt_text: &str) -> bool {
self.redundant_words.is_match(alt_text)
for mat in self.redundant_words.find_iter(alt_text) {
// check if followed by space or is whole text
if mat.end() == alt_text.len() || alt_text.as_bytes()[mat.end()] == b' ' {
return true;
}
}
false
}
}

Expand Down

0 comments on commit 608d637

Please sign in to comment.