Repository: swc-project/swc (rust)

Issue:
ascii_only handles object attribute names missing double quotes
### Describe the bug

input: https://unpkg.com/lower-case@2.0.2/dist.es2015/index.js

```js
{
	Ì: "\u0069\u0307\u0300",
}
```
asciiOnly = true

```js
{
	 \xcc: "i\u0307\u0300",
}
```

`\xcc` should be in double quotes


### Input code

_No response_

### Config

_No response_

### Playground link

https://play.swc.rs/?version=1.3.74&code=H4sIAAAAAAAAA8VUTU%2FCMBi%2B8yve6IURsg4wfoxwIAMTzQwE5ITG1FKWmbEtXadE5exF%2F4cn43%2BQoz%2FKdh0DlqFHe%2Bjb7Xnet0%2BfvimqVEpQgWEQM0JNmPLQREjMeuy7JJhQPWAO6se3nkvQyOogD3MacRSTCRqGlLjYs3Dk%2Bo7O51wUQqV7zGA46vd7g8tu58buWW27Cy14KoEYnJnpSg5GHToPTUBXsVFrGM8iGAcnaRBzwzhCTjWjz3C4mS3H8tOEPck%2FPNmrbiFnCqg1anng%2B6UoZ6GWacCPv%2Bj8J00e36UpM60tQ63eTb4sS4WO%2Bnn8h%2ByzTIFyPifxfAW3C%2BHlR3q2%2Bmkh%2FvWaK5%2FMRp71VsTKu7V8L2I1Co1bNEtIdbgdEOy5j3QCXvBAGRAcUT3pWOFjwDhMY59wN%2FAFLpjUlizR27QccVZNf2qpabLJPew7orHzvT5WTJ0H6wradTNJc6dQlmnaxjXymPlK0mozndHQw4QmVF1ddHUtrzwTKrJESRG3OZ5dN2GhaWqfoqoCWqy9WDkAOAKc1d7lx2aZ1IF0Cyl366TJLmgfouRBucBhKB6H0cBuuf6EzvW7SKr9AViblfp1BAAA&config=H4sIAAAAAAAAA2VQuw7CMAzc%2BxWVZ2YGvoAF8Q1WcFFQXrJTqVHVfycJSSliiey78%2FmcdRhHeImCy7jmMjcBWYj3PiOSXMQlIxBTIFGsQ4RTZ6MUakIjVKHtwwAtkdihuZIJxJI1kWdqpPFeqI81zGqnp3RcrLwNTCK%2FwiJF9zT0B0%2BeLcaDQ8ZQlNZ3Z1IL0Jht6G%2FNC9Y%2F5urYfqFcWi4mOcNX1BPua0HLrU9W9%2B0NfSXnk1EBAAA%3D

### Expected behavior

ascii_only When dealing with object attribute names, double quotes should be used

```diff
- \xcc: "i\u0307\u0300",
+ "\xcc": "i\u0307\u0300",
```

### Actual behavior

_No response_

### Version

1.3.74

### Additional context

_No response_

Pull request description:
fix(es/codegen): Add quotes to property names when `ascii_only` is `true`
**Description:**


**Related issue:**

 - Closes #7805.

Patch:
diff --git a/crates/swc_ecma_codegen/src/lib.rs b/crates/swc_ecma_codegen/src/lib.rs
index e065ad8a38..72a7dc387a 100644
--- a/crates/swc_ecma_codegen/src/lib.rs
+++ b/crates/swc_ecma_codegen/src/lib.rs
@@ -1603,8 +1603,24 @@ where
 
     #[emitter]
     fn emit_prop_name(&mut self, node: &PropName) -> Result {
-        match *node {
-            PropName::Ident(ref n) => emit!(n),
+        match node {
+            PropName::Ident(ident) => {
+                if self.cfg.ascii_only && !ident.sym.is_ascii() {
+                    punct!("\"");
+                    self.wr.write_symbol(
+                        DUMMY_SP,
+                        &get_ascii_only_ident(
+                            &handle_invalid_unicodes(&ident.sym),
+                            self.cfg.target,
+                        ),
+                    )?;
+                    punct!("\"");
+
+                    return Ok(());
+                }
+
+                emit!(ident)
+            }
             PropName::Str(ref n) => emit!(n),
             PropName::Num(ref n) => emit!(n),
             PropName::BigInt(ref n) => emit!(n),


Test patch:
diff --git a/crates/swc/tests/fixture/issues-7xxx/7240/output/index.js b/crates/swc/tests/fixture/issues-7xxx/7240/output/index.js
index 240bd27309..708e259f83 100644
--- a/crates/swc/tests/fixture/issues-7xxx/7240/output/index.js
+++ b/crates/swc/tests/fixture/issues-7xxx/7240/output/index.js
@@ -8,6 +8,6 @@ Object.defineProperty(exports, "__esModule", {
     }
 });
 var _obj, _default = ((_obj = {
-    \u3131: "\u11B0",
-    \u3141: "\u11B1"
+    "\u3131": "\u11B0",
+    "\u3141": "\u11B1"
 })["\u3142"] = "\u11B2", _obj);
diff --git a/crates/swc/tests/fixture/issues-7xxx/7805/input/.swcrc b/crates/swc/tests/fixture/issues-7xxx/7805/input/.swcrc
new file mode 100644
index 0000000000..514d0592cf
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-7xxx/7805/input/.swcrc
@@ -0,0 +1,22 @@
+{
+    "jsc": {
+        "parser": {
+            "syntax": "typescript",
+            "tsx": false
+        },
+        "externalHelpers": true,
+        "loose": false,
+        "minify": {
+            "compress": false,
+            "mangle": false,
+            "format": {
+                "asciiOnly": true
+            }
+        }
+    },
+    "module": {
+        "type": "es6"
+    },
+    "minify": false,
+    "isModule": true
+}
\ No newline at end of file
diff --git a/crates/swc/tests/fixture/issues-7xxx/7805/input/1.js b/crates/swc/tests/fixture/issues-7xxx/7805/input/1.js
new file mode 100644
index 0000000000..2be997792a
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-7xxx/7805/input/1.js
@@ -0,0 +1,48 @@
+/**
+ * Source: ftp://ftp.unicode.org/Public/UCD/latest/ucd/SpecialCasing.txt
+ */
+var SUPPORTED_LOCALE = {
+    tr: {
+        regexp: /\u0130|\u0049|\u0049\u0307/g,
+        map: {
+            İ: "\u0069",
+            I: "\u0131",
+            İ: "\u0069",
+        },
+    },
+    az: {
+        regexp: /\u0130/g,
+        map: {
+            İ: "\u0069",
+            I: "\u0131",
+            İ: "\u0069",
+        },
+    },
+    lt: {
+        regexp: /\u0049|\u004A|\u012E|\u00CC|\u00CD|\u0128/g,
+        map: {
+            I: "\u0069\u0307",
+            J: "\u006A\u0307",
+            Į: "\u012F\u0307",
+            Ì: "\u0069\u0307\u0300",
+            Í: "\u0069\u0307\u0301",
+            Ĩ: "\u0069\u0307\u0303",
+        },
+    },
+};
+/**
+ * Localized lower case.
+ */
+export function localeLowerCase(str, locale) {
+    var lang = SUPPORTED_LOCALE[locale.toLowerCase()];
+    if (lang)
+        return lowerCase(str.replace(lang.regexp, function (m) { return lang.map[m]; }));
+    return lowerCase(str);
+}
+/**
+ * Lower case as a function.
+ */
+export function lowerCase(str) {
+    return str.toLowerCase();
+}
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/crates/swc/tests/fixture/issues-7xxx/7805/output/1.js b/crates/swc/tests/fixture/issues-7xxx/7805/output/1.js
new file mode 100644
index 0000000000..b7618cc853
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-7xxx/7805/output/1.js
@@ -0,0 +1,39 @@
+var SUPPORTED_LOCALE = {
+    tr: {
+        regexp: /\u0130|\u0049|\u0049\u0307/g,
+        map: {
+            "\u0130": "i",
+            I: "\u0131",
+            "I\u0307": "i"
+        }
+    },
+    az: {
+        regexp: /\u0130/g,
+        map: {
+            "\u0130": "i",
+            I: "\u0131",
+            "I\u0307": "i"
+        }
+    },
+    lt: {
+        regexp: /\u0049|\u004A|\u012E|\u00CC|\u00CD|\u0128/g,
+        map: {
+            I: "i\u0307",
+            J: "j\u0307",
+            "\u012E": "\u012F\u0307",
+            "\xcc": "i\u0307\u0300",
+            "\xcd": "i\u0307\u0301",
+            "\u0128": "i\u0307\u0303"
+        }
+    }
+};
+export function localeLowerCase(str, locale) {
+    var lang = SUPPORTED_LOCALE[locale.toLowerCase()];
+    if (lang) return lowerCase(str.replace(lang.regexp, function(m) {
+        return lang.map[m];
+    }));
+    return lowerCase(str);
+}
+export function lowerCase(str) {
+    return str.toLowerCase();
+}
diff --git a/crates/swc_ecma_codegen/src/tests.rs b/crates/swc_ecma_codegen/src/tests.rs
index 2dc63743af..d0a758bab7 100644
--- a/crates/swc_ecma_codegen/src/tests.rs
+++ b/crates/swc_ecma_codegen/src/tests.rs
@@ -872,17 +872,17 @@ fn ascii_only_tpl_lit() {
 #[test]
 fn ascii_only_issue_7240() {
     test_all(
-        r"
+        r#"
         export default {
-            \u3131: '\u11B0',
+            "\u3131": '\u11B0',
         }
-        ",
-        r"
+        "#,
+        r#"
 export default {
-    \u3131: '\u11B0'
+    "\u3131": '\u11B0'
 };
-        ",
-        r#"export default{\u3131:"\u11B0"}"#,
+        "#,
+        r#"export default{"\u3131":"\u11B0"}"#,
         Config {
             ascii_only: true,
             ..Default::default()