Repository: swc-project/swc (rust)

Issue:
does not allow reassign ref to default exported fn
### Describe the bug

- Followup edge cases for https://github.com/swc-project/swc/issues/2549, https://github.com/swc-project/swc/issues/2606

When an function is async, default exported it does not reassign its ref to export as similar to original #2549 does.

### Input code

```typescript
export default function someCall() {
  region();
}

export const text = {};
Object.defineProperty(test, 'someCall', {
  set: (v) => {
    someCall = v;
  }
})
```


### Config

```json
{
  "jsc": {
    "target": "es2017"
  },
  "module": {
    "type": "commonjs",
    "noInterop": false
  },
  "env": {
    "targets": {
      "node": 14
    },
    "include": ["transform-async-to-generator"]
  }
}
```


### Playground link

https://play.swc.rs/?version=1.2.106&code=H4sIAAAAAAAAAz2NQQrCMBBF94Hc4e%2BaQPEAlrrxAHqFGqdSiUlJpqVScndHgm7f579H2xwT407jsHjGuATHUwzI8UXnwXtjsWsFJHoINrbTqmilFdWfiyEzmDZGj73Ierk9yfFBhFOga4ozJX4bpswtmp%2B1aas1Ex9hVov%2BVAH%2BYfGt3RdJrtgP6sRtQKcAAAA%3D&config=H4sIAAAAAAAAA0WNSwrDMAxE76J1Fm2hXeQOPYRxleDgHxoFGozvXju4ZCfNPD0V2mBpLpSNgKVPOKKaL82kR2ZYcVlpIkWLFuPBtS1GVtaGMB63%2B7PVPiXwACYKLrrl6DKbQhYGrsrE1f%2FJ2lwhffYelPPf6XxRvRzjzuE9QJWd6w%2ByirtzuAAAAA%3D%3D

### Expected behavior

Same as #2549, #2606, expect to get reassign like 

```
  set: (v) => {
	exports.someCall = someCall = v;
  }

```

### Version

1.2.106 (and potentially master TOT)

### Additional context

- Looks like potentially related to https://github.com/swc-project/swc/issues/2677 , but for now separating issue until we can triage if it shares same root cause.

Pull request:
fix(es/transforms/cjs): bind reassign scope to default export fn
- closes #2678 

This PR attempt to fix #2678, one of the edge cases of #2549.

As same as fix for #2549, this PR sets scope to the exported. The only difference is it doesn't set scope to name of the declaration (or FnExpr's) as default export uses fixed name `default` for the export. Given current fold already creates default export member expr, reuses created one to assign into scope.


Patch:
diff --git a/ecmascript/transforms/module/src/common_js.rs b/ecmascript/transforms/module/src/common_js.rs
index 88b100ab8c..5375892cc2 100644
--- a/ecmascript/transforms/module/src/common_js.rs
+++ b/ecmascript/transforms/module/src/common_js.rs
@@ -372,6 +372,21 @@ where
                                     // init_export!("default");
                                     let ident = ident.unwrap_or_else(|| private_ident!("_default"));
 
+                                    // bind default exported fn into scope. Note this assigns
+                                    // syntaxcontext
+                                    // for the `default` ident, since default export is always named
+                                    // as `export.default`
+                                    // instead of actual ident of FnExpr even if it exists.
+                                    {
+                                        let mut scope = self.scope.borrow_mut();
+
+                                        scope
+                                            .exported_bindings
+                                            .entry((ident.sym.clone(), ident.span.ctxt()))
+                                            .or_default()
+                                            .push((js_word!("default"), DUMMY_SP.ctxt()));
+                                    }
+
                                     extra_stmts.push(ModuleItem::Stmt(Stmt::Decl(Decl::Fn(
                                         FnDecl {
                                             ident: ident.clone(),


Test patch:
diff --git a/ecmascript/transforms/module/tests/fixture/commonjs/issue-2678/input.js b/ecmascript/transforms/module/tests/fixture/commonjs/issue-2678/input.js
new file mode 100644
index 0000000000..a546951d97
--- /dev/null
+++ b/ecmascript/transforms/module/tests/fixture/commonjs/issue-2678/input.js
@@ -0,0 +1,21 @@
+export default function someCall() {
+    throw new Error('this should not be called');
+}
+
+export function warn() {
+    throw new Error('this should not be called');
+}
+
+export const test = {};
+Object.defineProperty(test, 'someCall', {
+    set: (v) => {
+        someCall = v;
+    }
+})
+
+Object.defineProperty(test, 'warn', {
+    get: () => warn,
+    set: (v) => {
+        warn = v;
+    },
+});
diff --git a/ecmascript/transforms/module/tests/fixture/commonjs/issue-2678/output.js b/ecmascript/transforms/module/tests/fixture/commonjs/issue-2678/output.js
new file mode 100644
index 0000000000..e9b9ddc998
--- /dev/null
+++ b/ecmascript/transforms/module/tests/fixture/commonjs/issue-2678/output.js
@@ -0,0 +1,28 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", {
+    value: true
+});
+exports.default = someCall;
+exports.warn = warn;
+exports.test = void 0;
+function someCall() {
+    throw new Error("this should not be called");
+}
+function warn() {
+    throw new Error("this should not be called");
+}
+const test = {
+};
+exports.test = test;
+Object.defineProperty(test, "someCall", {
+    set: (v)=>{
+        exports.default = someCall = v;
+    }
+});
+Object.defineProperty(test, "warn", {
+    get: ()=>warn
+    ,
+    set: (v)=>{
+        exports.warn = warn = v;
+    }
+});