Repository: swc-project/swc (rust)

Issue:
SWC does not honour pragma when spread is used before additional props 
### Describe the bug

Hello, 

We recently switched from using babel to SWC for our transpilation purposes. We noticed an issue with SWC not honouring `jsc.transform.react.importSource` when a spread operator is used before additional props.

In our case we are using typescript, emotion and react as can be seen in the SWC config provided. I will provide an example component the expected SWC output and the one obtained.


### Input code

```tsx
import type { FC, ReactNode } from "react";
import { isValidElement, Children } from "react";

import * as styles from "./CheckmarkList.styles";

interface Props {
  children: ReactNode;
}

const CheckmarkList: FC<Props> = ({ children}) => {
  const listItems = () =>
    Children.map(children, (child, index) => {
      if (!isValidElement(child)) {
        return null;
      }
      const { children: liChildren, css: liCss, ...otherProps } = child.props;

      return (
        <li {...otherProps} key={`checkmark-list-item-${index}`} css={[styles.listItem, liCss]}>
          {liChildren}
        </li>
      );
    });

  return <ul css={styles.list}>{listItems()}</ul>;
};

export { CheckmarkList };
```


### Config

```json
{
  "$schema": "http://json.schemastore.org/swcrc",
  "jsc": {
    "externalHelpers": true,
    "parser": {
      "syntax": "typescript",
      "tsx": true,
      "dynamicImport": true
    },
    "experimental": {
      "plugins": [
        ["@fullscript/swc-plugin-translation-converter", {}],
        [
          "@fullscript/swc-plugin-jsx-remove-attribute",
          {
            "attributesToRemove": ["data-testid"]
          }
        ],
        [
          "@swc/plugin-emotion",
          {
            "autoLabel": "always",
            "labelFormat": "[dirname]"
          }
        ],
        ["@swc/plugin-loadable-components", {}]
      ]
    },
    "transform": {
      "react": {
        "runtime": "automatic",
        "importSource": "@emotion/react",
        "pragma": "React.createElement",
        "pragmaFrag": "React.Fragment",
        "throwIfNamespace": true,
        "useBuiltins": true,
        "refresh": true
      }
    }
  },
  "env": {
    "mode": "usage",
    "coreJs": "3.23",
    "shippedProposals": true,
    "targets": "defaults, last 1 version, > 0.2%, not dead, not IE > 0, ios_saf >= 10, safari >= 10, not op_mini all, not baidu <= 100, not kaiOS <= 100, not android <= 5.0, not and_uc <= 100, not and_qq <= 100"
  }
}
```


### Playground link

_No response_

### Expected behavior

SWC should honour `jsc.transform.react.importSource` and have the following output as it does when the `{...otherProp}` spread is used after non spread props 

```JS
import _object_spread_props from "@swc/helpers/src/_object_spread_props.mjs";
import _object_without_properties from "@swc/helpers/src/_object_without_properties.mjs";
import { jsx as _jsx } from "@emotion/react/jsx-runtime";
import { isValidElement, Children } from "react";
import * as styles from "./CheckmarkList.styles";
var CheckmarkList = param => {
  var { children } = param;
  var listItems = () =>
    Children.map(children, (child, index) => {
      if (!(/*#__PURE__*/ isValidElement(child))) {
        return null;
      }
      var _child_props = child.props,
        { children: liChildren, css: liCss } = _child_props,
        otherProps = _object_without_properties(_child_props, ["children", "css"]);
      return /*#__PURE__*/ _jsx(
        "li",
        _object_spread_props(
          _object_spread(
            {
              css: [styles.listItem, liCss],
            },
            otherProps
          ),
          {
            children: liChildren,
          }
        ),
        "checkmark-list-item-".concat(index)
      );
    });
  return /*#__PURE__*/ _jsx("ul", {
    css: styles.list,
    children: listItems(),
  });
};
export { CheckmarkList };
```

### Actual behavior

Instead SWC does not honour `jsc.transform.react.importSource` and uses `React.createElement`

```JS
import _object_spread from "@swc/helpers/src/_object_spread.mjs";
import _object_spread_props from "@swc/helpers/src/_object_spread_props.mjs";
import _object_without_properties from "@swc/helpers/src/_object_without_properties.mjs";
import { jsx as _jsx } from "@emotion/react/jsx-runtime";
import { createElement as _createElement } from "react";
import { isValidElement, Children } from "react";
import * as styles from "./CheckmarkList.styles";
var CheckmarkList = param => {
  var { children } = param;
  var listItems = () =>
    Children.map(children, (child, index) => {
      if (!(/*#__PURE__*/ isValidElement(child))) {
        return null;
      }
      var _child_props = child.props,
        { children: liChildren, css: liCss } = _child_props,
        otherProps = _object_without_properties(_child_props, ["children", "css"]);
      return /*#__PURE__*/ _createElement(
        "li",
        _object_spread_props(_object_spread({}, otherProps), {
          key: "checkmark-list-item-".concat(index),
          css: [styles.listItem, liCss],
        }),
        liChildren
      );
    });
  return /*#__PURE__*/ _jsx("ul", {
    css: styles.list,
    children: listItems(),
  });
};
export { CheckmarkList };
```

This results in an error for emotion when rendering the component and results in styles being rendered as `[object Object],`
![Screenshot 2023-02-24 at 12 14 08 PM](https://user-images.githubusercontent.com/26819992/221244169-e77acab6-49d7-4d1d-a79f-f7b6720a2064.png)



### Version

1.3.32

### Additional context

_No response_

Pull request:
fix(react): honour `import_source` in new jsx
<!-- 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? -->

**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 #6987 

Patch:
diff --git a/crates/swc_ecma_transforms_react/src/jsx/mod.rs b/crates/swc_ecma_transforms_react/src/jsx/mod.rs
index 54d77e01ce..d227d20608 100644
--- a/crates/swc_ecma_transforms_react/src/jsx/mod.rs
+++ b/crates/swc_ecma_transforms_react/src/jsx/mod.rs
@@ -993,7 +993,7 @@ where
                         src: Str {
                             span: DUMMY_SP,
                             raw: None,
-                            value: "react".into(),
+                            value: self.import_source.clone(),
                         }
                         .into(),
                         type_only: Default::default(),


Test patch:
diff --git a/crates/swc/tests/tsc-references/jsxJsxsCjsTransformKeyPropCustomImportPragma.1.normal.js b/crates/swc/tests/tsc-references/jsxJsxsCjsTransformKeyPropCustomImportPragma.1.normal.js
index 06ab7740ed..d838486b6d 100644
--- a/crates/swc/tests/tsc-references/jsxJsxsCjsTransformKeyPropCustomImportPragma.1.normal.js
+++ b/crates/swc/tests/tsc-references/jsxJsxsCjsTransformKeyPropCustomImportPragma.1.normal.js
@@ -7,14 +7,14 @@ Object.defineProperty(exports, "__esModule", {
 var _objectSpread = require("@swc/helpers/lib/_object_spread.js").default;
 var _objectSpreadProps = require("@swc/helpers/lib/_object_spread_props.js").default;
 var _jsxRuntime = require("preact/jsx-runtime");
-var _react = require("react");
+var _preact = require("preact");
 var props = {
     answer: 42
 };
 var a = /*#__PURE__*/ (0, _jsxRuntime.jsx)("div", _objectSpreadProps(_objectSpread({}, props), {
     children: "text"
 }), "foo");
-var b = /*#__PURE__*/ (0, _react.createElement)("div", _objectSpreadProps(_objectSpread({}, props), {
+var b = /*#__PURE__*/ (0, _preact.createElement)("div", _objectSpreadProps(_objectSpread({}, props), {
     key: "bar"
 }), "text");
 //// [react.tsx]
diff --git a/crates/swc/tests/tsc-references/jsxJsxsCjsTransformKeyPropCustomImportPragma.2.minified.js b/crates/swc/tests/tsc-references/jsxJsxsCjsTransformKeyPropCustomImportPragma.2.minified.js
index 9f53a9f732..4b5fee103a 100644
--- a/crates/swc/tests/tsc-references/jsxJsxsCjsTransformKeyPropCustomImportPragma.2.minified.js
+++ b/crates/swc/tests/tsc-references/jsxJsxsCjsTransformKeyPropCustomImportPragma.2.minified.js
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
     value: !0
 });
 var _objectSpread = require("@swc/helpers/lib/_object_spread.js").default, _objectSpreadProps = require("@swc/helpers/lib/_object_spread_props.js").default;
-require("preact/jsx-runtime"), require("react");
+require("preact/jsx-runtime"), require("preact");
 var props = {
     answer: 42
 };
diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-6987/input.js b/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-6987/input.js
new file mode 100644
index 0000000000..4a95ae81a8
--- /dev/null
+++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-6987/input.js
@@ -0,0 +1,24 @@
+import { isValidElement, Children } from "react";
+
+import * as styles from "./CheckmarkList.styles";
+
+
+const CheckmarkList = ({ children}) => {
+  const listItems = () =>
+    Children.map(children, (child, index) => {
+      if (!isValidElement(child)) {
+        return null;
+      }
+      const { children: liChildren, css: liCss, ...otherProps } = child.props;
+
+      return (
+        <li {...otherProps} key={`checkmark-list-item-${index}`} css={[styles.listItem, liCss]}>
+          {liChildren}
+        </li>
+      );
+    });
+
+  return <ul css={styles.list}>{listItems()}</ul>;
+};
+
+export { CheckmarkList };
diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-6987/options.json b/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-6987/options.json
new file mode 100644
index 0000000000..ff4d322783
--- /dev/null
+++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-6987/options.json
@@ -0,0 +1,6 @@
+{
+    "runtime": "automatic",
+    "importSource": "@emotion/react",
+    "pragma": "React.createElement",
+    "pragmaFrag": "React.Fragment"
+}
diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-6987/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-6987/output.mjs
new file mode 100644
index 0000000000..6da3dafea1
--- /dev/null
+++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-6987/output.mjs
@@ -0,0 +1,25 @@
+import { jsx as _jsx } from "@emotion/react/jsx-runtime";
+import { createElement as _createElement } from "@emotion/react";
+import { isValidElement, Children } from "react";
+import * as styles from "./CheckmarkList.styles";
+const CheckmarkList = ({ children  })=>{
+    const listItems = ()=>Children.map(children, (child, index)=>{
+            if (!/*#__PURE__*/ isValidElement(child)) {
+                return null;
+            }
+            const { children: liChildren , css: liCss , ...otherProps } = child.props;
+            return /*#__PURE__*/ _createElement("li", {
+                ...otherProps,
+                key: `checkmark-list-item-${index}`,
+                css: [
+                    styles.listItem,
+                    liCss
+                ]
+            }, liChildren);
+        });
+    return /*#__PURE__*/ _jsx("ul", {
+        css: styles.list,
+        children: listItems()
+    });
+};
+export { CheckmarkList };