Skip to content

Commit cd45f71

Browse files
costajohntleaysgur
andauthored
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>
1 parent 5186328 commit cd45f71

5 files changed

Lines changed: 214 additions & 1 deletion

File tree

‎crates/oxc_formatter/src/formatter/trivia.rs‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,9 +564,17 @@ impl<'a> Format<'a, JsFormatContext<'a>> for FormatCommentText<'_> {
564564
let first_line = lines.next().unwrap();
565565
write!(f, [text(first_line.trim_end())]);
566566

567+
// Not `comment.is_jsdoc()`, which also accepts `/***`
568+
let is_jsdoc = content.starts_with("/**") && !content.starts_with("/***");
569+
567570
// Indent the remaining lines by one space so that all `*` are aligned.
568571
for line in lines {
569-
write!(f, [hard_line_break(), " ", text(line.trim())]);
572+
let trimmed = line.trim();
573+
write!(f, [hard_line_break(), " ", text(trimmed)]);
574+
// Keep a Markdown hard line break in JSDoc, as 2 trailing spaces
575+
if is_jsdoc && trimmed != "*" && line.ends_with(" ") {
576+
write!(f, [" "]);
577+
}
570578
}
571579
} else {
572580
// Normalize line endings `\r\n` to `\n`
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Prettier keeps a trailing double space on JSDoc lines (prettier/prettier#18594).
2+
/**
3+
* Two spaces stay.
4+
* It's on another line
5+
*/
6+
function two() {}
7+
8+
/**
9+
* Three spaces collapse to two.
10+
* next
11+
*/
12+
function three() {}
13+
14+
/**
15+
* One space goes.
16+
* next
17+
*/
18+
function one() {}
19+
20+
/**
21+
*
22+
* A bare star line drops its spaces.
23+
*/
24+
function bare() {}
25+
26+
/**
27+
* Spaces on the opening line go, spaces here stay.
28+
*/
29+
function opening() {}
30+
31+
function nested() {
32+
/**
33+
* Misaligned and indented, spaces stay.
34+
*/
35+
return 1;
36+
}
37+
38+
/***
39+
* Not JSDoc, spaces go.
40+
*/
41+
function notJsdoc() {}
42+
43+
/*
44+
* Plain block comment, spaces go.
45+
*/
46+
function plain() {}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
---
2+
source: crates/oxc_formatter/tests/fixtures/mod.rs
3+
---
4+
==================== Input ====================
5+
// Prettier keeps a trailing double space on JSDoc lines (prettier/prettier#18594).
6+
/**
7+
* Two spaces stay.
8+
* It's on another line
9+
*/
10+
function two() {}
11+
12+
/**
13+
* Three spaces collapse to two.
14+
* next
15+
*/
16+
function three() {}
17+
18+
/**
19+
* One space goes.
20+
* next
21+
*/
22+
function one() {}
23+
24+
/**
25+
*
26+
* A bare star line drops its spaces.
27+
*/
28+
function bare() {}
29+
30+
/**
31+
* Spaces on the opening line go, spaces here stay.
32+
*/
33+
function opening() {}
34+
35+
function nested() {
36+
/**
37+
* Misaligned and indented, spaces stay.
38+
*/
39+
return 1;
40+
}
41+
42+
/***
43+
* Not JSDoc, spaces go.
44+
*/
45+
function notJsdoc() {}
46+
47+
/*
48+
* Plain block comment, spaces go.
49+
*/
50+
function plain() {}
51+
52+
==================== Output ====================
53+
------------------
54+
{ printWidth: 80 }
55+
------------------
56+
// Prettier keeps a trailing double space on JSDoc lines (prettier/prettier#18594).
57+
/**
58+
* Two spaces stay.
59+
* It's on another line
60+
*/
61+
function two() {}
62+
63+
/**
64+
* Three spaces collapse to two.
65+
* next
66+
*/
67+
function three() {}
68+
69+
/**
70+
* One space goes.
71+
* next
72+
*/
73+
function one() {}
74+
75+
/**
76+
*
77+
* A bare star line drops its spaces.
78+
*/
79+
function bare() {}
80+
81+
/**
82+
* Spaces on the opening line go, spaces here stay.
83+
*/
84+
function opening() {}
85+
86+
function nested() {
87+
/**
88+
* Misaligned and indented, spaces stay.
89+
*/
90+
return 1;
91+
}
92+
93+
/***
94+
* Not JSDoc, spaces go.
95+
*/
96+
function notJsdoc() {}
97+
98+
/*
99+
* Plain block comment, spaces go.
100+
*/
101+
function plain() {}
102+
103+
-------------------
104+
{ printWidth: 100 }
105+
-------------------
106+
// Prettier keeps a trailing double space on JSDoc lines (prettier/prettier#18594).
107+
/**
108+
* Two spaces stay.
109+
* It's on another line
110+
*/
111+
function two() {}
112+
113+
/**
114+
* Three spaces collapse to two.
115+
* next
116+
*/
117+
function three() {}
118+
119+
/**
120+
* One space goes.
121+
* next
122+
*/
123+
function one() {}
124+
125+
/**
126+
*
127+
* A bare star line drops its spaces.
128+
*/
129+
function bare() {}
130+
131+
/**
132+
* Spaces on the opening line go, spaces here stay.
133+
*/
134+
function opening() {}
135+
136+
function nested() {
137+
/**
138+
* Misaligned and indented, spaces stay.
139+
*/
140+
return 1;
141+
}
142+
143+
/***
144+
* Not JSDoc, spaces go.
145+
*/
146+
function notJsdoc() {}
147+
148+
/*
149+
* Plain block comment, spaces go.
150+
*/
151+
function plain() {}
152+
153+
===================== End =====================

‎crates/oxc_formatter/tests/fixtures/js/crlf/block-comment.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ block
66

77
/**
88
* js doc
9+
* hard break kept
910
* @type {string}
1011
* @description This is a description.
1112
*/

‎crates/oxc_formatter/tests/fixtures/js/crlf/block-comment.js.snap‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ block
1010

1111
/**
1212
* js doc
13+
* hard break kept
1314
* @type {string}
1415
* @description This is a description.
1516
*/
@@ -28,6 +29,7 @@ block
2829

2930
/**
3031
* js doc
32+
* hard break kept
3133
* @type {string}
3234
* @description This is a description.
3335
*/
@@ -45,6 +47,7 @@ block
4547

4648
/**
4749
* js doc
50+
* hard break kept
4851
* @type {string}
4952
* @description This is a description.
5053
*/
@@ -62,6 +65,7 @@ block
6265

6366
/**
6467
* js doc
68+
* hard break kept
6569
* @type {string}
6670
* @description This is a description.
6771
*/
@@ -79,6 +83,7 @@ block
7983

8084
/**
8185
* js doc
86+
* hard break kept
8287
* @type {string}
8388
* @description This is a description.
8489
*/

0 commit comments

Comments
 (0)