11use oxc_ast:: {
22 AstKind ,
3- ast:: { ArrowFunctionExpression , AwaitExpression , ForOfStatement , Function , PropertyKey } ,
3+ ast:: {
4+ ArrowFunctionExpression , AwaitExpression , ForOfStatement , Function , FunctionType ,
5+ MethodDefinition , ObjectProperty , PropertyKey ,
6+ } ,
47} ;
58use oxc_ast_visit:: { Visit , walk:: walk_for_of_statement} ;
69use oxc_diagnostics:: OxcDiagnostic ;
710use oxc_macros:: declare_oxc_lint;
811use oxc_semantic:: ScopeFlags ;
9- use oxc_span:: Span ;
12+ use oxc_span:: { GetSpan , Span } ;
1013
1114use crate :: { AstNode , context:: LintContext , rule:: Rule } ;
1215
1316#[ derive( Debug , Default , Clone ) ]
1417pub struct RequireAwait ;
1518
1619fn 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)
1823}
1924
2025declare_oxc_lint ! (
@@ -70,6 +75,7 @@ declare_oxc_lint!(
7075 RequireAwait ,
7176 eslint,
7277 pedantic,
78+ fix_dangerous
7379) ;
7480
7581impl Rule for RequireAwait {
@@ -90,18 +96,41 @@ impl Rule for RequireAwait {
9096 let mut finder = AwaitFinder { found : false } ;
9197 finder. visit_function_body ( body) ;
9298 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+ ) ;
98125 } 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+ ) ;
100133 }
101- } else {
102- ctx. diagnostic ( require_await_diagnostic (
103- func. id . as_ref ( ) . map_or ( func. span , |ident| ident. span ) ,
104- ) ) ;
105134 }
106135 }
107136 }
@@ -111,7 +140,11 @@ impl Rule for RequireAwait {
111140 let mut finder = AwaitFinder { found : false } ;
112141 finder. visit_function_body ( body) ;
113142 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+ ) ;
115148 }
116149 }
117150 }
@@ -120,6 +153,19 @@ impl Rule for RequireAwait {
120153 }
121154}
122155
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+
123169struct AwaitFinder {
124170 found : bool ,
125171}
@@ -209,5 +255,40 @@ fn test() {
209255 "async function foo() { await (async () => { doSomething() }) }" ,
210256 ] ;
211257
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 ( ) ;
213294}
0 commit comments