Repository: swc-project/swc (rust)

Issue:
Can not import named-export from transpiled cjs
### Describe the bug

The transpiled cjs code can not be imported by named. Only workaroud is: `import lib from 'lib'; const fn = lib.fn`

```
//test.mjs
import {fn} from 'lib';
```


The codes to be transpiled:


### Input code

```js
// fn.js
export function fn(){}
export default fn
```
```js
// fn2.js
export function fn2(){}
export default fn2
```

```typescript
//index.js

export * from './fn.js'
export * from './fn2.js'
```


### Config

```json
{
  "jsc": {
    "target": "es2015",
    "keepClassNames": true,
    "parser": {
      "syntax": "typescript",
      "decorators": true,
      "dynamicImport": true,
    },
    "minify": {
      "compress": false,
      "mangle": false,
    },
    "transform": {
      "legacyDecorator": true,
    }
  },
  "module": {
    "type": "commonjs",
    "importInterop": "node",
  },
}
```


### Playground link

_No response_

### Expected behavior

Can be imported by name.

### Actual behavior

raise error:


```
SyntaxError: Named export 'fn' not found. The requested module 'lib' is a CommonJS module, which may not support all module.exports as named exports.
```


### Version

1.3.42

### Additional context

```
@swc/cli: 0.1.62
@swc/core: 1.3.42
node: v18.15.0
```

Pull request:
fix(es/modules): Hint nodejs for multiple `export *`
<!-- 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? -->
`cjs-module-lexer` detection is fragile. Redundant parentheses can cause detection failure.
Therefore, I replaced the sequence expression with a binary expression.

before:

```JavaScript 
0 && (__export(require("foo")), __export(require("bar")));
```

after this pull request

```JavaScript 
0 && __export(require("foo")) &&  __export(require("bar"));
```

**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 #7180 

Patch:
diff --git a/crates/swc_ecma_transforms_module/src/common_js.rs b/crates/swc_ecma_transforms_module/src/common_js.rs
index c982480198..c096f3d5d5 100644
--- a/crates/swc_ecma_transforms_module/src/common_js.rs
+++ b/crates/swc_ecma_transforms_module/src/common_js.rs
@@ -530,41 +530,36 @@ where
 
     /// emit [cjs-module-lexer](https://github.com/nodejs/cjs-module-lexer) friendly exports list
     /// ```javascript
-    /// 0 && (__export(require("foo")));
+    /// 0 && __export(require("foo")) && __export(require("bar"));
     /// ```
     fn emit_lexer_ts_reexport(&self, link: &Link) -> Option<Stmt> {
-        let mut seq_list = vec![];
-        link.iter().for_each(|(src, LinkItem(_, _, link_flag))| {
-            if link_flag.export_star() {
+        link.iter()
+            .filter(|(.., LinkItem(.., link_flag))| link_flag.export_star())
+            .map(|(src, ..)| {
                 let import_expr =
                     self.resolver
                         .make_require_call(self.unresolved_mark, src.clone(), DUMMY_SP);
 
-                let export = Expr::Ident(quote_ident!("__export"))
-                    .as_call(DUMMY_SP, vec![import_expr.as_arg()]);
-
-                seq_list.push(Box::new(export));
-            }
-        });
-
-        if seq_list.is_empty() {
-            None
-        } else {
-            let seq_expr = SeqExpr {
-                span: DUMMY_SP,
-                exprs: seq_list,
-            }
-            .into();
-
-            let expr = BinExpr {
-                span: DUMMY_SP,
-                op: op!("&&"),
-                left: 0.into(),
-                right: seq_expr,
-            };
-
-            Some(expr.into_stmt())
-        }
+                Expr::Ident(quote_ident!("__export")).as_call(DUMMY_SP, vec![import_expr.as_arg()])
+            })
+            .reduce(|left, right| {
+                BinExpr {
+                    span: DUMMY_SP,
+                    op: op!("&&"),
+                    left: left.into(),
+                    right: right.into(),
+                }
+                .into()
+            })
+            .map(|expr| {
+                BinExpr {
+                    span: DUMMY_SP,
+                    op: op!("&&"),
+                    left: 0.into(),
+                    right: expr.into(),
+                }
+                .into_stmt()
+            })
     }
 
     fn pure_span(&self) -> Span {


Test patch:
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/issue-7180/input.js b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-7180/input.js
new file mode 100644
index 0000000000..d687c5868a
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-7180/input.js
@@ -0,0 +1,2 @@
+export * from "./fn.js";
+export * from "./fn2.js";
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/issue-7180/module.json b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-7180/module.json
new file mode 100644
index 0000000000..2923d83b41
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-7180/module.json
@@ -0,0 +1,3 @@
+{
+    "importInterop": "node"
+}
\ No newline at end of file
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/issue-7180/output.amd.js b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-7180/output.amd.js
new file mode 100644
index 0000000000..bffc7f407b
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-7180/output.amd.js
@@ -0,0 +1,13 @@
+define([
+    "require",
+    "exports",
+    "./fn.js",
+    "./fn2.js"
+], function(require, exports, _fn, _fn2) {
+    "use strict";
+    Object.defineProperty(exports, "__esModule", {
+        value: true
+    });
+    _export_star(_fn, exports);
+    _export_star(_fn2, exports);
+});
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/issue-7180/output.cjs b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-7180/output.cjs
new file mode 100644
index 0000000000..8d6f49cdd5
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-7180/output.cjs
@@ -0,0 +1,7 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", {
+    value: true
+});
+0 && __export(require("./fn.js")) && __export(require("./fn2.js"));
+_export_star(require("./fn.js"), exports);
+_export_star(require("./fn2.js"), exports);
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/issue-7180/output.umd.js b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-7180/output.umd.js
new file mode 100644
index 0000000000..c1aa067096
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-7180/output.umd.js
@@ -0,0 +1,16 @@
+(function(global, factory) {
+    if (typeof module === "object" && typeof module.exports === "object") factory(exports, require("./fn.js"), require("./fn2.js"));
+    else if (typeof define === "function" && define.amd) define([
+        "exports",
+        "./fn.js",
+        "./fn2.js"
+    ], factory);
+    else if (global = typeof globalThis !== "undefined" ? globalThis : global || self) factory(global.input = {}, global.fnJs, global.fn2Js);
+})(this, function(exports, _fn, _fn2) {
+    "use strict";
+    Object.defineProperty(exports, "__esModule", {
+        value: true
+    });
+    _export_star(_fn, exports);
+    _export_star(_fn2, exports);
+});