mirror of
https://github.com/swc-project/swc.git
synced 2024-11-28 02:29:04 +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")]
|
#[cfg(feature = "non_critical_lints")]
|
||||||
#[serde(default, alias = "defaultCaseLast")]
|
#[serde(default, alias = "defaultCaseLast")]
|
||||||
pub default_case_last: RuleConfig<()>,
|
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 dot_notation;
|
||||||
pub mod eqeqeq;
|
pub mod eqeqeq;
|
||||||
pub mod no_alert;
|
pub mod no_alert;
|
||||||
|
pub mod no_await_in_loop;
|
||||||
pub mod no_bitwise;
|
pub mod no_bitwise;
|
||||||
pub mod no_compare_neg_zero;
|
pub mod no_compare_neg_zero;
|
||||||
pub mod no_console;
|
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(
|
rules.extend(default_case_last::default_case_last(
|
||||||
&lint_config.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
|
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