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: 6 additions & 6 deletions crates/oxc_formatter/src/ast_nodes/generated/ast_nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1396,7 +1396,7 @@ impl<'a> AstNode<'a, ObjectProperty<'a>> {

#[inline]
pub fn value(&self) -> &AstNode<'a, Expression<'a>> {
let following_span = None;
let following_span = self.following_span;
self.allocator.alloc(AstNode {
inner: &self.inner.value,
allocator: self.allocator,
Expand Down Expand Up @@ -1623,7 +1623,7 @@ impl<'a> AstNode<'a, ComputedMemberExpression<'a>> {

#[inline]
pub fn expression(&self) -> &AstNode<'a, Expression<'a>> {
let following_span = None;
let following_span = self.following_span;
self.allocator.alloc(AstNode {
inner: &self.inner.expression,
allocator: self.allocator,
Expand Down Expand Up @@ -1660,7 +1660,7 @@ impl<'a> AstNode<'a, StaticMemberExpression<'a>> {

#[inline]
pub fn property(&self) -> &AstNode<'a, IdentifierName<'a>> {
let following_span = None;
let following_span = self.following_span;
self.allocator.alloc(AstNode {
inner: &self.inner.property,
allocator: self.allocator,
Expand Down Expand Up @@ -2144,7 +2144,7 @@ impl<'a> AstNode<'a, AssignmentExpression<'a>> {

#[inline]
pub fn right(&self) -> &AstNode<'a, Expression<'a>> {
let following_span = None;
let following_span = self.following_span;
self.allocator.alloc(AstNode {
inner: &self.inner.right,
allocator: self.allocator,
Expand Down Expand Up @@ -4131,7 +4131,7 @@ impl<'a> AstNode<'a, FormalParameters<'a>> {

#[inline]
pub fn items(&self) -> &AstNode<'a, Vec<'a, FormalParameter<'a>>> {
let following_span = self.inner.rest.as_deref().map(GetSpan::span);
let following_span = self.inner.rest.as_deref().map(GetSpan::span).or(self.following_span);
self.allocator.alloc(AstNode {
inner: &self.inner.items,
allocator: self.allocator,
Expand All @@ -4142,7 +4142,7 @@ impl<'a> AstNode<'a, FormalParameters<'a>> {

#[inline]
pub fn rest(&self) -> Option<&AstNode<'a, BindingRestElement<'a>>> {
let following_span = None;
let following_span = self.following_span;
self.allocator
.alloc(self.inner.rest.as_ref().map(|inner| AstNode {
inner: inner.as_ref(),
Expand Down
6 changes: 6 additions & 0 deletions crates/oxc_formatter/src/formatter/comments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,12 @@ impl<'a> Comments<'a> {
&self.unprinted_comments()[..index]
}

/// Returns all block comments that end before or at the given position.
pub fn line_comments_before(&self, pos: u32) -> &'a [Comment] {
let index = self.comments_before_iter(pos).take_while(|c| c.is_line()).count();
&self.unprinted_comments()[..index]
}

/// 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 =
Expand Down
29 changes: 2 additions & 27 deletions crates/oxc_formatter/src/write/array_pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ use crate::{
Format, FormatResult,
ast_nodes::{AstNode, AstNodes},
formatter::{Formatter, prelude::*, trivia::format_dangling_comments},
utils::{
array::write_array_node,
format_node_without_trailing_comments::FormatNodeWithoutTrailingComments,
},
utils::array::write_array_node,
write,
};

Expand All @@ -26,23 +23,6 @@ impl<'a> Deref for FormatArrayPattern<'a, '_> {
}
}

impl GetSpan for FormatArrayPattern<'_, '_> {
fn span(&self) -> Span {
// `[a, b]: [a, b]`
// ^^^^^^^^^^^^^^ ArrayPattern's span covers the type annotation if exists,
// ^^^^^^ but we want the span to cover only the pattern itself, otherwise,
// the comments of type annotation will be treated as dangling comments
// of ArrayPattern.
if let AstNodes::FormalParameter(param) = self.parent
&& let Some(ty) = &param.pattern.type_annotation
{
Span::new(self.span.start, ty.span.start)
} else {
self.span
}
}
}

impl<'a> Format<'a> for FormatArrayPattern<'a, '_> {
fn fmt(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
write!(f, "[")?;
Expand Down Expand Up @@ -75,11 +55,6 @@ impl<'a> Format<'a> for FormatArrayPattern<'a, '_> {

impl<'a> FormatWrite<'a> for AstNode<'a, ArrayPattern<'a>> {
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
if matches!(self.parent, AstNodes::FormalParameter(param) if param.pattern.type_annotation.is_some())
{
FormatNodeWithoutTrailingComments(&FormatArrayPattern(self)).fmt(f)
} else {
FormatArrayPattern(self).fmt(f)
}
FormatArrayPattern(self).fmt(f)
}
}
40 changes: 20 additions & 20 deletions crates/oxc_formatter/src/write/export_declarations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,10 @@ fn format_export_keyword_with_class_decorators<'a>(
) -> FormatResult<()> {
// `@decorator export class Cls {}`
// ^ print leading comments here
let format_leading_comments = |f: &mut Formatter<'_, 'a>| -> FormatResult<()> {
let format_leading_comments = format_once(|f| {
let comments = f.context().comments().comments_before(span.start);
FormatLeadingComments::Comments(comments).fmt(f)?;
Ok(())
};
FormatLeadingComments::Comments(comments).fmt(f)
});

if let AstNodes::Class(class) = declaration
&& !class.decorators.is_empty()
Expand All @@ -41,19 +40,26 @@ fn format_export_keyword_with_class_decorators<'a>(
// `@decorator export class Cls {}`
// decorators are placed before the export keyword
if class.decorators[0].span.end < span.start {
write!(f, [class.decorators(), hard_line_break()])?;
format_leading_comments(f)?;
write!(f, [keyword, space()])
write!(
f,
[class.decorators(), hard_line_break(), format_leading_comments, keyword, space()]
)
} else {
// `export @decorator class Cls {}`
// decorators are placed after the export keyword
format_leading_comments(f)?;
write!(f, [keyword, hard_line_break()])?;
write!(f, [class.decorators(), hard_line_break()])
write!(
f,
[
format_leading_comments,
keyword,
hard_line_break(),
class.decorators(),
hard_line_break()
]
)
}
} else {
format_leading_comments(f)?;
write!(f, [keyword, space()])
write!(f, [format_leading_comments, keyword, space()])
}
}

Expand Down Expand Up @@ -195,14 +201,8 @@ impl<'a> Format<'a> for AstNode<'a, Vec<'a, ExportSpecifier<'a>>> {

impl<'a> FormatWrite<'a> for AstNode<'a, ExportSpecifier<'a>> {
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
let comments = f.context().comments().comments_before(self.exported.span().end);
let mut len = comments.len();
while len != 0 && comments[len - 1].is_block() {
len -= 1;
}
if len != 0 {
write!(f, [FormatLeadingComments::Comments(&comments[..len])])?;
}
let comments = f.context().comments().line_comments_before(self.exported.span().end);
write!(f, [FormatLeadingComments::Comments(comments)])?;

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

if let Some(with_clause) = with_clause {
if f.comments().has_comment_before(with_clause.span.start) {
Expand Down Expand Up @@ -145,15 +144,8 @@ impl<'a> Format<'a> for AstNode<'a, Vec<'a, ImportDeclarationSpecifier<'a>>> {

impl<'a> FormatWrite<'a> for AstNode<'a, ImportSpecifier<'a>> {
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
let comments = f.context().comments().comments_before(self.local.span.end);
let mut len = comments.len();
while len != 0 && comments[len - 1].is_block() {
len -= 1;
}
if len != 0 {
write!(f, [FormatLeadingComments::Comments(&comments[..len])])?;
}
write!(f, [self.import_kind()])?;
let comments = f.context().comments().line_comments_before(self.local.span.end);
write!(f, [FormatLeadingComments::Comments(comments), self.import_kind()])?;
if self.local.span == self.imported.span() {
write!(f, [self.local()])
} else {
Expand Down
11 changes: 2 additions & 9 deletions crates/oxc_formatter/src/write/jsx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ use crate::{
prelude::*,
trivia::{DanglingIndentMode, FormatDanglingComments, FormatTrailingComments},
},
utils::format_node_without_trailing_comments::FormatNodeWithoutTrailingComments,
write,
};

Expand Down Expand Up @@ -206,20 +205,14 @@ impl<'a> FormatWrite<'a> for AstNode<'a, JSXExpressionContainer<'a>> {
// JSXAttributeValue
let should_inline = !has_comment(f) && should_inline_jsx_expression(self, f.comments());

let format_expression = format_once(|f| {
write!(f, FormatNodeWithoutTrailingComments(&self.expression()));
let comments = f.context().comments().comments_before(self.span.end);
write!(f, FormatTrailingComments::Comments(comments))
});

if should_inline {
write!(f, ["{", format_expression, line_suffix_boundary(), "}"])
write!(f, ["{", self.expression(), line_suffix_boundary(), "}"])
} else {
write!(
f,
[group(&format_args!(
"{",
soft_block_indent(&format_expression),
soft_block_indent(&self.expression()),
line_suffix_boundary(),
"}"
))]
Expand Down
26 changes: 3 additions & 23 deletions crates/oxc_formatter/src/write/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,13 +252,7 @@ impl<'a> FormatWrite<'a> for AstNode<'a, CallExpression<'a>> {

impl<'a> FormatWrite<'a> for AstNode<'a, NewExpression<'a>> {
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
write!(f, ["new", space()]);
if self.type_arguments.is_some() {
write!(f, [self.callee()]);
} else {
write!(f, [FormatNodeWithoutTrailingComments(self.callee())]);
}
write!(f, [self.type_arguments(), self.arguments()])
write!(f, ["new", space(), self.callee(), self.type_arguments(), self.arguments()])
}
}

Expand Down Expand Up @@ -962,12 +956,7 @@ impl<'a> FormatWrite<'a> for AstNode<'a, AssignmentPattern<'a>> {

impl<'a> FormatWrite<'a> for AstNode<'a, ObjectPattern<'a>> {
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
if matches!(self.parent, AstNodes::FormalParameter(param) if param.pattern.type_annotation.is_some())
{
FormatNodeWithoutTrailingComments(&ObjectPatternLike::ObjectPattern(self)).fmt(f)
} else {
ObjectPatternLike::ObjectPattern(self).fmt(f)
}
ObjectPatternLike::ObjectPattern(self).fmt(f)
}
}

Expand Down Expand Up @@ -1210,16 +1199,7 @@ impl<'a> FormatWrite<'a> for AstNode<'a, TSTypeOperator<'a>> {

impl<'a> FormatWrite<'a> for AstNode<'a, TSArrayType<'a>> {
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
if let AstNodes::TSUnionType(union) = self.element_type().as_ast_nodes() {
// `TSUnionType` has special logic for comments, so we need to delegate to it.
union.fmt(f)?;
} else {
FormatNodeWithoutTrailingComments(self.element_type()).fmt(f)?;
}
let comments =
f.context().comments().comments_before_character(self.element_type.span().end, b'[');
FormatTrailingComments::Comments(comments).fmt(f)?;
write!(f, ["[]"])
write!(f, [self.element_type(), "[]"])
}
}

Expand Down
15 changes: 1 addition & 14 deletions crates/oxc_formatter/src/write/object_pattern_like.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,7 @@ pub enum ObjectPatternLike<'a, 'b> {
impl GetSpan for ObjectPatternLike<'_, '_> {
fn span(&self) -> Span {
match self {
Self::ObjectPattern(node) => {
// `{a, b}: {a: number, b: string}`
// ^^^^^^^^^^^^^^ ObjectPattern's span covers the type annotation if exists,
// ^^^^^^ but we want the span to cover only the pattern itself, otherwise,
// the comments of type annotation will be treated as dangling comments
// of ObjectPattern.
if let AstNodes::FormalParameter(param) = node.parent
&& let Some(ty) = &param.pattern.type_annotation
{
Span::new(node.span.start, ty.span.start)
} else {
node.span
}
}
Self::ObjectPattern(node) => node.span,
Self::ObjectAssignmentTarget(node) => node.span,
}
}
Expand Down
5 changes: 2 additions & 3 deletions crates/oxc_formatter/src/write/program.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::ops::Deref;
use std::{ops::Deref, ptr::dangling};

use oxc_allocator::{Address, Vec};
use oxc_ast::{ast::*, match_expression};
Expand All @@ -25,8 +25,7 @@ use super::FormatWrite;
impl<'a> FormatWrite<'a> for AstNode<'a, Program<'a>> {
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
let format_trailing_comments = format_once(|f| {
let comments = f.context().comments().comments_before(self.span.end);
write!(f, FormatTrailingComments::Comments(comments))
write!(f, FormatTrailingComments::Comments(f.context().comments().unprinted_comments()))
});

write!(
Expand Down
8 changes: 1 addition & 7 deletions tasks/ast_tools/src/generators/formatter/ast_nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,7 @@ pub fn get_node_type(ty: &TokenStream) -> TokenStream {

/// Based on the printing comments algorithm, the last child of these AST nodes don't need to print comments.
/// Without following nodes could lead to only print comments that before the end of the node, which is what we want.
const AST_NODE_WITHOUT_FOLLOWING_NODE_LIST: &[&str] = &[
"AssignmentExpression",
"FormalParameters",
"StaticMemberExpression",
"ComputedMemberExpression",
"ObjectProperty",
];
const AST_NODE_WITHOUT_FOLLOWING_NODE_LIST: &[&str] = &[];

const AST_NODE_WITH_FOLLOWING_NODE_LIST: &[&str] = &["Function", "Class"];

Expand Down
Loading