Skip to content

Commit cda9b64

Browse files
committed
handle crlf lines better
1 parent 32c1050 commit cda9b64

File tree

3 files changed

+225
-32
lines changed

3 files changed

+225
-32
lines changed

crates/biome_js_analyze/src/lint/nursery/use_single_js_doc_asterisk.rs

+28-32
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::borrow::Cow;
2+
13
use biome_analyze::{
24
Ast, FixKind, Rule, RuleDiagnostic, RuleSource, context::RuleContext, declare_lint_rule,
35
};
@@ -86,13 +88,7 @@ impl Rule for UseSingleJsDocAsterisk {
8688
let text = comment.text();
8789

8890
let invalid_line = get_invalid_jsdoc_line(text)?;
89-
90-
let line_offset =
91-
text.lines()
92-
.take(invalid_line.line_index)
93-
.fold(0, |acc, line| {
94-
acc + line.len() + 1 // +1 for the line break
95-
});
91+
let line_offset = get_line_char_start_index(text, invalid_line.line_index);
9692

9793
let start_size =
9894
comment.text_range().start() + TextSize::from(line_offset as u32);
@@ -107,7 +103,9 @@ impl Rule for UseSingleJsDocAsterisk {
107103
Some(RuleState {
108104
token: token.clone(),
109105
range: range_modified,
110-
line_indexes: invalid_line,
106+
is_end_line: invalid_line.is_end_line,
107+
char_start: line_offset + invalid_line.char_start,
108+
char_end: line_offset + invalid_line.char_end,
111109
comment_text: text.to_string(),
112110
})
113111
})
@@ -120,11 +118,7 @@ impl Rule for UseSingleJsDocAsterisk {
120118
}
121119

122120
fn diagnostic(_ctx: &RuleContext<Self>, state: &Self::State) -> Option<RuleDiagnostic> {
123-
let position = if state.line_indexes.is_end_line {
124-
"end"
125-
} else {
126-
"start"
127-
};
121+
let position = if state.is_end_line { "end" } else { "start" };
128122

129123
Some(RuleDiagnostic::new(
130124
rule_category!(),
@@ -136,30 +130,26 @@ impl Rule for UseSingleJsDocAsterisk {
136130
}
137131

138132
fn action(ctx: &RuleContext<Self>, state: &Self::State) -> Option<JsRuleAction> {
139-
let invalid_line_data = &state.line_indexes;
140133
let token = state.token.clone();
141134
let mut mutation = ctx.root().begin();
142135
let mut new_trivia = vec![];
143136
let mut text = String::new();
144137
for trivia in token.clone().leading_trivia().pieces() {
145138
let kind = trivia.kind();
146139
if let Some(comment) = trivia.as_comments() {
147-
let comment_text = comment.text();
148-
let mut lines: Vec<&str> = comment_text.lines().collect();
140+
let mut comment_text = Cow::Borrowed(comment.text());
149141

150142
if comment.text() == state.comment_text {
151-
if let Some(line) = lines.get_mut(invalid_line_data.line_index) {
152-
let start = invalid_line_data.char_start;
153-
let end = invalid_line_data.char_end;
154-
155-
let new_line = format!("{}{}", &line[..start], &line[end..]);
156-
lines[invalid_line_data.line_index] = Box::leak(new_line.into_boxed_str());
157-
}
143+
let new_comment_text = format!(
144+
"{}{}",
145+
&comment_text[..state.char_start],
146+
&comment_text[state.char_end..]
147+
);
148+
comment_text = Cow::Owned(new_comment_text);
158149
}
159150

160-
let new_comment = lines.join("\n");
161-
new_trivia.push(TriviaPiece::new(kind, new_comment.text_len()));
162-
text.push_str(new_comment.as_str());
151+
new_trivia.push(TriviaPiece::new(kind, comment_text.text_len()));
152+
text.push_str(comment_text.as_ref());
163153
} else {
164154
new_trivia.push(TriviaPiece::new(kind, trivia.text_len()));
165155
text.push_str(trivia.text());
@@ -184,7 +174,9 @@ impl Rule for UseSingleJsDocAsterisk {
184174
pub struct RuleState {
185175
token: JsSyntaxToken,
186176
range: TextRange,
187-
line_indexes: InvalidJsDocLineIndexes,
177+
is_end_line: bool,
178+
char_start: usize,
179+
char_end: usize,
188180
comment_text: String,
189181
}
190182

@@ -246,12 +238,9 @@ fn get_invalid_jsdoc_line_start(text: &str) -> Option<InvalidJsDocLineIndexes> {
246238
continue;
247239
}
248240

249-
if char_is_whitespace(b) {
250-
continue;
241+
if !char_is_whitespace(b) {
242+
break;
251243
}
252-
253-
// Found non-whitespace character
254-
break;
255244
}
256245

257246
invalid_asterisk_index.map(|char_index| (line_index, char_index + 1))
@@ -306,3 +295,10 @@ fn get_invalid_jsdoc_line(text: &str) -> Option<InvalidJsDocLineIndexes> {
306295

307296
get_invalid_jsdoc_line_start(text).or_else(|| get_invalid_jsdoc_last_line(text))
308297
}
298+
299+
fn get_line_char_start_index(text: &str, line_index: usize) -> usize {
300+
// Use split() instead of lines() to properly handle windows CRLF line endings
301+
text.split('\n').take(line_index).fold(0, |acc, line| {
302+
acc + line.len() + 1 // +1 for the newline character
303+
})
304+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* End of comment double asterisk
3+
**/
4+
5+
/**
6+
*
7+
** Middle
8+
*/
9+
10+
/**
11+
*
12+
**
13+
*
14+
*/
15+
16+
/**
17+
*
18+
* *Asterisk right next to the text
19+
*/
20+
21+
/**
22+
* Desc.
23+
*
24+
abc * **/
25+
26+
/** @someTag SameLine2 Double **/
27+
28+
/** SameLine DoubleWithSpace * */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
---
2+
source: crates/biome_js_analyze/tests/spec_tests.rs
3+
expression: invalid-crlf.js
4+
---
5+
# Input
6+
```js
7+
/**
8+
* End of comment double asterisk
9+
**/
10+
11+
/**
12+
*
13+
** Middle
14+
*/
15+
16+
/**
17+
*
18+
**
19+
*
20+
*/
21+
22+
/**
23+
*
24+
* *Asterisk right next to the text
25+
*/
26+
27+
/**
28+
* Desc.
29+
*
30+
abc * **/
31+
32+
/** @someTag SameLine2 Double **/
33+
34+
/** SameLine DoubleWithSpace * */
35+
36+
```
37+
38+
# Diagnostics
39+
```
40+
invalid-crlf.js:3:1 lint/nursery/useSingleJsDocAsterisk FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
41+
42+
i JSDoc comment line should end with a single asterisk.
43+
44+
1 │ /**
45+
2 │ * End of comment double asterisk
46+
> 3 │ **/
47+
│ ^^^^
48+
4 │
49+
5 │ /**
50+
51+
i Unsafe fix: Remove additional asterisks.
52+
53+
3 │ ·**/␍
54+
│ -
55+
56+
```
57+
58+
```
59+
invalid-crlf.js:7:1 lint/nursery/useSingleJsDocAsterisk FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
60+
61+
i JSDoc comment line should start with a single asterisk.
62+
63+
5 │ /**
64+
6 │ *
65+
> 7 │ ** Middle
66+
│ ^^^^^^^^^^
67+
8 │ */
68+
9 │
69+
70+
i Unsafe fix: Remove additional asterisks.
71+
72+
7 │ ·**·Middle␍
73+
│ -
74+
75+
```
76+
77+
```
78+
invalid-crlf.js:12:1 lint/nursery/useSingleJsDocAsterisk FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
79+
80+
i JSDoc comment line should start with a single asterisk.
81+
82+
10 │ /**
83+
11 │ *
84+
> 12 │ **
85+
│ ^^^
86+
13 │ *
87+
14 │ */
88+
89+
i Unsafe fix: Remove additional asterisks.
90+
91+
12 │ ·**␍
92+
│ -
93+
94+
```
95+
96+
```
97+
invalid-crlf.js:18:1 lint/nursery/useSingleJsDocAsterisk FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
98+
99+
i JSDoc comment line should start with a single asterisk.
100+
101+
16 │ /**
102+
17 │ *
103+
> 18 │ * *Asterisk right next to the text
104+
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
105+
19 │ */
106+
20 │
107+
108+
i Unsafe fix: Remove additional asterisks.
109+
110+
18 │ ·*·*Asterisk·right·next·to·the·text␍
111+
│ --
112+
113+
```
114+
115+
```
116+
invalid-crlf.js:24:1 lint/nursery/useSingleJsDocAsterisk FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
117+
118+
i JSDoc comment line should end with a single asterisk.
119+
120+
22 │ * Desc.
121+
23 │ *
122+
> 24 │ abc * **/
123+
│ ^^^^^^^^^^
124+
25 │
125+
26 │ /** @someTag SameLine2 Double **/
126+
127+
i Unsafe fix: Remove additional asterisks.
128+
129+
24 │ ·abc·*·**/␍
130+
│ ---
131+
132+
```
133+
134+
```
135+
invalid-crlf.js:26:1 lint/nursery/useSingleJsDocAsterisk FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
136+
137+
i JSDoc comment line should end with a single asterisk.
138+
139+
24 │ abc * **/
140+
25 │
141+
> 26 │ /** @someTag SameLine2 Double **/
142+
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
143+
27 │
144+
28 │ /** SameLine DoubleWithSpace * */
145+
146+
i Unsafe fix: Remove additional asterisks.
147+
148+
26 │ /**·@someTag·SameLine2·Double·**/␍
149+
│ -
150+
151+
```
152+
153+
```
154+
invalid-crlf.js:28:1 lint/nursery/useSingleJsDocAsterisk FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
155+
156+
i JSDoc comment line should end with a single asterisk.
157+
158+
26 │ /** @someTag SameLine2 Double **/
159+
27 │
160+
> 28 │ /** SameLine DoubleWithSpace * */
161+
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
162+
29 │
163+
164+
i Unsafe fix: Remove additional asterisks.
165+
166+
28 │ /**·SameLine·DoubleWithSpace·*·*/␍
167+
│ --
168+
169+
```

0 commit comments

Comments
 (0)