From 8d9bf4cfaaeef9a9f3307b53c3349bff1359ccdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donny/=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Sun, 14 Jan 2024 17:11:08 +0900 Subject: [PATCH] fix(es/codegen): Fix codegen of a property key in ascii-only mode (#8493) **Related issue:** - Closes #8491 --- .../fixture/issues-7xxx/7805/output/1.js | 4 +- .../fixture/issues-8xxx/8260/output/1.js | 2 +- .../fixture/issues-8xxx/8491/input/.swcrc | 21 +++++++ .../tests/fixture/issues-8xxx/8491/input/1.js | 3 + .../fixture/issues-8xxx/8491/output/1.js | 3 + crates/swc_ecma_codegen/src/lib.rs | 55 ++++++++++++++++--- 6 files changed, 78 insertions(+), 10 deletions(-) create mode 100644 crates/swc/tests/fixture/issues-8xxx/8491/input/.swcrc create mode 100644 crates/swc/tests/fixture/issues-8xxx/8491/input/1.js create mode 100644 crates/swc/tests/fixture/issues-8xxx/8491/output/1.js diff --git a/crates/swc/tests/fixture/issues-7xxx/7805/output/1.js b/crates/swc/tests/fixture/issues-7xxx/7805/output/1.js index 0ca9c927f06..69e95d33824 100644 --- a/crates/swc/tests/fixture/issues-7xxx/7805/output/1.js +++ b/crates/swc/tests/fixture/issues-7xxx/7805/output/1.js @@ -21,8 +21,8 @@ var SUPPORTED_LOCALE = { I: "i\u0307", J: "j\u0307", \u012E: "\u012F\u0307", - \u00CC: "i\u0307\u0300", - \u00CD: "i\u0307\u0301", + "\xcc": "i\u0307\u0300", + "\xcd": "i\u0307\u0301", \u0128: "i\u0307\u0303" } } diff --git a/crates/swc/tests/fixture/issues-8xxx/8260/output/1.js b/crates/swc/tests/fixture/issues-8xxx/8260/output/1.js index eb9aa7df1d5..ec1e52900f8 100644 --- a/crates/swc/tests/fixture/issues-8xxx/8260/output/1.js +++ b/crates/swc/tests/fixture/issues-8xxx/8260/output/1.js @@ -1,2 +1,2 @@ -function p(\u00B5, \u03C3) {} +function p(\xb5, \u03C3) {} console.log(p); diff --git a/crates/swc/tests/fixture/issues-8xxx/8491/input/.swcrc b/crates/swc/tests/fixture/issues-8xxx/8491/input/.swcrc new file mode 100644 index 00000000000..98f55cc78c2 --- /dev/null +++ b/crates/swc/tests/fixture/issues-8xxx/8491/input/.swcrc @@ -0,0 +1,21 @@ +{ + "jsc": { + "parser": { + "syntax": "ecmascript", + "jsx": false + }, + "target": "es5", + "loose": false, + "minify": { + "compress": true, + "format": { + "asciiOnly": true + } + } + }, + "module": { + "type": "es6" + }, + "minify": false, + "isModule": true +} \ No newline at end of file diff --git a/crates/swc/tests/fixture/issues-8xxx/8491/input/1.js b/crates/swc/tests/fixture/issues-8xxx/8491/input/1.js new file mode 100644 index 00000000000..7d39d5e7d6e --- /dev/null +++ b/crates/swc/tests/fixture/issues-8xxx/8491/input/1.js @@ -0,0 +1,3 @@ +const a = { aób: 'ó' } + +console.log(a) \ No newline at end of file diff --git a/crates/swc/tests/fixture/issues-8xxx/8491/output/1.js b/crates/swc/tests/fixture/issues-8xxx/8491/output/1.js new file mode 100644 index 00000000000..17c8ecf6f42 --- /dev/null +++ b/crates/swc/tests/fixture/issues-8xxx/8491/output/1.js @@ -0,0 +1,3 @@ +console.log({ + "a\xf3b": "\xf3" +}); diff --git a/crates/swc_ecma_codegen/src/lib.rs b/crates/swc_ecma_codegen/src/lib.rs index 3d00612f616..7dfa870b063 100644 --- a/crates/swc_ecma_codegen/src/lib.rs +++ b/crates/swc_ecma_codegen/src/lib.rs @@ -1721,7 +1721,33 @@ where fn emit_prop_name(&mut self, node: &PropName) -> Result { match node { PropName::Ident(ident) => { - emit!(ident) + // TODO: Use write_symbol when ident is a symbol. + self.emit_leading_comments_of_span(ident.span, false)?; + + // Source map + self.wr.commit_pending_semi()?; + + srcmap!(ident, true); + + if self.cfg.ascii_only { + if self.wr.can_ignore_invalid_unicodes() { + self.wr.write_symbol( + DUMMY_SP, + &get_ascii_only_ident(&ident.sym, true, self.cfg.target), + )?; + } else { + self.wr.write_symbol( + DUMMY_SP, + &get_ascii_only_ident( + &handle_invalid_unicodes(&ident.sym), + true, + self.cfg.target, + ), + )?; + } + } else { + emit!(ident); + } } PropName::Str(ref n) => emit!(n), PropName::Num(ref n) => emit!(n), @@ -2259,12 +2285,18 @@ where if self.cfg.ascii_only { if self.wr.can_ignore_invalid_unicodes() { - self.wr - .write_symbol(DUMMY_SP, &get_ascii_only_ident(&ident.sym, self.cfg.target))?; + self.wr.write_symbol( + DUMMY_SP, + &get_ascii_only_ident(&ident.sym, false, self.cfg.target), + )?; } else { self.wr.write_symbol( DUMMY_SP, - &get_ascii_only_ident(&handle_invalid_unicodes(&ident.sym), self.cfg.target), + &get_ascii_only_ident( + &handle_invalid_unicodes(&ident.sym), + false, + self.cfg.target, + ), )?; } } else if self.wr.can_ignore_invalid_unicodes() { @@ -3751,7 +3783,7 @@ fn get_template_element_from_raw(s: &str, ascii_only: bool) -> String { buf } -fn get_ascii_only_ident(sym: &str, target: EsVersion) -> Cow { +fn get_ascii_only_ident(sym: &str, may_need_quote: bool, target: EsVersion) -> Cow { if sym.chars().all(|c| c.is_ascii()) { return Cow::Borrowed(sym); } @@ -3759,6 +3791,7 @@ fn get_ascii_only_ident(sym: &str, target: EsVersion) -> Cow { let mut first = true; let mut buf = String::with_capacity(sym.len() + 8); let mut iter = sym.chars().peekable(); + let mut need_quote = false; while let Some(c) = iter.next() { match c { @@ -3859,7 +3892,11 @@ fn get_ascii_only_ident(sym: &str, target: EsVersion) -> Cow { '\x20'..='\x7e' => { buf.push(c); } - '\u{7f}'..='\u{ff}' if !first => { + '\u{7f}'..='\u{ff}' => { + if may_need_quote { + need_quote = true; + } + let _ = write!(buf, "\\x{:x}", c as u8); } '\u{2028}' => { @@ -3897,7 +3934,11 @@ fn get_ascii_only_ident(sym: &str, target: EsVersion) -> Cow { first = false; } - Cow::Owned(buf) + if need_quote { + Cow::Owned(format!("\"{}\"", buf)) + } else { + Cow::Owned(buf) + } } fn get_quoted_utf16(v: &str, ascii_only: bool, target: EsVersion) -> String {