Refactor simple member expressions etc (#15423)
This commit is contained in:
1 parent
86d0d146e6
commit
77310c49ea
4 files changed
+154
-111
No files matched your search
@@ -16,15 +16,12 @@ import {
|
||||
isCallExpression,
|
||||
isMemberExpression,
|
||||
getCallArguments,
|
||||
rawText,
|
||||
hasComment,
|
||||
isSignedNumericLiteral,
|
||||
isLoneShortArgument,
|
||||
isObjectProperty,
|
||||
createTypeCheckFunction,
|
||||
} from "../utils/index.js";
|
||||
import { shouldInlineLogicalExpression } from "./binaryish.js";
|
||||
import { printCallExpression } from "./call-expression.js";
|
||||
import { isLiteral } from "./literal.js";
|
||||
|
||||
function printAssignment(
|
||||
path,
|
||||
@@ -369,46 +366,6 @@ function isPoorlyBreakableMemberOrCallChain(
|
||||
return deep && (node.type === "Identifier" || node.type === "ThisExpression");
|
||||
}
|
||||
|
||||
const LONE_SHORT_ARGUMENT_THRESHOLD_RATE = 0.25;
|
||||
|
||||
function isLoneShortArgument(node, { printWidth }) {
|
||||
if (hasComment(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const threshold = printWidth * LONE_SHORT_ARGUMENT_THRESHOLD_RATE;
|
||||
|
||||
if (
|
||||
node.type === "ThisExpression" ||
|
||||
(node.type === "Identifier" && node.name.length <= threshold) ||
|
||||
(isSignedNumericLiteral(node) && !hasComment(node.argument))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const regexpPattern =
|
||||
(node.type === "Literal" && "regex" in node && node.regex.pattern) ||
|
||||
(node.type === "RegExpLiteral" && node.pattern);
|
||||
|
||||
if (regexpPattern) {
|
||||
return regexpPattern.length <= threshold;
|
||||
}
|
||||
|
||||
if (isStringLiteral(node)) {
|
||||
return rawText(node).length <= threshold;
|
||||
}
|
||||
|
||||
if (node.type === "TemplateLiteral") {
|
||||
return (
|
||||
node.expressions.length === 0 &&
|
||||
node.quasis[0].value.raw.length <= threshold &&
|
||||
!node.quasis[0].value.raw.includes("\n")
|
||||
);
|
||||
}
|
||||
|
||||
return isLiteral(node);
|
||||
}
|
||||
|
||||
function isObjectPropertyWithShortKey(node, keyDoc, options) {
|
||||
if (!isObjectProperty(node)) {
|
||||
return false;
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
isCallExpression,
|
||||
isMemberExpression,
|
||||
isArrayOrTupleExpression,
|
||||
isLiteral,
|
||||
isObjectOrRecordExpression,
|
||||
startsWithNoLookaheadToken,
|
||||
} from "../utils/index.js";
|
||||
@@ -67,7 +68,7 @@ import { printBinaryishExpression } from "./binaryish.js";
|
||||
import { printStatementSequence } from "./statement.js";
|
||||
import { printMemberExpression } from "./member.js";
|
||||
import { printBlock, printBlockBody } from "./block.js";
|
||||
import { printLiteral, isLiteral } from "./literal.js";
|
||||
import { printLiteral } from "./literal.js";
|
||||
import { printTypeAnnotationProperty } from "./type-annotation.js";
|
||||
import { printExpressionStatement } from "./expression-statement.js";
|
||||
import { printHtmlBinding } from "./html-binding.js";
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import printString from "../../utils/print-string.js";
|
||||
import printNumber from "../../utils/print-number.js";
|
||||
import { replaceEndOfLine } from "../../document/utils.js";
|
||||
import { createTypeCheckFunction } from "../utils/index.js";
|
||||
|
||||
/**
|
||||
* @typedef {import("../types/estree.js").Node} Node
|
||||
@@ -92,21 +91,4 @@ function printDirective(rawText, options) {
|
||||
return enclosingQuote + rawContent + enclosingQuote;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node
|
||||
* @returns {boolean}
|
||||
*/
|
||||
const isLiteral = createTypeCheckFunction([
|
||||
"Literal",
|
||||
// Babel, flow uses `BigIntLiteral` too
|
||||
"BigIntLiteral",
|
||||
"BooleanLiteral",
|
||||
"DecimalLiteral",
|
||||
"DirectiveLiteral",
|
||||
"NullLiteral",
|
||||
"NumericLiteral",
|
||||
"RegExpLiteral",
|
||||
"StringLiteral",
|
||||
]);
|
||||
|
||||
export { printLiteral, printBigInt, isLiteral };
|
||||
export { printLiteral, printBigInt };
|
||||
+150
-47
@@ -189,6 +189,35 @@ function isRegExpLiteral(node) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node
|
||||
* @returns {boolean}
|
||||
*/
|
||||
const isLiteral = createTypeCheckFunction([
|
||||
"Literal",
|
||||
"BooleanLiteral",
|
||||
"BigIntLiteral", // Babel, flow use `BigIntLiteral` too
|
||||
"DecimalLiteral",
|
||||
"DirectiveLiteral",
|
||||
"NullLiteral",
|
||||
"NumericLiteral",
|
||||
"RegExpLiteral",
|
||||
"StringLiteral",
|
||||
]);
|
||||
|
||||
/**
|
||||
* @param {Node} node
|
||||
* @returns {boolean}
|
||||
*/
|
||||
const isSingleWordType = createTypeCheckFunction([
|
||||
"Identifier",
|
||||
"ThisExpression",
|
||||
"Super",
|
||||
"PrivateName",
|
||||
"PrivateIdentifier",
|
||||
"Import",
|
||||
]);
|
||||
|
||||
/**
|
||||
* @param {Node} node
|
||||
* @returns {boolean}
|
||||
@@ -442,47 +471,127 @@ function isSimpleTemplateLiteral(node) {
|
||||
}
|
||||
|
||||
return expressions.every((expr) => {
|
||||
// Disallow comments since printDocToString can't print them here
|
||||
if (hasComment(expr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allow `x` and `this`
|
||||
if (expr.type === "Identifier" || expr.type === "ThisExpression") {
|
||||
if (isSimpleAtomicExpression(expr) || isSimpleMemberExpression(expr)) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (expr.type === "ChainExpression") {
|
||||
expr = expr.expression;
|
||||
}
|
||||
|
||||
// Allow `a.b.c`, `a.b[c]`, and `this.x.y`
|
||||
if (isMemberExpression(expr)) {
|
||||
let head = expr;
|
||||
while (isMemberExpression(head)) {
|
||||
if (
|
||||
head.property.type !== "Identifier" &&
|
||||
head.property.type !== "Literal" &&
|
||||
head.property.type !== "StringLiteral" &&
|
||||
head.property.type !== "NumericLiteral"
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
head = head.object;
|
||||
if (hasComment(head)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (head.type === "Identifier" || head.type === "ThisExpression") {
|
||||
return true;
|
||||
}
|
||||
function isSimpleMemberExpression(
|
||||
node,
|
||||
{ maxDepth = Number.POSITIVE_INFINITY } = {},
|
||||
) {
|
||||
if (hasComment(node)) {
|
||||
return false;
|
||||
}
|
||||
if (node.type === "ChainExpression") {
|
||||
return isSimpleMemberExpression(node.expression, { maxDepth });
|
||||
}
|
||||
if (!isMemberExpression(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let head = node;
|
||||
let depth = 0;
|
||||
while (isMemberExpression(head) && depth++ <= maxDepth) {
|
||||
if (!isSimpleAtomicExpression(head.property)) {
|
||||
return false;
|
||||
}
|
||||
head = head.object;
|
||||
if (hasComment(head)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return isSimpleAtomicExpression(head);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is intended to return true for small expressions
|
||||
* which cannot be broken.
|
||||
*/
|
||||
function isSimpleAtomicExpression(node) {
|
||||
if (hasComment(node)) {
|
||||
return false;
|
||||
});
|
||||
}
|
||||
return isLiteral(node) || isSingleWordType(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to gauge the rough complexity of a node, for example
|
||||
* to detect deeply-nested booleans, call expressions with lots of arguments, etc.
|
||||
*/
|
||||
function isSimpleExpressionByNodeCount(node, maxInnerNodeCount = 5) {
|
||||
const count = getExpressionInnerNodeCount(node, maxInnerNodeCount);
|
||||
return count <= maxInnerNodeCount;
|
||||
}
|
||||
|
||||
function getExpressionInnerNodeCount(node, maxCount) {
|
||||
let count = 0;
|
||||
for (const k in node) {
|
||||
const prop = node[k];
|
||||
|
||||
if (prop && typeof prop === "object" && typeof prop.type === "string") {
|
||||
count++;
|
||||
count += getExpressionInnerNodeCount(prop, maxCount - count);
|
||||
}
|
||||
|
||||
// Bail early to protect against bad performance.
|
||||
if (count > maxCount) {
|
||||
return count;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
const LONE_SHORT_ARGUMENT_THRESHOLD_RATE = 0.25;
|
||||
function isLoneShortArgument(node, { printWidth }) {
|
||||
if (hasComment(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const threshold = printWidth * LONE_SHORT_ARGUMENT_THRESHOLD_RATE;
|
||||
|
||||
if (
|
||||
node.type === "ThisExpression" ||
|
||||
(node.type === "Identifier" && node.name.length <= threshold) ||
|
||||
(isSignedNumericLiteral(node) && !hasComment(node.argument))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const regexpPattern =
|
||||
(node.type === "Literal" && "regex" in node && node.regex.pattern) ||
|
||||
(node.type === "RegExpLiteral" && node.pattern);
|
||||
|
||||
if (regexpPattern) {
|
||||
return regexpPattern.length <= threshold;
|
||||
}
|
||||
|
||||
if (isStringLiteral(node)) {
|
||||
return rawText(node).length <= threshold;
|
||||
}
|
||||
|
||||
if (node.type === "TemplateLiteral") {
|
||||
return (
|
||||
node.expressions.length === 0 &&
|
||||
node.quasis[0].value.raw.length <= threshold &&
|
||||
!node.quasis[0].value.raw.includes("\n")
|
||||
);
|
||||
}
|
||||
|
||||
if (node.type === "UnaryExpression") {
|
||||
return isLoneShortArgument(node.argument, { printWidth });
|
||||
}
|
||||
|
||||
if (
|
||||
node.type === "CallExpression" &&
|
||||
node.arguments.length === 0 &&
|
||||
node.callee.type === "Identifier"
|
||||
) {
|
||||
return node.callee.name.length <= threshold - 2;
|
||||
}
|
||||
|
||||
return isLiteral(node);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -654,20 +763,9 @@ function isSimpleCallArgument(node, depth = 2) {
|
||||
}
|
||||
|
||||
if (
|
||||
node.type === "Literal" ||
|
||||
node.type === "BigIntLiteral" ||
|
||||
node.type === "DecimalLiteral" ||
|
||||
node.type === "BooleanLiteral" ||
|
||||
node.type === "NullLiteral" ||
|
||||
node.type === "NumericLiteral" ||
|
||||
node.type === "StringLiteral" ||
|
||||
node.type === "Identifier" ||
|
||||
node.type === "ThisExpression" ||
|
||||
node.type === "Super" ||
|
||||
node.type === "PrivateName" ||
|
||||
node.type === "PrivateIdentifier" ||
|
||||
node.type === "ArgumentPlaceholder" ||
|
||||
node.type === "Import"
|
||||
isLiteral(node) ||
|
||||
isSingleWordType(node) ||
|
||||
node.type === "ArgumentPlaceholder"
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
@@ -1151,8 +1249,13 @@ export {
|
||||
isRegExpLiteral,
|
||||
isSimpleType,
|
||||
isSimpleNumber,
|
||||
isSimpleAtomicExpression,
|
||||
isSimpleMemberExpression,
|
||||
isSimpleTemplateLiteral,
|
||||
isSimpleExpressionByNodeCount,
|
||||
isLoneShortArgument,
|
||||
isStringLiteral,
|
||||
isLiteral,
|
||||
isStringPropSafeToUnquote,
|
||||
isTemplateOnItsOwnLine,
|
||||
isTestCall,
|
||||
|
||||
Reference in new issue
Block a user