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
5 changes: 4 additions & 1 deletion crates/oxc_formatter/src/write/call_arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,10 @@ impl<'a> Format<'a> for AstNode<'a, ArenaVec<'a, Argument<'a>>> {

let has_empty_line =
self.iter().any(|arg| f.source_text().get_lines_before(arg.span(), f.comments()) > 1);
if has_empty_line || is_function_composition_args(self) {
if has_empty_line
|| (!matches!(self.parent.parent(), AstNodes::Decorator(_))
&& is_function_composition_args(self))
{
return format_all_args_broken_out(self, true, f);
}

Expand Down
8 changes: 2 additions & 6 deletions crates/oxc_formatter/src/write/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ impl<'a> FormatWrite<'a> for AstNode<'a, MethodDefinition<'a>> {
// Write modifiers in the correct order:
// decorators -> accessibility -> static -> abstract -> override -> async -> generator
write!(f, [self.decorators()])?;
if let Some(accessibility) = &self.accessibility() {

if let Some(accessibility) = &self.accessibility {
write!(f, [accessibility.as_str(), space()])?;
}
if self.r#static {
Expand Down Expand Up @@ -157,11 +158,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())?;
// Handle comments between decorators and the 'accessor' keyword
// We look for comments before the first character 'a' of 'accessor'
// This ensures proper placement of comments like: @decorator /* comment */ accessor x
let comments = f.context().comments().comments_before_character(self.span.start, b'a');
FormatLeadingComments::Comments(comments).fmt(f)?;

if let Some(accessibility) = self.accessibility() {
write!(f, [accessibility.as_str(), space()])?;
Expand Down
101 changes: 70 additions & 31 deletions crates/oxc_formatter/src/write/decorators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ use oxc_span::GetSpan;

use crate::{
Format, FormatResult, format_args,
formatter::{Formatter, prelude::*},
formatter::{
Formatter,
prelude::*,
trivia::{FormatLeadingComments, FormatTrailingComments},
},
generated::ast_nodes::{AstNode, AstNodes},
write,
};
Expand All @@ -13,40 +17,46 @@ use super::FormatWrite;

impl<'a> Format<'a> for AstNode<'a, Vec<'a, Decorator<'a>>> {
fn fmt(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
if self.is_empty() {
let Some(last) = self.last() else {
return Ok(());
}
};

// 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()])?;
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()])?;
}
}
}

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()?;

write!(f, [soft_line_break_or_space()])
});

format_decorators.fmt(f)?;
format_trailing_comments_for_last_decorator(last.span.end, f)
}
}

Expand Down Expand Up @@ -103,3 +113,32 @@ 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: 8 additions & 0 deletions crates/oxc_formatter/src/write/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1725,6 +1725,9 @@ impl<'a> FormatWrite<'a> for AstNode<'a, TSFunctionType<'a>> {
write!(f, params)?;
}

let comments = f.context().comments().comments_before_character(params.span.end, b'=');
FormatTrailingComments::Comments(comments).fmt(f)?;

write!(f, [space(), "=>", space(), return_type.type_annotation()])
});

Expand Down Expand Up @@ -1756,6 +1759,11 @@ impl<'a> FormatWrite<'a> for AstNode<'a, TSConstructorType<'a>> {
space(),
type_parameters,
params,
format_once(|f| {
let comments =
f.context().comments().comments_before_character(params.span.end, b'=');
FormatTrailingComments::Comments(comments).fmt(f)
}),
space(),
"=>",
space(),
Expand Down
10 changes: 2 additions & 8 deletions tasks/prettier_conformance/snapshots/prettier.ts.snap.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ts compatibility: 521/573 (90.92%)
ts compatibility: 527/573 (91.97%)

# Failed

Expand All @@ -19,11 +19,8 @@ ts compatibility: 521/573 (90.92%)
| typescript/chain-expression/test.ts | 💥 | 0.00% |
| typescript/class/empty-method-body.ts | 💥 | 80.00% |
| typescript/class/quoted-property.ts | 💥 | 66.67% |
| typescript/comments/16065.ts | 💥 | 63.64% |
| typescript/comments/16207.ts | 💥 | 71.43% |
| typescript/comments/16889.ts | 💥 | 62.61% |
| typescript/comments/location.ts | 💥 | 95.00% |
| typescript/comments/method_types.ts | 💥 | 79.49% |
| typescript/comments/method_types.ts | 💥 | 84.62% |
| typescript/comments/type-parameters.ts | 💥 | 65.52% |
| typescript/conditional-types/comments.ts | 💥✨ | 31.51% |
| typescript/conditional-types/conditonal-types.ts | 💥✨ | 34.48% |
Expand All @@ -33,10 +30,7 @@ ts compatibility: 521/573 (90.92%)
| typescript/conditional-types/parentheses.ts | 💥✨ | 15.22% |
| typescript/conformance/types/functions/functionOverloadErrorsSyntax.ts | 💥 | 0.00% |
| typescript/custom/computedProperties/string.ts | 💥 | 73.33% |
| typescript/decorators/comments.ts | 💥 | 60.00% |
| typescript/decorators/decorators-comments.ts | 💥 | 65.71% |
| typescript/decorators-ts/angular.ts | 💥 | 87.50% |
| typescript/decorators-ts/typeorm.ts | 💥 | 88.37% |
| typescript/definite/without-annotation.ts | 💥 | 83.33% |
| typescript/enum/computed-members.ts | 💥 | 0.00% |
| typescript/function-type/consistent.ts | 💥 | 70.83% |
Expand Down
Loading