Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions crates/oxc_formatter/src/ast_nodes/generated/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4802,13 +4802,11 @@ impl<'a> Format<'a> for AstNode<'a, TSNonNullExpression<'a>> {
impl<'a> Format<'a> for AstNode<'a, Decorator<'a>> {
fn fmt(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
let is_suppressed = f.comments().is_suppressed(self.span().start);
if is_suppressed {
self.format_leading_comments(f)?;
FormatSuppressedNode(self.span()).fmt(f)?;
self.format_trailing_comments(f)
} else {
self.write(f)
}
self.format_leading_comments(f)?;
let result =
if is_suppressed { FormatSuppressedNode(self.span()).fmt(f) } else { self.write(f) };
self.format_trailing_comments(f)?;
result
}
}

Expand Down
22 changes: 14 additions & 8 deletions crates/oxc_formatter/src/formatter/comments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,8 @@ impl<'a> Comments<'a> {

/// Returns comments that are on their own line and end before or at the given position.
pub fn own_line_comments_before(&self, pos: u32) -> &'a [Comment] {
let index = self
.comments_before_iter(pos)
.take_while(|c| self.source_text.is_own_line_comment(c))
.count();
let index =
self.comments_before_iter(pos).take_while(|c| self.is_own_line_comment(c)).count();
&self.unprinted_comments()[..index]
}

Expand All @@ -191,9 +189,9 @@ impl<'a> Comments<'a> {
let comments = self.unprinted_comments();
for (index, comment) in comments.iter().enumerate() {
if self.source_text.all_bytes_match(pos, comment.span.start, |b| {
matches!(b, b'\t' | b' ' | b')' | b'=')
matches!(b, b'\t' | b' ') || b.is_ascii_punctuation()
}) {
if comment.is_line() || self.source_text.is_end_of_line_comment(comment) {
if comment.is_line() || self.is_end_of_line_comment(comment) {
return &comments[..=index];
}
pos = comment.span.end;
Expand Down Expand Up @@ -347,10 +345,10 @@ impl<'a> Comments<'a> {
break;
}

if source_text.is_own_line_comment(comment) {
if self.is_own_line_comment(comment) {
// Own line comments are typically leading comments for the next node
break;
} else if self.source_text.is_end_of_line_comment(comment) {
} else if self.is_end_of_line_comment(comment) {
return &comments[..=comment_index];
}

Expand Down Expand Up @@ -410,6 +408,14 @@ impl<'a> Comments<'a> {
false
}

pub fn is_own_line_comment(&self, comment: &Comment) -> bool {
self.source_text.has_newline_before(comment.span.start)
}

pub fn is_end_of_line_comment(&self, comment: &Comment) -> bool {
self.source_text.has_newline_after(comment.span.end)
}

/// Finds the index of a type cast comment before the given span.
///
/// Searches for a JSDoc comment containing @type or @satisfies that is followed
Expand Down
8 changes: 0 additions & 8 deletions crates/oxc_formatter/src/formatter/source_text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,12 +205,4 @@ impl<'a> SourceText<'a> {

0
}

pub fn is_own_line_comment(&self, comment: &Comment) -> bool {
self.has_newline_before(comment.span.start)
}

pub fn is_end_of_line_comment(&self, comment: &Comment) -> bool {
self.has_newline_after(comment.span.end)
}
}
3 changes: 1 addition & 2 deletions crates/oxc_formatter/src/utils/assignment_like.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ fn format_left_trailing_comments(

let comments = if end_of_line_comments.is_empty() {
let comments = f.context().comments().comments_before_character(start, b'=');
if comments.iter().any(|c| f.source_text().is_own_line_comment(c)) { &[] } else { comments }
if comments.iter().any(|c| f.comments().is_own_line_comment(c)) { &[] } else { comments }
} else if should_print_as_leading || end_of_line_comments.last().is_some_and(|c| c.is_block()) {
// No trailing comments for these expressions or if the trailing comment is a block comment
&[]
Expand Down Expand Up @@ -233,7 +233,6 @@ impl<'a> AssignmentLike<'a, '_> {
}
}
AssignmentLike::PropertyDefinition(property) => {
write!(f, property.decorators())?;
if property.declare {
write!(f, ["declare", space()])?;
}
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_formatter/src/utils/conditional.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ fn format_trailing_comments<'a>(
return &comments[..index];
}
// If this comment is a line comment or an end of line comment, so we stop here and return the comments with this comment
else if comment.is_line() || source_text.is_end_of_line_comment(comment) {
else if comment.is_line() || f.comments().is_end_of_line_comment(comment) {
return &comments[..=index];
}
// Store the index of the comment before the operator, if no line comment or no new line is found, then return all comments before operator
Expand Down
6 changes: 2 additions & 4 deletions crates/oxc_formatter/src/write/array_element_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ pub fn can_concisely_print_array_list(
return false;
}

let source_text = f.source_text();
let comments = f.comments();

let mut comments_iter = comments.comments_before_iter(array_expression_span.end);
Expand Down Expand Up @@ -151,11 +150,10 @@ pub fn can_concisely_print_array_list(
// ]
// ```

let source_text = f.source_text();
!comments.comments_before_iter(array_expression_span.end).any(|comment| {
comment.is_line()
&& !source_text.is_own_line_comment(comment)
&& source_text.is_end_of_line_comment(comment)
&& !comments.is_own_line_comment(comment)
&& comments.is_end_of_line_comment(comment)
})
}

Expand Down
21 changes: 14 additions & 7 deletions crates/oxc_formatter/src/write/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,25 @@ impl<'a> Format<'a> for AstNode<'a, Vec<'a, ClassElement<'a>>> {

impl<'a> Format<'a> for (&AstNode<'a, ClassElement<'a>>, Option<&AstNode<'a, ClassElement<'a>>>) {
fn fmt(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
write!(f, [self.0, ClassPropertySemicolon::new(self.0, self.1)])
let decorators = match self.0.as_ast_nodes() {
AstNodes::MethodDefinition(method) => {
write!(f, [method.decorators(), method])
}
AstNodes::PropertyDefinition(property) => {
write!(f, [property.decorators(), property])
}
AstNodes::AccessorProperty(accessor) => {
write!(f, [accessor.decorators(), accessor])
}
_ => write!(f, self.0),
};

write!(f, [ClassPropertySemicolon::new(self.0, self.1)])
}
}

impl<'a> FormatWrite<'a> for AstNode<'a, MethodDefinition<'a>> {
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
// Write modifiers in the correct order:
// decorators -> accessibility -> static -> abstract -> override -> async -> generator
write!(f, [self.decorators()])?;

if let Some(accessibility) = &self.accessibility {
write!(f, [accessibility.as_str(), space()])?;
}
Expand Down Expand Up @@ -157,8 +166,6 @@ impl<'a> FormatWrite<'a> for AstNode<'a, StaticBlock<'a>> {

impl<'a> FormatWrite<'a> for AstNode<'a, AccessorProperty<'a>> {
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
write!(f, self.decorators())?;

if let Some(accessibility) = self.accessibility() {
write!(f, [accessibility.as_str(), space()])?;
}
Expand Down
90 changes: 28 additions & 62 deletions crates/oxc_formatter/src/write/decorators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,42 +22,37 @@ impl<'a> Format<'a> for AstNode<'a, Vec<'a, Decorator<'a>>> {
return Ok(());
};

let format_decorators = format_once(|f| {
// Check parent to determine formatting context
match self.parent {
AstNodes::PropertyDefinition(_)
| AstNodes::MethodDefinition(_)
| AstNodes::AccessorProperty(_) => {
return write!(
f,
[group(&format_args!(
format_once(|f| {
f.join_nodes_with_soft_line().entries(self.iter()).finish()
}),
soft_line_break_or_space()
))
.should_expand(should_expand_decorators(self, f))]
);
}
// Parameter decorators
AstNodes::FormalParameter(_) => {
write!(f, should_expand_decorators(self, f).then_some(expand_parent()))?;
}
AstNodes::ExportNamedDeclaration(_) | AstNodes::ExportDefaultDeclaration(_) => {
write!(f, [hard_line_break()])?;
}
_ => {
write!(f, [expand_parent()])?;
}
// Check parent to determine formatting context
match self.parent {
AstNodes::PropertyDefinition(_)
| AstNodes::MethodDefinition(_)
| AstNodes::AccessorProperty(_) => {
return write!(
f,
[group(&format_args!(
format_once(|f| {
f.join_nodes_with_soft_line().entries(self.iter()).finish()
}),
soft_line_break_or_space()
))
.should_expand(should_expand_decorators(self, f))]
);
}
// Parameter decorators
AstNodes::FormalParameter(_) => {
write!(f, should_expand_decorators(self, f).then_some(expand_parent()))?;
}
AstNodes::ExportNamedDeclaration(_) | AstNodes::ExportDefaultDeclaration(_) => {
write!(f, [hard_line_break()])?;
}
_ => {
write!(f, [expand_parent()])?;
}
}

f.join_with(&soft_line_break_or_space()).entries(self.iter()).finish()?;

write!(f, [soft_line_break_or_space()])
});
f.join_with(&soft_line_break_or_space()).entries(self.iter()).finish()?;

format_decorators.fmt(f)?;
format_trailing_comments_for_last_decorator(last.span.end, f)
write!(f, [soft_line_break_or_space()])
}
}

Expand Down Expand Up @@ -114,32 +109,3 @@ fn should_expand_decorators<'a>(
) -> bool {
decorators.iter().any(|decorator| f.source_text().lines_after(decorator.span().end) > 0)
}

pub fn format_trailing_comments_for_last_decorator(
mut start: u32,
f: &mut Formatter<'_, '_>,
) -> FormatResult<()> {
let mut comments = f.context().comments().unprinted_comments();

for (i, comment) in comments.iter().enumerate() {
if !f.source_text().all_bytes_match(start, comment.span.start, |b| b.is_ascii_whitespace())
{
comments = &comments[..i];
break;
}

start = comment.span.end;
}

if !comments.is_empty() {
write!(
f,
[group(&format_args!(
FormatTrailingComments::Comments(comments),
soft_line_break_or_space()
))]
)?;
}

Ok(())
}
8 changes: 4 additions & 4 deletions crates/oxc_formatter/src/write/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ impl<'a> Deref for FormatFunction<'a, '_> {
}
}

impl<'a> FormatWrite<'a> for FormatFunction<'a, '_> {
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
impl<'a> Format<'a> for FormatFunction<'a, '_> {
fn fmt(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
let head = format_once(|f| {
write!(
f,
Expand Down Expand Up @@ -148,15 +148,15 @@ impl<'a> FormatWrite<'a> for FormatFunction<'a, '_> {

impl<'a> FormatWrite<'a, FormatFunctionOptions> for AstNode<'a, Function<'a>> {
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
FormatFunction { function: self, options: FormatFunctionOptions::default() }.write(f)
FormatFunction { function: self, options: FormatFunctionOptions::default() }.fmt(f)
}

fn write_with_options(
&self,
options: FormatFunctionOptions,
f: &mut Formatter<'_, 'a>,
) -> FormatResult<()> {
FormatFunction { function: self, options }.write(f)
FormatFunction { function: self, options }.fmt(f)
}
}

Expand Down
4 changes: 2 additions & 2 deletions crates/oxc_formatter/src/write/import_declaration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::{
separated::FormatSeparatedIter,
trivia::{FormatLeadingComments, FormatTrailingComments},
},
utils::format_node_without_trailing_comments::FormatNodeWithoutTrailingComments,
write,
write::semicolon::OptionalSemicolon,
};
Expand All @@ -30,8 +31,7 @@ pub fn format_import_and_export_source_with_clause<'a>(
with_clause: Option<&AstNode<'a, WithClause>>,
f: &mut Formatter<'_, 'a>,
) -> FormatResult<()> {
source.format_leading_comments(f)?;
source.write(f)?;
FormatNodeWithoutTrailingComments(source).fmt(f)?;

if let Some(with_clause) = with_clause {
if f.comments().has_comment_before(with_clause.span.start) {
Expand Down
12 changes: 5 additions & 7 deletions crates/oxc_formatter/src/write/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ pub fn get_this_param<'a>(parent: &AstNodes<'a>) -> Option<&'a AstNode<'a, TSThi

impl<'a> FormatWrite<'a> for AstNode<'a, FormalParameters<'a>> {
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
// `function foo /**/ () {}`
// ^^^ keep comments printed before parameters
let comments = f.context().comments().comments_before(self.span.start);
if !comments.is_empty() {
write!(f, [space(), FormatTrailingComments::Comments(comments)])?;
Expand Down Expand Up @@ -77,13 +79,9 @@ impl<'a> FormatWrite<'a> for AstNode<'a, FormalParameters<'a>> {
ParameterLayout::Default => {
write!(
f,
soft_block_indent(&format_args!(
&ParameterList::with_layout(self, this_param, layout),
format_once(|f| {
let comments = f.context().comments().comments_before(self.span.end);
write!(f, [FormatTrailingComments::Comments(comments)])
})
))
soft_block_indent(&format_args!(&ParameterList::with_layout(
self, this_param, layout
)))
);
}
}
Expand Down
15 changes: 7 additions & 8 deletions crates/oxc_formatter/src/write/return_or_throw_statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,19 +121,18 @@ fn has_argument_leading_comments(argument: &AstNode<Expression>, f: &Formatter<'

for left_side in ExpressionLeftSide::from(argument).iter() {
let start = left_side.span().start;
let comments = f.comments().comments_before(start);
let comments = f.context().comments();
let leading_comments = comments.comments_before(start);

if f.comments().comments_before_iter(start).any(|comment| {
source_text.contains_newline(comment.span)
|| source_text.is_end_of_line_comment(comment)
if leading_comments.iter().any(|comment| {
source_text.contains_newline(comment.span) || comments.is_end_of_line_comment(comment)
}) {
return true;
}

let is_own_line_comment_or_multi_line_comment = |comments: &[Comment]| {
comments.iter().any(|comment| {
source_text.is_own_line_comment(comment)
|| source_text.contains_newline(comment.span)
let is_own_line_comment_or_multi_line_comment = |leading_comments: &[Comment]| {
leading_comments.iter().any(|comment| {
comments.is_own_line_comment(comment) || source_text.contains_newline(comment.span)
})
};

Expand Down
6 changes: 4 additions & 2 deletions crates/oxc_formatter/src/write/switch_statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
formatter::{
Formatter,
prelude::*,
trivia::{DanglingIndentMode, FormatDanglingComments, FormatTrailingComments},
trivia::{DanglingIndentMode, FormatDanglingComments},
},
utils::statement_body::FormatStatementBody,
write,
Expand Down Expand Up @@ -114,7 +114,9 @@ impl<'a> FormatWrite<'a> for AstNode<'a, SwitchCase<'a>> {
let comments = if is_single_block_statement {
comments.block_comments_before(first_statement.span().start)
} else {
comments.comments_before_character(self.span.start, b'\n')
#[expect(clippy::cast_possible_truncation)]
const DEFAULT_LEN: u32 = "default".len() as u32;
comments.end_of_line_comments_after(self.span.start + DEFAULT_LEN)
};

if !comments.is_empty() {
Expand Down
Loading
Loading