Repository: swc-project/swc (rust)

Issue:
Async to generator can miss parentheses causing js parsing errors
### Describe the bug

Given the right construct (below), parens can be missing around the `yield`, which causes a JS parsing error:

```
        return true && yield b();
                       ^^^^^

SyntaxError: Unexpected strict mode reserved word
```

### Input code

```typescript
async function a() {
  return true && (await b)();
}
```


### Config

```json
{
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": false
    },
    "target": "es2016",
    "loose": false,
    "minify": {
      "compress": false,
      "mangle": false
    }
  },
  "module": {
    "type": "commonjs"
  },
  "minify": false,
  "isModule": true
}
```


### Playground link

https://play.swc.rs/?version=1.2.218&code=H4sIAAAAAAAAA0ssrsxLVkgrzUsuyczPU0jU0FSo5lJQKEotKS3KUygpKk1VUFNT0EgsT8wsUUjS1NC05qoFAC60ruA0AAAA&config=H4sIAAAAAAAAA0WNSwrDMAxE76J1Fm0XXeQOPYRxleDgHxoHaozvXrm4ZCdp3jw1OmBpbZSNgGVMqLGYD61UamZYcbnQQgV62owHd12M7FwUYTxu96fGPiXwBBYKLrqtDplNIQsDV2Ti7v9kV1dI73Mc2u%2BfOrUSUjxA%2FRLNssNr0kVO7l9t6JYwvQAAAA%3D%3D

### Expected behavior

```js
_a = _asyncToGenerator(function*() {
    return true && (yield b)();
});
```

### Actual behavior

```js
_a = _asyncToGenerator(function*() {
    return true && yield b();
});
```

### Version

1.2.218

### Additional context

_No response_

Pull request description:
fix(es/base): Wrap await and yield callee
<!-- 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 #5313 

Patch:
diff --git a/crates/swc_ecma_transforms_base/src/fixer.rs b/crates/swc_ecma_transforms_base/src/fixer.rs
index 33bf65b7a4..7d4c1fc941 100644
--- a/crates/swc_ecma_transforms_base/src/fixer.rs
+++ b/crates/swc_ecma_transforms_base/src/fixer.rs
@@ -100,9 +100,13 @@ impl Fixer<'_> {
     fn wrap_callee(&mut self, e: &mut Expr) {
         if match e {
             Expr::Lit(Lit::Num(..) | Lit::Str(..)) => false,
-            Expr::Cond(..) | Expr::Bin(..) | Expr::Lit(..) | Expr::Unary(..) | Expr::Object(..) => {
-                true
-            }
+            Expr::Cond(..)
+            | Expr::Bin(..)
+            | Expr::Lit(..)
+            | Expr::Unary(..)
+            | Expr::Object(..)
+            | Expr::Await(..)
+            | Expr::Yield(..) => true,
             _ => false,
         } {
             self.wrap(e)
@@ -1622,4 +1626,14 @@ var store = global[SHARED] || (global[SHARED] = {});
     identical!(issue_5109_1, "(0, b)?.()");
     identical!(issue_5109_2, "1 + (0, b)?.()");
     identical!(issue_5109_3, "(0, a)() ? undefined : (0, b)?.()");
+
+    identical!(
+        issue_5313,
+        "
+        async function* foo() {
+            (await a)();
+            (yield b)();
+        }
+        "
+    );
 }


Test patch:
diff --git a/crates/swc/tests/fixture/issues-5xxx/5313/1/input/.swcrc b/crates/swc/tests/fixture/issues-5xxx/5313/1/input/.swcrc
new file mode 100644
index 0000000000..01e6bed642
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-5xxx/5313/1/input/.swcrc
@@ -0,0 +1,19 @@
+{
+    "jsc": {
+        "parser": {
+            "syntax": "ecmascript",
+            "tsx": false
+        },
+        "target": "es2016",
+        "loose": false,
+        "minify": {
+            "compress": false,
+            "mangle": false
+        }
+    },
+    "module": {
+        "type": "commonjs"
+    },
+    "minify": false,
+    "isModule": true
+}
\ No newline at end of file
diff --git a/crates/swc/tests/fixture/issues-5xxx/5313/1/input/index.js b/crates/swc/tests/fixture/issues-5xxx/5313/1/input/index.js
new file mode 100644
index 0000000000..721ec1af0a
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-5xxx/5313/1/input/index.js
@@ -0,0 +1,3 @@
+async function a() {
+    return true && (await b)();
+}
diff --git a/crates/swc/tests/fixture/issues-5xxx/5313/1/output/index.js b/crates/swc/tests/fixture/issues-5xxx/5313/1/output/index.js
new file mode 100644
index 0000000000..d4491a6f94
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-5xxx/5313/1/output/index.js
@@ -0,0 +1,14 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", {
+    value: true
+});
+const _asyncToGenerator = require("@swc/helpers/lib/_async_to_generator.js").default;
+function a() {
+    return _a.apply(this, arguments);
+}
+function _a() {
+    _a = _asyncToGenerator(function*() {
+        return true && (yield b)();
+    });
+    return _a.apply(this, arguments);
+}
diff --git a/crates/swc/tests/fixture/issues-5xxx/5313/2/input/.swcrc b/crates/swc/tests/fixture/issues-5xxx/5313/2/input/.swcrc
new file mode 100644
index 0000000000..7db1e01b8d
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-5xxx/5313/2/input/.swcrc
@@ -0,0 +1,19 @@
+{
+    "jsc": {
+        "parser": {
+            "syntax": "ecmascript",
+            "tsx": false
+        },
+        "target": "es2022",
+        "loose": false,
+        "minify": {
+            "compress": false,
+            "mangle": false
+        }
+    },
+    "module": {
+        "type": "commonjs"
+    },
+    "minify": false,
+    "isModule": true
+}
\ No newline at end of file
diff --git a/crates/swc/tests/fixture/issues-5xxx/5313/2/input/index.js b/crates/swc/tests/fixture/issues-5xxx/5313/2/input/index.js
new file mode 100644
index 0000000000..721ec1af0a
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-5xxx/5313/2/input/index.js
@@ -0,0 +1,3 @@
+async function a() {
+    return true && (await b)();
+}
diff --git a/crates/swc/tests/fixture/issues-5xxx/5313/2/output/index.js b/crates/swc/tests/fixture/issues-5xxx/5313/2/output/index.js
new file mode 100644
index 0000000000..c18d33815a
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-5xxx/5313/2/output/index.js
@@ -0,0 +1,4 @@
+"use strict";
+async function a() {
+    return true && (await b)();
+}
diff --git a/crates/swc/tests/tsc-references/awaitCallExpression4_es2017_es2015.1.normal.js b/crates/swc/tests/tsc-references/awaitCallExpression4_es2017_es2015.1.normal.js
index e272ef9cd4..564d8a0436 100644
--- a/crates/swc/tests/tsc-references/awaitCallExpression4_es2017_es2015.1.normal.js
+++ b/crates/swc/tests/tsc-references/awaitCallExpression4_es2017_es2015.1.normal.js
@@ -7,7 +7,7 @@ function func() {
 function _func() {
     _func = _async_to_generator(function*() {
         before();
-        var b = yield pfn(a, a, a);
+        var b = (yield pfn)(a, a, a);
         after();
     });
     return _func.apply(this, arguments);
diff --git a/crates/swc/tests/tsc-references/awaitCallExpression4_es5_es2015.1.normal.js b/crates/swc/tests/tsc-references/awaitCallExpression4_es5_es2015.1.normal.js
index 92ce81274b..5f10963e8a 100644
--- a/crates/swc/tests/tsc-references/awaitCallExpression4_es5_es2015.1.normal.js
+++ b/crates/swc/tests/tsc-references/awaitCallExpression4_es5_es2015.1.normal.js
@@ -8,7 +8,7 @@ function func() {
 function _func() {
     _func = _async_to_generator(function*() {
         before();
-        var b = yield pfn(a, a, a);
+        var b = (yield pfn)(a, a, a);
         after();
     });
     return _func.apply(this, arguments);
diff --git a/crates/swc/tests/tsc-references/awaitCallExpression4_es6_es2015.1.normal.js b/crates/swc/tests/tsc-references/awaitCallExpression4_es6_es2015.1.normal.js
index 52a5e97491..fa482620ae 100644
--- a/crates/swc/tests/tsc-references/awaitCallExpression4_es6_es2015.1.normal.js
+++ b/crates/swc/tests/tsc-references/awaitCallExpression4_es6_es2015.1.normal.js
@@ -7,7 +7,7 @@ function func() {
 function _func() {
     _func = _async_to_generator(function*() {
         before();
-        var b = yield pfn(a, a, a);
+        var b = (yield pfn)(a, a, a);
         after();
     });
     return _func.apply(this, arguments);