mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
feat(linter): add fixer for no-single-promise-in-promise-methods (#3531)
Fixes look like this:
```rs
let fix = vec![
("Promise.all([null]).then()", "Promise.resolve(null).then()", None),
("let x = await Promise.all([foo()])", "let x = await foo()", None),
("let x = await (Promise.all([foo()]))", "let x = await (foo())", None),
];
```
---------
Co-authored-by: Boshen <boshenc@gmail.com>
This commit is contained in:
parent
0674604d7a
commit
6506d086b3
1 changed files with 52 additions and 29 deletions
|
|
@ -5,9 +5,9 @@ use oxc_ast::{
|
|||
use oxc_diagnostics::OxcDiagnostic;
|
||||
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
use oxc_span::{GetSpan, Span};
|
||||
|
||||
use crate::{ast_util::is_method_call, context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{ast_util::is_method_call, context::LintContext, fixer::Fix, rule::Rule, AstNode};
|
||||
|
||||
fn no_single_promise_in_promise_methods_diagnostic(span0: Span, x1: &str) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn(format!("eslint-plugin-unicorn(no-single-promise-in-promise-methods): Wrapping single-element array with `Promise.{x1}()` is unnecessary."))
|
||||
|
|
@ -57,7 +57,23 @@ impl Rule for NoSinglePromiseInPromiseMethods {
|
|||
return;
|
||||
};
|
||||
|
||||
if !is_promise_method_with_single_element_array(call_expr) {
|
||||
if !is_promise_method_with_single_argument(call_expr) {
|
||||
return;
|
||||
}
|
||||
let Some(first_argument) = call_expr.arguments[0].as_expression() else {
|
||||
return;
|
||||
};
|
||||
let first_argument = first_argument.without_parenthesized();
|
||||
let Expression::ArrayExpression(first_argument_array_expr) = first_argument else {
|
||||
return;
|
||||
};
|
||||
|
||||
if first_argument_array_expr.elements.len() != 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
let first = &first_argument_array_expr.elements[0];
|
||||
if !first.is_expression() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -68,34 +84,33 @@ impl Rule for NoSinglePromiseInPromiseMethods {
|
|||
.static_property_info()
|
||||
.expect("callee is a static property");
|
||||
|
||||
ctx.diagnostic(no_single_promise_in_promise_methods_diagnostic(info.0, info.1));
|
||||
let diagnostic = no_single_promise_in_promise_methods_diagnostic(info.0, info.1);
|
||||
ctx.diagnostic_with_fix(diagnostic, || {
|
||||
let elem_text = first.span().source_text(ctx.source_text());
|
||||
|
||||
let is_directly_in_await = ctx
|
||||
.semantic()
|
||||
.nodes()
|
||||
// get first non-parenthesis parent node
|
||||
.iter_parents(node.id())
|
||||
.skip(1) // first node is the call expr
|
||||
.find(|parent| !matches!(parent.kind(), AstKind::ParenthesizedExpression(_)))
|
||||
// check if it's an `await ...` expression
|
||||
.is_some_and(|parent| matches!(parent.kind(), AstKind::AwaitExpression(_)));
|
||||
|
||||
let call_span = call_expr.span;
|
||||
|
||||
if is_directly_in_await {
|
||||
Fix::new(elem_text, call_span)
|
||||
} else {
|
||||
Fix::new(format!("Promise.resolve({elem_text})"), call_span)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn is_promise_method_with_single_element_array(call_expr: &CallExpression) -> bool {
|
||||
if !is_method_call(
|
||||
call_expr,
|
||||
Some(&["Promise"]),
|
||||
Some(&["all", "any", "race"]),
|
||||
Some(1),
|
||||
Some(1),
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let Some(first_argument) = call_expr.arguments[0].as_expression() else {
|
||||
return false;
|
||||
};
|
||||
let first_argument = first_argument.without_parenthesized();
|
||||
let Expression::ArrayExpression(first_argument_array_expr) = first_argument else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if first_argument_array_expr.elements.len() != 1 {
|
||||
return false;
|
||||
}
|
||||
|
||||
first_argument_array_expr.elements[0].is_expression()
|
||||
fn is_promise_method_with_single_argument(call_expr: &CallExpression) -> bool {
|
||||
is_method_call(call_expr, Some(&["Promise"]), Some(&["all", "any", "race"]), Some(1), Some(1))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -183,5 +198,13 @@ fn test() {
|
|||
"Promise.all([null]).then()",
|
||||
];
|
||||
|
||||
Tester::new(NoSinglePromiseInPromiseMethods::NAME, pass, fail).test_and_snapshot();
|
||||
let fix = vec![
|
||||
("Promise.all([null]).then()", "Promise.resolve(null).then()", None),
|
||||
("let x = await Promise.all([foo()])", "let x = await foo()", None),
|
||||
("let x = await (Promise.all([foo()]))", "let x = await (foo())", None),
|
||||
];
|
||||
|
||||
Tester::new(NoSinglePromiseInPromiseMethods::NAME, pass, fail)
|
||||
.expect_fix(fix)
|
||||
.test_and_snapshot();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue