mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
refactor(linter): use RegExp AST visitor for no-hex-escape (#6117)
Updates the `no-hex-escape` to use the new standard `Visit` trait for visiting the RegExp AST, replacing the handwritten implementation in this rule. This makes it much simpler to maintain.
This commit is contained in:
parent
e7e8eada69
commit
3aa7e42826
1 changed files with 20 additions and 67 deletions
|
|
@ -4,8 +4,9 @@ use oxc_ast::{
|
||||||
};
|
};
|
||||||
use oxc_diagnostics::OxcDiagnostic;
|
use oxc_diagnostics::OxcDiagnostic;
|
||||||
use oxc_macros::declare_oxc_lint;
|
use oxc_macros::declare_oxc_lint;
|
||||||
use oxc_regular_expression::ast::{
|
use oxc_regular_expression::{
|
||||||
Alternative, Character, CharacterClassContents, CharacterKind, Disjunction, Pattern, Term,
|
ast::{Character, CharacterKind},
|
||||||
|
visit::Visit,
|
||||||
};
|
};
|
||||||
use oxc_span::Span;
|
use oxc_span::Span;
|
||||||
|
|
||||||
|
|
@ -97,80 +98,32 @@ impl Rule for NoHexEscape {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
visit_terms(pattern, &mut |term| match term {
|
let mut finder = HexEscapeFinder { hex_escapes: vec![] };
|
||||||
Term::Character(ch) => {
|
finder.visit_pattern(pattern);
|
||||||
check_character(ch, ctx);
|
|
||||||
}
|
for span in finder.hex_escapes {
|
||||||
Term::CharacterClass(class) => {
|
let unicode_escape =
|
||||||
for term in &class.body {
|
format!(r"\u00{}", &span.source_text(ctx.source_text())[2..]);
|
||||||
match term {
|
|
||||||
CharacterClassContents::Character(ch) => {
|
ctx.diagnostic_with_fix(no_hex_escape_diagnostic(span), |fixer| {
|
||||||
check_character(ch, ctx);
|
fixer.replace(span, unicode_escape)
|
||||||
}
|
});
|
||||||
CharacterClassContents::CharacterClassRange(range) => {
|
}
|
||||||
check_character(&range.min, ctx);
|
|
||||||
check_character(&range.max, ctx);
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_character(ch: &Character, ctx: &LintContext) {
|
struct HexEscapeFinder {
|
||||||
if ch.kind == CharacterKind::HexadecimalEscape {
|
hex_escapes: Vec<Span>,
|
||||||
let unicode_escape = format!(r"\u00{}", &ch.span.source_text(ctx.source_text())[2..]);
|
|
||||||
ctx.diagnostic_with_fix(no_hex_escape_diagnostic(ch.span), |fixer| {
|
|
||||||
fixer.replace(ch.span, unicode_escape)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Replace with proper regex AST visitor when available
|
impl<'a> Visit<'a> for HexEscapeFinder {
|
||||||
/// Calls the given closure on every [`Term`] in the [`Pattern`].
|
fn visit_character(&mut self, ch: &Character) {
|
||||||
fn visit_terms<'a, F: FnMut(&'a Term<'a>)>(pattern: &'a Pattern, f: &mut F) {
|
if ch.kind == CharacterKind::HexadecimalEscape {
|
||||||
visit_terms_disjunction(&pattern.body, f);
|
self.hex_escapes.push(ch.span);
|
||||||
}
|
|
||||||
|
|
||||||
/// Calls the given closure on every [`Term`] in the [`Disjunction`].
|
|
||||||
fn visit_terms_disjunction<'a, F: FnMut(&'a Term<'a>)>(disjunction: &'a Disjunction, f: &mut F) {
|
|
||||||
for alternative in &disjunction.body {
|
|
||||||
visit_terms_alternative(alternative, f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calls the given closure on every [`Term`] in the [`Alternative`].
|
|
||||||
fn visit_terms_alternative<'a, F: FnMut(&'a Term<'a>)>(alternative: &'a Alternative, f: &mut F) {
|
|
||||||
for term in &alternative.body {
|
|
||||||
visit_term(term, f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_term<'a, F: FnMut(&'a Term<'a>)>(term: &'a Term<'a>, f: &mut F) {
|
|
||||||
match term {
|
|
||||||
Term::LookAroundAssertion(lookaround) => {
|
|
||||||
f(term);
|
|
||||||
visit_terms_disjunction(&lookaround.body, f);
|
|
||||||
}
|
}
|
||||||
Term::Quantifier(quant) => {
|
|
||||||
f(term);
|
|
||||||
visit_term(&quant.body, f);
|
|
||||||
}
|
|
||||||
Term::CapturingGroup(group) => {
|
|
||||||
f(term);
|
|
||||||
visit_terms_disjunction(&group.body, f);
|
|
||||||
}
|
|
||||||
Term::IgnoreGroup(group) => {
|
|
||||||
f(term);
|
|
||||||
visit_terms_disjunction(&group.body, f);
|
|
||||||
}
|
|
||||||
_ => f(term),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue