Skip to content

Commit 76707bf

Browse files
authored
fix: ensure stable formatting for comment with spaced asterisks (#514)
1 parent 57d0d1b commit 76707bf

File tree

3 files changed

+102
-9
lines changed

3 files changed

+102
-9
lines changed

src/generation/generate.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6468,16 +6468,23 @@ fn gen_comment(comment: &Comment, context: &mut Context) -> Option<PrintItems> {
64686468
}
64696469

64706470
fn gen_js_doc_or_multiline_block(comment: &Comment, _context: &mut Context) -> PrintItems {
6471+
debug_assert_eq!(comment.kind, CommentKind::Block);
64716472
let is_js_doc = comment.text.starts_with('*');
64726473
return lines_to_print_items(is_js_doc, build_lines(comment));
64736474

64746475
fn build_lines(comment: &Comment) -> Vec<&str> {
64756476
let mut lines: Vec<&str> = Vec::new();
64766477

64776478
for line in utils::split_lines(&comment.text) {
6478-
let line = line[get_line_start_index(line)..].trim_end();
6479-
if !line.is_empty() || !lines.last().map(|l| l.is_empty()).unwrap_or(false) {
6480-
lines.push(line);
6479+
let text = if line.line_index == 0 && !line.text.starts_with('*') {
6480+
line.text
6481+
} else {
6482+
&line.text[get_line_start_index(line.text)..]
6483+
};
6484+
let text = if line.is_last && !text.trim().is_empty() { text } else { text.trim_end() };
6485+
6486+
if !text.is_empty() || !lines.last().map(|l| l.is_empty()).unwrap_or(false) {
6487+
lines.push(text);
64816488
}
64826489
}
64836490

@@ -6528,7 +6535,7 @@ fn gen_js_doc_or_multiline_block(comment: &Comment, _context: &mut Context) -> P
65286535

65296536
items.push_str(if lines.len() > 1 && lines.last().map(|l| l.is_empty()).unwrap_or(false) {
65306537
"/"
6531-
} else if lines.len() > 1 && lines.last().map(|l| l.ends_with('*')).unwrap_or(false) {
6538+
} else if lines.len() > 1 && lines.last().map(|l| l.ends_with('*') || l.ends_with(' ')).unwrap_or(false) {
65326539
"*/"
65336540
} else {
65346541
" */"

src/utils/string_utils.rs

Lines changed: 80 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,21 +80,52 @@ pub fn is_not_empty_and_only_spaces(text: &str) -> bool {
8080
true
8181
}
8282

83+
#[derive(Debug, PartialEq, Eq)]
84+
pub struct SplitLinesItem<'a> {
85+
pub text: &'a str,
86+
pub line_index: usize,
87+
pub is_last: bool,
88+
}
89+
8390
pub struct SplitLinesIterator<'a> {
91+
text: &'a str,
8492
inner: std::str::Split<'a, char>,
93+
line_index: usize,
94+
byte_index: usize,
8595
}
8696

8797
impl<'a> Iterator for SplitLinesIterator<'a> {
88-
type Item = &'a str;
98+
type Item = SplitLinesItem<'a>;
8999

90100
fn next(&mut self) -> Option<Self::Item> {
101+
let line_index = self.line_index;
91102
let line = self.inner.next();
92-
line.map(|line| line.strip_suffix('\r').unwrap_or(line))
103+
match line {
104+
Some(line) => {
105+
if self.line_index == 0 {
106+
self.byte_index += line.len();
107+
} else {
108+
self.byte_index += 1 + line.len();
109+
}
110+
self.line_index += 1;
111+
Some(SplitLinesItem {
112+
is_last: self.byte_index == self.text.len(),
113+
line_index,
114+
text: line.strip_suffix('\r').unwrap_or(line),
115+
})
116+
}
117+
None => None,
118+
}
93119
}
94120
}
95121

96122
pub fn split_lines(text: &str) -> SplitLinesIterator<'_> {
97-
SplitLinesIterator { inner: text.split('\n') }
123+
SplitLinesIterator {
124+
inner: text.split('\n'),
125+
line_index: 0,
126+
text,
127+
byte_index: 0,
128+
}
98129
}
99130

100131
#[cfg(test)]
@@ -105,13 +136,57 @@ mod test {
105136
fn split_lines_empty_last_line() {
106137
let text = "a\r\nb\nc\r\n";
107138
let lines = split_lines(text).collect::<Vec<_>>();
108-
assert_eq!(lines, vec!["a", "b", "c", ""]); // includes last line
139+
assert_eq!(
140+
lines,
141+
vec![
142+
SplitLinesItem {
143+
text: "a",
144+
is_last: false,
145+
line_index: 0,
146+
},
147+
SplitLinesItem {
148+
text: "b",
149+
is_last: false,
150+
line_index: 1,
151+
},
152+
SplitLinesItem {
153+
text: "c",
154+
is_last: false,
155+
line_index: 2
156+
},
157+
// includes last line
158+
SplitLinesItem {
159+
text: "",
160+
is_last: true,
161+
line_index: 3,
162+
}
163+
]
164+
);
109165
}
110166

111167
#[test]
112168
fn split_lines_non_empty_last_line() {
113169
let text = "a \n b\nc";
114170
let lines = split_lines(text).collect::<Vec<_>>();
115-
assert_eq!(lines, vec!["a ", " b", "c"]);
171+
assert_eq!(
172+
lines,
173+
vec![
174+
SplitLinesItem {
175+
text: "a ",
176+
line_index: 0,
177+
is_last: false,
178+
},
179+
SplitLinesItem {
180+
text: " b",
181+
line_index: 1,
182+
is_last: false,
183+
},
184+
SplitLinesItem {
185+
text: "c",
186+
line_index: 2,
187+
is_last: true,
188+
}
189+
]
190+
);
116191
}
117192
}

tests/specs/issues/issue0511.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
== should be stable ==
2+
/* * * * * * * * * * *
3+
* Some Text Here1 *
4+
* * * * * * * * * * */
5+
const test = 5;
6+
7+
[expect]
8+
/* * * * * * * * * * *
9+
* Some Text Here1 *
10+
* * * * * * * * * * */
11+
const test = 5;

0 commit comments

Comments
 (0)