diff --git a/crates/swc/tests/tsc-references/templateStringWhitespaceEscapes2_ES6_es5.1.normal.js b/crates/swc/tests/tsc-references/templateStringWhitespaceEscapes2_ES6_es5.1.normal.js index f45ffb9a6a3a..ef7e035356be 100644 --- a/crates/swc/tests/tsc-references/templateStringWhitespaceEscapes2_ES6_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/templateStringWhitespaceEscapes2_ES6_es5.1.normal.js @@ -1,3 +1,3 @@ //@target: es6 // , , , , , -"\t\v\f \xa0"; +"\t\v\f \xa0\uFEFF"; diff --git a/crates/swc/tests/tsc-references/templateStringWhitespaceEscapes2_es5.1.normal.js b/crates/swc/tests/tsc-references/templateStringWhitespaceEscapes2_es5.1.normal.js index 89f96afaa8f2..4e72eb4a801c 100644 --- a/crates/swc/tests/tsc-references/templateStringWhitespaceEscapes2_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/templateStringWhitespaceEscapes2_es5.1.normal.js @@ -1,2 +1,2 @@ // , , , , , -"\t\v\f \xa0"; +"\t\v\f \xa0\uFEFF"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings06_ES5_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings06_ES5_es5.1.normal.js index 6088f471691a..70770b241500 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings06_ES5_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings06_ES5_es5.1.normal.js @@ -1,4 +1,4 @@ // @target: es5 // ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp) // 1. Assert: 0 ≤ cp ≤ 0x10FFFF. -var x = "􏿿"; +var x = "\uDBFF\uDFFF"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings06_ES6_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings06_ES6_es5.1.normal.js index 1ffb788159a4..25613d866c42 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings06_ES6_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings06_ES6_es5.1.normal.js @@ -1,4 +1,4 @@ // @target: es6 // ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp) // 1. Assert: 0 ≤ cp ≤ 0x10FFFF. -var x = "􏿿"; +var x = "\uDBFF\uDFFF"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings08_ES5_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings08_ES5_es5.1.normal.js index a7ba86229a7d..d7da70015b20 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings08_ES5_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings08_ES5_es5.1.normal.js @@ -2,4 +2,4 @@ // ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp) // 2. If cp ≤ 65535, return cp. // (FFFF == 65535) -var x = "￿"; +var x = "\uFFFF"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings08_ES6_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings08_ES6_es5.1.normal.js index c9f7a321c679..88cf4d389668 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings08_ES6_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings08_ES6_es5.1.normal.js @@ -2,4 +2,4 @@ // ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp) // 2. If cp ≤ 65535, return cp. // (FFFF == 65535) -var x = "￿"; +var x = "\uFFFF"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings09_ES5_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings09_ES5_es5.1.normal.js index 370c189a9026..731d7275bb78 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings09_ES5_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings09_ES5_es5.1.normal.js @@ -2,4 +2,4 @@ // ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp) // 2. If cp ≤ 65535, return cp. // (10000 == 65536) -var x = "𐀀"; +var x = "\uD800\uDC00"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings09_ES6_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings09_ES6_es5.1.normal.js index 1f4a9590c952..89077e978c13 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings09_ES6_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings09_ES6_es5.1.normal.js @@ -2,4 +2,4 @@ // ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp) // 2. If cp ≤ 65535, return cp. // (10000 == 65536) -var x = "𐀀"; +var x = "\uD800\uDC00"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings13_ES5_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings13_ES5_es5.1.normal.js index 4382fd9c20cf..cc4b9052f398 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings13_ES5_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings13_ES5_es5.1.normal.js @@ -1,2 +1,2 @@ // @target: es5 -var x = "󝷝"; +var x = "\uDB37\uDDDD"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings13_ES6_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings13_ES6_es5.1.normal.js index fb3cf9c67315..ea3458a25a04 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings13_ES6_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings13_ES6_es5.1.normal.js @@ -1,2 +1,2 @@ // @target: es6 -var x = "󝷝"; +var x = "\uDB37\uDDDD"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings15_ES5_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings15_ES5_es5.1.normal.js index 98ceb7cb6230..e8708f018ece 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings15_ES5_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings15_ES5_es5.1.normal.js @@ -1,2 +1,2 @@ // @target: es5 -var x = "ꯍ㑖碐"; +var x = "\uABCD\uEF12\u3456\u7890"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings15_ES6_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings15_ES6_es5.1.normal.js index 288ef567c13b..70dd6e167b91 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings15_ES6_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings15_ES6_es5.1.normal.js @@ -1,2 +1,2 @@ // @target: es6 -var x = "ꯍ㑖碐"; +var x = "\uABCD\uEF12\u3456\u7890"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings16_ES5_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings16_ES5_es5.1.normal.js index 98ceb7cb6230..e8708f018ece 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings16_ES5_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings16_ES5_es5.1.normal.js @@ -1,2 +1,2 @@ // @target: es5 -var x = "ꯍ㑖碐"; +var x = "\uABCD\uEF12\u3456\u7890"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings16_ES6_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings16_ES6_es5.1.normal.js index 288ef567c13b..70dd6e167b91 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings16_ES6_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInStrings16_ES6_es5.1.normal.js @@ -1,2 +1,2 @@ // @target: es6 -var x = "ꯍ㑖碐"; +var x = "\uABCD\uEF12\u3456\u7890"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates06_ES5_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates06_ES5_es5.1.normal.js index 6088f471691a..70770b241500 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates06_ES5_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates06_ES5_es5.1.normal.js @@ -1,4 +1,4 @@ // @target: es5 // ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp) // 1. Assert: 0 ≤ cp ≤ 0x10FFFF. -var x = "􏿿"; +var x = "\uDBFF\uDFFF"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates06_ES6_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates06_ES6_es5.1.normal.js index 1ffb788159a4..25613d866c42 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates06_ES6_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates06_ES6_es5.1.normal.js @@ -1,4 +1,4 @@ // @target: es6 // ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp) // 1. Assert: 0 ≤ cp ≤ 0x10FFFF. -var x = "􏿿"; +var x = "\uDBFF\uDFFF"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates08_ES5_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates08_ES5_es5.1.normal.js index a7ba86229a7d..d7da70015b20 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates08_ES5_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates08_ES5_es5.1.normal.js @@ -2,4 +2,4 @@ // ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp) // 2. If cp ≤ 65535, return cp. // (FFFF == 65535) -var x = "￿"; +var x = "\uFFFF"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates08_ES6_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates08_ES6_es5.1.normal.js index c9f7a321c679..88cf4d389668 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates08_ES6_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates08_ES6_es5.1.normal.js @@ -2,4 +2,4 @@ // ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp) // 2. If cp ≤ 65535, return cp. // (FFFF == 65535) -var x = "￿"; +var x = "\uFFFF"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates09_ES5_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates09_ES5_es5.1.normal.js index 370c189a9026..731d7275bb78 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates09_ES5_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates09_ES5_es5.1.normal.js @@ -2,4 +2,4 @@ // ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp) // 2. If cp ≤ 65535, return cp. // (10000 == 65536) -var x = "𐀀"; +var x = "\uD800\uDC00"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates09_ES6_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates09_ES6_es5.1.normal.js index 1f4a9590c952..89077e978c13 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates09_ES6_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates09_ES6_es5.1.normal.js @@ -2,4 +2,4 @@ // ES6 Spec - 10.1.1 Static Semantics: UTF16Encoding (cp) // 2. If cp ≤ 65535, return cp. // (10000 == 65536) -var x = "𐀀"; +var x = "\uD800\uDC00"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates13_ES5_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates13_ES5_es5.1.normal.js index 4382fd9c20cf..cc4b9052f398 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates13_ES5_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates13_ES5_es5.1.normal.js @@ -1,2 +1,2 @@ // @target: es5 -var x = "󝷝"; +var x = "\uDB37\uDDDD"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates13_ES6_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates13_ES6_es5.1.normal.js index fb3cf9c67315..ea3458a25a04 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates13_ES6_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates13_ES6_es5.1.normal.js @@ -1,2 +1,2 @@ // @target: es6 -var x = "󝷝"; +var x = "\uDB37\uDDDD"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates15_ES5_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates15_ES5_es5.1.normal.js index 98ceb7cb6230..e8708f018ece 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates15_ES5_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates15_ES5_es5.1.normal.js @@ -1,2 +1,2 @@ // @target: es5 -var x = "ꯍ㑖碐"; +var x = "\uABCD\uEF12\u3456\u7890"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates15_ES6_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates15_ES6_es5.1.normal.js index 288ef567c13b..70dd6e167b91 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates15_ES6_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates15_ES6_es5.1.normal.js @@ -1,2 +1,2 @@ // @target: es6 -var x = "ꯍ㑖碐"; +var x = "\uABCD\uEF12\u3456\u7890"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates16_ES5_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates16_ES5_es5.1.normal.js index 98ceb7cb6230..e8708f018ece 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates16_ES5_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates16_ES5_es5.1.normal.js @@ -1,2 +1,2 @@ // @target: es5 -var x = "ꯍ㑖碐"; +var x = "\uABCD\uEF12\u3456\u7890"; diff --git a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates16_ES6_es5.1.normal.js b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates16_ES6_es5.1.normal.js index 288ef567c13b..70dd6e167b91 100644 --- a/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates16_ES6_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/unicodeExtendedEscapesInTemplates16_ES6_es5.1.normal.js @@ -1,2 +1,2 @@ // @target: es6 -var x = "ꯍ㑖碐"; +var x = "\uABCD\uEF12\u3456\u7890"; diff --git a/crates/swc_ecma_codegen/src/lib.rs b/crates/swc_ecma_codegen/src/lib.rs index 020c110ce71b..79607e91d5fd 100644 --- a/crates/swc_ecma_codegen/src/lib.rs +++ b/crates/swc_ecma_codegen/src/lib.rs @@ -508,7 +508,8 @@ where } StrKind::Synthesized => { let single_quote = false; - let value = escape_without_source(&node.value, self.wr.target(), single_quote); + let value = + escape_without_source(&node.value, self.wr.target(), single_quote, false); (single_quote, value) } @@ -3071,7 +3072,12 @@ fn unescape_tpl_lit(s: &str, is_synthesized: bool) -> String { result } -fn escape_without_source(v: &str, target: EsVersion, single_quote: bool) -> String { +fn escape_without_source( + v: &str, + target: EsVersion, + single_quote: bool, + emit_non_ascii_as_unicode: bool, +) -> String { let mut buf = String::with_capacity(v.len()); let mut iter = v.chars().peekable(); @@ -3093,7 +3099,6 @@ fn escape_without_source(v: &str, target: EsVersion, single_quote: bool) -> Stri buf.push_str("\\\\") } } - '\'' if single_quote => buf.push_str("\\'"), '"' if !single_quote => buf.push_str("\\\""), @@ -3111,16 +3116,33 @@ fn escape_without_source(v: &str, target: EsVersion, single_quote: bool) -> Stri '\u{7f}'..='\u{ff}' => { let _ = write!(buf, "\\x{:x}", c as u8); } - '\u{2028}' => { buf.push_str("\\u2028"); } '\u{2029}' => { buf.push_str("\\u2029"); } - _ => { - buf.push(c); + if !emit_non_ascii_as_unicode || c.is_ascii() { + buf.push(c); + } else if c > '\u{FFFF}' { + // if we've got this far the char isn't reserved and if the callee has specified + // we should output unicode for non-ascii chars then we have + // to make sure we output unicode that is safe for the target + // Es5 does not support code point escapes and so surrograte formula must be + // used + if target <= EsVersion::Es5 { + // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae + let h = ((c as u32 - 0x10000) / 0x400) + 0xd800; + let l = (c as u32 - 0x10000) % 0x400 + 0xdc00; + + let _ = write!(buf, "\\u{:04X}\\u{:04X}", h, l); + } else { + let _ = write!(buf, "\\u{{{:04X}}}", c as u32); + } + } else { + let _ = write!(buf, "\\u{:04X}", c as u16); + } } } } @@ -3135,25 +3157,31 @@ fn escape_with_source( s: &str, single_quote: Option, ) -> String { - if target <= EsVersion::Es5 { - return escape_without_source(s, target, single_quote.unwrap_or(false)); - } - if span.is_dummy() { - return escape_without_source(s, target, single_quote.unwrap_or(false)); + return escape_without_source(s, target, single_quote.unwrap_or(false), false); } - // let orig = cm.span_to_snippet(span); let orig = match orig { Ok(orig) => orig, Err(v) => { - return escape_without_source(s, target, single_quote.unwrap_or(false)); + return escape_without_source(s, target, single_quote.unwrap_or(false), false); } }; + if target <= EsVersion::Es5 { + let emit_non_ascii_as_unicode = orig.contains("\\u"); + + return escape_without_source( + s, + target, + single_quote.unwrap_or(false), + emit_non_ascii_as_unicode, + ); + } + if single_quote.is_some() && orig.len() <= 2 { - return escape_without_source(s, target, single_quote.unwrap_or(false)); + return escape_without_source(s, target, single_quote.unwrap_or(false), false); } let mut orig = &*orig; @@ -3163,7 +3191,7 @@ fn escape_with_source( { orig = &orig[1..orig.len() - 1]; } else if single_quote.is_some() { - return escape_without_source(s, target, single_quote.unwrap_or(false)); + return escape_without_source(s, target, single_quote.unwrap_or(false), false); } let mut buf = String::with_capacity(s.len()); diff --git a/crates/swc_ecma_codegen/src/tests.rs b/crates/swc_ecma_codegen/src/tests.rs index 8f3743ba4963..0e6fb6c83f03 100644 --- a/crates/swc_ecma_codegen/src/tests.rs +++ b/crates/swc_ecma_codegen/src/tests.rs @@ -554,7 +554,21 @@ CONTENT\r fn test_escape_without_source() { fn es2020(src: &str, expected: &str) { assert_eq!( - super::escape_without_source(src, EsVersion::Es2020, true), + super::escape_without_source(src, EsVersion::Es2020, true, false), + expected + ) + } + + fn es2020_nonascii(src: &str, expected: &str) { + assert_eq!( + super::escape_without_source(src, EsVersion::Es2020, true, true), + expected + ) + } + + fn es5(src: &str, expected: &str) { + assert_eq!( + super::escape_without_source(src, EsVersion::Es5, true, true), expected ) } @@ -576,6 +590,13 @@ fn test_escape_without_source() { es2020("\u{1000}", "\u{1000}"); es2020("\u{ff}", "\\xff"); es2020("\u{10ffff}", "\u{10ffff}"); + + es2020_nonascii("\u{FEFF}abc", "\\uFEFFabc"); + es2020_nonascii("\u{10ffff}", "\\u{10FFFF}"); + + es5("\u{FEFF}abc", "\\uFEFFabc"); + es5("\u{10ffff}", "\\uDBFF\\uDFFF"); + es5("\u{FFFF}", "\\uFFFF"); } #[test] @@ -612,7 +633,7 @@ fn issue_1619_2() { #[test] fn issue_1619_3() { assert_eq!( - escape_without_source("\x00\x31", EsVersion::Es3, true), + escape_without_source("\x00\x31", EsVersion::Es3, true, false), "\\x001" ); } @@ -657,3 +678,22 @@ impl Write for Buf { fn issue_2213() { assert_min("a - -b * c", "a- -b*c") } + +#[test] +fn issue3617() { + let from = r"// a string of all valid unicode whitespaces + module.exports = '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u2000\u2001\u2002' + + '\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF';"; + let expected = r#"// a string of all valid unicode whitespaces +module.exports = '\t\n\v\f\r \xa0\u1680\u2000\u2001\u2002' + '\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF';"#; + + let out = parse_then_emit(from, Default::default(), Syntax::default(), EsVersion::Es5); + + dbg!(&out); + dbg!(&expected); + + assert_eq!( + DebugUsingDisplay(out.trim()), + DebugUsingDisplay(expected.trim()), + ); +}