@@ -9,7 +9,6 @@ use oxc_diagnostics::OxcDiagnostic;
99use oxc_ecmascript:: ToBigInt ;
1010use oxc_macros:: declare_oxc_lint;
1111use oxc_span:: { GetSpan , Span } ;
12- use regex:: Regex ;
1312
1413use crate :: { context:: LintContext , rule:: Rule , utils:: is_same_expression, AstNode } ;
1514
@@ -264,6 +263,7 @@ fn is_not_yoda(expr: &BinaryExpression) -> bool {
264263 && is_literal_or_simple_template_literal ( expr. right . get_inner_expression ( ) )
265264}
266265
266+ #[ allow( clippy:: cast_possible_truncation) ]
267267fn do_diagnostic_with_fix ( expr : & BinaryExpression , ctx : & LintContext , never : bool ) {
268268 ctx. diagnostic_with_fix ( yoda_diagnostic ( expr. span , never, expr. operator . as_str ( ) ) , |fix| {
269269 let flipped_operator = flip_operator ( expr. operator ) ;
@@ -273,29 +273,34 @@ fn do_diagnostic_with_fix(expr: &BinaryExpression, ctx: &LintContext, never: boo
273273 let flipped_operator_str = flipped_operator. as_str ( ) ;
274274
275275 let operator_str = expr. operator . as_str ( ) ;
276- let source_str = ctx. source_range ( expr. span ) ;
277- let regex = Regex :: new ( operator_str) . unwrap ( ) ;
278- let mut operator_position_start: u32 = 0 ;
279- let mut operator_position_end: u32 = 0 ;
280- for mat in regex. find_iter ( source_str) {
281- let start = u32:: try_from ( mat. start ( ) ) . unwrap ( ) ;
282- let end = u32:: try_from ( mat. end ( ) ) . unwrap ( ) ;
283-
284- let is_inside_comments = ctx. comments ( ) . iter ( ) . any ( |c| {
285- c. span . start <= start + expr. span . start && end + expr. span . start <= c. span . end
286- } ) ;
287-
288- if !is_inside_comments {
289- operator_position_start = start + expr. span . start ;
290- operator_position_end = end + expr. span . start ;
291- break ;
276+ let source_str = ctx. source_range (
277+ Span :: new ( expr. left . span ( ) . end , expr. right . span ( ) . start )
278+ ) ;
279+
280+ let source_chars = source_str. char_indices ( ) . collect :: < Vec < _ > > ( ) ;
281+
282+ let search_start_position = expr. left . span ( ) . end ;
283+
284+ let operator_position_start = source_chars. windows ( operator_str. len ( ) ) . find ( |str| {
285+ if str. iter ( ) . enumerate ( ) . all ( |( i, ( _pos, c) ) | * c == operator_str. chars ( ) . nth ( i) . unwrap ( ) ) {
286+ !ctx. comments ( ) . iter ( ) . any ( |c| {
287+ c. span . start <= ( str[ 0 ] . 0 as u32 ) + search_start_position && ( str[ 0 ] . 0 as u32 ) + operator_str. len ( ) as u32 + search_start_position <= c. span . end
288+ } )
289+ } else {
290+ false
292291 }
293- }
292+ } ) ;
293+
294+ let Some ( operator_position_start) = operator_position_start else {
295+ debug_assert ! ( false ) ;
296+ return fix. noop ( ) ;
297+ } ;
298+
299+ let operator_position_start = search_start_position + operator_position_start[ 0 ] . 0 as u32 ;
294300
295- let str_between_left_and_operator =
296- ctx. source_range ( Span :: new ( expr. left . span ( ) . end , operator_position_start) ) ;
297- let str_between_operator_and_right =
298- ctx. source_range ( Span :: new ( operator_position_end, expr. right . span ( ) . start ) ) ;
301+ let operator_position_end = operator_position_start + operator_str. len ( ) as u32 ;
302+ let str_between_left_and_operator = ctx. source_range ( Span :: new ( expr. left . span ( ) . end , operator_position_start) ) ;
303+ let str_between_operator_and_right = ctx. source_range ( Span :: new ( operator_position_end, expr. right . span ( ) . start ) ) ;
299304
300305 let left_start = expr. left . span ( ) . start ;
301306 let left_prev_token = if left_start > 0 && ( expr. right . is_literal ( ) || expr. right . is_identifier_reference ( ) ) {
@@ -1156,6 +1161,7 @@ fn test() {
11561161 "if (a > 0 && b < max) {}" ,
11571162 Some ( serde_json:: json!( [ "never" , { "exceptRange" : true } ] ) ) ,
11581163 ) ,
1164+ ( "y>E>1" , "1<y>E" , Some ( serde_json:: json!( [ "always" , { "exceptRange" : false } ] ) ) ) ,
11591165 ] ;
11601166 Tester :: new ( Yoda :: NAME , Yoda :: CATEGORY , pass, fail) . expect_fix ( fix) . test_and_snapshot ( ) ;
11611167}
0 commit comments