Skip to content

Commit 0b372ea

Browse files
arendjrl0ngvh
authored andcommitted
fix: correctly place await after comment (biomejs#8169)
1 parent 9cd041b commit 0b372ea

File tree

6 files changed

+79
-2
lines changed

6 files changed

+79
-2
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@biomejs/biome": patch
3+
---
4+
5+
Fixed [#7999](https://github.com/biomejs/biome/issues/7999): Correctly place `await` after leading comment in auto-fix action from `noFloatingPromises` rule.

crates/biome_js_analyze/src/lint/nursery/no_floating_promises.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,10 +292,10 @@ impl Rule for NoFloatingPromises {
292292
AnyJsExpression::JsAwaitExpression(make::js_await_expression(
293293
make::token(JsSyntaxKind::AWAIT_KW)
294294
.with_trailing_trivia([(TriviaPieceKind::Whitespace, " ")]),
295-
expression.clone().trim_leading_trivia()?,
295+
expression.clone().trim_comments_and_trivia()?,
296296
));
297297

298-
mutation.replace_node(expression, await_expression);
298+
mutation.replace_node_transfer_trivia(expression, await_expression);
299299
Some(JsRuleAction::new(
300300
ctx.metadata().action_category(ctx.category(), ctx.group()),
301301
ctx.metadata().applicability(),

crates/biome_js_analyze/tests/specs/nursery/noFloatingPromises/invalid.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,8 @@ async function returnsPromise() {
33
}
44
returnsPromise();
55
returnsPromise().then(() => { }).finally(() => { });
6+
7+
async function issue7999() {
8+
// ✅
9+
returnsPromise();
10+
}

crates/biome_js_analyze/tests/specs/nursery/noFloatingPromises/invalid.js.snap

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ async function returnsPromise() {
1010
returnsPromise();
1111
returnsPromise().then(() => { }).finally(() => { });
1212
13+
async function issue7999() {
14+
//
15+
returnsPromise();
16+
}
17+
1318
```
1419

1520
# Diagnostics
@@ -40,8 +45,30 @@ invalid.js:5:1 lint/nursery/noFloatingPromises ━━━━━━━━━━━
4045
> 5 │ returnsPromise().then(() => { }).finally(() => { });
4146
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4247
6 │
48+
7 │ async function issue7999() {
4349
4450
i This happens when a Promise is not awaited, lacks a `.catch` or `.then` rejection handler, or is not explicitly ignored using the `void` operator.
4551
4652
4753
```
54+
55+
```
56+
invalid.js:9:3 lint/nursery/noFloatingPromises FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
57+
58+
i A "floating" Promise was found, meaning it is not properly handled and could lead to ignored errors or unexpected behavior.
59+
60+
7async function issue7999() {
61+
8//
62+
> 9returnsPromise();
63+
^^^^^^^^^^^^^^^^^
64+
10 │ }
65+
11
66+
67+
i This happens when a Promise is not awaited, lacks a `.catch` or `.then` rejection handler, or is not explicitly ignored using the `void` operator.
68+
69+
i Unsafe fix: Add await operator.
70+
71+
9 │ ··await·returnsPromise();
72+
++++++
73+
74+
```

crates/biome_rowan/src/ast/batch.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,37 @@ where
221221
self.replace_element_discard_trivia(prev_token.into(), next_token.into())
222222
}
223223

224+
/// Push a change to replace the "prev_node" with "next_node".
225+
///
226+
/// - leading trivia of `prev_node`
227+
/// - leading trivia of `next_node`
228+
/// - trailing trivia of `prev_node`
229+
/// - trailing trivia of `next_node`
230+
pub fn replace_node_transfer_trivia<T>(&mut self, prev_node: T, next_node: T) -> Option<()>
231+
where
232+
T: AstNode<Language = L>,
233+
{
234+
let prev_node = prev_node.into_syntax();
235+
let next_node = next_node.into_syntax();
236+
237+
let leading_trivia = chain_trivia_pieces(
238+
prev_node.first_token()?.leading_trivia().pieces(),
239+
next_node.first_token()?.leading_trivia().pieces(),
240+
);
241+
242+
let trailing_trivia = chain_trivia_pieces(
243+
prev_node.last_token()?.trailing_trivia().pieces(),
244+
next_node.last_token()?.trailing_trivia().pieces(),
245+
);
246+
let new_node = next_node
247+
.with_leading_trivia_pieces(leading_trivia)?
248+
.with_trailing_trivia_pieces(trailing_trivia)?;
249+
250+
self.replace_element_discard_trivia(prev_node.into(), new_node.into());
251+
252+
Some(())
253+
}
254+
224255
/// Push a change to replace the "prev_token" with "next_token".
225256
///
226257
/// - leading trivia of `prev_token`

crates/biome_rowan/src/ast/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,15 @@ pub trait AstNode: Clone {
276276
Self::cast(self.into_syntax().append_trivia_pieces(trivia)?)
277277
}
278278

279+
/// Returns a new version of this node with *all* trivia stripped.
280+
fn trim_comments_and_trivia(self) -> Option<Self> {
281+
Self::cast(
282+
self.into_syntax()
283+
.with_leading_trivia_pieces([])?
284+
.with_trailing_trivia_pieces([])?,
285+
)
286+
}
287+
279288
/// Return a new version of this node without leading and trailing newlines and whitespaces.
280289
fn trim_trivia(self) -> Option<Self> {
281290
Self::cast(

0 commit comments

Comments
 (0)