Skip to content

Commit 9c14c3e

Browse files
committed
fix(formatter): ignore comment does not work for sequence expressions in arrow function body (#18799)
Fixes `js/sequence-expression/ignored.js` prettier test
1 parent 54984ae commit 9c14c3e

2 files changed

Lines changed: 52 additions & 28 deletions

File tree

crates/oxc_formatter/src/print/arrow_function_expression.rs

Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use oxc_ast::ast::*;
2-
use oxc_span::GetSpan;
2+
use oxc_span::{GetSpan, Span};
33

44
use crate::{
55
ast_nodes::{AstNode, AstNodes},
@@ -13,6 +13,7 @@ use crate::{
1313
utils::{
1414
assignment_like::AssignmentLikeLayout, expression::ExpressionLeftSide,
1515
format_node_without_trailing_comments::FormatNodeWithoutTrailingComments,
16+
suppressed::FormatSuppressedNode,
1617
},
1718
write,
1819
};
@@ -143,20 +144,10 @@ impl<'a, 'b> FormatJsArrowFunctionExpression<'a, 'b> {
143144
let arrow_expression = arrow.get_expression();
144145

145146
if let Some(Expression::SequenceExpression(sequence)) = arrow_expression {
146-
return if f.context().comments().has_comment_before(sequence.span().start) {
147-
write!(
148-
f,
149-
[group(&format_args!(
150-
formatted_signature,
151-
group(&format_args!(indent(&format_args!(
152-
hard_line_break(),
153-
format_leading_comments(sequence.span()),
154-
token("("),
155-
format_body,
156-
token(")")
157-
))))
158-
))]
159-
);
147+
return if let Some(format_sequence) =
148+
format_sequence_with_leading_comment(sequence.span(), &format_body, f)
149+
{
150+
write!(f, [group(&format_args!(formatted_signature, format_sequence))]);
160151
} else {
161152
write!(
162153
f,
@@ -564,17 +555,10 @@ impl<'a> Format<'a> for ArrowChain<'a, '_> {
564555
// Ensure that the parens of sequence expressions end up on their own line if the
565556
// body breaks
566557
if let Some(Expression::SequenceExpression(sequence)) = tail.get_expression() {
567-
if f.context().comments().has_comment_before(sequence.span().start) {
568-
write!(
569-
f,
570-
[group(&format_args!(indent(&format_args!(
571-
hard_line_break(),
572-
format_leading_comments(sequence.span()),
573-
token("("),
574-
format_tail_body,
575-
token(")")
576-
))))]
577-
);
558+
if let Some(format_sequence) =
559+
format_sequence_with_leading_comment(sequence.span(), &format_tail_body, f)
560+
{
561+
write!(f, format_sequence);
578562
} else {
579563
write!(
580564
f,
@@ -761,3 +745,44 @@ impl<'a> Format<'a> for FormatMaybeCachedFunctionBody<'a, '_> {
761745
FormatContentWithCacheMode::new(self.body.span, content, self.mode).fmt(f);
762746
}
763747
}
748+
749+
/// Format a sequence expression in an arrow function body that has a leading comment.
750+
///
751+
/// When an arrow function body is a sequence expression (e.g., `() => (a, b, c)`) and has
752+
/// a leading comment, special formatting is needed to place the comment correctly:
753+
///
754+
/// ```js
755+
/// const f = () =>
756+
/// // comment
757+
/// (a, b, c);
758+
/// ```
759+
///
760+
/// Returns `Some(formatter)` if the sequence has a leading comment, `None` otherwise.
761+
/// When `None`, the caller should use normal formatting with `soft_block_indent`.
762+
///
763+
/// Handles `oxfmt-ignore` by preserving original source text when suppressed.
764+
fn format_sequence_with_leading_comment<'a, 'b>(
765+
sequence_span: Span,
766+
format_body: &'b impl Format<'a>,
767+
f: &Formatter<'_, 'a>,
768+
) -> Option<impl Format<'a> + 'b> {
769+
if !f.comments().has_comment_before(sequence_span.start) {
770+
return None;
771+
}
772+
773+
let is_suppressed = f.comments().is_suppressed(sequence_span.start);
774+
775+
let format_sequence = format_with(move |f| {
776+
write!(f, [format_leading_comments(sequence_span), "("]);
777+
if is_suppressed {
778+
write!(f, FormatSuppressedNode(sequence_span));
779+
} else {
780+
write!(f, format_body);
781+
}
782+
write!(f, [")"]);
783+
});
784+
785+
Some(format_with(move |f| {
786+
write!(f, group(&indent(&format_args!(hard_line_break(), format_sequence))));
787+
}))
788+
}

tasks/prettier_conformance/snapshots/prettier.js.snap.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
js compatibility: 743/753 (98.67%)
1+
js compatibility: 744/753 (98.80%)
22

33
# Failed
44

@@ -13,4 +13,3 @@ js compatibility: 743/753 (98.67%)
1313
| js/last-argument-expansion/dangling-comment-in-arrow-function.js | 💥 | 22.22% |
1414
| js/quote-props/objects.js | 💥💥✨✨ | 48.04% |
1515
| js/quote-props/with_numbers.js | 💥💥✨✨ | 46.43% |
16-
| js/sequence-expression/ignored.js | 💥 | 66.67% |

0 commit comments

Comments
 (0)