mirror of
https://github.com/swc-project/swc.git
synced 2024-11-23 17:54:15 +03:00
fix(es/minifier): Fix a bug in tpl string <-> string logic (#8510)
**Related issue:** - Closes #8496
This commit is contained in:
parent
104f604e50
commit
4946a11137
70
crates/swc/tests/fixture/issues-8xxx/8496/input/.swcrc
Normal file
70
crates/swc/tests/fixture/issues-8xxx/8496/input/.swcrc
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
{
|
||||||
|
"jsc": {
|
||||||
|
"parser": {
|
||||||
|
"syntax": "ecmascript",
|
||||||
|
"jsx": false
|
||||||
|
},
|
||||||
|
"loose": true,
|
||||||
|
"minify": {
|
||||||
|
"mangle": false,
|
||||||
|
"compress": {
|
||||||
|
"arguments": false,
|
||||||
|
"arrows": true,
|
||||||
|
"booleans": true,
|
||||||
|
"booleans_as_integers": false,
|
||||||
|
"collapse_vars": true,
|
||||||
|
"comparisons": true,
|
||||||
|
"computed_props": true,
|
||||||
|
"conditionals": true,
|
||||||
|
"dead_code": true,
|
||||||
|
"directives": true,
|
||||||
|
"drop_console": false,
|
||||||
|
"drop_debugger": true,
|
||||||
|
"evaluate": true,
|
||||||
|
"expression": false,
|
||||||
|
"hoist_funs": false,
|
||||||
|
"hoist_props": true,
|
||||||
|
"hoist_vars": false,
|
||||||
|
"if_return": true,
|
||||||
|
"join_vars": true,
|
||||||
|
"keep_classnames": false,
|
||||||
|
"keep_fargs": true,
|
||||||
|
"keep_fnames": false,
|
||||||
|
"keep_infinity": false,
|
||||||
|
"loops": true,
|
||||||
|
"negate_iife": true,
|
||||||
|
"properties": true,
|
||||||
|
"reduce_funcs": false,
|
||||||
|
"reduce_vars": false,
|
||||||
|
"side_effects": true,
|
||||||
|
"switches": true,
|
||||||
|
"typeofs": true,
|
||||||
|
"unsafe": false,
|
||||||
|
"unsafe_arrows": false,
|
||||||
|
"unsafe_comps": false,
|
||||||
|
"unsafe_Function": false,
|
||||||
|
"unsafe_math": false,
|
||||||
|
"unsafe_symbols": false,
|
||||||
|
"unsafe_methods": false,
|
||||||
|
"unsafe_proto": false,
|
||||||
|
"unsafe_regexp": false,
|
||||||
|
"unsafe_undefined": false,
|
||||||
|
"unused": true,
|
||||||
|
"const_to_let": true,
|
||||||
|
"pristine_globals": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"module": {
|
||||||
|
"type": "es6"
|
||||||
|
},
|
||||||
|
"minify": true,
|
||||||
|
"isModule": true,
|
||||||
|
"env": {
|
||||||
|
"targets": {
|
||||||
|
"chrome": 109
|
||||||
|
},
|
||||||
|
"coreJs": "3.21",
|
||||||
|
"mode": "usage"
|
||||||
|
}
|
||||||
|
}
|
3
crates/swc/tests/fixture/issues-8xxx/8496/input/1.js
Normal file
3
crates/swc/tests/fixture/issues-8xxx/8496/input/1.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const strWithDollar = `$login`;
|
||||||
|
|
||||||
|
export const use = `${strWithDollar}`; // expected: "$login" without \\
|
3
crates/swc/tests/fixture/issues-8xxx/8496/input/2.js
Normal file
3
crates/swc/tests/fixture/issues-8xxx/8496/input/2.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const strWithDollar = `$login`;
|
||||||
|
|
||||||
|
export const use = `${strWithDollar}${1}`; // expected: "$login" without \\
|
3
crates/swc/tests/fixture/issues-8xxx/8496/input/3.js
Normal file
3
crates/swc/tests/fixture/issues-8xxx/8496/input/3.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const strWithDollar = `$login`;
|
||||||
|
|
||||||
|
export const use = `${1}${strWithDollar}`; // expected: "$login" without \\
|
3
crates/swc/tests/fixture/issues-8xxx/8496/input/4.js
Normal file
3
crates/swc/tests/fixture/issues-8xxx/8496/input/4.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const strWithDollar = `$login`;
|
||||||
|
|
||||||
|
export const use = `asd${strWithDollar}`; // expected: "$login" without \\
|
3
crates/swc/tests/fixture/issues-8xxx/8496/input/5.js
Normal file
3
crates/swc/tests/fixture/issues-8xxx/8496/input/5.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const strWithDollar = `$login`;
|
||||||
|
|
||||||
|
export const use = `$${strWithDollar}`; // expected: "$login" without \\
|
3
crates/swc/tests/fixture/issues-8xxx/8496/input/6.js
Normal file
3
crates/swc/tests/fixture/issues-8xxx/8496/input/6.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const strWithDollar = `$login`;
|
||||||
|
|
||||||
|
export const use = `{${strWithDollar}`; // expected: "$login" without \\
|
3
crates/swc/tests/fixture/issues-8xxx/8496/input/7.js
Normal file
3
crates/swc/tests/fixture/issues-8xxx/8496/input/7.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const strWithDollar = `$login`;
|
||||||
|
|
||||||
|
export const use = `\{${strWithDollar}`; // expected: "$login" without \\
|
1
crates/swc/tests/fixture/issues-8xxx/8496/input/8.js
Normal file
1
crates/swc/tests/fixture/issues-8xxx/8496/input/8.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const use = `\xffathjax{$login`;
|
1
crates/swc/tests/fixture/issues-8xxx/8496/output/1.js
Normal file
1
crates/swc/tests/fixture/issues-8xxx/8496/output/1.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const strWithDollar="$login";export const use="$login";
|
1
crates/swc/tests/fixture/issues-8xxx/8496/output/2.js
Normal file
1
crates/swc/tests/fixture/issues-8xxx/8496/output/2.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const strWithDollar="$login";export const use="$login1";
|
1
crates/swc/tests/fixture/issues-8xxx/8496/output/3.js
Normal file
1
crates/swc/tests/fixture/issues-8xxx/8496/output/3.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const strWithDollar="$login";export const use="1$login";
|
1
crates/swc/tests/fixture/issues-8xxx/8496/output/4.js
Normal file
1
crates/swc/tests/fixture/issues-8xxx/8496/output/4.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const strWithDollar="$login";export const use="asd$login";
|
1
crates/swc/tests/fixture/issues-8xxx/8496/output/5.js
Normal file
1
crates/swc/tests/fixture/issues-8xxx/8496/output/5.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const strWithDollar="$login";export const use="$$login";
|
1
crates/swc/tests/fixture/issues-8xxx/8496/output/6.js
Normal file
1
crates/swc/tests/fixture/issues-8xxx/8496/output/6.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const strWithDollar="$login";export const use="{$login";
|
1
crates/swc/tests/fixture/issues-8xxx/8496/output/7.js
Normal file
1
crates/swc/tests/fixture/issues-8xxx/8496/output/7.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const strWithDollar="$login";export const use="{$login";
|
1
crates/swc/tests/fixture/issues-8xxx/8496/output/8.js
Normal file
1
crates/swc/tests/fixture/issues-8xxx/8496/output/8.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const use=`\xffathjax{$login`;
|
@ -265,6 +265,43 @@ impl Pure<'_> {
|
|||||||
let mut cur_raw = String::new();
|
let mut cur_raw = String::new();
|
||||||
let mut cur_cooked = Some(String::new());
|
let mut cur_cooked = Some(String::new());
|
||||||
|
|
||||||
|
for i in 0..(tpl.exprs.len() + tpl.quasis.len()) {
|
||||||
|
if i % 2 == 0 {
|
||||||
|
let i = i / 2;
|
||||||
|
let q = tpl.quasis[i].clone();
|
||||||
|
|
||||||
|
if q.cooked.is_some() {
|
||||||
|
if let Some(cur_cooked) = &mut cur_cooked {
|
||||||
|
cur_cooked.push_str("");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If cooked is None, it means that the template literal contains invalid escape
|
||||||
|
// sequences.
|
||||||
|
cur_cooked = None;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let i = i / 2;
|
||||||
|
let e = &tpl.exprs[i];
|
||||||
|
|
||||||
|
match &**e {
|
||||||
|
Expr::Lit(Lit::Str(s)) => {
|
||||||
|
if cur_cooked.is_none() && s.raw.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(cur_cooked) = &mut cur_cooked {
|
||||||
|
cur_cooked.push_str("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
cur_cooked = Some(String::new());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_cooked = Some(Default::default());
|
||||||
|
|
||||||
for i in 0..(tpl.exprs.len() + tpl.quasis.len()) {
|
for i in 0..(tpl.exprs.len() + tpl.quasis.len()) {
|
||||||
if i % 2 == 0 {
|
if i % 2 == 0 {
|
||||||
let i = i / 2;
|
let i = i / 2;
|
||||||
@ -286,10 +323,19 @@ impl Pure<'_> {
|
|||||||
|
|
||||||
match *e {
|
match *e {
|
||||||
Expr::Lit(Lit::Str(s)) => {
|
Expr::Lit(Lit::Str(s)) => {
|
||||||
cur_raw.push_str(&convert_str_value_to_tpl_raw(&s.value));
|
|
||||||
if let Some(cur_cooked) = &mut cur_cooked {
|
if let Some(cur_cooked) = &mut cur_cooked {
|
||||||
cur_cooked.push_str(&convert_str_value_to_tpl_cooked(&s.value));
|
cur_cooked.push_str(&convert_str_value_to_tpl_cooked(&s.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(raw) = &s.raw {
|
||||||
|
if raw.len() >= 2 {
|
||||||
|
// Exclude quotes
|
||||||
|
cur_raw
|
||||||
|
.push_str(&convert_str_raw_to_tpl_raw(&raw[1..raw.len() - 1]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cur_raw.push_str(&convert_str_value_to_tpl_raw(&s.value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
quasis.push(TplElement {
|
quasis.push(TplElement {
|
||||||
@ -325,6 +371,12 @@ impl Pure<'_> {
|
|||||||
pub(super) fn concat_tpl(&mut self, l: &mut Expr, r: &mut Expr) {
|
pub(super) fn concat_tpl(&mut self, l: &mut Expr, r: &mut Expr) {
|
||||||
match (&mut *l, &mut *r) {
|
match (&mut *l, &mut *r) {
|
||||||
(Expr::Tpl(l), Expr::Lit(Lit::Str(rs))) => {
|
(Expr::Tpl(l), Expr::Lit(Lit::Str(rs))) => {
|
||||||
|
if let Some(raw) = &rs.raw {
|
||||||
|
if raw.len() <= 2 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Append
|
// Append
|
||||||
if let Some(l_last) = l.quasis.last_mut() {
|
if let Some(l_last) = l.quasis.last_mut() {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
@ -340,15 +392,27 @@ impl Pure<'_> {
|
|||||||
.into();
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
let new: Atom =
|
l_last.raw = format!(
|
||||||
format!("{}{}", l_last.raw, convert_str_value_to_tpl_raw(&rs.value)).into();
|
"{}{}",
|
||||||
l_last.raw = new;
|
l_last.raw,
|
||||||
|
rs.raw
|
||||||
|
.clone()
|
||||||
|
.map(|s| convert_str_raw_to_tpl_raw(&s[1..s.len() - 1]))
|
||||||
|
.unwrap_or_else(|| convert_str_value_to_tpl_raw(&rs.value).into())
|
||||||
|
)
|
||||||
|
.into();
|
||||||
|
|
||||||
r.take();
|
r.take();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(Expr::Lit(Lit::Str(ls)), Expr::Tpl(r)) => {
|
(Expr::Lit(Lit::Str(ls)), Expr::Tpl(r)) => {
|
||||||
|
if let Some(raw) = &ls.raw {
|
||||||
|
if raw.len() <= 2 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Append
|
// Append
|
||||||
if let Some(r_first) = r.quasis.first_mut() {
|
if let Some(r_first) = r.quasis.first_mut() {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
@ -364,9 +428,15 @@ impl Pure<'_> {
|
|||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
let new: Atom =
|
let new: Atom = format!(
|
||||||
format!("{}{}", convert_str_value_to_tpl_raw(&ls.value), r_first.raw)
|
"{}{}",
|
||||||
.into();
|
ls.raw
|
||||||
|
.clone()
|
||||||
|
.map(|s| convert_str_raw_to_tpl_raw(&s[1..s.len() - 1]))
|
||||||
|
.unwrap_or_else(|| convert_str_value_to_tpl_raw(&ls.value).into()),
|
||||||
|
r_first.raw
|
||||||
|
)
|
||||||
|
.into();
|
||||||
r_first.raw = new;
|
r_first.raw = new;
|
||||||
|
|
||||||
l.take();
|
l.take();
|
||||||
@ -392,7 +462,7 @@ impl Pure<'_> {
|
|||||||
|
|
||||||
debug_assert!(l.quasis.len() == l.exprs.len() + 1, "{:?} is invalid", l);
|
debug_assert!(l.quasis.len() == l.exprs.len() + 1, "{:?} is invalid", l);
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
report_change!("strings: Merged to template literals");
|
report_change!("strings: Merged two template literals");
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -498,9 +568,9 @@ impl Pure<'_> {
|
|||||||
|
|
||||||
pub(super) fn convert_str_value_to_tpl_cooked(value: &JsWord) -> Cow<str> {
|
pub(super) fn convert_str_value_to_tpl_cooked(value: &JsWord) -> Cow<str> {
|
||||||
value
|
value
|
||||||
.replace('\\', "\\\\")
|
.replace("\\\\", "\\")
|
||||||
.replace('`', "\\`")
|
.replace("\\`", "`")
|
||||||
.replace('$', "\\$")
|
.replace("\\$", "$")
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,3 +583,7 @@ pub(super) fn convert_str_value_to_tpl_raw(value: &JsWord) -> Cow<str> {
|
|||||||
.replace('\r', "\\r")
|
.replace('\r', "\\r")
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn convert_str_raw_to_tpl_raw(value: &str) -> Atom {
|
||||||
|
value.replace('`', "\\`").replace('$', "\\$").into()
|
||||||
|
}
|
||||||
|
@ -479,7 +479,7 @@ fn fixture(input: PathBuf) {
|
|||||||
|
|
||||||
let expected = {
|
let expected = {
|
||||||
let expected = read_to_string(dir.join("output.js")).unwrap();
|
let expected = read_to_string(dir.join("output.js")).unwrap();
|
||||||
let fm = cm.new_source_file(FileName::Anon, expected);
|
let fm = cm.new_source_file(FileName::Custom("expected.js".into()), expected);
|
||||||
let lexer = Lexer::new(
|
let lexer = Lexer::new(
|
||||||
Default::default(),
|
Default::default(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
|
Loading…
Reference in New Issue
Block a user