Repository: swc-project/swc (rust)

Issue:
spread syntax differs between swc loose mode and babel loose mode
### Describe the bug

I'm migrating my code's compiler from babel to swc, and my code crashed because the generated code with loose config is kind of different from babel.
Code contains es spread syntax. While babel with loose config removes all TypeError and other stuff, swc with loose config remains the same as non-loose config. TypeError is the key reason of my code crash.

### Input code

```typescript
const data = {}
const temp  = [...data.demo, ...data.demo2]
```


### Config

_No response_

### Playground link

**babel**
https://babeljs.io/repl#?browsers=&build=&builtIns=false&corejs=3.21&spec=false&loose=true&code_lz=MYewdgzgLgBAJgQygmBeGBvAvgKFJWKAUwFsAHGNGAbQDp7Fla5SQAaGe5pBZ1gJgC6QA&debug=false&forceAllTransforms=false&modules=commonjs&shippedProposals=false&circleciRepo=&evaluate=false&fileSize=false&timeTravel=false&sourceType=module&lineWrap=true&presets=env%2Creact%2Cstage-2&prettier=false&targets=&version=7.21.8&externalPlugins=&assumptions=%7B%7D 
**swc**
 https://play.swc.rs/?version=1.3.56&code=H4sIAAAAAAAAA0vOzysuUUhJLElUsFWoruVKBvNLUnMLFIAC0Xp6eiA5vZTU3HwdBWSeUSwALJOS2TsAAAA%3D&config=H4sIAAAAAAAAA1WPPQ7DIAxGd06BPHdth94hh7CoExHxJ0ykoih3LyFA2w2%2Fz%2FYzu5ASVlbwlHt5liJgZIqjLoSzS%2FguBEhZZBV1SHDr6cpnNKNhqui4EkgYF0p1iu%2BtHYz3TIWluFFDVjs951%2Bf8jZEYu5rh8qiWwz920QzgvWvrYbtHykHuuwP%2BDZ12VgMmqc%2BeV4ljg%2F3WmjeEwEAAA%3D%3D

### Expected behavior

Using es spread syntax in loose config, swc behaves the same as babel.

### Actual behavior

_No response_

### Version

@swc/core: 1.3.56 @babel/core: 7.21.8

### Additional context

_No response_

Pull request description:
fix(es/compat): Fix loose mode of the `spread` pass
<!-- 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? -->

<!--
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:** 
- Closes #7354


Patch:
diff --git a/crates/swc_ecma_transforms_compat/src/es2015/spread.rs b/crates/swc_ecma_transforms_compat/src/es2015/spread.rs
index 4e27ddb00b..3ea792b216 100644
--- a/crates/swc_ecma_transforms_compat/src/es2015/spread.rs
+++ b/crates/swc_ecma_transforms_compat/src/es2015/spread.rs
@@ -251,6 +251,27 @@ impl Spread {
             };
         }
 
+        // shorthand [].concat(arr1, arr2) shoule be used under loose mode
+        if self.c.loose {
+            let mut arg_list = vec![];
+            for arg in args.flatten() {
+                let expr = arg.expr;
+                arg_list.push(expr.as_arg());
+            }
+
+            return Expr::Call(CallExpr {
+                span: DUMMY_SP,
+                callee: ArrayLit {
+                    span: DUMMY_SP,
+                    elems: vec![],
+                }
+                .make_member(quote_ident!("concat"))
+                .as_callee(),
+                args: arg_list,
+                type_args: Default::default(),
+            });
+        }
+
         for arg in args {
             if let Some(arg) = arg {
                 let ExprOrSpread { expr, spread } = arg;
@@ -338,7 +359,6 @@ impl Spread {
                                         Expr::Call(to_consumable_array(expr, span))
                                     };
                                 }
-
                                 to_consumable_array(expr, span).as_arg()
                             }
                         });


Test patch:
diff --git a/crates/swc/tests/fixture/issues-7xxx/7354/case1/input/.swcrc b/crates/swc/tests/fixture/issues-7xxx/7354/case1/input/.swcrc
new file mode 100644
index 0000000000..f7d5e20472
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-7xxx/7354/case1/input/.swcrc
@@ -0,0 +1,11 @@
+{
+    "jsc": {
+        "parser": {
+            "syntax": "ecmascript",
+            "jsx": false
+        },
+        "target": "es5",
+        "loose": true
+    },
+    "isModule": false
+}
\ No newline at end of file
diff --git a/crates/swc/tests/fixture/issues-7xxx/7354/case1/input/index.js b/crates/swc/tests/fixture/issues-7xxx/7354/case1/input/index.js
new file mode 100644
index 0000000000..8e1589e557
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-7xxx/7354/case1/input/index.js
@@ -0,0 +1,2 @@
+const data = {}
+const temp  = [...data.demo, ...data.demo2]
\ No newline at end of file
diff --git a/crates/swc/tests/fixture/issues-7xxx/7354/case1/output/index.js b/crates/swc/tests/fixture/issues-7xxx/7354/case1/output/index.js
new file mode 100644
index 0000000000..7e490be49a
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-7xxx/7354/case1/output/index.js
@@ -0,0 +1,2 @@
+var data = {};
+var temp = [].concat(data.demo, data.demo2);
diff --git a/crates/swc/tests/fixture/issues-7xxx/7354/case2/input/.swcrc b/crates/swc/tests/fixture/issues-7xxx/7354/case2/input/.swcrc
new file mode 100644
index 0000000000..632ca8a59c
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-7xxx/7354/case2/input/.swcrc
@@ -0,0 +1,10 @@
+{
+    "jsc": {
+        "parser": {
+            "syntax": "ecmascript",
+            "jsx": false
+        },
+        "target": "es5"
+    },
+    "isModule": false
+}
\ No newline at end of file
diff --git a/crates/swc/tests/fixture/issues-7xxx/7354/case2/input/index.js b/crates/swc/tests/fixture/issues-7xxx/7354/case2/input/index.js
new file mode 100644
index 0000000000..8e1589e557
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-7xxx/7354/case2/input/index.js
@@ -0,0 +1,2 @@
+const data = {}
+const temp  = [...data.demo, ...data.demo2]
\ No newline at end of file
diff --git a/crates/swc/tests/fixture/issues-7xxx/7354/case2/output/index.js b/crates/swc/tests/fixture/issues-7xxx/7354/case2/output/index.js
new file mode 100644
index 0000000000..64d5b3b692
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-7xxx/7354/case2/output/index.js
@@ -0,0 +1,3 @@
+var _to_consumable_array = require("@swc/helpers/_/_to_consumable_array");
+var data = {};
+var temp = _to_consumable_array._(data.demo).concat(_to_consumable_array._(data.demo2));