Repository: swc-project/swc (rust)

Issue:
Minify option incorrectly strips escape characters
### Describe the bug

When escaping specific strings, SWC strips necessary escape characters in minified output. This results in the incorrect string being output. See the given input code and playground link for examples.

### Input code

```typescript
let str = "\\uD83D\\uDC68\\u200D\\uD83D\\uDE80";

let obj = {
    "\\uD83D\\uDC68\\u200D\\uD83D\\uDE80": "wrong"
};
```


### Config

```json
{
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": false
    },
    "target": "es2015",
    "loose": false,
    "minify": {
      "compress": false,
      "mangle": false
    }
  },
  "module": {
    "type": "commonjs"
  },
  "minify": true,
  "isModule": false
}
```


### Playground link

https://play.swc.rs/?version=1.3.70&code=H4sIAAAAAAAAA8tJLVEoLilSsFVQiokpdbEwdgFRzmYWQMrIwMAFSdDVwkDJmosrB6gjPykLqKOaSwEIiNJnpaBUXpSfl67EVWsNAEudP25zAAAA&config=H4sIAAAAAAAAA1VPOw7DIAzdcwrkuUNbqUvv0EMg6kRE%2FIQdqSjK3QME2maz39deByFgJgVPseYxL0FGwvjdM0LJsfxkBDgFJBV1YLh0lqlQozSEFdoOBljGCbm4kO7X26M5wHhP2B0Ns9rpMf13Km9DRKKzsEilmwyeG4fWCta%2Fl0q2X8q95YKcZr2bCX7K3shxqeGg6dXdR%2FS2AzVy5M4cAQAA

### Expected behavior

SWC should not strip escape characters and produce the following output:

```javascript
let str="\\uD83D\\uDC68\\u200D\\uD83D\\uDE80";let obj={"\\uD83D\\uDC68\\u200D\\uD83D\\uDE80":"wrong"};
```

### Actual behavior

SWC strips escape characters and produces the following output:

```javascript
let str="\uD83D\uDC68\\u200D\uD83D\uDE80";let obj={"\uD83D\uDC68\\u200D\uD83D\uDE80":"wrong"};
```

Note the missing `\` before `\uD83D` (twice), `\uDC68` and `\uDE80`.

### Version

1.3.70

### Additional context

As a workaround, the following produces the correct output:

```typescript
let workaround = {
    [`\\uD83D\\uDC68\\u200D\\uD83D\\uDE80`]: "correct",
};
```

Pull request description:
fix(es/codegen): Don't strip necessary escape characters
**Description:**


**Related issue:**

 - Closes #7678.

Patch:
diff --git a/crates/swc_ecma_codegen/src/lib.rs b/crates/swc_ecma_codegen/src/lib.rs
index e0f86d1d2d..e065ad8a38 100644
--- a/crates/swc_ecma_codegen/src/lib.rs
+++ b/crates/swc_ecma_codegen/src/lib.rs
@@ -3770,6 +3770,8 @@ fn get_quoted_utf16(v: &str, ascii_only: bool, target: EsVersion) -> String {
 
                             inner_iter.next();
                             next = inner_iter.peek();
+                        } else if next != Some(&'D') && next != Some(&'d') {
+                            buf.push('\\');
                         }
 
                         if let Some(c @ 'D' | c @ 'd') = next {
@@ -3816,8 +3818,10 @@ fn get_quoted_utf16(v: &str, ascii_only: bool, target: EsVersion) -> String {
                                     iter.next();
                                 }
                             }
-                        } else {
+                        } else if is_curly {
                             buf.push_str("\\\\");
+                        } else {
+                            buf.push('\\');
                         }
                     }
                     _ => {


Test patch:
diff --git a/crates/swc/tests/fixture/issues-7xxx/7678/input/.swcrc b/crates/swc/tests/fixture/issues-7xxx/7678/input/.swcrc
new file mode 100644
index 0000000000..2609f171fa
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-7xxx/7678/input/.swcrc
@@ -0,0 +1,19 @@
+{
+    "jsc": {
+        "parser": {
+            "syntax": "typescript",
+            "tsx": false
+        },
+        "target": "es2015",
+        "loose": false,
+        "minify": {
+            "compress": false,
+            "mangle": false
+        }
+    },
+    "module": {
+        "type": "commonjs"
+    },
+    "minify": true,
+    "isModule": false
+}
\ No newline at end of file
diff --git a/crates/swc/tests/fixture/issues-7xxx/7678/input/1.js b/crates/swc/tests/fixture/issues-7xxx/7678/input/1.js
new file mode 100644
index 0000000000..7cadcdba97
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-7xxx/7678/input/1.js
@@ -0,0 +1,5 @@
+let str = "\\uD83D\\uDC68\\u200D\\uD83D\\uDE80";
+
+let obj = {
+    "\\uD83D\\uDC68\\u200D\\uD83D\\uDE80": "wrong"
+};
diff --git a/crates/swc/tests/fixture/issues-7xxx/7678/output/1.js b/crates/swc/tests/fixture/issues-7xxx/7678/output/1.js
new file mode 100644
index 0000000000..4581a38201
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-7xxx/7678/output/1.js
@@ -0,0 +1,1 @@
+let str="\uD83D\uDC68\\u200D\uD83D\uDE80";let obj={"\uD83D\uDC68\\u200D\uD83D\uDE80":"wrong"};
diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/7678/input.js b/crates/swc_ecma_minifier/tests/fixture/issues/7678/input.js
new file mode 100644
index 0000000000..825ed47ef6
--- /dev/null
+++ b/crates/swc_ecma_minifier/tests/fixture/issues/7678/input.js
@@ -0,0 +1,5 @@
+export let str = "\\uD83D\\uDC68\\u200D\\uD83D\\uDE80";
+
+export let obj = {
+    "\\uD83D\\uDC68\\u200D\\uD83D\\uDE80": "wrong"
+};
diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/7678/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/7678/output.js
new file mode 100644
index 0000000000..8bcfd3ac8f
--- /dev/null
+++ b/crates/swc_ecma_minifier/tests/fixture/issues/7678/output.js
@@ -0,0 +1,4 @@
+export let str = "\\uD83D\\uDC68\\u200D\\uD83D\\uDE80";
+export let obj = {
+    "\\uD83D\\uDC68\\u200D\\uD83D\\uDE80": "wrong"
+};