mirror of
https://github.com/swc-project/swc.git
synced 2024-12-25 14:43:33 +03:00
feat(es/lints): Add no-await-in-loop
rule (#4936)
This commit is contained in:
parent
6fdf84da15
commit
b041f2911f
@ -0,0 +1,9 @@
|
||||
{
|
||||
"jsc": {
|
||||
"lints": {
|
||||
"no-await-in-loop": [
|
||||
"error"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
async function foo() { while (baz) { await bar; } }
|
||||
async function foo() { while (await foo()) { } }
|
||||
async function foo() { while (baz) { for await (x of xs); } }
|
||||
async function foo() { for (var bar of baz) { await bar; } }
|
||||
async function foo() { for (var bar of baz) await bar; }
|
||||
async function foo() { for (var bar in baz) { await bar; } }
|
||||
async function foo() { for (var i; i < n; i++) { await bar; } }
|
||||
async function foo() { for (var i; await foo(i); i++) { } }
|
||||
async function foo() { for (var i; i < n; i = await bar) { } }
|
||||
async function foo() { do { await bar; } while (baz); }
|
||||
async function foo() { do { } while (await bar); }
|
||||
async function foo() { while (true) { if (bar) { foo(await bar); } } }
|
||||
async function foo() { while (xyz || 5 > await x) { } }
|
||||
async function foo() { for await (var x of xs) { while (1) await f(x) } }
|
||||
|
||||
// valid
|
||||
async function foo() { await bar; }
|
||||
async function foo() { for (var bar in await baz) { } }
|
||||
async function foo() { for (var bar of await baz) { } }
|
||||
async function foo() { for await (var bar of await baz) { } }
|
||||
async function foo() { while (true) { async function foo() { await bar; } } }
|
||||
async function foo() { for (var i = await bar; i < n; i++) { } }
|
||||
async function foo() { do { } while (bar); }
|
||||
async function foo() { while (true) { var y = async function () { await bar; } } }
|
||||
async function foo() { while (true) { var y = async () => await foo; } }
|
||||
async function foo() { while (true) { var y = async () => { await foo; } } }
|
||||
async function foo() { while (true) { class Foo { async foo() { await bar; } } } }
|
||||
async function foo() { while (true) { class Foo { async foo() { await bar; } } } }
|
||||
async function foo() { for await (var x of xs) { await f(x) } }
|
@ -0,0 +1,84 @@
|
||||
|
||||
x Unexpected `await` inside a loop
|
||||
,----
|
||||
1 | async function foo() { while (baz) { await bar; } }
|
||||
: ^^^^^^^^^
|
||||
`----
|
||||
|
||||
x Unexpected `await` inside a loop
|
||||
,----
|
||||
2 | async function foo() { while (await foo()) { } }
|
||||
: ^^^^^^^^^^^
|
||||
`----
|
||||
|
||||
x Unexpected `await` inside a loop
|
||||
,----
|
||||
3 | async function foo() { while (baz) { for await (x of xs); } }
|
||||
: ^^^^^^^^^^^^^^^^^^^^
|
||||
`----
|
||||
|
||||
x Unexpected `await` inside a loop
|
||||
,----
|
||||
4 | async function foo() { for (var bar of baz) { await bar; } }
|
||||
: ^^^^^^^^^
|
||||
`----
|
||||
|
||||
x Unexpected `await` inside a loop
|
||||
,----
|
||||
5 | async function foo() { for (var bar of baz) await bar; }
|
||||
: ^^^^^^^^^
|
||||
`----
|
||||
|
||||
x Unexpected `await` inside a loop
|
||||
,----
|
||||
6 | async function foo() { for (var bar in baz) { await bar; } }
|
||||
: ^^^^^^^^^
|
||||
`----
|
||||
|
||||
x Unexpected `await` inside a loop
|
||||
,----
|
||||
7 | async function foo() { for (var i; i < n; i++) { await bar; } }
|
||||
: ^^^^^^^^^
|
||||
`----
|
||||
|
||||
x Unexpected `await` inside a loop
|
||||
,----
|
||||
8 | async function foo() { for (var i; await foo(i); i++) { } }
|
||||
: ^^^^^^^^^^^^
|
||||
`----
|
||||
|
||||
x Unexpected `await` inside a loop
|
||||
,----
|
||||
9 | async function foo() { for (var i; i < n; i = await bar) { } }
|
||||
: ^^^^^^^^^
|
||||
`----
|
||||
|
||||
x Unexpected `await` inside a loop
|
||||
,----
|
||||
10 | async function foo() { do { await bar; } while (baz); }
|
||||
: ^^^^^^^^^
|
||||
`----
|
||||
|
||||
x Unexpected `await` inside a loop
|
||||
,----
|
||||
11 | async function foo() { do { } while (await bar); }
|
||||
: ^^^^^^^^^
|
||||
`----
|
||||
|
||||
x Unexpected `await` inside a loop
|
||||
,----
|
||||
12 | async function foo() { while (true) { if (bar) { foo(await bar); } } }
|
||||
: ^^^^^^^^^
|
||||
`----
|
||||
|
||||
x Unexpected `await` inside a loop
|
||||
,----
|
||||
13 | async function foo() { while (xyz || 5 > await x) { } }
|
||||
: ^^^^^^^
|
||||
`----
|
||||
|
||||
x Unexpected `await` inside a loop
|
||||
,----
|
||||
14 | async function foo() { for await (var x of xs) { while (1) await f(x) } }
|
||||
: ^^^^^^^^^^
|
||||
`----
|
@ -203,4 +203,8 @@ pub struct LintConfig {
|
||||
#[cfg(feature = "non_critical_lints")]
|
||||
#[serde(default, alias = "defaultCaseLast")]
|
||||
pub default_case_last: RuleConfig<()>,
|
||||
|
||||
#[cfg(feature = "non_critical_lints")]
|
||||
#[serde(default, alias = "noAwaitInLoop")]
|
||||
pub no_await_in_loop: RuleConfig<()>,
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ pub(crate) mod non_critical_lints {
|
||||
pub mod dot_notation;
|
||||
pub mod eqeqeq;
|
||||
pub mod no_alert;
|
||||
pub mod no_await_in_loop;
|
||||
pub mod no_bitwise;
|
||||
pub mod no_compare_neg_zero;
|
||||
pub mod no_console;
|
||||
@ -181,6 +182,10 @@ pub fn all(lint_params: LintParams) -> Vec<Box<dyn Rule>> {
|
||||
rules.extend(default_case_last::default_case_last(
|
||||
&lint_config.default_case_last,
|
||||
));
|
||||
|
||||
rules.extend(no_await_in_loop::no_await_in_loop(
|
||||
&lint_config.no_await_in_loop,
|
||||
));
|
||||
}
|
||||
|
||||
rules
|
||||
|
139
crates/swc_ecma_lints/src/rules/no_await_in_loop.rs
Normal file
139
crates/swc_ecma_lints/src/rules/no_await_in_loop.rs
Normal file
@ -0,0 +1,139 @@
|
||||
use swc_common::{errors::HANDLER, Span};
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_visit::{Visit, VisitWith};
|
||||
|
||||
use crate::{
|
||||
config::{LintRuleReaction, RuleConfig},
|
||||
rule::{visitor_rule, Rule},
|
||||
};
|
||||
|
||||
const MESSAGE: &str = "Unexpected `await` inside a loop";
|
||||
|
||||
pub fn no_await_in_loop(config: &RuleConfig<()>) -> Option<Box<dyn Rule>> {
|
||||
let rule_reaction = config.get_rule_reaction();
|
||||
|
||||
match rule_reaction {
|
||||
LintRuleReaction::Off => None,
|
||||
_ => Some(visitor_rule(NoAwaitInLoop::new(rule_reaction))),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct NoAwaitInLoop {
|
||||
expected_reaction: LintRuleReaction,
|
||||
await_restricted: bool,
|
||||
}
|
||||
|
||||
impl NoAwaitInLoop {
|
||||
fn new(expected_reaction: LintRuleReaction) -> Self {
|
||||
Self {
|
||||
expected_reaction,
|
||||
await_restricted: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_report(&self, span: Span) {
|
||||
HANDLER.with(|handler| match self.expected_reaction {
|
||||
LintRuleReaction::Error => {
|
||||
handler.struct_span_err(span, MESSAGE).emit();
|
||||
}
|
||||
LintRuleReaction::Warning => {
|
||||
handler.struct_span_warn(span, MESSAGE).emit();
|
||||
}
|
||||
_ => {}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit for NoAwaitInLoop {
|
||||
fn visit_for_stmt(&mut self, for_stmt: &ForStmt) {
|
||||
let prev_await_restriction = self.await_restricted;
|
||||
|
||||
for_stmt.init.visit_children_with(self);
|
||||
|
||||
self.await_restricted = true;
|
||||
|
||||
for_stmt.test.visit_children_with(self);
|
||||
for_stmt.update.visit_children_with(self);
|
||||
for_stmt.body.visit_children_with(self);
|
||||
|
||||
self.await_restricted = prev_await_restriction;
|
||||
}
|
||||
|
||||
fn visit_do_while_stmt(&mut self, do_while_stmt: &DoWhileStmt) {
|
||||
let prev_await_restriction = self.await_restricted;
|
||||
|
||||
self.await_restricted = true;
|
||||
|
||||
do_while_stmt.body.visit_children_with(self);
|
||||
do_while_stmt.test.visit_children_with(self);
|
||||
|
||||
self.await_restricted = prev_await_restriction;
|
||||
}
|
||||
|
||||
fn visit_for_in_stmt(&mut self, for_in_stmt: &ForInStmt) {
|
||||
let prev_await_restriction = self.await_restricted;
|
||||
|
||||
for_in_stmt.left.visit_children_with(self);
|
||||
for_in_stmt.right.visit_children_with(self);
|
||||
|
||||
self.await_restricted = true;
|
||||
|
||||
for_in_stmt.body.visit_children_with(self);
|
||||
|
||||
self.await_restricted = prev_await_restriction;
|
||||
}
|
||||
|
||||
fn visit_for_of_stmt(&mut self, for_of_stmt: &ForOfStmt) {
|
||||
let prev_await_restriction = self.await_restricted;
|
||||
|
||||
if self.await_restricted {
|
||||
self.emit_report(for_of_stmt.span);
|
||||
}
|
||||
|
||||
for_of_stmt.left.visit_children_with(self);
|
||||
for_of_stmt.right.visit_children_with(self);
|
||||
|
||||
self.await_restricted = for_of_stmt.await_token.is_none();
|
||||
|
||||
for_of_stmt.body.visit_children_with(self);
|
||||
|
||||
self.await_restricted = prev_await_restriction;
|
||||
}
|
||||
|
||||
fn visit_while_stmt(&mut self, while_stmt: &WhileStmt) {
|
||||
let prev_await_restriction = self.await_restricted;
|
||||
self.await_restricted = true;
|
||||
|
||||
while_stmt.test.visit_children_with(self);
|
||||
while_stmt.body.visit_children_with(self);
|
||||
|
||||
self.await_restricted = prev_await_restriction;
|
||||
}
|
||||
|
||||
fn visit_await_expr(&mut self, await_expr: &AwaitExpr) {
|
||||
if self.await_restricted {
|
||||
self.emit_report(await_expr.span);
|
||||
}
|
||||
|
||||
await_expr.visit_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_function(&mut self, function: &Function) {
|
||||
let prev_await_restriction = self.await_restricted;
|
||||
self.await_restricted = false;
|
||||
|
||||
function.visit_children_with(self);
|
||||
|
||||
self.await_restricted = prev_await_restriction;
|
||||
}
|
||||
|
||||
fn visit_arrow_expr(&mut self, arrow_expr: &ArrowExpr) {
|
||||
let prev_await_restriction = self.await_restricted;
|
||||
self.await_restricted = false;
|
||||
|
||||
arrow_expr.visit_children_with(self);
|
||||
|
||||
self.await_restricted = prev_await_restriction;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user