Keep parentheses in yield expression (#19913)

Co-authored-by: fisker <lionkay@gmail.com>
This commit is contained in:
Bao Nguyenandfisker authored and GitHub committed 2026-09-11 06:33:16 +08:00
1 parent c4c3320496
commit f6ddf6e437
6 files changed
+163 -16

No files matched your search

+24
View File
@@ -0,0 +1,24 @@
#### Keep necessary parentheses in `yield` expression (#19913 by @giaBaoJS)
<!-- prettier-ignore -->
```jsx
// Input
function* f() {
yield (/*
*/ a);
}
// Prettier stable
function* f() {
yield /*
*/ a;
}
// Prettier main
function* f() {
yield (
/*
*/ a
);
}
```
@@ -27,7 +27,8 @@ function parentNeedsParentheses(path, options, needsParentheses) {
switch (parent.type) {
case "ReturnStatement":
case "ThrowStatement":
if (willReturnOrThrowStatementBreak(path, options)) {
case "YieldExpression":
if (willArgumentBreakAndAddParentheses(path, options)) {
return false;
}
break;
@@ -128,14 +129,17 @@ function parentNeedsParentheses(path, options, needsParentheses) {
}
}
function willReturnOrThrowStatementBreak(path, options) {
function willArgumentBreakAndAddParentheses(path, options) {
const { key, parent } = path;
if (!(key === "argument" && isReturnOrThrowStatement(parent))) {
if (!(
key === "argument" &&
(isReturnOrThrowStatement(parent) || parent.type === "YieldExpression")
)) {
return false;
}
/*
When `ReturnStatement` or `ThrowStatement` breaks, parentheses will be added around it's argument.
When `ReturnStatement`, `ThrowStatement`, or `YieldExpression` breaks, parentheses will be added around it's argument.
So don't need add parentheses again.
But we can't know how the argument printed, so only matches cases that will break for sure
*/
+3 -4
View File
@@ -57,6 +57,7 @@ import { printRestElement, printSpreadElement } from "./rest-element.js";
import {
printReturnStatement,
printThrowStatement,
printYieldExpression,
} from "./return-statement.js";
import { printSequenceExpression } from "./sequence-expression.js";
import { printSwitchCase, printSwitchStatement } from "./switch-statement.js";
@@ -156,10 +157,8 @@ function printEstree(path, options, print, args) {
case "ArrowFunctionExpression":
return printArrowFunction(path, options, print, args);
case "YieldExpression":
return [
`yield${node.delegate ? "*" : ""}`,
node.argument ? [" ", print("argument")] : "",
];
return printYieldExpression(path, options, print);
case "AwaitExpression":
return printAwaitExpression(path, options, print);
+13 -8
View File
@@ -13,7 +13,7 @@ import { printSemicolon } from "./miscellaneous.js";
@import {Doc} from "../../document/index.js";
*/
function printReturnOrThrowArgument(path, options, print) {
function printArgument(path, options, print) {
const { node } = path;
const argumentDoc = print();
@@ -45,19 +45,24 @@ function printReturnOrThrowStatement(path, options, print) {
return [
node.type === "ThrowStatement" ? "throw" : "return",
node.argument
? [
" ",
path.call(
() => printReturnOrThrowArgument(path, options, print),
"argument",
),
]
? [" ", path.call(() => printArgument(path, options, print), "argument")]
: "",
printSemicolon(options),
];
}
function printYieldExpression(path, options, print) {
const { node } = path;
return [
`yield${node.delegate ? "*" : ""}`,
node.argument
? [" ", path.call(() => printArgument(path, options, print), "argument")]
: "",
];
}
export {
printReturnOrThrowStatement as printReturnStatement,
printReturnOrThrowStatement as printThrowStatement,
printYieldExpression,
};
@@ -21,6 +21,91 @@ function* f() {
================================================================================
`;
exports[`comment.js format 1`] = `
====================================options=====================================
parsers: ["babel", "typescript"]
printWidth: 80 (default) |
=====================================input======================================
function* f() {
// Line terminators are not allowed between \`yield\` and its argument, so the
// parentheses must be kept.
yield (/*
*/ a);
foo(
yield (/*
*/ a)
);
yield (// comment
a);
yield (/*
*/ a + b);
yield (/*
*/ a, b);
yield (/* comment */
a);
// Safe, the comment is printed on one line.
yield (/* comment */ a);
// \`yield*\` is not restricted, but it is printed the same way.
yield* (/*
*/ a);
}
=====================================output=====================================
function* f() {
// Line terminators are not allowed between \`yield\` and its argument, so the
// parentheses must be kept.
yield (
/*
*/ a
);
foo(
yield (
/*
*/ a
),
);
yield (
// comment
a
);
yield (
/*
*/ a + b
);
yield (
/*
*/ a, b
);
yield (
/* comment */
a
);
// Safe, the comment is printed on one line.
yield /* comment */ a;
// \`yield*\` is not restricted, but it is printed the same way.
yield* (
/*
*/ a
);
}
================================================================================
`;
exports[`conditional.js format 1`] = `
====================================options=====================================
parsers: ["babel", "typescript"]
+30
View File
@@ -0,0 +1,30 @@
function* f() {
// Line terminators are not allowed between `yield` and its argument, so the
// parentheses must be kept.
yield (/*
*/ a);
foo(
yield (/*
*/ a)
);
yield (// comment
a);
yield (/*
*/ a + b);
yield (/*
*/ a, b);
yield (/* comment */
a);
// Safe, the comment is printed on one line.
yield (/* comment */ a);
// `yield*` is not restricted, but it is printed the same way.
yield* (/*
*/ a);
}