Repository: swc-project/swc (rust)

Issue:
Dynamically importing JSON module containing simple string in CJS loads wrong shape
### Describe the bug

When a JSON module is imported using `import()` and it contains a primitive, SWC's output is not spec-compliant, because when traversing keys, it doesn't check whether the object is a primitive.

### Input code

```js
import("./data.json").then(console.log);
```

`data.json`:

```json
"foo"
```

### Config

```json
{
  "jsc": {
    "parser": {
      "syntax": "ecmascript"
    },
    "target": "es2017"
  },
  "module": {
    "type": "commonjs"
  }
}
```

[Playground](https://play.swc.rs/?version=1.2.164&code=H4sIAAAAAAAAA8vMLcgvKtFQ0tNPSSxJ1Msqzs9T0tQryUjN00jOzyvOz0nVy8lP17TmAgAoHhbMKQAAAA%3D%3D&config=H4sIAAAAAAAAA0WMSwrDMAxE76K1t93kDj2EcJXg4B8aBWqM714bUrKSmPdmOp3wtHWqrBBdH1o2%2FtJG4hPDa6hGbmoz2jlChiNjPcSWgtdksRTITR2lkMPe1pIvqaoAD%2BJ8xL855lAqn2sFnazVeVcllXyCxjN0lwPet216yfgBCKaI9boAAAA%3D)

### Expected behavior

It should log `{ default: 'foo' }`.

### Actual behavior

It logs `{ '0': 'f', '1': 'o', '2': 'o', default: 'foo' }`.

Here's [Babel's playground](https://babeljs.io/repl#?browsers=defaults%2C%20not%20ie%2011%2C%20not%20ie_mob%2011&build=&builtIns=false&corejs=3.6&spec=false&loose=false&code_lz=JYWwDg9gTgLgFAIgHQHoAmBDGGkCsDOEAdggJRIwAWApkXAMbGEA21SzEA5qQNwBQQA&debug=false&forceAllTransforms=false&shippedProposals=false&circleciRepo=&evaluate=false&fileSize=false&timeTravel=false&sourceType=module&lineWrap=true&presets=env%2Creact%2Cstage-3%2Ctypescript&prettier=true&targets=&version=7.17.9&externalPlugins=%40babel%2Fplugin-transform-spread%407.16.7&assumptions=%7B%7D). You can see they have an additional

```js
if (obj === null || (typeof obj !== "object" && typeof obj !== "function")) {
  return { default: obj };
}
```

### Version

1.2.164

### Additional context

Originally reported in https://github.com/swc-project/swc-loader/issues/43

Pull request:
fix(helper): update _interopRequireWildcard
<!-- 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:**
since we don't have `importInterop: "node"`, I didn't update to the latest version in babel.
<!-- 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 #4284

Patch:
diff --git a/crates/swc_ecma_transforms_base/src/helpers/_interop_require_wildcard.js b/crates/swc_ecma_transforms_base/src/helpers/_interop_require_wildcard.js
index a14b971ca8..f4a0861b95 100644
--- a/crates/swc_ecma_transforms_base/src/helpers/_interop_require_wildcard.js
+++ b/crates/swc_ecma_transforms_base/src/helpers/_interop_require_wildcard.js
@@ -1,24 +1,42 @@
+function _getRequireWildcardCache() {
+  if (typeof WeakMap !== "function") return null;
+  var cache = new WeakMap();
+  _getRequireWildcardCache = function () { return cache; };
+  return cache;
+}
 function _interopRequireWildcard(obj) {
   if (obj && obj.__esModule) {
     return obj;
-  } else {
-    var newObj = {};
+  }
+  
+  if (obj === null || (typeof obj !== "object" && typeof obj !== "function")) {
+    return { default: obj }
+  }
+  
+  var cache = _getRequireWildcardCache();
+  if (cache && cache.has(obj)) {
+    return cache.get(obj);
+  }
 
-    if (obj != null) {
-      for (var key in obj) {
-        if (Object.prototype.hasOwnProperty.call(obj, key)) {
-          var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {};
+  var newObj = {};
 
-          if (desc.get || desc.set) {
-            Object.defineProperty(newObj, key, desc);
-          } else {
-            newObj[key] = obj[key];
-          }
-        }
+  var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
+  for (var key in obj) {
+    if (Object.prototype.hasOwnProperty.call(obj, key)) {
+      var desc = hasPropertyDescriptor
+        ? Object.getOwnPropertyDescriptor(obj, key)
+        : null;
+      if (desc && (desc.get || desc.set)) {
+        Object.defineProperty(newObj, key, desc);
+      } else {
+        newObj[key] = obj[key];
       }
     }
-
-    newObj.default = obj;
-    return newObj;
   }
+  newObj.default = obj;
+  if (cache) {
+    cache.set(obj, newObj);
+  }
+  return newObj;
+  
 }
diff --git a/packages/swc-helpers/src/_interop_require_wildcard.js b/packages/swc-helpers/src/_interop_require_wildcard.js
index 7af9ad49b1..a81c1e4f5c 100644
--- a/packages/swc-helpers/src/_interop_require_wildcard.js
+++ b/packages/swc-helpers/src/_interop_require_wildcard.js
@@ -1,24 +1,42 @@
+function _getRequireWildcardCache() {
+  if (typeof WeakMap !== "function") return null;
+  var cache = new WeakMap();
+  _getRequireWildcardCache = function () { return cache; };
+  return cache;
+}
 export default function _interopRequireWildcard(obj) {
   if (obj && obj.__esModule) {
     return obj;
-  } else {
-    var newObj = {};
+  }
+  
+  if (obj === null || (typeof obj !== "object" && typeof obj !== "function")) {
+    return { default: obj }
+  }
+  
+  var cache = _getRequireWildcardCache();
+  if (cache && cache.has(obj)) {
+    return cache.get(obj);
+  }
 
-    if (obj != null) {
-      for (var key in obj) {
-        if (Object.prototype.hasOwnProperty.call(obj, key)) {
-          var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {};
+  var newObj = {};
 
-          if (desc.get || desc.set) {
-            Object.defineProperty(newObj, key, desc);
-          } else {
-            newObj[key] = obj[key];
-          }
-        }
+  var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
+  for (var key in obj) {
+    if (Object.prototype.hasOwnProperty.call(obj, key)) {
+      var desc = hasPropertyDescriptor
+        ? Object.getOwnPropertyDescriptor(obj, key)
+        : null;
+      if (desc && (desc.get || desc.set)) {
+        Object.defineProperty(newObj, key, desc);
+      } else {
+        newObj[key] = obj[key];
       }
     }
-
-    newObj.default = obj;
-    return newObj;
   }
+  newObj.default = obj;
+  if (cache) {
+    cache.set(obj, newObj);
+  }
+  return newObj;
+  
 }


Test patch:
diff --git a/crates/swc_ecma_transforms_module/tests/common_js.rs b/crates/swc_ecma_transforms_module/tests/common_js.rs
index 3f5363fc77..f6c6179acc 100644
--- a/crates/swc_ecma_transforms_module/tests/common_js.rs
+++ b/crates/swc_ecma_transforms_module/tests/common_js.rs
@@ -3,7 +3,7 @@ use std::{cell::RefCell, path::PathBuf, rc::Rc};
 use swc_cached::regex::CachedRegex;
 use swc_common::{chain, Mark};
 use swc_ecma_parser::{EsConfig, Syntax, TsConfig};
-use swc_ecma_transforms_base::{fixer::fixer, helpers::inject_helpers, hygiene::hygiene, resolver};
+use swc_ecma_transforms_base::{fixer::fixer, hygiene::hygiene, resolver};
 use swc_ecma_transforms_compat::{
     es2015::{
         block_scoped_functions, block_scoping, classes, destructuring, for_of, parameters,
@@ -102,7 +102,6 @@ test!(
             resolver(unresolved_mark, top_level_mark, false),
             // Optional::new(typescript::strip(mark), syntax.typescript()),
             import_analyzer(Rc::clone(&scope)),
-            inject_helpers(),
             common_js(unresolved_mark, Default::default(), Some(scope)),
             hygiene(),
             fixer(None)
@@ -116,11 +115,6 @@ Foo.bar = true;
     "
 \"use strict\";
 var _foo = _interopRequireDefault(require(\"foo\"));
-function _interopRequireDefault(obj) {
-    return obj && obj.__esModule ? obj : {
-        default: obj
-    };
-}
 _foo.default.bar = true;
 "
 );
@@ -5175,7 +5169,6 @@ test!(
         let scope = Rc::new(RefCell::new(Scope::default()));
         chain!(
             import_analyzer(Rc::clone(&scope)),
-            inject_helpers(),
             common_js(Mark::fresh(Mark::root()), Default::default(), Some(scope)),
             hygiene(),
             fixer(None)
@@ -5198,28 +5191,6 @@ test!(
       }
     });
     var _foo = _interopRequireWildcard(require(\"foo\"));
-    function _interopRequireWildcard(obj) {
-        if (obj && obj.__esModule) {
-            return obj;
-        } else {
-            var newObj = {};
-            if (obj != null) {
-                for(var key in obj) {
-                    if (Object.prototype.hasOwnProperty.call(obj, key)) {
-                        var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? \
-     Object.getOwnPropertyDescriptor(obj, key) : {};
-                        if (desc.get || desc.set) {
-                            Object.defineProperty(newObj, key, desc);
-                        } else {
-                            newObj[key] = obj[key];
-                        }
-                    }
-                }
-            }
-            newObj.default = obj;
-            return newObj;
-        }
-    }
     "
 );