mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(linter): Add "strict" option to promise/prefer-await-to-then rule (#8674)
Implementation of the strict option [specified in the eslint docs for `promise/prefer-await-to-then`](https://github.com/eslint-community/eslint-plugin-promise/blob/main/docs/rules/prefer-await-to-then.md) ```js // Examples of **incorrect** code with `{ strict: true }`: async function hi() { await thing().then(x => {}) } ```
This commit is contained in:
parent
75a579b619
commit
dcaebe69b1
2 changed files with 93 additions and 30 deletions
|
|
@ -2,6 +2,7 @@ use oxc_ast::AstKind;
|
||||||
use oxc_diagnostics::OxcDiagnostic;
|
use oxc_diagnostics::OxcDiagnostic;
|
||||||
use oxc_macros::declare_oxc_lint;
|
use oxc_macros::declare_oxc_lint;
|
||||||
use oxc_span::Span;
|
use oxc_span::Span;
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
fn prefer_wait_to_then_diagnostic(span: Span) -> OxcDiagnostic {
|
fn prefer_wait_to_then_diagnostic(span: Span) -> OxcDiagnostic {
|
||||||
OxcDiagnostic::warn("Prefer await to then()/catch()/finally()").with_label(span)
|
OxcDiagnostic::warn("Prefer await to then()/catch()/finally()").with_label(span)
|
||||||
|
|
@ -10,7 +11,20 @@ fn prefer_wait_to_then_diagnostic(span: Span) -> OxcDiagnostic {
|
||||||
use crate::{context::LintContext, rule::Rule, utils::is_promise, AstNode};
|
use crate::{context::LintContext, rule::Rule, utils::is_promise, AstNode};
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct PreferAwaitToThen;
|
pub struct PreferAwaitToThen(PreferAwaitToThenConfig);
|
||||||
|
|
||||||
|
impl std::ops::Deref for PreferAwaitToThen {
|
||||||
|
type Target = PreferAwaitToThenConfig;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone)]
|
||||||
|
pub struct PreferAwaitToThenConfig {
|
||||||
|
strict: bool,
|
||||||
|
}
|
||||||
|
|
||||||
declare_oxc_lint!(
|
declare_oxc_lint!(
|
||||||
/// ### What it does
|
/// ### What it does
|
||||||
|
|
@ -32,6 +46,14 @@ declare_oxc_lint!(
|
||||||
/// ```javascript
|
/// ```javascript
|
||||||
/// async function hi() { await thing() }
|
/// async function hi() { await thing() }
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// ### Example with strict mode
|
||||||
|
/// Examples of **incorrect** code with `{ strict: true }`:
|
||||||
|
/// ```javascript
|
||||||
|
/// async function hi() {
|
||||||
|
/// await thing().then(x => {})
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
PreferAwaitToThen,
|
PreferAwaitToThen,
|
||||||
promise,
|
promise,
|
||||||
style,
|
style,
|
||||||
|
|
@ -42,6 +64,15 @@ fn is_inside_yield_or_await(node: &AstNode) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rule for PreferAwaitToThen {
|
impl Rule for PreferAwaitToThen {
|
||||||
|
fn from_configuration(value: serde_json::Value) -> Self {
|
||||||
|
let strict = match value {
|
||||||
|
Value::Object(obj) => obj.get("strict").and_then(Value::as_bool).unwrap_or(false),
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
Self(PreferAwaitToThenConfig { strict })
|
||||||
|
}
|
||||||
|
|
||||||
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
|
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
|
||||||
let AstKind::CallExpression(call_expr) = node.kind() else {
|
let AstKind::CallExpression(call_expr) = node.kind() else {
|
||||||
return;
|
return;
|
||||||
|
|
@ -51,13 +82,15 @@ impl Rule for PreferAwaitToThen {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Already inside a yield or await
|
if !self.strict {
|
||||||
if ctx
|
// Already inside a yield or await
|
||||||
.nodes()
|
if ctx
|
||||||
.ancestor_ids(node.id())
|
.nodes()
|
||||||
.any(|node_id| is_inside_yield_or_await(ctx.nodes().get_node(node_id)))
|
.ancestor_ids(node.id())
|
||||||
{
|
.any(|node_id| is_inside_yield_or_await(ctx.nodes().get_node(node_id)))
|
||||||
return;
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.diagnostic(prefer_wait_to_then_diagnostic(call_expr.span));
|
ctx.diagnostic(prefer_wait_to_then_diagnostic(call_expr.span));
|
||||||
|
|
@ -69,33 +102,51 @@ fn test() {
|
||||||
use crate::tester::Tester;
|
use crate::tester::Tester;
|
||||||
|
|
||||||
let pass = vec![
|
let pass = vec![
|
||||||
"async function hi() { await thing() }",
|
("async function hi() { await thing() }", None),
|
||||||
"async function hi() { await thing().then() }",
|
("async function hi() { await thing().then() }", None),
|
||||||
"async function hi() { await thing().catch() }",
|
("async function hi() { await thing().catch() }", None),
|
||||||
"a = async () => (await something())",
|
("a = async () => (await something())", None),
|
||||||
"a = async () => {
|
(
|
||||||
try { await something() } catch (error) { somethingElse() }
|
"a = async () => {
|
||||||
}",
|
try { await something() } catch (error) { somethingElse() }
|
||||||
|
}",
|
||||||
|
None,
|
||||||
|
),
|
||||||
// <https://github.com/tc39/proposal-top-level-await>
|
// <https://github.com/tc39/proposal-top-level-await>
|
||||||
// Top level await is allowed now, so comment this out
|
// Top level await is allowed now, so comment this out
|
||||||
// "something().then(async () => await somethingElse())",
|
// ("something().then(async () => await somethingElse())", None),
|
||||||
"function foo() { hey.somethingElse(x => {}) }",
|
("function foo() { hey.somethingElse(x => {}) }", None),
|
||||||
"const isThenable = (obj) => {
|
(
|
||||||
return obj && typeof obj.then === 'function';
|
"const isThenable = (obj) => {
|
||||||
};",
|
return obj && typeof obj.then === 'function';
|
||||||
"function isThenable(obj) {
|
};",
|
||||||
return obj && typeof obj.then === 'function';
|
None,
|
||||||
}",
|
),
|
||||||
|
(
|
||||||
|
"function isThenable(obj) {
|
||||||
|
return obj && typeof obj.then === 'function';
|
||||||
|
}",
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"async function hi() { await thing().then() }",
|
||||||
|
Some(serde_json::json!({ "strict": false })),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
let fail = vec![
|
let fail = vec![
|
||||||
"function foo() { hey.then(x => {}) }",
|
("function foo() { hey.then(x => {}) }", None),
|
||||||
"function foo() { hey.then(function() { }).then() }",
|
("function foo() { hey.then(function() { }).then() }", None),
|
||||||
"function foo() { hey.then(function() { }).then(x).catch() }",
|
("function foo() { hey.then(function() { }).then(x).catch() }", None),
|
||||||
"async function a() { hey.then(function() { }).then(function() { }) }",
|
("async function a() { hey.then(function() { }).then(function() { }) }", None),
|
||||||
"function foo() { hey.catch(x => {}) }",
|
("function foo() { hey.catch(x => {}) }", None),
|
||||||
"function foo() { hey.finally(x => {}) }",
|
("function foo() { hey.finally(x => {}) }", None),
|
||||||
"something().then(async () => await somethingElse())",
|
("something().then(async () => await somethingElse())", None),
|
||||||
|
(
|
||||||
|
"async function foo() { await thing().then() }",
|
||||||
|
Some(serde_json::json!({ "strict": true })),
|
||||||
|
),
|
||||||
|
("async function foo() { thing().then() }", Some(serde_json::json!({ "strict": false }))),
|
||||||
];
|
];
|
||||||
|
|
||||||
Tester::new(PreferAwaitToThen::NAME, PreferAwaitToThen::PLUGIN, pass, fail).test_and_snapshot();
|
Tester::new(PreferAwaitToThen::NAME, PreferAwaitToThen::PLUGIN, pass, fail).test_and_snapshot();
|
||||||
|
|
|
||||||
|
|
@ -67,3 +67,15 @@ snapshot_kind: text
|
||||||
1 │ something().then(async () => await somethingElse())
|
1 │ something().then(async () => await somethingElse())
|
||||||
· ───────────────────────────────────────────────────
|
· ───────────────────────────────────────────────────
|
||||||
╰────
|
╰────
|
||||||
|
|
||||||
|
⚠ eslint-plugin-promise(prefer-await-to-then): Prefer await to then()/catch()/finally()
|
||||||
|
╭─[prefer_await_to_then.tsx:1:30]
|
||||||
|
1 │ async function foo() { await thing().then() }
|
||||||
|
· ──────────────
|
||||||
|
╰────
|
||||||
|
|
||||||
|
⚠ eslint-plugin-promise(prefer-await-to-then): Prefer await to then()/catch()/finally()
|
||||||
|
╭─[prefer_await_to_then.tsx:1:24]
|
||||||
|
1 │ async function foo() { thing().then() }
|
||||||
|
· ──────────────
|
||||||
|
╰────
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue