Repository: swc-project/swc (rust)

Issue:
swc is removing parenthesis incorrectly
### Describe the bug

The outmost parenthesis cannot be removed in following code:

### Input code

```typescript
(function(){}(), console)
```


### Config

```json
{
  "jsc": {
    "parser": {
      "syntax": "ecmascript"
    },
    "target": "es5",
    "minify": {
      "compress": false,
      "mangle": false
    },
    "loose": false
  },
  "minify": false
}
```


### Playground link

https://play.swc.rs/?version=1.2.233&code=H4sIAAAAAAAAA9NIK81LLsnMz9PQrK7V0NRRSM7PK87PSdUEAHCXoCcZAAAA&config=H4sIAAAAAAAAA02LSwqAMBBD75K1Wze9zVCmUumPSReKeHctKrjLS%2FIOrPRwB5oY1UbiXrpscFCfhd5i6zgndLFF%2B6g5Y0KOJYZ9%2FH3NzZSEC5Ko9yRlSfribaZa%2BcPPfPgCbUYHSoEAAAA%3D

### Expected behavior

`(function(){}(), console)`

### Actual behavior

`function() {}(), console;`

which triggers an error: `Uncaught SyntaxError: Function statements require a function name`

### Version

1.2.233

### Additional context

_No response_

Pull request:
fix(es/fixer): Wrap paren in seq in some edge cases
<!-- Note: CI script will automatically rebase your PR so please do not rebase unless required -->

<!-- Thanks for submitting a pull request! Please provide enough information so that others can review your pull request. -->

**Description:**

<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->

**BREAKING CHANGE:**

<!--
If this PR introduces a breaking change, it must contain a notice for it to be included in the CHANGELOG. Add description or remove entirely if not breaking.

You may need to update `MIGRATION.md` for the breaking changes.
-->

**Related issue (if exists):**
- fix #5505 

Patch:
diff --git a/.prettierignore b/.prettierignore
index 49eaa40c06..9d7a7a820c 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -9,6 +9,7 @@ node_modules/
 # Space sensitive
 crates/jsdoc/tests/
 crates/swc/tests/errors/
+crates/swc/tests/fixture/
 crates/swc/tests/projects/
 crates/swc/tests/serde/
 crates/swc_css_codegen/tests/
@@ -57,7 +58,6 @@ node-swc/tests
 crates/swc/tests/srcmap/
 crates/swc/tests/stacktrace/
 
-
 # git submodules
 crates/swc_ecma_parser/tests/test262-parser
-crates/swc_html_parser/tests/html5lib-tests
\ No newline at end of file
+crates/swc_html_parser/tests/html5lib-tests
diff --git a/crates/swc_ecma_transforms_base/src/fixer.rs b/crates/swc_ecma_transforms_base/src/fixer.rs
index 26bc5c145e..c581794995 100644
--- a/crates/swc_ecma_transforms_base/src/fixer.rs
+++ b/crates/swc_ecma_transforms_base/src/fixer.rs
@@ -708,7 +708,7 @@ impl Fixer<'_> {
 
                 let exprs_len = exprs.len();
                 // don't has child seq
-                let expr = if len == exprs_len {
+                let mut exprs = if len == exprs_len {
                     let mut exprs = exprs
                         .iter_mut()
                         .enumerate()
@@ -725,8 +725,7 @@ impl Fixer<'_> {
                         *e = *exprs.pop().unwrap();
                         return;
                     }
-                    let exprs = ignore_padding_value(exprs);
-                    Expr::Seq(SeqExpr { span: *span, exprs })
+                    ignore_padding_value(exprs)
                 } else {
                     let mut buf = Vec::with_capacity(len);
                     for (i, expr) in exprs.iter_mut().enumerate() {
@@ -772,11 +771,23 @@ impl Fixer<'_> {
                         return;
                     }
 
-                    let exprs = ignore_padding_value(buf);
-
-                    Expr::Seq(SeqExpr { span: *span, exprs })
+                    ignore_padding_value(buf)
                 };
 
+                if self.ctx == Context::Default {
+                    if let Some(expr) = exprs.first_mut() {
+                        match &mut **expr {
+                            Expr::Call(CallExpr {
+                                callee: Callee::Expr(callee_expr),
+                                ..
+                            }) if callee_expr.is_fn_expr() => self.wrap(callee_expr),
+                            _ => (),
+                        }
+                    }
+                }
+
+                let expr = Expr::Seq(SeqExpr { span: *span, exprs });
+
                 match self.ctx {
                     Context::ForcedExpr => {
                         *e = Expr::Paren(ParenExpr {


Test patch:
diff --git a/crates/swc/tests/fixture/issues-5xxx/5505/input/.swcrc b/crates/swc/tests/fixture/issues-5xxx/5505/input/.swcrc
new file mode 100644
index 0000000000..1a275fa287
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-5xxx/5505/input/.swcrc
@@ -0,0 +1,9 @@
+{
+    "jsc": {
+        "parser": {
+            "syntax": "ecmascript"
+        },
+        "target": "es2022"
+    },
+    "isModule": true
+}
\ No newline at end of file
diff --git a/crates/swc/tests/fixture/issues-5xxx/5505/input/index.js b/crates/swc/tests/fixture/issues-5xxx/5505/input/index.js
new file mode 100644
index 0000000000..5cd2518c1d
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-5xxx/5505/input/index.js
@@ -0,0 +1,17 @@
+(function () {}(), console); // keep paren
+(console, function () {}()); // remove paren
+
+(function () {}, console); // keep paren
+(console, function () {}); // remove paren
+
+(function foo() {}(), console); // keep paren
+(console, function foo() {}()); // remove paren
+
+(function foo() {}, console); // keep paren
+(console, function foo() {}); // remove paren
+
+(class {}, console); // keep paren
+(console, class {}); // remove paren
+
+(class Bar{}, console); // keep paren
+(console, class Bar{}); // remove paren
diff --git a/crates/swc/tests/fixture/issues-5xxx/5505/output/index.js b/crates/swc/tests/fixture/issues-5xxx/5505/output/index.js
new file mode 100644
index 0000000000..e64de09a39
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-5xxx/5505/output/index.js
@@ -0,0 +1,16 @@
+(function() {})(), console; // keep paren
+console, function() {}(); // remove paren
+(function() {}), console; // keep paren
+console, function() {}; // remove paren
+(function foo() {})(), console; // keep paren
+console, function foo() {}(); // remove paren
+(function foo() {}), console; // keep paren
+console, function foo() {}; // remove paren
+(class {
+}), console; // keep paren
+console, class {
+}; // remove paren
+(class Bar {
+}), console; // keep paren
+console, class Bar {
+}; // remove paren