Fix ignored forX initializer (#20204)

This commit is contained in:
fisker Cheung authored and GitHub committed 2026-10-02 05:46:25 +08:00
1 parent 9794545df1
commit 8dafda772d
9 files changed
+146 -53

No files matched your search

+13
View File
@@ -0,0 +1,13 @@
#### Fix `prettier-ignore`d `for` initializer (#20204 by @fisker)
<!-- prettier-ignore -->
```jsx
// Input
for (/* prettier-ignore */ let i = 0; i < 1; i++) {}
// Prettier stable
for (/* prettier-ignore */ let i = 0;; i < 1; i++) {}
// Prettier main
for (/* prettier-ignore */ let i = 0; i < 1; i++) {}
```
+1 -5
View File
@@ -1,8 +1,4 @@
export { hasSameLoc, hasSameLocStart } from "./comparison.js"; export { hasSameLoc, hasSameLocStart } from "./comparison.js";
export { locEndWithFullText } from "./end-with-full-text.js"; export { locEndWithFullText } from "./end-with-full-text.js";
export { export { locEnd, shouldAddContentEnd } from "./overrides.js";
locEnd,
shouldAddContentEnd,
shouldIgnoredNodePrintSemicolon,
} from "./overrides.js";
export { locStart } from "./start.js"; export { locStart } from "./start.js";
+1 -35
View File
@@ -51,40 +51,6 @@ const overrides =
const shouldAddContentEnd = createTypeCheckFunction(nodeTypesWithContentEnd); const shouldAddContentEnd = createTypeCheckFunction(nodeTypesWithContentEnd);
const shouldIgnoredNodePrintSemicolon = (node) => {
if (shouldAddContentEnd(node) && node.__contentEnd) {
return true;
}
const { type } = node;
if (
type === "BreakStatement" ||
type === "ContinueStatement" ||
type === "DebuggerStatement" ||
type === "VariableDeclaration"
) {
return true;
}
if (type === "IfStatement") {
return shouldIgnoredNodePrintSemicolon(node.alternate ?? node.consequent);
}
if (
type === "ForInStatement" ||
type === "ForOfStatement" ||
type === "ForStatement" ||
type === "LabeledStatement" ||
type === "WithStatement" ||
type === "WhileStatement"
) {
return shouldIgnoredNodePrintSemicolon(node.body);
}
return false;
};
/** /**
@param {Node | Comment} node @param {Node | Comment} node
@return {number} @return {number}
@@ -116,4 +82,4 @@ function locEnd(node) {
); );
} }
export { locEnd, shouldAddContentEnd, shouldIgnoredNodePrintSemicolon }; export { locEnd, shouldAddContentEnd };
+3 -6
View File
@@ -1,17 +1,14 @@
import { indent, softline } from "../../document/index.js"; import { indent, softline } from "../../document/index.js";
import isNonEmptyArray from "../../utilities/is-non-empty-array.js"; import isNonEmptyArray from "../../utilities/is-non-empty-array.js";
import { import { locEnd, locStart } from "../location/index.js";
locEnd,
locStart,
shouldIgnoredNodePrintSemicolon,
} from "../location/index.js";
import { shouldExpressionStatementPrintLeadingSemicolon } from "../semicolon/semicolon.js"; import { shouldExpressionStatementPrintLeadingSemicolon } from "../semicolon/semicolon.js";
import { shouldIgnoredNodePrintSemicolon } from "../semicolon/should-ignored-node-print-semicolon.js";
function printIgnored(path, options /* , print*/) { function printIgnored(path, options /* , print*/) {
const { node } = path; const { node } = path;
let text = options.originalText.slice(locStart(node), locEnd(node)); let text = options.originalText.slice(locStart(node), locEnd(node));
if (options.semi && shouldIgnoredNodePrintSemicolon(node)) { if (options.semi && shouldIgnoredNodePrintSemicolon(path)) {
text += ";"; text += ";";
} else if (shouldExpressionStatementPrintLeadingSemicolon(path, options)) { } else if (shouldExpressionStatementPrintLeadingSemicolon(path, options)) {
text = `;${text}`; text = `;${text}`;
@@ -1,5 +1,6 @@
import { group, hardline, indent, line } from "../../document/index.js"; import { group, hardline, indent, line } from "../../document/index.js";
import { hasComment } from "../utilities/comments.js"; import { hasComment } from "../utilities/comments.js";
import { isForXStatementInitializer } from "../utilities/is-for-x-statement-initializer.js";
import { printDeclareToken, printSemicolon } from "./miscellaneous.js"; import { printDeclareToken, printSemicolon } from "./miscellaneous.js";
function printVariableDeclaration(path, options, print) { function printVariableDeclaration(path, options, print) {
@@ -9,11 +10,7 @@ function printVariableDeclaration(path, options, print) {
// We generally want to terminate all variable declarations with a // We generally want to terminate all variable declarations with a
// semicolon, except when they in the () part of for loops. // semicolon, except when they in the () part of for loops.
const isForXStatementInitializer = const isForXInitializer = isForXStatementInitializer(path);
(path.key === "init" && path.parent.type === "ForStatement") ||
(path.key === "left" &&
(path.parent.type === "ForInStatement" ||
path.parent.type === "ForOfStatement"));
const hasValue = node.declarations.some((declarator) => declarator.init); const hasValue = node.declarations.some((declarator) => declarator.init);
@@ -34,11 +31,11 @@ function printVariableDeclaration(path, options, print) {
.slice(1) .slice(1)
.map((doc) => [ .map((doc) => [
",", ",",
hasValue && !isForXStatementInitializer ? hardline : line, hasValue && !isForXInitializer ? hardline : line,
doc, doc,
]), ]),
), ),
isForXStatementInitializer ? "" : printSemicolon(options), isForXInitializer ? "" : printSemicolon(options),
]); ]);
} }
@@ -0,0 +1,42 @@
import { shouldAddContentEnd } from "../location/index.js";
import { isForXStatementInitializer } from "../utilities/is-for-x-statement-initializer.js";
function shouldPrintSemicolon(node) {
if (shouldAddContentEnd(node) && node.__contentEnd) {
return true;
}
const { type } = node;
if (
type === "BreakStatement" ||
type === "ContinueStatement" ||
type === "DebuggerStatement" ||
type === "VariableDeclaration"
) {
return true;
}
if (type === "IfStatement") {
return shouldPrintSemicolon(node.alternate ?? node.consequent);
}
if (
type === "ForInStatement" ||
type === "ForOfStatement" ||
type === "ForStatement" ||
type === "LabeledStatement" ||
type === "WithStatement" ||
type === "WhileStatement"
) {
return shouldPrintSemicolon(node.body);
}
return false;
}
function shouldIgnoredNodePrintSemicolon(path) {
return !isForXStatementInitializer(path) && shouldPrintSemicolon(path.node);
}
export { shouldIgnoredNodePrintSemicolon };
@@ -0,0 +1,9 @@
function isForXStatementInitializer({ key, parent }) {
return (
(key === "init" && parent.type === "ForStatement") ||
(key === "left" &&
(parent.type === "ForInStatement" || parent.type === "ForOfStatement"))
);
}
export { isForXStatementInitializer };
@@ -209,6 +209,69 @@ function foo() {
================================================================================ ================================================================================
`; `;
exports[`for-x-initializer.js - {"semi":false} format 1`] = `
====================================options=====================================
parsers: ["babel", "flow", "typescript"]
semi: false
printWidth: 80 (default) |
=====================================input======================================
for (/* prettier-ignore */ let i = 0; i < 1; i++) {}
for (/* prettier-ignore */ let [a,b] in c) foo();
for (/* prettier-ignore */ const {a,b} of c) foo();
for (
// prettier-ignore
let i = 0, j = 1;
i < 1;
i++
) {}
for (/* prettier-ignore */ i = 0; i < 1; i++) {}
=====================================output=====================================
for (/* prettier-ignore */ let i = 0; i < 1; i++) {}
for (/* prettier-ignore */ let [a,b] in c) foo()
for (/* prettier-ignore */ const {a,b} of c) foo()
for (
// prettier-ignore
let i = 0, j = 1;
i < 1;
i++
) {}
for (/* prettier-ignore */ i = 0; i < 1; i++) {}
================================================================================
`;
exports[`for-x-initializer.js format 1`] = `
====================================options=====================================
parsers: ["babel", "flow", "typescript"]
printWidth: 80 (default) |
=====================================input======================================
for (/* prettier-ignore */ let i = 0; i < 1; i++) {}
for (/* prettier-ignore */ let [a,b] in c) foo();
for (/* prettier-ignore */ const {a,b} of c) foo();
for (
// prettier-ignore
let i = 0, j = 1;
i < 1;
i++
) {}
for (/* prettier-ignore */ i = 0; i < 1; i++) {}
=====================================output=====================================
for (/* prettier-ignore */ let i = 0; i < 1; i++) {}
for (/* prettier-ignore */ let [a,b] in c) foo();
for (/* prettier-ignore */ const {a,b} of c) foo();
for (
// prettier-ignore
let i = 0, j = 1;
i < 1;
i++
) {}
for (/* prettier-ignore */ i = 0; i < 1; i++) {}
================================================================================
`;
exports[`head-ignored.js - {"semi":false} format 1`] = ` exports[`head-ignored.js - {"semi":false} format 1`] = `
====================================options===================================== ====================================options=====================================
parsers: ["babel", "flow", "typescript"] parsers: ["babel", "flow", "typescript"]
@@ -0,0 +1,10 @@
for (/* prettier-ignore */ let i = 0; i < 1; i++) {}
for (/* prettier-ignore */ let [a,b] in c) foo();
for (/* prettier-ignore */ const {a,b} of c) foo();
for (
// prettier-ignore
let i = 0, j = 1;
i < 1;
i++
) {}
for (/* prettier-ignore */ i = 0; i < 1; i++) {}