Repository: swc-project/swc (rust)

Issue:
wrong output of export Class
### Describe the bug

error ouput code causing `can not read property of undefined`

### Input code

```typescript
export class Foo {
  bar() {
  }
}
```


### Config

```json
{
  "jsc": {
    "parser": {
      "syntax": "ecmascript",
      "jsx": false
    },
    "target": "es5",
    "loose": false,
    "minify": {
      "compress": false,
      "mangle": false
    }
  },
  "module": {
    "type": "commonjs"
  },
  "minify": false,
  "isModule": true
}
```


### Playground link

https://play.swc.rs/?version=1.2.150&code=H4sIAAAAAAAAA0utKMgvKlFIzkksLlZwy89XqOblUlBISizS0IQwa3m5gAgANcDmXicAAAA%3D&config=H4sIAAAAAAAAA0WMSwrDMAxE76K1t93kDj2EcJXg4B8aBWqM714bUrKSmPdmOp3wtHWqrBBdH1o2%2FtJG4hPDa6hGbmoz2jlChiNjPcSWgtdksRTITR2lkMPe1pIvqaoAD%2BJ8xL855lAqn2sFnazVeVcllXyCxjN0lwPet216yfgBCKaI9boAAAA%3D

### Expected behavior

```js
var Foo = function() {
    "use strict";
    function Foo() {
        _classCallCheck(this, exports.Foo);
    }
    _createClass(exports.Foo, [  // this line should be `_createClass(Foo, [` which works in the previous versions
        {
            key: "bar",
            value: function bar() {}
        }
    ]);
    return exports.Foo;
}();
```

### Actual behavior

_No response_

### Version

1.2.150

### Additional context

_No response_

Pull request:
fix(es/module): Revert fix for `jest.spyOn`
**Description:**


**Related issue (if exists):**
 - Closes #3892


Patch:
diff --git a/crates/swc_ecma_transforms_module/src/common_js.rs b/crates/swc_ecma_transforms_module/src/common_js.rs
index ee5736090a..5ad0764570 100644
--- a/crates/swc_ecma_transforms_module/src/common_js.rs
+++ b/crates/swc_ecma_transforms_module/src/common_js.rs
@@ -12,8 +12,8 @@ use swc_common::{
 use swc_ecma_ast::*;
 use swc_ecma_transforms_base::helper;
 use swc_ecma_utils::{
-    find_ids, ident::IdentLike, member_expr, private_ident, quote_ident, quote_str,
-    var::VarCollector, DestructuringFinder, ExprFactory, IsDirective,
+    ident::IdentLike, member_expr, private_ident, quote_ident, quote_str, var::VarCollector,
+    DestructuringFinder, ExprFactory, IsDirective,
 };
 use swc_ecma_visit::{noop_fold_type, noop_visit_type, Fold, FoldWith, Visit, VisitWith};
 
@@ -193,19 +193,6 @@ impl Fold for CommonJs {
             }
         }
 
-        for item in &items {
-            if let ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
-                decl: Decl::Var(v),
-                ..
-            })) = item
-            {
-                self.scope
-                    .borrow_mut()
-                    .exported_var_decls
-                    .extend(find_ids(&v.decls));
-            }
-        }
-
         // Make another preliminary pass to collect all import sources and their
         // specifiers.
         for item in &items {
@@ -399,9 +386,9 @@ impl Fold for CommonJs {
                             decl: Decl::Var(var),
                             ..
                         })) => {
-                            let new_var = var.clone().fold_with(self);
-
-                            extra_stmts.push(ModuleItem::Stmt(Stmt::Decl(Decl::Var(new_var))));
+                            extra_stmts.push(ModuleItem::Stmt(Stmt::Decl(Decl::Var(
+                                var.clone().fold_with(self),
+                            ))));
 
                             let mut scope = self.scope.borrow_mut();
                             var.decls.visit_with(&mut VarCollector {
diff --git a/crates/swc_ecma_transforms_module/src/util.rs b/crates/swc_ecma_transforms_module/src/util.rs
index 3b1759d830..513fa98679 100644
--- a/crates/swc_ecma_transforms_module/src/util.rs
+++ b/crates/swc_ecma_transforms_module/src/util.rs
@@ -12,7 +12,7 @@ use swc_cached::regex::CachedRegex;
 use swc_common::{
     collections::{AHashMap, AHashSet},
     util::take::Take,
-    Span, SyntaxContext, DUMMY_SP,
+    Span, DUMMY_SP,
 };
 use swc_ecma_ast::*;
 use swc_ecma_utils::{
@@ -135,7 +135,7 @@ pub struct Scope {
     ///   -> `{foo: ('bar', default)}`
     pub(crate) idents: AHashMap<Id, (JsWord, JsWord)>,
 
-    /// Declared variables.
+    /// Declared variables except const.
     pub(crate) declared_vars: Vec<Id>,
 
     /// Maps of exported bindings.
@@ -149,13 +149,9 @@ pub struct Scope {
     ///   -> `{ a: [b] }`
     pub(crate) exported_bindings: AHashMap<Id, Vec<Id>>,
 
-    pub(crate) exported_var_decls: AHashSet<Id>,
-
     /// This is required to handle
     /// `export * from 'foo';`
     pub(crate) lazy_blacklist: AHashSet<JsWord>,
-
-    exports: Option<Ident>,
 }
 
 impl Scope {
@@ -444,28 +440,13 @@ impl Scope {
         match value {
             Ok(value) => Prop::KeyValue(KeyValueProp {
                 key: PropName::Ident(key),
-                value: Box::new(value.0),
+                value: Box::new(value),
             }),
             Err(ident) => Prop::Shorthand(ident),
         }
     }
 
-    /// Try converting identifier to member expression referring imports.
-    ///
-    /// returns `(expr, true)` for import refs and `(expr, false)` for exports.
-    fn fold_ident(folder: &mut impl ModulePass, i: Ident) -> Result<(Expr, bool), Ident> {
-        if folder.scope().exported_var_decls.contains(&i.to_id()) {
-            return Ok((
-                folder
-                    .scope()
-                    .exports
-                    .clone()
-                    .unwrap()
-                    .make_member(Ident::new(i.sym, i.span.with_ctxt(SyntaxContext::empty()))),
-                false,
-            ));
-        }
-
+    fn fold_ident(folder: &mut impl ModulePass, i: Ident) -> Result<Expr, Ident> {
         let orig_span = i.span;
         let v = folder.scope().idents.get(&i.to_id()).cloned();
         match v {
@@ -497,9 +478,9 @@ impl Scope {
 
                 if *prop == js_word!("") {
                     // import * as foo from 'foo';
-                    Ok((obj, true))
+                    Ok(obj)
                 } else {
-                    Ok((obj.make_member(Ident::new(prop, DUMMY_SP)), true))
+                    Ok(obj.make_member(Ident::new(prop, DUMMY_SP)))
                 }
             }
         }
@@ -511,8 +492,6 @@ impl Scope {
         top_level: bool,
         expr: Expr,
     ) -> Expr {
-        folder.scope_mut().exports = Some(exports.clone());
-
         macro_rules! chain_assign {
             ($entry:expr, $e:expr) => {{
                 let mut e = $e;
@@ -536,7 +515,7 @@ impl Scope {
             // In a JavaScript module, this is undefined at the top level (i.e., outside functions).
             Expr::This(ThisExpr { span }) if top_level => *undefined(span),
             Expr::Ident(i) => match Self::fold_ident(folder, i) {
-                Ok(expr) => expr.0,
+                Ok(expr) => expr,
                 Err(ident) => Expr::Ident(ident),
             },
 
@@ -566,7 +545,7 @@ impl Scope {
 
                 let expr = match *expr {
                     Expr::Ident(ident) => match Self::fold_ident(folder, ident) {
-                        Ok(expr) => expr.0,
+                        Ok(expr) => expr,
                         Err(ident) => Expr::Ident(ident),
                     },
                     expr => expr,
@@ -584,24 +563,21 @@ impl Scope {
                 let callee = if let Callee::Expr(expr) = callee {
                     let callee = if let Expr::Ident(ident) = *expr {
                         match Self::fold_ident(folder, ident) {
-                            Ok((mut expr, need_zero)) => {
-                                if need_zero {
-                                    if let Expr::Member(member) = &mut expr {
-                                        if let Expr::Ident(ident) = member.obj.as_mut() {
-                                            member.obj = Box::new(Expr::Paren(ParenExpr {
-                                                expr: Box::new(Expr::Seq(SeqExpr {
-                                                    span,
-                                                    exprs: vec![
-                                                        Box::new(0_f64.into()),
-                                                        Box::new(ident.take().into()),
-                                                    ],
-                                                })),
+                            Ok(mut expr) => {
+                                if let Expr::Member(member) = &mut expr {
+                                    if let Expr::Ident(ident) = member.obj.as_mut() {
+                                        member.obj = Box::new(Expr::Paren(ParenExpr {
+                                            expr: Box::new(Expr::Seq(SeqExpr {
                                                 span,
-                                            }))
-                                        }
-                                    };
-                                }
-
+                                                exprs: vec![
+                                                    Box::new(0_f64.into()),
+                                                    Box::new(ident.take().into()),
+                                                ],
+                                            })),
+                                            span,
+                                        }))
+                                    }
+                                };
                                 expr
                             }
                             Err(ident) => Expr::Ident(ident),
@@ -761,7 +737,7 @@ impl Scope {
                         let left = if let PatOrExpr::Pat(ref left_pat) = expr.left {
                             if let Pat::Ident(BindingIdent { ref id, .. }) = **left_pat {
                                 let expr = match Self::fold_ident(folder, id.clone()) {
-                                    Ok(expr) => expr.0,
+                                    Ok(expr) => expr,
                                     Err(ident) => Expr::Ident(ident),
                                 };
                                 PatOrExpr::Expr(Box::new(expr))


Test patch:
diff --git a/crates/swc/tests/fixture/issue-2606/1/output/index.ts b/crates/swc/tests/fixture/issue-2606/1/output/index.ts
index f21112289c..76249b3624 100644
--- a/crates/swc/tests/fixture/issue-2606/1/output/index.ts
+++ b/crates/swc/tests/fixture/issue-2606/1/output/index.ts
@@ -11,14 +11,14 @@ const test = {};
 exports.test = test;
 const test2 = {};
 exports.test2 = test2;
-Object.defineProperty(exports.test, "warn", {
+Object.defineProperty(test, "warn", {
     get: ()=>warn
     ,
     set: (v)=>{
         exports.warn = warn = v;
     }
 });
-Object.defineProperty(exports.test2, "work", {
+Object.defineProperty(test2, "work", {
     get: ()=>warn
     ,
     set: (v)=>{
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/commonjs/issue-2549/output.js b/crates/swc_ecma_transforms_module/tests/fixture/commonjs/issue-2549/output.js
index e72fda5a0a..26692b536d 100644
--- a/crates/swc_ecma_transforms_module/tests/fixture/commonjs/issue-2549/output.js
+++ b/crates/swc_ecma_transforms_module/tests/fixture/commonjs/issue-2549/output.js
@@ -21,12 +21,13 @@ exports.errors = errors;
 const addOne = (x)=>`${x + 1}`
 ;
 exports.addOne = addOne;
-const someFunc = (x)=>`The answer is : ${exports.addOne(x)}`
+const someFunc = (x)=>`The answer is : ${addOne(x)}`
 ;
 exports.someFunc = someFunc;
-const test = {};
+const test = {
+};
 exports.test = test;
-Object.defineProperty(exports.test, "log", {
+Object.defineProperty(test, "log", {
     get: function get() {
         return log;
     },
@@ -34,15 +35,15 @@ Object.defineProperty(exports.test, "log", {
         log = v;
     }
 });
-Object.defineProperty(exports.test, "warn", {
+Object.defineProperty(test, "warn", {
     get: ()=>warn
     ,
     set: (v)=>{
         exports.warn = warn = v;
     }
 });
-Object.defineProperty(exports.test, "errors", {
-    get: ()=>exports.errors
+Object.defineProperty(test, "errors", {
+    get: ()=>errors
     ,
     set: (v)=>{
         exports.errors = errors = v;
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/commonjs/issue-2678/output.js b/crates/swc_ecma_transforms_module/tests/fixture/commonjs/issue-2678/output.js
index f27465abf3..e9b9ddc998 100644
--- a/crates/swc_ecma_transforms_module/tests/fixture/commonjs/issue-2678/output.js
+++ b/crates/swc_ecma_transforms_module/tests/fixture/commonjs/issue-2678/output.js
@@ -11,14 +11,15 @@ function someCall() {
 function warn() {
     throw new Error("this should not be called");
 }
-const test = {};
+const test = {
+};
 exports.test = test;
-Object.defineProperty(exports.test, "someCall", {
+Object.defineProperty(test, "someCall", {
     set: (v)=>{
         exports.default = someCall = v;
     }
 });
-Object.defineProperty(exports.test, "warn", {
+Object.defineProperty(test, "warn", {
     get: ()=>warn
     ,
     set: (v)=>{
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/commonjs/issue-3843/1/input.js b/crates/swc_ecma_transforms_module/tests/fixture/commonjs/issue-3843/1/input.js
deleted file mode 100644
index 394a93b729..0000000000
--- a/crates/swc_ecma_transforms_module/tests/fixture/commonjs/issue-3843/1/input.js
+++ /dev/null
@@ -1,7 +0,0 @@
-export const child = () => {
-    console.log('Hello World!');
-};
-
-export const callChild = () => {
-    child();
-};
\ No newline at end of file
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/commonjs/issue-3843/1/output.js b/crates/swc_ecma_transforms_module/tests/fixture/commonjs/issue-3843/1/output.js
deleted file mode 100644
index c0ec616910..0000000000
--- a/crates/swc_ecma_transforms_module/tests/fixture/commonjs/issue-3843/1/output.js
+++ /dev/null
@@ -1,13 +0,0 @@
-"use strict";
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-exports.callChild = exports.child = void 0;
-const child = ()=>{
-    console.log("Hello World!");
-};
-exports.child = child;
-const callChild = ()=>{
-    exports.child();
-};
-exports.callChild = callChild;