@@ -68,6 +68,7 @@ export default class ExpressionFormatter {
6868 private dialectCfg : ProcessedDialectFormatOptions ;
6969 private params : Params ;
7070 private layout : Layout ;
71+ private pendingLineComment : ( LineCommentNode | BlockCommentNode | DisableCommentNode ) [ ] = [ ] ; // Keeps track if any pending Line/Comment is remaining
7172
7273 private inline = false ;
7374 private nodes : AstNode [ ] = [ ] ;
@@ -184,9 +185,38 @@ export default class ExpressionFormatter {
184185 }
185186
186187 private formatPropertyAccess ( node : PropertyAccessNode ) {
187- this . formatNode ( node . object ) ;
188+ this . formatComments ( node . object . leadingComments ) ;
189+ this . formatNodeWithoutComments ( node . object ) ;
190+
191+ // Handle trailing comments of object BEFORE the dot (inline)
192+ if ( node . object . trailingComments && node . object . trailingComments . length > 0 ) {
193+ for ( const comment of node . object . trailingComments ) {
194+ if ( comment . type === NodeType . block_comment ) {
195+ this . layout . add ( WS . NO_SPACE , WS . SPACE , ( comment as BlockCommentNode ) . text ) ;
196+ } else if ( comment . type === NodeType . line_comment ) {
197+ this . layout . add ( WS . NO_SPACE , WS . SPACE , ( comment as LineCommentNode ) . text ) ;
198+ }
199+ }
200+ }
201+
202+ // Add the dot operator
188203 this . layout . add ( WS . NO_SPACE , node . operator ) ;
189- this . formatNode ( node . property ) ;
204+
205+ // Handle leading comments of property AFTER the dot (inline)
206+ if ( node . property . leadingComments && node . property . leadingComments . length > 0 ) {
207+ for ( const comment of node . property . leadingComments ) {
208+ if ( comment . type === NodeType . block_comment ) {
209+ this . layout . add ( ( comment as BlockCommentNode ) . text , WS . SPACE ) ;
210+ } else if ( comment . type === NodeType . line_comment ) {
211+ this . layout . add ( ( comment as LineCommentNode ) . text , WS . SPACE ) ;
212+ }
213+ }
214+ // Format property without leading comments (already handled above)
215+ this . formatNodeWithoutComments ( node . property ) ;
216+ this . formatComments ( node . property . trailingComments ) ;
217+ } else {
218+ this . formatNode ( node . property ) ;
219+ }
190220 }
191221
192222 private formatParenthesis ( node : ParenthesisNode ) {
@@ -345,13 +375,36 @@ export default class ExpressionFormatter {
345375 // Look ahead: check if next node is a line comment
346376 this . formatLeadingComma ( ) ;
347377 } else {
348- this . layout . add ( WS . NO_SPACE , ',' , WS . NEWLINE , WS . INDENT ) ;
378+ this . formatTrailingComma ( ) ;
349379 }
350380 } else {
351381 this . layout . add ( WS . NO_SPACE , ',' , WS . SPACE ) ;
352382 }
353383 }
354-
384+ private formatTrailingComma ( ) {
385+ if ( this . pendingLineComment && this . pendingLineComment . length > 0 ) {
386+ // We have a line comment that should come after the comma
387+ while ( this . pendingLineComment . length > 0 ) {
388+ const comment = this . pendingLineComment . shift ( ) ;
389+ if ( comment ) {
390+ if ( comment . type === NodeType . line_comment ) {
391+ this . layout . add (
392+ WS . NO_SPACE ,
393+ ',' ,
394+ WS . SPACE ,
395+ ( comment as LineCommentNode ) . text ,
396+ WS . MANDATORY_NEWLINE ,
397+ WS . INDENT
398+ ) ;
399+ } else {
400+ this . layout . add ( ( comment as BlockCommentNode ) . text , WS . MANDATORY_NEWLINE , WS . INDENT ) ;
401+ }
402+ }
403+ }
404+ } else {
405+ this . layout . add ( WS . NO_SPACE , ',' , WS . NEWLINE , WS . INDENT ) ;
406+ }
407+ }
355408 private formatLeadingComma ( ) {
356409 const comments : AstNode [ ] = [ ] ;
357410 let lookAheadIndex = this . index + 1 ;
@@ -433,6 +486,11 @@ export default class ExpressionFormatter {
433486 }
434487
435488 private formatLineComment ( node : LineCommentNode ) {
489+ if ( ! this . inline && this . cfg . commaPosition === 'trailing' && this . isNextNonCommentNodeComma ( ) ) {
490+ // Store the comment to be output after the comma
491+ this . pendingLineComment . push ( node ) ;
492+ return ;
493+ }
436494 if ( isMultiline ( node . precedingWhitespace || '' ) ) {
437495 this . layout . add ( WS . NEWLINE , WS . INDENT , node . text , WS . MANDATORY_NEWLINE , WS . INDENT ) ;
438496 } else if ( this . layout . getLayoutItems ( ) . length > 0 ) {
@@ -442,8 +500,25 @@ export default class ExpressionFormatter {
442500 this . layout . add ( node . text , WS . MANDATORY_NEWLINE , WS . INDENT ) ;
443501 }
444502 }
503+ private isNextNonCommentNodeComma ( ) : boolean {
504+ let lookAheadIndex = this . index + 1 ;
505+ while ( lookAheadIndex < this . nodes . length ) {
506+ const nextNode = this . nodes [ lookAheadIndex ] ;
507+ if ( nextNode . type === NodeType . line_comment || nextNode . type === NodeType . block_comment ) {
508+ lookAheadIndex ++ ;
509+ } else {
510+ return nextNode . type === NodeType . comma ;
511+ }
512+ }
513+ return false ;
514+ }
445515
446516 private formatBlockComment ( node : BlockCommentNode | DisableCommentNode ) {
517+ if ( ! this . inline && this . cfg . commaPosition === 'trailing' && this . isNextNonCommentNodeComma ( ) ) {
518+ // Store the comment to be output after the comma
519+ this . pendingLineComment . push ( node ) ;
520+ return ;
521+ }
447522 if ( node . type === NodeType . block_comment && this . isMultilineBlockComment ( node ) ) {
448523 this . splitBlockComment ( node . text ) . forEach ( line => {
449524 this . layout . add ( WS . NEWLINE , WS . INDENT , line ) ;
0 commit comments