From 9c14c3e0005533727e385e507c7240b61c9f3bc3 Mon Sep 17 00:00:00 2001 From: Dunqing <29533304+Dunqing@users.noreply.github.com> Date: Mon, 2 Feb 2026 01:42:48 +0000 Subject: [PATCH] fix(formatter): ignore comment does not work for sequence expressions in arrow function body (#18799) Fixes `js/sequence-expression/ignored.js` prettier test --- .../src/print/arrow_function_expression.rs | 77 ++++++++++++------- .../snapshots/prettier.js.snap.md | 3 +- 2 files changed, 52 insertions(+), 28 deletions(-) diff --git a/crates/oxc_formatter/src/print/arrow_function_expression.rs b/crates/oxc_formatter/src/print/arrow_function_expression.rs index e1ba6da2a7797..066866588bdd0 100644 --- a/crates/oxc_formatter/src/print/arrow_function_expression.rs +++ b/crates/oxc_formatter/src/print/arrow_function_expression.rs @@ -1,5 +1,5 @@ use oxc_ast::ast::*; -use oxc_span::GetSpan; +use oxc_span::{GetSpan, Span}; use crate::{ ast_nodes::{AstNode, AstNodes}, @@ -13,6 +13,7 @@ use crate::{ utils::{ assignment_like::AssignmentLikeLayout, expression::ExpressionLeftSide, format_node_without_trailing_comments::FormatNodeWithoutTrailingComments, + suppressed::FormatSuppressedNode, }, write, }; @@ -143,20 +144,10 @@ impl<'a, 'b> FormatJsArrowFunctionExpression<'a, 'b> { let arrow_expression = arrow.get_expression(); if let Some(Expression::SequenceExpression(sequence)) = arrow_expression { - return if f.context().comments().has_comment_before(sequence.span().start) { - write!( - f, - [group(&format_args!( - formatted_signature, - group(&format_args!(indent(&format_args!( - hard_line_break(), - format_leading_comments(sequence.span()), - token("("), - format_body, - token(")") - )))) - ))] - ); + return if let Some(format_sequence) = + format_sequence_with_leading_comment(sequence.span(), &format_body, f) + { + write!(f, [group(&format_args!(formatted_signature, format_sequence))]); } else { write!( f, @@ -564,17 +555,10 @@ impl<'a> Format<'a> for ArrowChain<'a, '_> { // Ensure that the parens of sequence expressions end up on their own line if the // body breaks if let Some(Expression::SequenceExpression(sequence)) = tail.get_expression() { - if f.context().comments().has_comment_before(sequence.span().start) { - write!( - f, - [group(&format_args!(indent(&format_args!( - hard_line_break(), - format_leading_comments(sequence.span()), - token("("), - format_tail_body, - token(")") - ))))] - ); + if let Some(format_sequence) = + format_sequence_with_leading_comment(sequence.span(), &format_tail_body, f) + { + write!(f, format_sequence); } else { write!( f, @@ -761,3 +745,44 @@ impl<'a> Format<'a> for FormatMaybeCachedFunctionBody<'a, '_> { FormatContentWithCacheMode::new(self.body.span, content, self.mode).fmt(f); } } + +/// Format a sequence expression in an arrow function body that has a leading comment. +/// +/// When an arrow function body is a sequence expression (e.g., `() => (a, b, c)`) and has +/// a leading comment, special formatting is needed to place the comment correctly: +/// +/// ```js +/// const f = () => +/// // comment +/// (a, b, c); +/// ``` +/// +/// Returns `Some(formatter)` if the sequence has a leading comment, `None` otherwise. +/// When `None`, the caller should use normal formatting with `soft_block_indent`. +/// +/// Handles `oxfmt-ignore` by preserving original source text when suppressed. +fn format_sequence_with_leading_comment<'a, 'b>( + sequence_span: Span, + format_body: &'b impl Format<'a>, + f: &Formatter<'_, 'a>, +) -> Option + 'b> { + if !f.comments().has_comment_before(sequence_span.start) { + return None; + } + + let is_suppressed = f.comments().is_suppressed(sequence_span.start); + + let format_sequence = format_with(move |f| { + write!(f, [format_leading_comments(sequence_span), "("]); + if is_suppressed { + write!(f, FormatSuppressedNode(sequence_span)); + } else { + write!(f, format_body); + } + write!(f, [")"]); + }); + + Some(format_with(move |f| { + write!(f, group(&indent(&format_args!(hard_line_break(), format_sequence)))); + })) +} diff --git a/tasks/prettier_conformance/snapshots/prettier.js.snap.md b/tasks/prettier_conformance/snapshots/prettier.js.snap.md index 787d650dd70a1..664760f85185e 100644 --- a/tasks/prettier_conformance/snapshots/prettier.js.snap.md +++ b/tasks/prettier_conformance/snapshots/prettier.js.snap.md @@ -1,4 +1,4 @@ -js compatibility: 743/753 (98.67%) +js compatibility: 744/753 (98.80%) # Failed @@ -13,4 +13,3 @@ js compatibility: 743/753 (98.67%) | js/last-argument-expansion/dangling-comment-in-arrow-function.js | 💥 | 22.22% | | js/quote-props/objects.js | 💥💥✨✨ | 48.04% | | js/quote-props/with_numbers.js | 💥💥✨✨ | 46.43% | -| js/sequence-expression/ignored.js | 💥 | 66.67% |