1
1
use oxc_ast:: {
2
2
AstKind ,
3
- ast:: { ArrowFunctionExpression , AwaitExpression , ForOfStatement , Function , PropertyKey } ,
3
+ ast:: {
4
+ ArrowFunctionExpression , AwaitExpression , ForOfStatement , Function , FunctionType ,
5
+ MethodDefinition , ObjectProperty , PropertyKey ,
6
+ } ,
4
7
} ;
5
8
use oxc_ast_visit:: { Visit , walk:: walk_for_of_statement} ;
6
9
use oxc_diagnostics:: OxcDiagnostic ;
7
10
use oxc_macros:: declare_oxc_lint;
8
11
use oxc_semantic:: ScopeFlags ;
9
- use oxc_span:: Span ;
12
+ use oxc_span:: { GetSpan , Span } ;
10
13
11
14
use crate :: { AstNode , context:: LintContext , rule:: Rule } ;
12
15
13
16
#[ derive( Debug , Default , Clone ) ]
14
17
pub struct RequireAwait ;
15
18
16
19
fn require_await_diagnostic ( span : Span ) -> OxcDiagnostic {
17
- OxcDiagnostic :: warn ( "Async function has no 'await' expression." ) . with_label ( span)
20
+ OxcDiagnostic :: warn ( "Async function has no 'await' expression." )
21
+ . with_help ( "Consider removing the 'async' keyword." )
22
+ . with_label ( span)
18
23
}
19
24
20
25
declare_oxc_lint ! (
@@ -70,6 +75,7 @@ declare_oxc_lint!(
70
75
RequireAwait ,
71
76
eslint,
72
77
pedantic,
78
+ fix_dangerous
73
79
) ;
74
80
75
81
impl Rule for RequireAwait {
@@ -90,18 +96,41 @@ impl Rule for RequireAwait {
90
96
let mut finder = AwaitFinder { found : false } ;
91
97
finder. visit_function_body ( body) ;
92
98
if !finder. found {
93
- if let Some ( AstKind :: ObjectProperty ( p) ) =
94
- ctx. nodes ( ) . parent_kind ( parent. id ( ) )
95
- {
96
- if let PropertyKey :: StaticIdentifier ( iden) = & p. key {
97
- ctx. diagnostic ( require_await_diagnostic ( iden. span ) ) ;
99
+ if matches ! ( func. r#type, FunctionType :: FunctionDeclaration ) {
100
+ let need_delete_span = get_delete_span ( ctx, func. span . start ) ;
101
+ ctx. diagnostic_with_dangerous_fix (
102
+ require_await_diagnostic (
103
+ func. id . as_ref ( ) . map_or ( func. span , |ident| ident. span ) ,
104
+ ) ,
105
+ |fixer| fixer. delete_range ( need_delete_span) ,
106
+ ) ;
107
+ } else {
108
+ let parent_parent_node = ctx. nodes ( ) . parent_kind ( parent. id ( ) ) ;
109
+ if let Some (
110
+ AstKind :: ObjectProperty ( ObjectProperty { span, key, .. } )
111
+ | AstKind :: MethodDefinition ( MethodDefinition { span, key, .. } ) ,
112
+ ) = parent_parent_node
113
+ {
114
+ let need_delete_span = get_delete_span ( ctx, span. start ) ;
115
+ let check_span = if matches ! ( key, PropertyKey :: StaticIdentifier ( _) )
116
+ {
117
+ key. span ( )
118
+ } else {
119
+ func. span
120
+ } ;
121
+ ctx. diagnostic_with_dangerous_fix (
122
+ require_await_diagnostic ( check_span) ,
123
+ |fixer| fixer. delete_range ( need_delete_span) ,
124
+ ) ;
98
125
} else {
99
- ctx. diagnostic ( require_await_diagnostic ( func. span ) ) ;
126
+ let need_delete_span = get_delete_span ( ctx, func. span . start ) ;
127
+ ctx. diagnostic_with_dangerous_fix (
128
+ require_await_diagnostic (
129
+ func. id . as_ref ( ) . map_or ( func. span , |ident| ident. span ) ,
130
+ ) ,
131
+ |fixer| fixer. delete_range ( need_delete_span) ,
132
+ ) ;
100
133
}
101
- } else {
102
- ctx. diagnostic ( require_await_diagnostic (
103
- func. id . as_ref ( ) . map_or ( func. span , |ident| ident. span ) ,
104
- ) ) ;
105
134
}
106
135
}
107
136
}
@@ -111,7 +140,11 @@ impl Rule for RequireAwait {
111
140
let mut finder = AwaitFinder { found : false } ;
112
141
finder. visit_function_body ( body) ;
113
142
if !finder. found {
114
- ctx. diagnostic ( require_await_diagnostic ( func. span ) ) ;
143
+ let need_delete_span = get_delete_span ( ctx, func. span . start ) ;
144
+ ctx. diagnostic_with_dangerous_fix (
145
+ require_await_diagnostic ( func. span ) ,
146
+ |fixer| fixer. delete_range ( need_delete_span) ,
147
+ ) ;
115
148
}
116
149
}
117
150
}
@@ -120,6 +153,19 @@ impl Rule for RequireAwait {
120
153
}
121
154
}
122
155
156
+ fn get_delete_span ( ctx : & LintContext , start : u32 ) -> Span {
157
+ let end = start + 5 ;
158
+ let async_key_span = Span :: new ( start, end) ;
159
+ let mut offset: u32 = 0 ;
160
+ for c in ctx. source_text ( ) [ ( end as usize ) ..] . chars ( ) {
161
+ if !c. is_whitespace ( ) {
162
+ break ;
163
+ }
164
+ offset += 1 ;
165
+ }
166
+ async_key_span. expand_right ( offset)
167
+ }
168
+
123
169
struct AwaitFinder {
124
170
found : bool ,
125
171
}
@@ -209,5 +255,40 @@ fn test() {
209
255
"async function foo() { await (async () => { doSomething() }) }" ,
210
256
] ;
211
257
212
- Tester :: new ( RequireAwait :: NAME , RequireAwait :: PLUGIN , pass, fail) . test_and_snapshot ( ) ;
258
+ let fix = vec ! [
259
+ ( "const a =async() => { let v = 3 ;}" , "const a =() => { let v = 3 ;}" ) ,
260
+ ( "const a = async () => { let v = 3 }" , "const a = () => { let v = 3 }" ) ,
261
+ ( "async function foo() { doSomething() }" , "function foo() { doSomething() }" ) ,
262
+ ( "(async function() { doSomething() })" , "(function() { doSomething() })" ) ,
263
+ ( "async () => { doSomething() }" , "() => { doSomething() }" ) ,
264
+ ( "async () => doSomething()" , "() => doSomething()" ) ,
265
+ ( "({ async foo() { doSomething() } })" , "({ foo() { doSomething() } })" ) ,
266
+ ( "class A { async foo() { doSomething() } }" , "class A { foo() { doSomething() } }" ) ,
267
+ ( "(class { async ''() { doSomething() } })" , "(class { ''() { doSomething() } })" ) ,
268
+ (
269
+ "async function foo() { async () => { await doSomething() } }" ,
270
+ "function foo() { async () => { await doSomething() } }" ,
271
+ ) ,
272
+ (
273
+ "async function foo() { await (async () => { doSomething() }) }" ,
274
+ "async function foo() { await (() => { doSomething() }) }" ,
275
+ ) ,
276
+ (
277
+ "async /** comments */ function name() { doSomething() }" ,
278
+ "/** comments */ function name() { doSomething() }" ,
279
+ ) ,
280
+ ( "async function foo() { doSomething() }" , "function foo() { doSomething() }" ) ,
281
+ (
282
+ "async /** cc */ function foo() { doSomething() }" ,
283
+ "/** cc */ function foo() { doSomething() }" ,
284
+ ) ,
285
+ (
286
+ "let a = { c: async () => { let c }, t:async()=>{ let r } }" ,
287
+ "let a = { c: () => { let c }, t:()=>{ let r } }" ,
288
+ ) ,
289
+ ] ;
290
+
291
+ Tester :: new ( RequireAwait :: NAME , RequireAwait :: PLUGIN , pass, fail)
292
+ . expect_fix ( fix)
293
+ . test_and_snapshot ( ) ;
213
294
}
0 commit comments