refactor(formatter): treat a sibling starting at the enclosing end as outside for trailing comments (#28174)

- Use `>=` for trailing comment bound
- Remove the explicit trailing comment prints that worked around it in `JSXExpressionContainer`, `write_jsx_spread` and `FormatOpeningElement`
This commit is contained in:
leaysgur committed 2026-10-26 08:29:50 +00:00
1 parent 5042019bc5
commit 8d86bd250b
5 files changed
+79 -31

No files matched your search

@@ -447,6 +447,9 @@ impl<'a> Comments<'a> {
let mut comment_index = 0;
let mut type_cast_comment = None;
// The following node starts at or after the enclosing end (spans are half-open),
// so every comment inside the enclosing node is trailing.
let following_is_outside = following_span_start >= enclosing_span.end;
while let Some(comment) = comments.get(comment_index) {
// Stop if the comment:
@@ -456,9 +459,8 @@ impl<'a> Comments<'a> {
break;
}
if following_span_start > enclosing_span.end && comment.span.end <= enclosing_span.end {
// Do nothing; this comment is inside the enclosing node, and the following node is outside the enclosing node.
// So it must be a trailing comment, continue checking the next comment.
if following_is_outside {
// Inside the enclosing node by the check above, so continue checking the next comment.
} else if self.is_type_cast_comment(comment) {
// `A || /* @type {Number} */ (B)`:
// ^^^^^^^^^^^^^^^^^^^^^^^^
+4 -20
View File
@@ -17,7 +17,7 @@ use crate::{
formatter::{
TailwindContextEntry,
prelude::*,
trivia::{DanglingIndentMode, FormatDanglingComments, FormatTrailingComments},
trivia::{DanglingIndentMode, FormatDanglingComments},
},
utils::{
expression::as_call_expression_without_chain_wrappers,
@@ -187,15 +187,7 @@ impl<'a> FormatWrite<'a> for AstNode<'_, 'a, JSXExpressionContainer<'a>> {
if should_inline {
write!(f, self.expression());
} else {
write!(
f,
soft_block_indent(&format_with(|f| {
write!(f, [self.expression()]);
let comments =
f.context().comments().comments_before(self.span.end);
write!(f, [FormatTrailingComments::Comments(comments)]);
}))
);
write!(f, soft_block_indent(&self.expression()));
}
});
@@ -215,11 +207,7 @@ impl<'a> FormatWrite<'a> for AstNode<'_, 'a, JSXExpressionContainer<'a>> {
f,
[group(&format_args!(
"{",
soft_block_indent(&format_with(|f| {
write!(f, [self.expression()]);
let comments = f.context().comments().comments_before(self.span.end);
write!(f, [FormatTrailingComments::Comments(comments)]);
})),
soft_block_indent(&self.expression()),
line_suffix_boundary(),
"}"
))]
@@ -363,11 +351,7 @@ fn write_jsx_spread<'a>(
let has_comment = comments.has_comment_before(argument_span.start)
|| comments.has_comment_in_range(argument_span.end, span.end);
let format_inner = format_with(|f| {
write!(f, [format_leading_comments(argument_span), "..."]);
argument.fmt(f);
// Keep the comments before `}` inside the braces, like `JSXExpressionContainer`
let comments = f.context().comments().comments_before(span.end);
write!(f, [FormatTrailingComments::Comments(comments)]);
write!(f, [format_leading_comments(argument_span), "...", argument]);
});
write!(f, "{");
@@ -3,11 +3,7 @@ use std::ops::Deref;
use oxc_ast::ast::{JSXAttributeItem, JSXAttributeValue, JSXOpeningElement, StringLiteral};
use oxc_span::GetSpan;
use crate::{
ast_nodes::AstNode,
formatter::{prelude::*, trivia::FormatTrailingComments},
write,
};
use crate::{ast_nodes::AstNode, formatter::prelude::*, write};
pub struct FormatOpeningElement<'a, 'b> {
element: &'b AstNode<'b, 'a, JSXOpeningElement<'a>>,
@@ -103,9 +99,6 @@ impl<'a> Format<'a, JsFormatContext<'a>> for FormatOpeningElement<'a, '_> {
write!(f, [soft_line_indent_or_space(&attributes)]);
}
let comments = f.context().comments().comments_before(self.span.end);
FormatTrailingComments::Comments(comments).fmt(f);
let force_bracket_same_line = f.options().bracket_same_line.value();
let wants_bracket_same_line = attributes.is_empty() && !name_has_comment;
@@ -0,0 +1,10 @@
// A comment before `>` stays inside the opening element, also without attributes.
<Foo
// c
>x</Foo>;
<Foo
/* c */
>x</Foo>;
<Foo a
// c
>x</Foo>;
@@ -0,0 +1,59 @@
---
source: crates/oxc_formatter/tests/fixtures/mod.rs
---
==================== Input ====================
// A comment before `>` stays inside the opening element, also without attributes.
<Foo
// c
>x</Foo>;
<Foo
/* c */
>x</Foo>;
<Foo a
// c
>x</Foo>;
==================== Output ====================
------------------
{ printWidth: 80 }
------------------
// A comment before `>` stays inside the opening element, also without attributes.
<Foo
// c
>
x
</Foo>;
<Foo
/* c */
>
x
</Foo>;
<Foo
a
// c
>
x
</Foo>;
-------------------
{ printWidth: 100 }
-------------------
// A comment before `>` stays inside the opening element, also without attributes.
<Foo
// c
>
x
</Foo>;
<Foo
/* c */
>
x
</Foo>;
<Foo
a
// c
>
x
</Foo>;
===================== End =====================