diff --git a/crates/oxc_formatter/src/write/member_expression.rs b/crates/oxc_formatter/src/write/member_expression.rs index 1bbbc45638b5d..75888902f6d92 100644 --- a/crates/oxc_formatter/src/write/member_expression.rs +++ b/crates/oxc_formatter/src/write/member_expression.rs @@ -1,11 +1,18 @@ use std::ops::Deref; use oxc_ast::ast::*; +use oxc_span::GetSpan; use crate::{ JsLabels, format_args, formatter::{ - Buffer, Format, FormatResult, Formatter, prelude::*, trivia::format_dangling_comments, + Buffer, Format, FormatResult, Formatter, + buffer::RemoveSoftLinesBuffer, + prelude::*, + trivia::{ + DanglingIndentMode, FormatDanglingComments, FormatLeadingComments, + FormatTrailingComments, format_dangling_comments, + }, }, generated::ast_nodes::{AstNode, AstNodes}, options::Expand, @@ -30,7 +37,7 @@ impl<'a> FormatWrite<'a> for AstNode<'a, StaticMemberExpression<'a>> { recording.stop().has_label(LabelId::of(JsLabels::MemberChain)) }; - match layout(self, is_member_chain) { + match layout(self, is_member_chain, f) { StaticMemberLayout::NoBreak => { let format_no_break = format_with(|f| write!(f, [operator_token(self.optional()), self.property()])); @@ -46,6 +53,19 @@ impl<'a> FormatWrite<'a> for AstNode<'a, StaticMemberExpression<'a>> { f, [group(&indent(&format_args!( soft_line_break(), + &format_once(|f| { + if f.comments().has_leading_own_line_comment(self.property.span.start) { + let comments = f + .context() + .comments() + .comments_before(self.property.span.start); + write!( + f, + [FormatLeadingComments::Comments(comments), soft_line_break()] + )?; + } + Ok(()) + }), operator_token(self.optional()), self.property(), )))] @@ -71,7 +91,12 @@ fn operator_token(optional: bool) -> &'static str { fn layout<'a>( node: &AstNode<'a, StaticMemberExpression<'a>>, is_member_chain: bool, + f: &Formatter<'_, 'a>, ) -> StaticMemberLayout { + if f.comments().has_leading_own_line_comment(node.property.span.start) { + return StaticMemberLayout::BreakAfterObject; + } + // `a.b.c!` and `a.b?.c` // `TSNonNullExpression` is a wrapper node for `!`, and `ChainExpression` is a wrapper node for `?.`, // so we need to skip them to find the real parent node. diff --git a/tasks/coverage/snapshots/formatter_typescript.snap b/tasks/coverage/snapshots/formatter_typescript.snap index ed8d64514b1ae..4cf4bd2e1cd59 100644 --- a/tasks/coverage/snapshots/formatter_typescript.snap +++ b/tasks/coverage/snapshots/formatter_typescript.snap @@ -2,15 +2,13 @@ commit: 261630d6 formatter_typescript Summary: AST Parsed : 8816/8816 (100.00%) -Positive Passed: 8808/8816 (99.91%) +Positive Passed: 8809/8816 (99.92%) Mismatch: tasks/coverage/typescript/tests/cases/compiler/amdLikeInputDeclarationEmit.ts Expect to Parse: tasks/coverage/typescript/tests/cases/compiler/arrayFromAsync.ts `await` is only allowed within async functions and at the top levels of modules`await` is only allowed within async functions and at the top levels of modules`await` is only allowed within async functions and at the top levels of modules`await` is only allowed within async functions and at the top levels of modules`await` is only allowed within async functions and at the top levels of modules`await` is only allowed within async functions and at the top levels of modules`await` is only allowed within async functions and at the top levels of modules`await` is only allowed within async functions and at the top levels of modules`await` is only allowed within async functions and at the top levels of modules`await` is only allowed within async functions and at the top levels of modules`await` is only allowed within async functions and at the top levels of modules Expect to Parse: tasks/coverage/typescript/tests/cases/compiler/genericTypeAssertions3.ts Unexpected token -Mismatch: tasks/coverage/typescript/tests/cases/compiler/propertyAccessExpressionInnerComments.ts - Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts Classes may not have a static property named prototypeClasses may not have a static property named prototypeClasses may not have a static property named prototypeClasses may not have a static property named prototypeClasses may not have a static property named prototypeClasses may not have a static property named prototype Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/expressions/elementAccess/letIdentifierInElementAccess01.ts