Skip to content

Commit 4fb55cf

Browse files
authored
perf(lint): optimize noIrregularWhitespace rule (#9111)
1 parent b99e7db commit 4fb55cf

3 files changed

Lines changed: 64 additions & 62 deletions

File tree

.changeset/new-dolls-flow.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@biomejs/biome": patch
3+
---
4+
5+
Slightly improved performance of [`noIrregularWhitespace`](https://biomejs.dev/linter/rules/no-irregular-whitespace/) by adding early return optimization and simplifying character detection logic.

crates/biome_css_analyze/src/lint/suspicious/no_irregular_whitespace.rs

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,11 @@ use biome_analyze::{
22
Ast, Rule, RuleDiagnostic, RuleSource, context::RuleContext, declare_lint_rule,
33
};
44
use biome_console::markup;
5-
use biome_css_syntax::{AnyCssRule, CssLanguage};
5+
use biome_css_syntax::{AnyCssRule, CssSyntaxNode};
66
use biome_diagnostics::Severity;
7-
use biome_rowan::{AstNode, Direction, SyntaxToken, TextRange};
7+
use biome_rowan::{AstNode, Direction, TextRange};
88
use biome_rule_options::no_irregular_whitespace::NoIrregularWhitespaceOptions;
99

10-
const IRREGULAR_WHITESPACES: &[char; 22] = &[
11-
'\u{c}', '\u{b}', '\u{85}', '\u{feff}', '\u{a0}', '\u{1680}', '\u{180e}', '\u{2000}',
12-
'\u{2001}', '\u{2002}', '\u{2003}', '\u{2004}', '\u{2005}', '\u{2006}', '\u{2007}', '\u{2008}',
13-
'\u{2009}', '\u{200a}', '\u{200b}', '\u{202f}', '\u{205f}', '\u{3000}',
14-
];
15-
1610
declare_lint_rule! {
1711
/// Disallows the use of irregular whitespace characters.
1812
///
@@ -53,8 +47,7 @@ impl Rule for NoIrregularWhitespace {
5347
type Options = NoIrregularWhitespaceOptions;
5448

5549
fn run(ctx: &RuleContext<Self>) -> Self::Signals {
56-
let node = ctx.query();
57-
get_irregular_whitespace(node).into_boxed_slice()
50+
get_irregular_whitespace(ctx.query().syntax()).into_boxed_slice()
5851
}
5952

6053
fn diagnostic(_: &RuleContext<Self>, range: &Self::State) -> Option<RuleDiagnostic> {
@@ -73,24 +66,31 @@ impl Rule for NoIrregularWhitespace {
7366
}
7467
}
7568

76-
fn get_irregular_whitespace(node: &AnyCssRule) -> Vec<TextRange> {
77-
let syntax = node.syntax();
78-
let mut all_whitespaces_token: Vec<TextRange> = vec![];
79-
let matches_irregular_whitespace = |token: &SyntaxToken<CssLanguage>| {
80-
!token.has_leading_comments()
81-
&& !token.has_trailing_comments()
82-
&& token.text().chars().any(|char| {
83-
IRREGULAR_WHITESPACES
84-
.iter()
85-
.any(|irregular_whitespace| &char == irregular_whitespace)
86-
})
87-
};
69+
fn is_irregular_whitespace(c: char) -> bool {
70+
matches!(
71+
c,
72+
'\u{000B}' | '\u{000C}' | '\u{0085}' | '\u{00A0}' | '\u{1680}' | '\u{180E}' | '\u{2000}'
73+
..='\u{200B}' | '\u{202F}' | '\u{205F}' | '\u{3000}' | '\u{FEFF}'
74+
)
75+
}
8876

77+
fn get_irregular_whitespace(syntax: &CssSyntaxNode) -> Vec<TextRange> {
78+
if !syntax
79+
.text_with_trivia()
80+
.chars()
81+
.any(is_irregular_whitespace)
82+
{
83+
return vec![];
84+
}
85+
86+
let mut results = vec![];
8987
for token in syntax.descendants_tokens(Direction::Next) {
90-
if matches_irregular_whitespace(&token) {
91-
all_whitespaces_token.push(token.text_range());
88+
if !token.has_leading_comments()
89+
&& !token.has_trailing_comments()
90+
&& token.text().chars().any(is_irregular_whitespace)
91+
{
92+
results.push(token.text_range());
9293
}
9394
}
94-
95-
all_whitespaces_token
95+
results
9696
}

crates/biome_js_analyze/src/lint/suspicious/no_irregular_whitespace.rs

Lines changed: 33 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,10 @@ use biome_analyze::RuleSource;
22
use biome_analyze::{Ast, Rule, RuleDiagnostic, context::RuleContext, declare_lint_rule};
33
use biome_console::markup;
44
use biome_diagnostics::Severity;
5-
use biome_js_syntax::{AnyJsRoot, JsLanguage, JsSyntaxNode};
6-
use biome_rowan::{AstNode, Direction, SyntaxTriviaPiece, TextRange};
5+
use biome_js_syntax::{AnyJsRoot, JsSyntaxNode};
6+
use biome_rowan::{AstNode, Direction, TextRange};
77
use biome_rule_options::no_irregular_whitespace::NoIrregularWhitespaceOptions;
88

9-
const IRREGULAR_WHITESPACES: &[char; 22] = &[
10-
'\u{c}', '\u{b}', '\u{85}', '\u{feff}', '\u{a0}', '\u{1680}', '\u{180e}', '\u{2000}',
11-
'\u{2001}', '\u{2002}', '\u{2003}', '\u{2004}', '\u{2005}', '\u{2006}', '\u{2007}', '\u{2008}',
12-
'\u{2009}', '\u{200a}', '\u{200b}', '\u{202f}', '\u{205f}', '\u{3000}',
13-
];
14-
159
declare_lint_rule! {
1610
/// Disallows the use of irregular whitespace characters.
1711
///
@@ -78,38 +72,41 @@ impl Rule for NoIrregularWhitespace {
7872
}
7973
}
8074

75+
fn is_irregular_whitespace(c: char) -> bool {
76+
matches!(
77+
c,
78+
'\u{000B}'
79+
| '\u{000C}'
80+
| '\u{0085}'
81+
| '\u{00A0}'
82+
| '\u{1680}'
83+
| '\u{180E}'
84+
| '\u{2000}'..='\u{200B}'
85+
| '\u{202F}'
86+
| '\u{205F}'
87+
| '\u{3000}'
88+
| '\u{FEFF}'
89+
)
90+
}
91+
8192
fn get_irregular_whitespace(syntax: &JsSyntaxNode) -> Vec<TextRange> {
82-
let mut all_whitespaces_trivia: Vec<SyntaxTriviaPiece<JsLanguage>> = vec![];
83-
let is_whitespace = |trivia: &SyntaxTriviaPiece<JsLanguage>| {
84-
trivia.is_whitespace() && !trivia.text().replace(' ', "").is_empty()
85-
};
93+
if !syntax.text_with_trivia().chars().any(is_irregular_whitespace) {
94+
return vec![];
95+
}
8696

97+
let mut results = vec![];
8798
for token in syntax.descendants_tokens(Direction::Next) {
88-
let leading_trivia_pieces = token.leading_trivia().pieces();
89-
let trailing_trivia_pieces = token.trailing_trivia().pieces();
90-
91-
for trivia in leading_trivia_pieces {
92-
if is_whitespace(&trivia) {
93-
all_whitespaces_trivia.push(trivia);
94-
}
95-
}
96-
97-
for trivia in trailing_trivia_pieces {
98-
if is_whitespace(&trivia) {
99-
all_whitespaces_trivia.push(trivia);
99+
for trivia in token
100+
.leading_trivia()
101+
.pieces()
102+
.chain(token.trailing_trivia().pieces())
103+
{
104+
if trivia.is_whitespace()
105+
&& trivia.text().chars().any(is_irregular_whitespace)
106+
{
107+
results.push(trivia.text_range());
100108
}
101109
}
102110
}
103-
104-
all_whitespaces_trivia
105-
.iter()
106-
.filter_map(|trivia| {
107-
let has_irregular_whitespace = trivia.text().chars().any(|char| {
108-
IRREGULAR_WHITESPACES
109-
.iter()
110-
.any(|irregular_whitespace| &char == irregular_whitespace)
111-
});
112-
has_irregular_whitespace.then(|| trivia.text_range())
113-
})
114-
.collect::<Vec<TextRange>>()
111+
results
115112
}

0 commit comments

Comments
 (0)