Repository: swc-project/swc (rust)

Issue:
`_interopRequireWildcard` is injected without definition
### Describe the bug

When `import React from 'react'` is used, and also a `{...props}` with a `key={}` in JSX, `_interopRequireWildcard` is injected at the top of the TSX file while not being initialized. 

This create the error `ReferenceError: _interopRequireWildcard is not defined`

### Input code

```typescript
import React from 'react';

export const element = (
  <div {...innerTbodyProps} key={true ? 1 : 2} />
);
```


### Config

For TS:

```json
{
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": true
    },
    "transform": {
      "react": {
        "runtime": "automatic"
      }
    }
  },
  "module": {
    "type": "commonjs"
  }
}
```

For JS:

```json
{
  "jsc": {
    "parser": {
      "syntax": "ecmascript",
      "jsx": true
    },
    "transform": {
      "react": {
        "runtime": "automatic"
      }
    }
  },
  "module": {
    "type": "commonjs"
  }
}
```

Both have the same issue

### Output code

```tsx
"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
exports.element = void 0;
var _react = _interopRequireWildcard(require("react"));
function _defineProperty(obj, key, value) {
    if (key in obj) {
        Object.defineProperty(obj, key, {
            value: value,
            enumerable: true,
            configurable: true,
            writable: true
        });
    } else {
        obj[key] = value;
    }
    return obj;
}
function _interopRequireDefault(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
function _objectSpread(target) {
    for(var i = 1; i < arguments.length; i++){
        var source = arguments[i] != null ? arguments[i] : {
        };
        var ownKeys = Object.keys(source);
        if (typeof Object.getOwnPropertySymbols === "function") {
            ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
                return Object.getOwnPropertyDescriptor(source, sym).enumerable;
            }));
        }
        ownKeys.forEach(function(key) {
            _defineProperty(target, key, source[key]);
        });
    }
    return target;
}
const element = /*#__PURE__*/ (0, _react).createElement("div", _objectSpread({
}, innerTbodyProps, {
    key: true ? 1 : 2
}));
exports.element = element;
```

### Playground link

_No response_

### Expected behavior

it should haved inject `_interopRequireWildcard`, just like if `import * as React from 'react'` was used, so something like that:

```tsx
"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
exports.element = void 0;
var React = _interopRequireWildcard(require("react"));
function _defineProperty(obj, key, value) {
    if (key in obj) {
        Object.defineProperty(obj, key, {
            value: value,
            enumerable: true,
            configurable: true,
            writable: true
        });
    } else {
        obj[key] = value;
    }
    return obj;
}
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;
    }
}
function _objectSpread(target) {
    for(var i = 1; i < arguments.length; i++){
        var source = arguments[i] != null ? arguments[i] : {
        };
        var ownKeys = Object.keys(source);
        if (typeof Object.getOwnPropertySymbols === "function") {
            ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
                return Object.getOwnPropertyDescriptor(source, sym).enumerable;
            }));
        }
        ownKeys.forEach(function(key) {
            _defineProperty(target, key, source[key]);
        });
    }
    return target;
}
const element = /*#__PURE__*/ (0, React).createElement("div", _objectSpread({
}, innerTbodyProps, {
    key: true ? 1 : 2
}));
exports.element = element;
```

### Version

1.2.112

### Additional context

I tried to use the swc playground to share a link, but it wasn't working. So here is a screenshot proving what I'm saying:

![image](https://user-images.githubusercontent.com/22725671/143154188-cb941102-498d-479b-97a4-e2b67668d98d.png)


Pull request:
fix(es/transforms/module): fix helper injection detection across import order
- closes #2856

As commented in issue, crux is depends on import order import_analysis does not flag wildcard interop need to be used correctly. PR includes a scoped property to contain import sets to determine which interop is requred regardless of import order.

Patch:
diff --git a/crates/swc_ecma_transforms_module/src/import_analysis.rs b/crates/swc_ecma_transforms_module/src/import_analysis.rs
index 88e17fc9c9..c385ebe53d 100644
--- a/crates/swc_ecma_transforms_module/src/import_analysis.rs
+++ b/crates/swc_ecma_transforms_module/src/import_analysis.rs
@@ -1,7 +1,7 @@
 use super::util::Scope;
 use std::{cell::RefCell, rc::Rc};
-use swc_atoms::js_word;
-use swc_common::DUMMY_SP;
+use swc_atoms::{js_word, JsWord};
+use swc_common::{collections::AHashSet, DUMMY_SP};
 use swc_ecma_ast::*;
 use swc_ecma_transforms_base::enable_helper;
 use swc_ecma_visit::{
@@ -9,11 +9,15 @@ use swc_ecma_visit::{
 };
 
 pub fn import_analyzer(scope: Rc<RefCell<Scope>>) -> impl Fold + VisitMut {
-    as_folder(ImportAnalyzer { scope })
+    as_folder(ImportAnalyzer {
+        scope,
+        import_srcs: Default::default(),
+    })
 }
 
 pub struct ImportAnalyzer {
     scope: Rc<RefCell<Scope>>,
+    import_srcs: AHashSet<JsWord>,
 }
 
 /// Inject required helpers methods **for** module transform passes.
@@ -97,6 +101,7 @@ impl Visit for ImportAnalyzer {
             }
         } else {
             let mut has_non_default = false;
+
             for s in &import.specifiers {
                 match *s {
                     ImportSpecifier::Namespace(ref _ns) => {
@@ -105,10 +110,10 @@ impl Visit for ImportAnalyzer {
                         }
                     }
                     ImportSpecifier::Default(_) => {
-                        scope
-                            .import_types
-                            .entry(import.src.value.clone())
-                            .or_insert(false);
+                        let src = import.src.value.clone();
+                        let src_already_exist = self.import_srcs.contains(&src);
+
+                        scope.import_types.entry(src).or_insert(src_already_exist);
                     }
                     ImportSpecifier::Named(ref i) => {
                         let ImportNamedSpecifier {
@@ -122,6 +127,11 @@ impl Visit for ImportAnalyzer {
                             .unwrap_or_else(|| local.sym.clone());
                         let is_default = name == js_word!("default");
 
+                        // in case of default import comes after named import, it needs to know
+                        // if there's prior import to same src to determine interopDefault or
+                        // interopWildcard.
+                        self.import_srcs.insert(import.src.value.clone());
+
                         if is_default {
                             scope
                                 .import_types


Test patch:
diff --git a/crates/swc/tests/fixture/issue-1734/case1-B/output/index.js b/crates/swc/tests/fixture/issue-1734/case1-B/output/index.js
index e02a8c80c9..8f5036f072 100644
--- a/crates/swc/tests/fixture/issue-1734/case1-B/output/index.js
+++ b/crates/swc/tests/fixture/issue-1734/case1-B/output/index.js
@@ -1,8 +1,26 @@
 "use strict";
 var _a = _interopRequireWildcard(require("./A"));
-function _interopRequireDefault(obj) {
-    return obj && obj.__esModule ? obj : {
-        default: obj
-    };
+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;
+    }
 }
 console.log(_a.default, _a.foo);
diff --git a/crates/swc/tests/fixture/issue-2856/1/input/.swcrc b/crates/swc/tests/fixture/issue-2856/1/input/.swcrc
new file mode 100644
index 0000000000..c21ddb51c0
--- /dev/null
+++ b/crates/swc/tests/fixture/issue-2856/1/input/.swcrc
@@ -0,0 +1,11 @@
+{
+  "jsc": {
+    "parser": {
+      "syntax": "ecmascript"
+    },
+    "target": "es2015"
+  },
+  "module": {
+    "type": "commonjs"
+  }
+}
\ No newline at end of file
diff --git a/crates/swc/tests/fixture/issue-2856/1/input/index.js b/crates/swc/tests/fixture/issue-2856/1/input/index.js
new file mode 100644
index 0000000000..e5f306dee8
--- /dev/null
+++ b/crates/swc/tests/fixture/issue-2856/1/input/index.js
@@ -0,0 +1,5 @@
+import { sdx } from 'boo';
+import boo from 'boo';
+
+boo.some();
+sdx();
\ No newline at end of file
diff --git a/crates/swc/tests/fixture/issue-2856/1/output/index.js b/crates/swc/tests/fixture/issue-2856/1/output/index.js
new file mode 100644
index 0000000000..9e0577c765
--- /dev/null
+++ b/crates/swc/tests/fixture/issue-2856/1/output/index.js
@@ -0,0 +1,27 @@
+"use strict";
+var _boo = _interopRequireWildcard(require("boo"));
+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;
+    }
+}
+_boo.default.some();
+(0, _boo).sdx();