Skip to content

Commit

Permalink
fix(lint/useTemplate): correctly escape characters (#2600)
Browse files Browse the repository at this point in the history
  • Loading branch information
Conaclos authored and ematipico committed Apr 26, 2024
1 parent 4cd10c0 commit 1ba2c49
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 21 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b

Contributed by @Conaclos

- Fix [useTemplate](https://biomejs.dev/linter/rules/use-template/) that wrongly escaped strings in some edge cases ([#2580](https://github.com/biomejs/biome/issues/2580)).

Previously, the rule didn't correctly escaped characters preceded by an escaped character.

Contributed by @Conaclos

### Parser

## 1.7.1 (2024-04-22)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Issue https://github.com/biomejs/biome/issues/2580
'```ts\n' + x + '\n```';
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
source: crates/biome_js_analyze/tests/spec_tests.rs
expression: invalidIssue2580.js
---
# Input
```jsx
// Issue https://github.com/biomejs/biome/issues/2580
'```ts\n' + x + '\n```';
```

# Diagnostics
```
invalidIssue2580.js:2:1 lint/style/useTemplate FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
! Template literals are preferred over string concatenation.
1 │ // Issue https://github.com/biomejs/biome/issues/2580
> 2 │ '```ts\n' + x + '\n```';
│ ^^^^^^^^^^^^^^^^^^^^^^^
i Unsafe fix: Use a template literal.
1 1 │ // Issue https://github.com/biomejs/biome/issues/2580
2 │ - '```ts\n'·+·x·+·'\n```';
2 │ + `\`\`\`ts\n${x}\n\`\`\``;
```
39 changes: 18 additions & 21 deletions crates/biome_js_factory/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,41 +17,36 @@ pub fn escape<'a>(
needs_escaping: &[&str],
escaping_char: char,
) -> std::borrow::Cow<'a, str> {
debug_assert!(!needs_escaping.is_empty());
let mut escaped = String::new();
let mut iter = unescaped_string.char_indices();
let mut is_escaped = false;
'unescaped: while let Some((idx, chr)) = iter.next() {
let mut last_copied_idx = 0;
while let Some((idx, chr)) = iter.next() {
if chr == escaping_char {
is_escaped = !is_escaped;
// The next character is esacaped
iter.next();
} else {
for candidate in needs_escaping {
if unescaped_string[idx..].starts_with(candidate) {
if !is_escaped {
if escaped.is_empty() {
escaped = String::with_capacity(unescaped_string.len() * 2);
escaped.push_str(&unescaped_string[0..idx]);
}
escaped.push(escaping_char);
escaped.push_str(candidate);
for _ in candidate.chars().skip(1) {
iter.next();
}
continue 'unescaped;
} else {
is_escaped = false;
if escaped.is_empty() {
escaped = String::with_capacity(unescaped_string.len() * 2 - idx);
}
escaped.push_str(&unescaped_string[last_copied_idx..idx]);
escaped.push(escaping_char);
escaped.push_str(candidate);
for _ in candidate.chars().skip(1) {
iter.next();
}
last_copied_idx = idx + candidate.len();
break;
}
}
}

if !escaped.is_empty() {
escaped.push(chr);
}
}

if escaped.is_empty() {
std::borrow::Cow::Borrowed(unescaped_string)
} else {
escaped.push_str(&unescaped_string[last_copied_idx..unescaped_string.len()]);
std::borrow::Cow::Owned(escaped)
}
}
Expand Down Expand Up @@ -87,5 +82,7 @@ mod tests {
);
assert_eq!(escape(r"abc \${bca}", &["${", "`"], '\\'), r"abc \${bca}");
assert_eq!(escape(r"abc \`bca", &["${", "`"], '\\'), r"abc \`bca");

assert_eq!(escape(r"\n`", &["`"], '\\'), r"\n\`");
}
}

0 comments on commit 1ba2c49

Please sign in to comment.