1
1
use oxc_ast:: {
2
2
AstKind ,
3
- ast:: { CallExpression , Expression , MemberExpression } ,
3
+ ast:: { CallExpression , Expression } ,
4
4
} ;
5
5
use oxc_diagnostics:: OxcDiagnostic ;
6
6
use oxc_macros:: declare_oxc_lint;
7
7
use oxc_semantic:: ScopeId ;
8
8
use oxc_span:: { GetSpan , Span } ;
9
9
10
- use crate :: { AstNode , context:: LintContext , rule:: Rule } ;
10
+ use crate :: { AstNode , context:: LintContext , rule:: Rule , utils :: is_promise } ;
11
11
12
12
fn no_nesting_diagnostic ( span : Span ) -> OxcDiagnostic {
13
13
OxcDiagnostic :: warn ( "Avoid nesting promises." )
@@ -32,26 +32,20 @@ declare_oxc_lint!(
32
32
/// Examples of **incorrect** code for this rule:
33
33
/// ```javascript
34
34
/// doThing().then(() => a.then())
35
- /// ```
36
35
///
37
- /// ```javascript
38
36
/// doThing().then(function() { a.then() })
39
- /// ```
40
37
///
41
- /// ```javascript
42
38
/// doThing().then(() => { b.catch() })
39
+ ///
40
+ /// doThing().catch((val) => doSomething(val).catch(errors))
43
41
/// ```
44
42
///
45
43
/// Examples of **correct** code for this rule:
46
44
/// ```javascript
47
45
/// doThing().then(() => 4)
48
- /// ```
49
46
///
50
- /// ```javascript
51
47
/// doThing().then(function() { return 4 })
52
- /// ```
53
48
///
54
- /// ```javascript
55
49
/// doThing().catch(() => 4)
56
50
/// ```
57
51
///
@@ -82,10 +76,11 @@ fn is_inside_promise(node: &AstNode, ctx: &LintContext) -> bool {
82
76
return false ;
83
77
}
84
78
85
- ctx. nodes ( )
86
- . ancestors ( node. id ( ) )
87
- . nth ( 2 )
88
- . is_some_and ( |node| node. kind ( ) . as_call_expression ( ) . is_some_and ( has_promise_callback) )
79
+ ctx. nodes ( ) . ancestors ( node. id ( ) ) . nth ( 2 ) . is_some_and ( |node| {
80
+ node. kind ( ) . as_call_expression ( ) . is_some_and ( |a| {
81
+ is_promise ( a) . is_some_and ( |prop_name| prop_name == "then" || prop_name == "catch" )
82
+ } )
83
+ } )
89
84
}
90
85
91
86
/// Gets the closest promise callback function of the nested promise.
@@ -96,27 +91,13 @@ fn closest_promise_cb<'a, 'b>(
96
91
ctx. nodes ( )
97
92
. ancestors ( node. id ( ) )
98
93
. filter_map ( |node| node. kind ( ) . as_call_expression ( ) )
99
- . filter ( |a| has_promise_callback ( a) )
94
+ . filter ( |ancestor| {
95
+ is_promise ( ancestor)
96
+ . is_some_and ( |prop_name| prop_name == "then" || prop_name == "catch" )
97
+ } )
100
98
. nth ( 1 )
101
99
}
102
100
103
- fn has_promise_callback ( call_expr : & CallExpression ) -> bool {
104
- matches ! (
105
- call_expr. callee. as_member_expression( ) . and_then( MemberExpression :: static_property_name) ,
106
- Some ( "then" | "catch" )
107
- )
108
- }
109
-
110
- fn is_promise_then_or_catch ( call_expr : & CallExpression ) -> bool {
111
- let Some ( member_expr) = call_expr. callee . get_member_expr ( ) else {
112
- return false ;
113
- } ;
114
-
115
- member_expr
116
- . static_property_name ( )
117
- . map_or_else ( || false , |prop_name| matches ! ( prop_name, "then" | "catch" ) )
118
- }
119
-
120
101
/// Checks if we can safely unnest the promise callback.
121
102
///
122
103
/// 1. This function gets variable bindings defined in closest parent promise callback function
@@ -205,7 +186,9 @@ impl Rule for NoNesting {
205
186
return ;
206
187
} ;
207
188
208
- if !is_promise_then_or_catch ( call_expr) {
189
+ if !is_promise ( call_expr)
190
+ . is_some_and ( |prop_name| prop_name == "then" || prop_name == "catch" )
191
+ {
209
192
return ;
210
193
} ;
211
194
@@ -284,6 +267,8 @@ fn test() {
284
267
"doThing().then(() => { b.catch() })" ,
285
268
"doThing().then(() => a.then())" ,
286
269
"doThing().then(() => b.catch())" ,
270
+ "doThing().then((val) => doSomething(val).catch(errors))" ,
271
+ "doThing().catch((val) => doSomething(val).catch(errors))" ,
287
272
"doThing()
288
273
.then(() =>
289
274
a.then(() => Promise.resolve(1)))" ,
0 commit comments