Skip to content

Commit 6506d08

Browse files
DonIsaacBoshen
andauthored
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>
1 parent 0674604 commit 6506d08

File tree

1 file changed

+52
-29
lines changed

1 file changed

+52
-29
lines changed

crates/oxc_linter/src/rules/unicorn/no_single_promise_in_promise_methods.rs

+52-29
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ use oxc_ast::{
55
use oxc_diagnostics::OxcDiagnostic;
66

77
use oxc_macros::declare_oxc_lint;
8-
use oxc_span::Span;
8+
use oxc_span::{GetSpan, Span};
99

10-
use crate::{ast_util::is_method_call, context::LintContext, rule::Rule, AstNode};
10+
use crate::{ast_util::is_method_call, context::LintContext, fixer::Fix, rule::Rule, AstNode};
1111

1212
fn no_single_promise_in_promise_methods_diagnostic(span0: Span, x1: &str) -> OxcDiagnostic {
1313
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 {
5757
return;
5858
};
5959

60-
if !is_promise_method_with_single_element_array(call_expr) {
60+
if !is_promise_method_with_single_argument(call_expr) {
61+
return;
62+
}
63+
let Some(first_argument) = call_expr.arguments[0].as_expression() else {
64+
return;
65+
};
66+
let first_argument = first_argument.without_parenthesized();
67+
let Expression::ArrayExpression(first_argument_array_expr) = first_argument else {
68+
return;
69+
};
70+
71+
if first_argument_array_expr.elements.len() != 1 {
72+
return;
73+
}
74+
75+
let first = &first_argument_array_expr.elements[0];
76+
if !first.is_expression() {
6177
return;
6278
}
6379

@@ -68,34 +84,33 @@ impl Rule for NoSinglePromiseInPromiseMethods {
6884
.static_property_info()
6985
.expect("callee is a static property");
7086

71-
ctx.diagnostic(no_single_promise_in_promise_methods_diagnostic(info.0, info.1));
87+
let diagnostic = no_single_promise_in_promise_methods_diagnostic(info.0, info.1);
88+
ctx.diagnostic_with_fix(diagnostic, || {
89+
let elem_text = first.span().source_text(ctx.source_text());
90+
91+
let is_directly_in_await = ctx
92+
.semantic()
93+
.nodes()
94+
// get first non-parenthesis parent node
95+
.iter_parents(node.id())
96+
.skip(1) // first node is the call expr
97+
.find(|parent| !matches!(parent.kind(), AstKind::ParenthesizedExpression(_)))
98+
// check if it's an `await ...` expression
99+
.is_some_and(|parent| matches!(parent.kind(), AstKind::AwaitExpression(_)));
100+
101+
let call_span = call_expr.span;
102+
103+
if is_directly_in_await {
104+
Fix::new(elem_text, call_span)
105+
} else {
106+
Fix::new(format!("Promise.resolve({elem_text})"), call_span)
107+
}
108+
});
72109
}
73110
}
74111

75-
fn is_promise_method_with_single_element_array(call_expr: &CallExpression) -> bool {
76-
if !is_method_call(
77-
call_expr,
78-
Some(&["Promise"]),
79-
Some(&["all", "any", "race"]),
80-
Some(1),
81-
Some(1),
82-
) {
83-
return false;
84-
}
85-
86-
let Some(first_argument) = call_expr.arguments[0].as_expression() else {
87-
return false;
88-
};
89-
let first_argument = first_argument.without_parenthesized();
90-
let Expression::ArrayExpression(first_argument_array_expr) = first_argument else {
91-
return false;
92-
};
93-
94-
if first_argument_array_expr.elements.len() != 1 {
95-
return false;
96-
}
97-
98-
first_argument_array_expr.elements[0].is_expression()
112+
fn is_promise_method_with_single_argument(call_expr: &CallExpression) -> bool {
113+
is_method_call(call_expr, Some(&["Promise"]), Some(&["all", "any", "race"]), Some(1), Some(1))
99114
}
100115

101116
#[test]
@@ -183,5 +198,13 @@ fn test() {
183198
"Promise.all([null]).then()",
184199
];
185200

186-
Tester::new(NoSinglePromiseInPromiseMethods::NAME, pass, fail).test_and_snapshot();
201+
let fix = vec![
202+
("Promise.all([null]).then()", "Promise.resolve(null).then()", None),
203+
("let x = await Promise.all([foo()])", "let x = await foo()", None),
204+
("let x = await (Promise.all([foo()]))", "let x = await (foo())", None),
205+
];
206+
207+
Tester::new(NoSinglePromiseInPromiseMethods::NAME, pass, fail)
208+
.expect_fix(fix)
209+
.test_and_snapshot();
187210
}

0 commit comments

Comments
 (0)