Refactor ConditionalExpression and TSConditionalType print (#9753)
This commit is contained in:
1 parent
895a177b0d
commit
3337fc1509
2 files changed
+77
-91
No files matched your search
@@ -23,15 +23,6 @@ const {
|
||||
* @typedef {import("../../common/fast-path")} FastPath
|
||||
*
|
||||
* @typedef {any} Options - Prettier options (TBD ...)
|
||||
*
|
||||
* @typedef {Object} OperatorOptions
|
||||
* @property {() => Array<string | Doc>} beforeParts - Parts to print before the `?`.
|
||||
* @property {(breakClosingParen: boolean) => Array<string | Doc>} afterParts - Parts to print after the conditional expression.
|
||||
* @property {boolean} shouldCheckJsx - Whether to check for and print in JSX mode.
|
||||
* @property {string} conditionalNodeType - The type of the conditional expression node, ie "ConditionalExpression" or "TSConditionalType".
|
||||
* @property {string} consequentNodePropertyName - The property at which the consequent node can be found on the main node, eg "consequent".
|
||||
* @property {string} alternateNodePropertyName - The property at which the alternate node can be found on the main node, eg "alternate".
|
||||
* @property {string[]} testNodePropertyNames - The properties at which the test nodes can be found on the main node, eg "test".
|
||||
*/
|
||||
|
||||
// If we have nested conditional expressions, we want to print them in JSX mode
|
||||
@@ -129,6 +120,40 @@ function conditionalExpressionChainContainsJSX(node) {
|
||||
return getConditionalChainContents(node).some(isJSXNode);
|
||||
}
|
||||
|
||||
function printTernaryTest(path, options, print) {
|
||||
const node = path.getValue();
|
||||
const isConditionalExpression = node.type === "ConditionalExpression";
|
||||
const alternateNodePropertyName = isConditionalExpression
|
||||
? "alternate"
|
||||
: "falseType";
|
||||
|
||||
const parent = path.getParentNode();
|
||||
|
||||
const printed = isConditionalExpression
|
||||
? path.call(print, "test")
|
||||
: concat([
|
||||
path.call(print, "checkType"),
|
||||
" ",
|
||||
"extends",
|
||||
" ",
|
||||
path.call(print, "extendsType"),
|
||||
]);
|
||||
/**
|
||||
* a
|
||||
* ? b
|
||||
* : multiline
|
||||
* test
|
||||
* node
|
||||
* ^^ align(2)
|
||||
* ? d
|
||||
* : e
|
||||
*/
|
||||
if (parent.type === node.type && parent[alternateNodePropertyName] === node) {
|
||||
return align(2, printed);
|
||||
}
|
||||
return printed;
|
||||
}
|
||||
|
||||
/**
|
||||
* The following is the shared logic for
|
||||
* ternary operators, namely ConditionalExpression
|
||||
@@ -136,13 +161,22 @@ function conditionalExpressionChainContainsJSX(node) {
|
||||
* @param {FastPath} path - The path to the ConditionalExpression/TSConditionalType node.
|
||||
* @param {Options} options - Prettier options
|
||||
* @param {Function} print - Print function to call recursively
|
||||
* @param {OperatorOptions} operatorOptions
|
||||
* @returns {Doc}
|
||||
*/
|
||||
function printTernaryOperator(path, options, print, operatorOptions) {
|
||||
function printTernary(path, options, print) {
|
||||
const node = path.getValue();
|
||||
const consequentNode = node[operatorOptions.consequentNodePropertyName];
|
||||
const alternateNode = node[operatorOptions.alternateNodePropertyName];
|
||||
const isConditionalExpression = node.type === "ConditionalExpression";
|
||||
const consequentNodePropertyName = isConditionalExpression
|
||||
? "consequent"
|
||||
: "trueType";
|
||||
const alternateNodePropertyName = isConditionalExpression
|
||||
? "alternate"
|
||||
: "falseType";
|
||||
const testNodePropertyNames = isConditionalExpression
|
||||
? ["test"]
|
||||
: ["checkType", "extendsType"];
|
||||
const consequentNode = node[consequentNodePropertyName];
|
||||
const alternateNode = node[alternateNodePropertyName];
|
||||
const parts = [];
|
||||
|
||||
// We print a ConditionalExpression in either "JSX mode" or "normal mode".
|
||||
@@ -150,10 +184,9 @@ function printTernaryOperator(path, options, print, operatorOptions) {
|
||||
let jsxMode = false;
|
||||
const parent = path.getParentNode();
|
||||
const isParentTest =
|
||||
parent.type === operatorOptions.conditionalNodeType &&
|
||||
operatorOptions.testNodePropertyNames.some((prop) => parent[prop] === node);
|
||||
let forceNoIndent =
|
||||
parent.type === operatorOptions.conditionalNodeType && !isParentTest;
|
||||
parent.type === node.type &&
|
||||
testNodePropertyNames.some((prop) => parent[prop] === node);
|
||||
let forceNoIndent = parent.type === node.type && !isParentTest;
|
||||
|
||||
// Find the outermost non-ConditionalExpression parent, and the outermost
|
||||
// ConditionalExpression parent. We'll use these to determine if we should
|
||||
@@ -167,8 +200,8 @@ function printTernaryOperator(path, options, print, operatorOptions) {
|
||||
i++;
|
||||
} while (
|
||||
currentParent &&
|
||||
currentParent.type === operatorOptions.conditionalNodeType &&
|
||||
operatorOptions.testNodePropertyNames.every(
|
||||
currentParent.type === node.type &&
|
||||
testNodePropertyNames.every(
|
||||
(prop) => currentParent[prop] !== previousParent
|
||||
)
|
||||
);
|
||||
@@ -176,8 +209,8 @@ function printTernaryOperator(path, options, print, operatorOptions) {
|
||||
const lastConditionalParent = previousParent;
|
||||
|
||||
if (
|
||||
operatorOptions.shouldCheckJsx &&
|
||||
(isJSXNode(node[operatorOptions.testNodePropertyNames[0]]) ||
|
||||
isConditionalExpression &&
|
||||
(isJSXNode(node[testNodePropertyNames[0]]) ||
|
||||
isJSXNode(consequentNode) ||
|
||||
isJSXNode(alternateNode) ||
|
||||
conditionalExpressionChainContainsJSX(lastConditionalParent))
|
||||
@@ -208,35 +241,30 @@ function printTernaryOperator(path, options, print, operatorOptions) {
|
||||
parts.push(
|
||||
" ? ",
|
||||
isNil(consequentNode)
|
||||
? path.call(print, operatorOptions.consequentNodePropertyName)
|
||||
: wrap(path.call(print, operatorOptions.consequentNodePropertyName)),
|
||||
? path.call(print, consequentNodePropertyName)
|
||||
: wrap(path.call(print, consequentNodePropertyName)),
|
||||
" : ",
|
||||
alternateNode.type === operatorOptions.conditionalNodeType ||
|
||||
isNil(alternateNode)
|
||||
? path.call(print, operatorOptions.alternateNodePropertyName)
|
||||
: wrap(path.call(print, operatorOptions.alternateNodePropertyName))
|
||||
alternateNode.type === node.type || isNil(alternateNode)
|
||||
? path.call(print, alternateNodePropertyName)
|
||||
: wrap(path.call(print, alternateNodePropertyName))
|
||||
);
|
||||
} else {
|
||||
// normal mode
|
||||
const part = concat([
|
||||
line,
|
||||
"? ",
|
||||
consequentNode.type === operatorOptions.conditionalNodeType
|
||||
? ifBreak("", "(")
|
||||
: "",
|
||||
align(2, path.call(print, operatorOptions.consequentNodePropertyName)),
|
||||
consequentNode.type === operatorOptions.conditionalNodeType
|
||||
? ifBreak("", ")")
|
||||
: "",
|
||||
consequentNode.type === node.type ? ifBreak("", "(") : "",
|
||||
align(2, path.call(print, consequentNodePropertyName)),
|
||||
consequentNode.type === node.type ? ifBreak("", ")") : "",
|
||||
line,
|
||||
": ",
|
||||
alternateNode.type === operatorOptions.conditionalNodeType
|
||||
? path.call(print, operatorOptions.alternateNodePropertyName)
|
||||
: align(2, path.call(print, operatorOptions.alternateNodePropertyName)),
|
||||
alternateNode.type === node.type
|
||||
? path.call(print, alternateNodePropertyName)
|
||||
: align(2, path.call(print, alternateNodePropertyName)),
|
||||
]);
|
||||
parts.push(
|
||||
parent.type !== operatorOptions.conditionalNodeType ||
|
||||
parent[operatorOptions.alternateNodePropertyName] === node ||
|
||||
parent.type !== node.type ||
|
||||
parent[alternateNodePropertyName] === node ||
|
||||
isParentTest
|
||||
? part
|
||||
: options.useTabs
|
||||
@@ -249,9 +277,7 @@ function printTernaryOperator(path, options, print, operatorOptions) {
|
||||
// break if any of them break. That means we should only group around the
|
||||
// outer-most ConditionalExpression.
|
||||
const comments = flat([
|
||||
...operatorOptions.testNodePropertyNames.map(
|
||||
(propertyName) => node[propertyName].comments
|
||||
),
|
||||
...testNodePropertyNames.map((propertyName) => node[propertyName].comments),
|
||||
consequentNode.comments,
|
||||
alternateNode.comments,
|
||||
]).filter(Boolean);
|
||||
@@ -284,27 +310,11 @@ function printTernaryOperator(path, options, print, operatorOptions) {
|
||||
!parent.computed;
|
||||
|
||||
const result = maybeGroup(
|
||||
concat(
|
||||
[].concat(
|
||||
((testDoc) =>
|
||||
/**
|
||||
* a
|
||||
* ? b
|
||||
* : multiline
|
||||
* test
|
||||
* node
|
||||
* ^^ align(2)
|
||||
* ? d
|
||||
* : e
|
||||
*/
|
||||
parent.type === operatorOptions.conditionalNodeType &&
|
||||
parent[operatorOptions.alternateNodePropertyName] === node
|
||||
? align(2, testDoc)
|
||||
: testDoc)(concat(operatorOptions.beforeParts())),
|
||||
forceNoIndent ? concat(parts) : indent(concat(parts)),
|
||||
operatorOptions.afterParts(breakClosingParen)
|
||||
)
|
||||
)
|
||||
concat([
|
||||
printTernaryTest(path, options, print),
|
||||
forceNoIndent ? concat(parts) : indent(concat(parts)),
|
||||
isConditionalExpression && breakClosingParen ? softline : "",
|
||||
])
|
||||
);
|
||||
|
||||
return isParentTest
|
||||
@@ -312,4 +322,4 @@ function printTernaryOperator(path, options, print, operatorOptions) {
|
||||
: result;
|
||||
}
|
||||
|
||||
module.exports = printTernaryOperator;
|
||||
module.exports = { printTernary };
|
||||
@@ -81,7 +81,7 @@ const {
|
||||
printExportAllDeclaration,
|
||||
printModuleSpecifier,
|
||||
} = require("./print/module");
|
||||
const printTernaryOperator = require("./print/ternary");
|
||||
const { printTernary } = require("./print/ternary");
|
||||
const { printFunctionParameters } = require("./print/function-parameters");
|
||||
const { printTemplateLiteral } = require("./print/template-literal");
|
||||
const { printArray, printArrayItems } = require("./print/array");
|
||||
@@ -646,15 +646,8 @@ function printPathNoParens(path, options, print, args) {
|
||||
|
||||
return concat(parts);
|
||||
case "ConditionalExpression":
|
||||
return printTernaryOperator(path, options, print, {
|
||||
beforeParts: () => [path.call(print, "test")],
|
||||
afterParts: (breakClosingParen) => [breakClosingParen ? softline : ""],
|
||||
shouldCheckJsx: true,
|
||||
conditionalNodeType: "ConditionalExpression",
|
||||
consequentNodePropertyName: "consequent",
|
||||
alternateNodePropertyName: "alternate",
|
||||
testNodePropertyNames: ["test"],
|
||||
});
|
||||
case "TSConditionalType":
|
||||
return printTernary(path, options, print);
|
||||
case "VariableDeclaration": {
|
||||
const printed = path.map((childPath) => {
|
||||
return print(childPath);
|
||||
@@ -2038,23 +2031,6 @@ function printPathNoParens(path, options, print, args) {
|
||||
case "TSPrivateIdentifier":
|
||||
return n.escapedText;
|
||||
|
||||
case "TSConditionalType":
|
||||
return printTernaryOperator(path, options, print, {
|
||||
beforeParts: () => [
|
||||
path.call(print, "checkType"),
|
||||
" ",
|
||||
"extends",
|
||||
" ",
|
||||
path.call(print, "extendsType"),
|
||||
],
|
||||
afterParts: () => [],
|
||||
shouldCheckJsx: false,
|
||||
conditionalNodeType: "TSConditionalType",
|
||||
consequentNodePropertyName: "trueType",
|
||||
alternateNodePropertyName: "falseType",
|
||||
testNodePropertyNames: ["checkType", "extendsType"],
|
||||
});
|
||||
|
||||
case "TSInferType":
|
||||
return concat(["infer", " ", path.call(print, "typeParameter")]);
|
||||
|
||||
|
||||
Reference in new issue
Block a user