Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 53394a7

Browse files
feat(linter): add auto-fix for eslint/require-await (#10624)
related #10477
1 parent 966fb03 commit 53394a7

File tree

2 files changed

+110
-19
lines changed

2 files changed

+110
-19
lines changed

crates/oxc_linter/src/rules/eslint/require_await.rs

Lines changed: 96 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,25 @@
11
use 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
};
58
use oxc_ast_visit::{Visit, walk::walk_for_of_statement};
69
use oxc_diagnostics::OxcDiagnostic;
710
use oxc_macros::declare_oxc_lint;
811
use oxc_semantic::ScopeFlags;
9-
use oxc_span::Span;
12+
use oxc_span::{GetSpan, Span};
1013

1114
use crate::{AstNode, context::LintContext, rule::Rule};
1215

1316
#[derive(Debug, Default, Clone)]
1417
pub struct RequireAwait;
1518

1619
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)
1823
}
1924

2025
declare_oxc_lint!(
@@ -70,6 +75,7 @@ declare_oxc_lint!(
7075
RequireAwait,
7176
eslint,
7277
pedantic,
78+
fix_dangerous
7379
);
7480

7581
impl 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+
123169
struct 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
}

crates/oxc_linter/src/snapshots/eslint_require_await.snap

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,57 +6,67 @@ source: crates/oxc_linter/src/tester.rs
66
1 │ async function foo() { doSomething() }
77
· ───
88
╰────
9+
help: Consider removing the 'async' keyword.
910

1011
eslint(require-await): Async function has no 'await' expression.
1112
╭─[require_await.tsx:1:2]
1213
1 │ (async function() { doSomething() })
1314
· ──────────────────────────────────
1415
╰────
16+
help: Consider removing the 'async' keyword.
1517

1618
eslint(require-await): Async function has no 'await' expression.
1719
╭─[require_await.tsx:1:1]
1820
1 │ async () => { doSomething() }
1921
· ─────────────────────────────
2022
╰────
23+
help: Consider removing the 'async' keyword.
2124

2225
eslint(require-await): Async function has no 'await' expression.
2326
╭─[require_await.tsx:1:1]
2427
1 │ async () => doSomething()
2528
· ─────────────────────────
2629
╰────
30+
help: Consider removing the 'async' keyword.
2731

2832
⚠ eslint(require-await): Async function has no 'await' expression.
2933
╭─[require_await.tsx:1:10]
3034
1 │ ({ async foo() { doSomething() } })
3135
· ───
3236
╰────
37+
help: Consider removing the 'async' keyword.
3338

3439
⚠ eslint(require-await): Async function has no 'await' expression.
35-
╭─[require_await.tsx:1:20]
40+
╭─[require_await.tsx:1:17]
3641
1 │ class A { async foo() { doSomething() } }
37-
· ────────────────────
42+
· ───
3843
╰────
44+
help: Consider removing the 'async' keyword.
3945

4046
eslint(require-await): Async function has no 'await' expression.
41-
╭─[require_await.tsx:1:19]
47+
╭─[require_await.tsx:1:16]
4248
1 │ (class { async foo() { doSomething() } })
43-
· ────────────────────
49+
· ───
4450
╰────
51+
help: Consider removing the 'async' keyword.
4552

4653
⚠ eslint(require-await): Async function has no 'await' expression.
4754
╭─[require_await.tsx:1:18]
4855
1 │ (class { async ''() { doSomething() } })
4956
· ────────────────────
5057
╰────
58+
help: Consider removing the 'async' keyword.
5159

5260
⚠ eslint(require-await): Async function has no 'await' expression.
5361
╭─[require_await.tsx:1:16]
5462
1 │ async function foo() { async () => { await doSomething() } }
5563
· ───
5664
╰────
65+
help: Consider removing the 'async' keyword.
5766

5867
eslint(require-await): Async function has no 'await' expression.
5968
╭─[require_await.tsx:1:31]
6069
1 │ async function foo() { await (async () => { doSomething() }) }
6170
· ─────────────────────────────
6271
╰────
72+
help: Consider removing the 'async' keyword.

0 commit comments

Comments
 (0)