mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-06 17:34:25 +00:00
fix(minifier): preserve raw CR in template literals (#21645)
## Summary
Fixes raw carriage return escaping when the minifier folds a `RegExp` constructor argument into a template literal.
## Problem
`replace_known_methods` can combine a string literal and template literal into a new template literal raw segment, for example:
```js
const re = new RegExp('\r' + `${x.source}`)
```
The old escaping handled backslashes, backticks, `${`, and the `\r\n` sequence, but not a standalone carriage return. That allowed a raw CR to be emitted directly into the generated template literal source.
This is not only a second-run idempotency issue. The first minifier pass was already producing unsafe generated source for a raw template element. Re-parsing that output can normalize it differently, which then shows up as a second-pass output change.
## Fix
- Escape every `\r` in generated template literal raw text as `\\r`.
- Keep the existing escaping for `\`, `` ` ``, and `$`.
- Preserve CRLF behavior: `\r\n` still becomes `\\r` followed by the LF line break, matching the existing intended output shape while also covering lone CR.
## Test
Adds minimal regressions to the existing `test_add_template_literal` test in `replace_known_methods.rs`, using the existing `test_value` helper:
```js
const re = new RegExp('\r' + `${x.source}`)
```
The cases cover a lone CR, CRLF, and multiple CR characters. The shared helper verifies the first minifier pass emits the expected raw template text and that running the minifier again on that output is idempotent.
## Testing
- `cargo test -p oxc_minifier test_add_template_literal`
This commit is contained in:
1 parent
453d64781c
commit
0d608c2930
2 files changed
+6
-1
No files matched your search
@@ -353,7 +353,7 @@ impl<'a> PeepholeOptimizations {
|
||||
s.cow_replace("\\", "\\\\")
|
||||
.cow_replace("`", "\\`")
|
||||
.cow_replace("$", "\\$")
|
||||
.cow_replace("\r\n", "\\r\n")
|
||||
.cow_replace('\r', "\\r")
|
||||
.into_owned(),
|
||||
)
|
||||
} else {
|
||||
|
||||
@@ -817,6 +817,11 @@ fn test_add_template_literal() {
|
||||
test("x = `{${x}}` + '$'", "x = `{${x}}\\$`");
|
||||
test("x = `$` + `{${x}}`", "x = `\\${${x}}`");
|
||||
test("x = `{${x}}` + `$`", "x = `{${x}}\\$`");
|
||||
// `\r` must be escaped, otherwise the parser would normalize a literal CR
|
||||
// in template raw to `\n` on re-parse, changing the cooked value.
|
||||
test_value("'\\r' + `${x}`", "`\\r${x}`");
|
||||
test_value("'\\r\\n' + `${x}`", "`\\r\n${x}`");
|
||||
test_value("'\\r\\rfoo' + `${x}`", "`\\r\\rfoo${x}`");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in new issue
Block a user