@@ -7,7 +7,7 @@ use oxc_macros::declare_oxc_lint;
7
7
use oxc_span:: { GetSpan , Span } ;
8
8
use phf:: { phf_set, Set } ;
9
9
10
- use crate :: { context:: LintContext , rule:: Rule , AstNode } ;
10
+ use crate :: { ast_util :: outermost_paren_parent , context:: LintContext , rule:: Rule , AstNode } ;
11
11
12
12
fn use_jest_mocked ( span : Span ) -> OxcDiagnostic {
13
13
OxcDiagnostic :: warn ( "Prefer `jest.mocked()` over `fn as jest.Mock`." )
@@ -51,17 +51,17 @@ declare_oxc_lint!(
51
51
/// ```
52
52
PreferJestMocked ,
53
53
style,
54
- fix
54
+ conditional_fix
55
55
) ;
56
56
57
57
impl Rule for PreferJestMocked {
58
- fn run ( & self , node : & AstNode , ctx : & LintContext ) {
58
+ fn run < ' a > ( & self , node : & AstNode < ' a > , ctx : & LintContext < ' a > ) {
59
59
if let AstKind :: TSAsExpression ( ts_expr) = node. kind ( ) {
60
60
if !matches ! ( ctx. nodes( ) . parent_kind( node. id( ) ) , Some ( AstKind :: TSAsExpression ( _) ) ) {
61
- Self :: check_ts_as_expression ( ts_expr, ctx) ;
61
+ Self :: check_ts_as_expression ( node , ts_expr, ctx) ;
62
62
}
63
63
} else if let AstKind :: TSTypeAssertion ( assert_type) = node. kind ( ) {
64
- Self :: check_assert_type ( assert_type, ctx) ;
64
+ Self :: check_assert_type ( node , assert_type, ctx) ;
65
65
}
66
66
}
67
67
}
@@ -74,23 +74,37 @@ const MOCK_TYPES: Set<&'static str> = phf_set! {
74
74
} ;
75
75
76
76
impl PreferJestMocked {
77
- fn check_ts_as_expression ( as_expr : & TSAsExpression , ctx : & LintContext ) {
77
+ fn check_ts_as_expression < ' a > (
78
+ node : & AstNode < ' a > ,
79
+ as_expr : & TSAsExpression ,
80
+ ctx : & LintContext < ' a > ,
81
+ ) {
78
82
let TSType :: TSTypeReference ( ts_reference) = & as_expr. type_annotation else {
79
83
return ;
80
84
} ;
81
85
let arg_span = as_expr. expression . get_inner_expression ( ) . span ( ) ;
82
- Self :: check ( ts_reference, arg_span, as_expr. span , ctx) ;
86
+ Self :: check ( node , ts_reference, arg_span, as_expr. span , ctx) ;
83
87
}
84
88
85
- fn check_assert_type ( assert_type : & TSTypeAssertion , ctx : & LintContext ) {
89
+ fn check_assert_type < ' a > (
90
+ node : & AstNode < ' a > ,
91
+ assert_type : & TSTypeAssertion ,
92
+ ctx : & LintContext < ' a > ,
93
+ ) {
86
94
let TSType :: TSTypeReference ( ts_reference) = & assert_type. type_annotation else {
87
95
return ;
88
96
} ;
89
97
let arg_span = assert_type. expression . get_inner_expression ( ) . span ( ) ;
90
- Self :: check ( ts_reference, arg_span, assert_type. span , ctx) ;
98
+ Self :: check ( node , ts_reference, arg_span, assert_type. span , ctx) ;
91
99
}
92
100
93
- fn check ( ts_reference : & TSTypeReference , arg_span : Span , span : Span , ctx : & LintContext ) {
101
+ fn check < ' a > (
102
+ node : & AstNode < ' a > ,
103
+ ts_reference : & TSTypeReference ,
104
+ arg_span : Span ,
105
+ span : Span ,
106
+ ctx : & LintContext < ' a > ,
107
+ ) {
94
108
let TSTypeName :: QualifiedName ( qualified_name) = & ts_reference. type_name else {
95
109
return ;
96
110
} ;
@@ -104,13 +118,22 @@ impl PreferJestMocked {
104
118
return ;
105
119
}
106
120
107
- ctx. diagnostic_with_fix ( use_jest_mocked ( span) , |fixer| {
108
- let span_source_code = fixer. source_range ( arg_span) ;
109
- fixer. replace ( span, format ! ( "jest.mocked({span_source_code})" ) )
110
- } ) ;
121
+ if can_fix ( node, ctx) {
122
+ ctx. diagnostic_with_fix ( use_jest_mocked ( span) , |fixer| {
123
+ let span_source_code = fixer. source_range ( arg_span) ;
124
+ fixer. replace ( span, format ! ( "jest.mocked({span_source_code})" ) )
125
+ } ) ;
126
+ } else {
127
+ ctx. diagnostic ( use_jest_mocked ( span) ) ;
128
+ }
111
129
}
112
130
}
113
131
132
+ fn can_fix < ' a > ( node : & AstNode < ' a > , ctx : & LintContext < ' a > ) -> bool {
133
+ outermost_paren_parent ( node, ctx)
134
+ . map_or ( false , |parent| !matches ! ( parent. kind( ) , AstKind :: SimpleAssignmentTarget ( _) ) )
135
+ }
136
+
114
137
#[ test]
115
138
fn test ( ) {
116
139
use crate :: tester:: Tester ;
@@ -320,6 +343,9 @@ fn test() {
320
343
).mockReturnValue(1);
321
344
" ,
322
345
) ,
346
+ // we can't fix this case, as fixing it would result in a syntax error
347
+ // (we'd be attempting attempting to assign `jest.fn()` to invalid left-hand side)
348
+ ( "(foo as jest.Mock) = jest.fn();" , "(foo as jest.Mock) = jest.fn();" ) ,
323
349
] ;
324
350
325
351
Tester :: new ( PreferJestMocked :: NAME , pass, fail)
0 commit comments