|
1 | 1 | use itertools::Itertools as _; |
2 | | -use oxc_allocator::Allocator; |
3 | | -use oxc_ast::{AstKind, ast::Argument}; |
4 | 2 | use oxc_diagnostics::OxcDiagnostic; |
5 | 3 | use oxc_macros::declare_oxc_lint; |
6 | 4 | use oxc_regular_expression::{ |
7 | | - ConstructorParser, Options, |
8 | 5 | ast::{CapturingGroup, Character, Pattern}, |
9 | 6 | visit::{Visit, walk}, |
10 | 7 | }; |
11 | 8 | use oxc_span::Span; |
12 | 9 |
|
13 | | -use crate::{AstNode, context::LintContext, rule::Rule}; |
| 10 | +use crate::{AstNode, context::LintContext, rule::Rule, utils::run_on_regex_node}; |
14 | 11 |
|
15 | 12 | fn no_control_regex_diagnostic(count: usize, regex: &str, span: Span) -> OxcDiagnostic { |
16 | 13 | debug_assert!(count > 0); |
@@ -71,77 +68,13 @@ declare_oxc_lint!( |
71 | 68 | ); |
72 | 69 |
|
73 | 70 | impl Rule for NoControlRegex { |
74 | | - fn run<'a>(&self, node: &AstNode<'a>, context: &LintContext<'a>) { |
75 | | - match node.kind() { |
76 | | - // regex literal |
77 | | - AstKind::RegExpLiteral(reg) => { |
78 | | - let Some(pattern) = reg.regex.pattern.as_pattern() else { |
79 | | - return; |
80 | | - }; |
81 | | - |
82 | | - check_pattern(context, pattern, reg.span); |
83 | | - } |
84 | | - |
85 | | - // new RegExp() |
86 | | - AstKind::NewExpression(expr) if expr.callee.is_specific_id("RegExp") => { |
87 | | - // note: improvements required for strings used via identifier references |
88 | | - // Missing or non-string arguments will be runtime errors, but are not covered by this rule. |
89 | | - match (&expr.arguments.first(), &expr.arguments.get(1)) { |
90 | | - ( |
91 | | - Some(Argument::StringLiteral(pattern)), |
92 | | - Some(Argument::StringLiteral(flags)), |
93 | | - ) => { |
94 | | - parse_and_check_regex(context, pattern.span, Some(flags.span)); |
95 | | - } |
96 | | - (Some(Argument::StringLiteral(pattern)), _) => { |
97 | | - parse_and_check_regex(context, pattern.span, None); |
98 | | - } |
99 | | - _ => {} |
100 | | - } |
101 | | - } |
102 | | - |
103 | | - // RegExp() |
104 | | - AstKind::CallExpression(expr) if expr.callee.is_specific_id("RegExp") => { |
105 | | - // note: improvements required for strings used via identifier references |
106 | | - // Missing or non-string arguments will be runtime errors, but are not covered by this rule. |
107 | | - match (&expr.arguments.first(), &expr.arguments.get(1)) { |
108 | | - ( |
109 | | - Some(Argument::StringLiteral(pattern)), |
110 | | - Some(Argument::StringLiteral(flags)), |
111 | | - ) => { |
112 | | - parse_and_check_regex(context, pattern.span, Some(flags.span)); |
113 | | - } |
114 | | - (Some(Argument::StringLiteral(pattern)), _) => { |
115 | | - parse_and_check_regex(context, pattern.span, None); |
116 | | - } |
117 | | - _ => {} |
118 | | - } |
119 | | - } |
120 | | - |
121 | | - _ => {} |
122 | | - } |
| 71 | + fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { |
| 72 | + run_on_regex_node(node, ctx, |pattern, span| { |
| 73 | + check_pattern(ctx, pattern, span); |
| 74 | + }); |
123 | 75 | } |
124 | 76 | } |
125 | 77 |
|
126 | | -fn parse_and_check_regex(ctx: &LintContext, pattern_span: Span, flags_span: Option<Span>) { |
127 | | - let allocator = Allocator::default(); |
128 | | - |
129 | | - let flags_text = flags_span.map(|span| span.source_text(ctx.source_text())); |
130 | | - let parser = ConstructorParser::new( |
131 | | - &allocator, |
132 | | - pattern_span.source_text(ctx.source_text()), |
133 | | - flags_text, |
134 | | - Options { |
135 | | - pattern_span_offset: pattern_span.start, |
136 | | - flags_span_offset: flags_span.map_or(0, |span| span.start), |
137 | | - }, |
138 | | - ); |
139 | | - let Ok(pattern) = parser.parse() else { |
140 | | - return; |
141 | | - }; |
142 | | - check_pattern(ctx, &pattern, pattern_span); |
143 | | -} |
144 | | - |
145 | 78 | fn check_pattern(context: &LintContext, pattern: &Pattern, span: Span) { |
146 | 79 | let mut finder = ControlCharacterFinder { |
147 | 80 | control_chars: Vec::new(), |
|
0 commit comments