Refactor leading semicolon print (#14313)
This commit is contained in:
1 parent
222d84f9ed
commit
de00f5bec0
3 files changed
+100
-96
No files matched your search
@@ -0,0 +1,89 @@
|
||||
import pathNeedsParens from "../needs-parens.js";
|
||||
import {
|
||||
getLeftSidePathName,
|
||||
hasNakedLeftSide,
|
||||
isJsxElement,
|
||||
isTheOnlyJsxElementInMarkdown,
|
||||
} from "../utils/index.js";
|
||||
import { shouldPrintParamsWithoutParens } from "./function.js";
|
||||
|
||||
function shouldPrintLeadingSemicolon(path, options) {
|
||||
if (options.semi || isTheOnlyJsxElementInMarkdown(options, path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { node, key, parent } = path;
|
||||
if (
|
||||
node.type === "ExpressionStatement" &&
|
||||
// `Program.directives` don't need leading semicolon
|
||||
((key === "body" &&
|
||||
(parent.type === "Program" ||
|
||||
parent.type === "BlockStatement" ||
|
||||
parent.type === "StaticBlock" ||
|
||||
parent.type === "TSModuleBlock")) ||
|
||||
(key === "consequent" && parent.type === "SwitchCase")) &&
|
||||
path.call(() => expressionNeedsASIProtection(path, options), "expression")
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function expressionNeedsASIProtection(path, options) {
|
||||
const { node } = path;
|
||||
switch (node.type) {
|
||||
case "ParenthesizedExpression":
|
||||
case "TypeCastExpression":
|
||||
case "ArrayExpression":
|
||||
case "ArrayPattern":
|
||||
case "TemplateLiteral":
|
||||
case "TemplateElement":
|
||||
case "RegExpLiteral":
|
||||
return true;
|
||||
case "ArrowFunctionExpression":
|
||||
if (!shouldPrintParamsWithoutParens(path, options)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case "UnaryExpression": {
|
||||
const { prefix, operator } = node;
|
||||
if (prefix && (operator === "+" || operator === "-")) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "BindExpression":
|
||||
if (!node.object) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case "Literal":
|
||||
if (node.regex) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isJsxElement(node)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (pathNeedsParens(path, options)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!hasNakedLeftSide(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return path.call(
|
||||
() => expressionNeedsASIProtection(path, options),
|
||||
...getLeftSidePathName(node)
|
||||
);
|
||||
}
|
||||
|
||||
export { shouldPrintLeadingSemicolon };
|
||||
@@ -1,21 +1,18 @@
|
||||
import { hardline } from "../../document/builders.js";
|
||||
import pathNeedsParens from "../needs-parens.js";
|
||||
import {
|
||||
getLeftSidePathName,
|
||||
hasNakedLeftSide,
|
||||
isJsxElement,
|
||||
isTheOnlyJsxElementInMarkdown,
|
||||
hasComment,
|
||||
CommentCheckFlags,
|
||||
isNextLineEmpty,
|
||||
} from "../utils/index.js";
|
||||
import { shouldPrintParamsWithoutParens } from "./function.js";
|
||||
import { isNextLineEmpty } from "../utils/index.js";
|
||||
|
||||
/**
|
||||
* @typedef {import("../../document/builders.js").Doc} Doc
|
||||
* @typedef {import("../../common/ast-path.js")} AstPath
|
||||
*/
|
||||
|
||||
/*
|
||||
- `Program` ("directives" and "body")
|
||||
- `BlockStatement`
|
||||
- `StaticBlock`
|
||||
- `SwitchCase` ("consequent")
|
||||
- `TSModuleBlock` (TypeScript)
|
||||
*/
|
||||
function printStatementSequence(path, options, print, property) {
|
||||
const { node } = path;
|
||||
const parts = [];
|
||||
@@ -28,21 +25,7 @@ function printStatementSequence(path, options, print, property) {
|
||||
return;
|
||||
}
|
||||
|
||||
const needsSemi =
|
||||
!options.semi &&
|
||||
!isTheOnlyJsxElementInMarkdown(options, path) &&
|
||||
statementNeedsASIProtection(path, options);
|
||||
|
||||
// in no-semi mode, prepend statement with semicolon if it might break ASI
|
||||
// don't prepend the only JSX element in a program with semicolon
|
||||
if (needsSemi && hasComment(node, CommentCheckFlags.Leading)) {
|
||||
parts.push(print([], { needsSemi: true }));
|
||||
} else {
|
||||
if (needsSemi) {
|
||||
parts.push(";");
|
||||
}
|
||||
parts.push(print());
|
||||
}
|
||||
parts.push(print());
|
||||
|
||||
if (node !== lastStatement) {
|
||||
parts.push(hardline);
|
||||
@@ -65,73 +48,4 @@ function getLastStatement(statements) {
|
||||
}
|
||||
}
|
||||
|
||||
function statementNeedsASIProtection(path, options) {
|
||||
const { node } = path;
|
||||
|
||||
if (node.type !== "ExpressionStatement") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return path.call(
|
||||
(childPath) => expressionNeedsASIProtection(childPath, options),
|
||||
"expression"
|
||||
);
|
||||
}
|
||||
|
||||
function expressionNeedsASIProtection(path, options) {
|
||||
const { node } = path;
|
||||
switch (node.type) {
|
||||
case "ParenthesizedExpression":
|
||||
case "TypeCastExpression":
|
||||
case "ArrayExpression":
|
||||
case "ArrayPattern":
|
||||
case "TemplateLiteral":
|
||||
case "TemplateElement":
|
||||
case "RegExpLiteral":
|
||||
return true;
|
||||
case "ArrowFunctionExpression":
|
||||
if (!shouldPrintParamsWithoutParens(path, options)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case "UnaryExpression": {
|
||||
const { prefix, operator } = node;
|
||||
if (prefix && (operator === "+" || operator === "-")) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "BindExpression":
|
||||
if (!node.object) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case "Literal":
|
||||
if (node.regex) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isJsxElement(node)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (pathNeedsParens(path, options)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!hasNakedLeftSide(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return path.call(
|
||||
() => expressionNeedsASIProtection(path, options),
|
||||
...getLeftSidePathName(node)
|
||||
);
|
||||
}
|
||||
|
||||
export { printStatementSequence };
|
||||
@@ -88,6 +88,7 @@ import { printBlock, printBlockBody } from "./print/block.js";
|
||||
import { printLiteral } from "./print/literal.js";
|
||||
import { printDecorators } from "./print/decorators.js";
|
||||
import { printTypeAnnotationProperty } from "./print/type-annotation.js";
|
||||
import { shouldPrintLeadingSemicolon } from "./print/semicolon.js";
|
||||
|
||||
/**
|
||||
* @typedef {import("../common/ast-path.js").default} AstPath
|
||||
@@ -143,7 +144,7 @@ function genericPrint(path, options, print, args) {
|
||||
}
|
||||
|
||||
const needsParens = pathNeedsParens(path, options);
|
||||
const needsSemi = args?.needsSemi;
|
||||
const needsSemi = shouldPrintLeadingSemicolon(path, options);
|
||||
|
||||
if (!needsParens) {
|
||||
if (needsSemi) {
|
||||
|
||||
Reference in new issue
Block a user