fix(formatter): keep trailing double spaces on JSDoc lines (#26861)

Prettier keeps a trailing double space on the middle lines of a `/**`
comment (prettier/prettier#18594, in the pinned 3.9.6): it is a Markdown
hard line break that doc tooling renders (prettier/prettier#6793). We
printed every aligned line through `trim()`, so the spaces were dropped:

```tsx
/**
 * JSDoc with new line using double space  
 * It's on another line
 */
```

Match Prettier's `printIndentableBlockComment`: in a `/**` comment (not
`/***`), a middle line whose source ends with two or more spaces keeps
exactly two after its trimmed content. A bare `*` line, a single
trailing space, the opening line, and non-JSDoc block comments are
trimmed as before. The check is textual rather than `comment.is_jsdoc()`
because the parser also tags `/***` as JSDoc and Prettier's test is
textual. The printer never trims text at a line end, so writing the two
spaces before the next hard line break is enough.

Fixture `js/comments/jsdoc-trailing-double-space.js` mirrors Prettier's
`tests/format/js/comments/trailing-spaces` cases plus a plain `/*`
block; its output is byte-identical to Prettier 3.9.8. One line added to
`js/crlf/block-comment.js` pins the CRLF output. `cargo test -p
oxc_formatter`, clippy and fmt are clean; I did not run the
`tasks/coverage` idempotency suites locally.

Written with help from an AI assistant (Claude); reviewed and tested by
me.

Closes #26854

---------

Co-authored-by: leaysgur <6259812+leaysgur@users.noreply.github.com>
This commit is contained in:
John Costaandleaysgur authored and GitHub committed 2026-09-25 15:00:43 +09:00
1 parent 5186328763
commit cd45f71d0d
5 files changed
+214 -1

No files matched your search

+9 -1
View File
@@ -564,9 +564,17 @@ impl<'a> Format<'a, JsFormatContext<'a>> for FormatCommentText<'_> {
let first_line = lines.next().unwrap();
write!(f, [text(first_line.trim_end())]);
// Not `comment.is_jsdoc()`, which also accepts `/***`
let is_jsdoc = content.starts_with("/**") && !content.starts_with("/***");
// Indent the remaining lines by one space so that all `*` are aligned.
for line in lines {
write!(f, [hard_line_break(), " ", text(line.trim())]);
let trimmed = line.trim();
write!(f, [hard_line_break(), " ", text(trimmed)]);
// Keep a Markdown hard line break in JSDoc, as 2 trailing spaces
if is_jsdoc && trimmed != "*" && line.ends_with(" ") {
write!(f, [" "]);
}
}
} else {
// Normalize line endings `\r\n` to `\n`
@@ -0,0 +1,46 @@
// Prettier keeps a trailing double space on JSDoc lines (prettier/prettier#18594).
/**
* Two spaces stay.
* It's on another line
*/
function two() {}
/**
* Three spaces collapse to two.
* next
*/
function three() {}
/**
* One space goes.
* next
*/
function one() {}
/**
*
* A bare star line drops its spaces.
*/
function bare() {}
/**
* Spaces on the opening line go, spaces here stay.
*/
function opening() {}
function nested() {
/**
* Misaligned and indented, spaces stay.
*/
return 1;
}
/***
* Not JSDoc, spaces go.
*/
function notJsdoc() {}
/*
* Plain block comment, spaces go.
*/
function plain() {}
@@ -0,0 +1,153 @@
---
source: crates/oxc_formatter/tests/fixtures/mod.rs
---
==================== Input ====================
// Prettier keeps a trailing double space on JSDoc lines (prettier/prettier#18594).
/**
* Two spaces stay.
* It's on another line
*/
function two() {}
/**
* Three spaces collapse to two.
* next
*/
function three() {}
/**
* One space goes.
* next
*/
function one() {}
/**
*
* A bare star line drops its spaces.
*/
function bare() {}
/**
* Spaces on the opening line go, spaces here stay.
*/
function opening() {}
function nested() {
/**
* Misaligned and indented, spaces stay.
*/
return 1;
}
/***
* Not JSDoc, spaces go.
*/
function notJsdoc() {}
/*
* Plain block comment, spaces go.
*/
function plain() {}
==================== Output ====================
------------------
{ printWidth: 80 }
------------------
// Prettier keeps a trailing double space on JSDoc lines (prettier/prettier#18594).
/**
* Two spaces stay.
* It's on another line
*/
function two() {}
/**
* Three spaces collapse to two.
* next
*/
function three() {}
/**
* One space goes.
* next
*/
function one() {}
/**
*
* A bare star line drops its spaces.
*/
function bare() {}
/**
* Spaces on the opening line go, spaces here stay.
*/
function opening() {}
function nested() {
/**
* Misaligned and indented, spaces stay.
*/
return 1;
}
/***
* Not JSDoc, spaces go.
*/
function notJsdoc() {}
/*
* Plain block comment, spaces go.
*/
function plain() {}
-------------------
{ printWidth: 100 }
-------------------
// Prettier keeps a trailing double space on JSDoc lines (prettier/prettier#18594).
/**
* Two spaces stay.
* It's on another line
*/
function two() {}
/**
* Three spaces collapse to two.
* next
*/
function three() {}
/**
* One space goes.
* next
*/
function one() {}
/**
*
* A bare star line drops its spaces.
*/
function bare() {}
/**
* Spaces on the opening line go, spaces here stay.
*/
function opening() {}
function nested() {
/**
* Misaligned and indented, spaces stay.
*/
return 1;
}
/***
* Not JSDoc, spaces go.
*/
function notJsdoc() {}
/*
* Plain block comment, spaces go.
*/
function plain() {}
===================== End =====================
@@ -6,6 +6,7 @@ block
/**
* js doc
* hard break kept
* @type {string}
* @description This is a description.
*/
@@ -10,6 +10,7 @@ block
/**
* js doc
* hard break kept
* @type {string}
* @description This is a description.
*/
@@ -28,6 +29,7 @@ block
/**
* js doc
* hard break kept
* @type {string}
* @description This is a description.
*/
@@ -45,6 +47,7 @@ block
/**
* js doc
* hard break kept
* @type {string}
* @description This is a description.
*/
@@ -62,6 +65,7 @@ block
/**
* js doc
* hard break kept
* @type {string}
* @description This is a description.
*/
@@ -79,6 +83,7 @@ block
/**
* js doc
* hard break kept
* @type {string}
* @description This is a description.
*/