Extract js utilities (#18772)

This commit is contained in:
fisker Cheung authored and GitHub committed 2026-01-28 12:36:39 +08:00
1 parent 16eb5096b6
commit 0fb018ccd5
94 files changed
+1304 -1102

No files matched your search

@@ -1,12 +1,10 @@
import isNonEmptyArray from "../../utilities/is-non-empty-array.js";
import { createTypeCheckFunction } from "../utilities/create-type-check-function.js";
import { getFunctionParameters } from "../utilities/function-parameters.js";
import { isTsAsConstExpression } from "../utilities/is-as-const-expression.js";
import { isMeaningfulEmptyStatement } from "../utilities/is-meaningful-empty-statement.js";
import {
getFunctionParameters,
isMethod,
isShorthandSpecifier,
isTsAsConstExpression,
} from "../utilities/utilities.js";
import { isMethod } from "../utilities/is-method.js";
import { isShorthandSpecifier } from "../utilities/is-shorthand-specifier.js";
/**
@import {Node} from "../types/estree.js";
+7 -9
View File
@@ -9,13 +9,17 @@ import hasNewline from "../../utilities/has-newline.js";
import hasNewlineInRange from "../../utilities/has-newline-in-range.js";
import isNonEmptyArray from "../../utilities/is-non-empty-array.js";
import { locEnd, locStart } from "../loc.js";
import { getCallArguments } from "../utilities/call-arguments.js";
import { isInsideCallOrNewExpressionParentheses } from "../utilities/call-or-new-expression-parentheses.js";
import { createTypeCheckFunction } from "../utilities/create-type-check-function.js";
import { getFunctionParameters } from "../utilities/function-parameters.js";
import getTextWithoutComments from "../utilities/get-text-without-comments.js";
import isBlockComment from "../utilities/is-block-comment.js";
import isLineComment from "../utilities/is-line-comment.js";
import { isBlockComment } from "../utilities/is-block-comment.js";
import { isLineComment } from "../utilities/is-line-comment.js";
import { isMethod } from "../utilities/is-method.js";
import { isObjectProperty } from "../utilities/is-object-property.js";
import { isPrettierIgnoreComment } from "../utilities/is-prettier-ignore-comment.js";
import isTypeCastComment from "../utilities/is-type-cast-comment.js";
import { isTypeCastComment } from "../utilities/is-type-cast-comment.js";
import {
isBinaryCastExpression,
isCallLikeExpression,
@@ -25,12 +29,6 @@ import {
isMemberExpression,
isUnionType,
} from "../utilities/node-types.js";
import {
getCallArguments,
getFunctionParameters,
isMethod,
isObjectProperty,
} from "../utilities/utilities.js";
/**
@import {Node, Comment, NodeMap} from "../types/estree.js";
@@ -1,11 +1,9 @@
import { createTypeCheckFunction } from "../utilities/create-type-check-function.js";
import { hasNodeIgnoreComment } from "../utilities/has-node-ignore-comment.js";
import { isIifeCalleeOrTaggedTemplateExpressionTag } from "../utilities/is-iife-callee-or-tagged-template-expression-tag.js";
import { isJsxElement, isUnionType } from "../utilities/node-types.js";
import { shouldExpressionStatementPrintOwnComments } from "../utilities/should-expression-statement-print-own-comments.js";
import {
isIifeCalleeOrTaggedTemplateExpressionTag,
shouldUnionTypePrintOwnComments,
} from "../utilities/utilities.js";
import { shouldUnionTypePrintOwnComments } from "../utilities/should-union-type-print-own-comments.js";
/**
@import {Node} from "../types/estree.js";
+1 -1
View File
@@ -1,6 +1,6 @@
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import { isObjectProperty } from "../utilities/is-object-property.js";
import { isArrayExpression } from "../utilities/node-types.js";
import { isObjectProperty } from "../utilities/utilities.js";
const angularComponentObjectExpressionPredicates = [
(node, name) => name === "properties" && node.type === "ObjectExpression",
+1 -1
View File
@@ -1,5 +1,5 @@
import { isBinaryCastExpression } from "../utilities/node-types.js";
import { startsWithNoLookaheadToken } from "../utilities/utilities.js";
import { startsWithNoLookaheadToken } from "../utilities/starts-with-no-lookahead-token.js";
function shouldAddParenthesesToIdentifier(path) {
const { node } = path;
@@ -1,5 +1,10 @@
import { hasComment } from "../utilities/comments.js";
import { createTypeCheckFunction } from "../utilities/create-type-check-function.js";
import { getFunctionParameters } from "../utilities/function-parameters.js";
import { getPrecedence } from "../utilities/get-precedence.js";
import { isBitwiseOperator } from "../utilities/is-bitwise-operator.js";
import { isNullishCoalescing } from "../utilities/is-nullish-coalescing.js";
import { isObjectProperty } from "../utilities/is-object-property.js";
import {
isArrayExpression,
isBinaryCastExpression,
@@ -13,15 +18,8 @@ import {
isReturnOrThrowStatement,
isUnionType,
} from "../utilities/node-types.js";
import {
getFunctionParameters,
getPrecedence,
isBitwiseOperator,
isNullishCoalescing,
isObjectProperty,
shouldFlatten,
startsWithNoLookaheadToken,
} from "../utilities/utilities.js";
import { shouldFlatten } from "../utilities/should-flatten.js";
import { startsWithNoLookaheadToken } from "../utilities/starts-with-no-lookahead-token.js";
import { shouldAddParenthesesToChainElement } from "./chain-expression.js";
import { shouldAddParenthesesToIdentifier } from "./identifier.js";
import { parentNeedsParentheses } from "./parent-needs-parentheses.js";
@@ -1,16 +1,16 @@
import isNonEmptyArray from "../../utilities/is-non-empty-array.js";
import { hasNode } from "../utilities/has-node.js";
import {
getLeftSidePathName,
hasNakedLeftSide,
} from "../utilities/left-side.js";
import {
isCallExpression,
isMemberExpression,
isReturnOrThrowStatement,
} from "../utilities/node-types.js";
import { returnArgumentHasLeadingComment } from "../utilities/return-statement-has-leading-comment.js";
import {
getLeftSidePathName,
hasNakedLeftSide,
hasNode,
stripChainElementWrappers,
} from "../utilities/utilities.js";
import { stripChainElementWrappers } from "../utilities/strip-chain-element-wrappers.js";
/**
* @import AstPath from "../../common/ast-path.js"
+5 -5
View File
@@ -1,12 +1,12 @@
import * as assert from "#universal/assert";
import { locEnd, locEndWithFullText, locStart } from "../../loc.js";
import { createTypeCheckFunction } from "../../utilities/create-type-check-function.js";
import getRaw from "../../utilities/get-raw.js";
import { getRaw } from "../../utilities/get-raw.js";
import getTextWithoutComments from "../../utilities/get-text-without-comments.js";
import isBlockComment from "../../utilities/is-block-comment.js";
import isLineComment from "../../utilities/is-line-comment.js";
import isTypeCastComment from "../../utilities/is-type-cast-comment.js";
import mergeNestledJsdocComments from "./merge-nestled-jsdoc-comments.js";
import { isBlockComment } from "../../utilities/is-block-comment.js";
import { isLineComment } from "../../utilities/is-line-comment.js";
import { isTypeCastComment } from "../../utilities/is-type-cast-comment.js";
import { mergeNestledJsdocComments } from "./merge-nestled-jsdoc-comments.js";
import visitNode from "./visit-node.js";
const isNodeWithRaw = createTypeCheckFunction([
@@ -1,7 +1,7 @@
import { locEnd, locStart } from "../../loc.js";
import isBlockComment from "../../utilities/is-block-comment.js";
import { isBlockComment } from "../../utilities/is-block-comment.js";
import isIndentableBlockComment from "../../utilities/is-indentable-block-comment.js";
import isLineComment from "../../utilities/is-line-comment.js";
import { isLineComment } from "../../utilities/is-line-comment.js";
function mergeNestledJsdocComments(comments) {
if (comments.length < 2) {
@@ -32,4 +32,4 @@ function mergeNestledJsdocComments(comments) {
}
}
export default mergeNestledJsdocComments;
export { mergeNestledJsdocComments };
+1 -1
View File
@@ -1,7 +1,7 @@
import { group, join, line } from "../../document/index.js";
import UnexpectedNodeError from "../../utilities/unexpected-node-error.js";
import { createTypeCheckFunction } from "../utilities/create-type-check-function.js";
import { hasNode } from "../utilities/utilities.js";
import { hasNode } from "../utilities/has-node.js";
import { printBinaryishExpression } from "./binaryish.js";
/** @import AstPath from "../../common/ast-path.js" */
+2 -4
View File
@@ -14,16 +14,14 @@ import skipInlineComment from "../../utilities/skip-inline-comment.js";
import skipTrailingComment from "../../utilities/skip-trailing-comment.js";
import { locEnd, locStart } from "../loc.js";
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import { isSignedNumericLiteral } from "../utilities/is-signed-numeric-literal.js";
import {
isArrayExpression,
isNumericLiteral,
isObjectExpression,
isTupleType,
} from "../utilities/node-types.js";
import {
isSignedNumericLiteral,
shouldPrintComma,
} from "../utilities/utilities.js";
import { shouldPrintComma } from "../utilities/should-print-comma.js";
import {
printDanglingCommentsInList,
printOptionalToken,
+5 -7
View File
@@ -15,6 +15,9 @@ import {
printDanglingComments,
} from "../../main/comments/print.js";
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import { getFunctionParameters } from "../utilities/function-parameters.js";
import { hasLeadingOwnLineComment } from "../utilities/has-leading-own-line-comment.js";
import { isTemplateOnItsOwnLine } from "../utilities/is-template-on-its-own-line.js";
import {
isArrayExpression,
isBinaryish,
@@ -22,13 +25,8 @@ import {
isJsxElement,
isObjectExpression,
} from "../utilities/node-types.js";
import {
getFunctionParameters,
hasLeadingOwnLineComment,
isTemplateOnItsOwnLine,
shouldPrintComma,
startsWithNoLookaheadToken,
} from "../utilities/utilities.js";
import { shouldPrintComma } from "../utilities/should-print-comma.js";
import { startsWithNoLookaheadToken } from "../utilities/starts-with-no-lookahead-token.js";
import { printReturnType, shouldPrintParamsWithoutParens } from "./function.js";
import { printFunctionParameters } from "./function-parameters.js";
+4 -6
View File
@@ -10,6 +10,10 @@ import {
} from "../../document/index.js";
import getStringWidth from "../../utilities/get-string-width.js";
import isNonEmptyArray from "../../utilities/is-non-empty-array.js";
import { getCallArguments } from "../utilities/call-arguments.js";
import { hasLeadingOwnLineComment } from "../utilities/has-leading-own-line-comment.js";
import { isLoneShortArgument } from "../utilities/is-lone-short-argument.js";
import { isObjectProperty } from "../utilities/is-object-property.js";
import {
isBinaryish,
isBooleanLiteral,
@@ -22,12 +26,6 @@ import {
isTypeAlias,
isUnionType,
} from "../utilities/node-types.js";
import {
getCallArguments,
hasLeadingOwnLineComment,
isLoneShortArgument,
isObjectProperty,
} from "../utilities/utilities.js";
import { shouldInlineLogicalExpression } from "./binaryish.js";
import { printCallExpression } from "./call-expression.js";
+1 -1
View File
@@ -3,7 +3,7 @@ import {
isCallExpression,
isMemberExpression,
} from "../utilities/node-types.js";
import { startsWithNoLookaheadToken } from "../utilities/utilities.js";
import { startsWithNoLookaheadToken } from "../utilities/starts-with-no-lookahead-token.js";
/**
* @import AstPath from "../../common/ast-path.js"
+5 -7
View File
@@ -15,7 +15,10 @@ import {
} from "../../document/index.js";
import { printComments } from "../../main/comments/print.js";
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import isTypeCastComment from "../utilities/is-type-cast-comment.js";
import { hasLeadingOwnLineComment } from "../utilities/has-leading-own-line-comment.js";
import { isBooleanTypeCoercion } from "../utilities/is-boolean-type-coercion.js";
import { isObjectProperty } from "../utilities/is-object-property.js";
import { isTypeCastComment } from "../utilities/is-type-cast-comment.js";
import {
isArrayExpression,
isBinaryish,
@@ -25,12 +28,7 @@ import {
isObjectExpression,
isReturnOrThrowStatement,
} from "../utilities/node-types.js";
import {
hasLeadingOwnLineComment,
isBooleanTypeCoercion,
isObjectProperty,
shouldFlatten,
} from "../utilities/utilities.js";
import { shouldFlatten } from "../utilities/should-flatten.js";
/** @import {Doc} from "../../document/index.js" */
+1 -1
View File
@@ -2,7 +2,7 @@ import { hardline, indent } from "../../document/index.js";
import { printDanglingComments } from "../../main/comments/print.js";
import isNonEmptyArray from "../../utilities/is-non-empty-array.js";
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import { isNextLineEmpty } from "../utilities/utilities.js";
import { isNextLineEmpty } from "../utilities/is-next-line-empty.js";
import { printStatementSequence } from "./statement-sequence.js";
/** @import {Doc} from "../../document/index.js" */
+15 -15
View File
@@ -10,7 +10,19 @@ import {
softline,
willBreak,
} from "../../document/index.js";
import {
getCallArguments,
getCallArgumentSelector,
iterateCallArgumentsPath,
} from "../utilities/call-arguments.js";
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import { getFunctionParameters } from "../utilities/function-parameters.js";
import { isFunctionCompositionArguments } from "../utilities/is-function-composition-arguments.js";
import { isLongCurriedCallExpression } from "../utilities/is-long-curried-call-expression.js";
import { isNextLineEmpty } from "../utilities/is-next-line-empty.js";
import { isObjectProperty } from "../utilities/is-object-property.js";
import { isSimpleCallArgument } from "../utilities/is-simple-call-argument.js";
import { isSimpleType } from "../utilities/is-simple-type.js";
import {
isArrayExpression,
isBinaryCastExpression,
@@ -22,20 +34,8 @@ import {
isRegExpLiteral,
isStringLiteral,
} from "../utilities/node-types.js";
import {
getCallArguments,
getCallArgumentSelector,
getFunctionParameters,
isFunctionCompositionArgs,
isLongCurriedCallExpression,
isNextLineEmpty,
isObjectProperty,
isSimpleCallArgument,
isSimpleType,
iterateCallArgumentsPath,
shouldPrintComma,
stripChainElementWrappers,
} from "../utilities/utilities.js";
import { shouldPrintComma } from "../utilities/should-print-comma.js";
import { stripChainElementWrappers } from "../utilities/strip-chain-element-wrappers.js";
import { isConciselyPrintedArray } from "./array.js";
import { printDanglingCommentsInList } from "./miscellaneous.js";
@@ -109,7 +109,7 @@ function printCallArguments(path, options, print) {
if (
anyArgEmptyLine ||
(path.parent.type !== "Decorator" && isFunctionCompositionArgs(args))
(path.parent.type !== "Decorator" && isFunctionCompositionArguments(args))
) {
return allArgsBrokenOut();
}
+7 -7
View File
@@ -1,15 +1,15 @@
import { group, join, lineSuffixBoundary } from "../../document/index.js";
import needsParentheses from "../parentheses/needs-parentheses.js";
import { hasComment } from "../utilities/comments.js";
import { isNodeMatches } from "../utilities/is-node-matches.js";
import { isCallExpression, isStringLiteral } from "../utilities/node-types.js";
import { isTestCall } from "../utilities/test-libraries.js";
import {
getCallArguments,
isMemberish,
isTemplateOnItsOwnLine,
iterateCallArgumentsPath,
} from "../utilities/utilities.js";
} from "../utilities/call-arguments.js";
import { hasComment } from "../utilities/comments.js";
import { isMemberish } from "../utilities/is-memberish.js";
import { isNodeMatches } from "../utilities/is-node-matches.js";
import { isTemplateOnItsOwnLine } from "../utilities/is-template-on-its-own-line.js";
import { isCallExpression, isStringLiteral } from "../utilities/node-types.js";
import { isTestCall } from "../utilities/test-libraries.js";
import printCallArguments from "./call-arguments.js";
import printMemberChain from "./member-chain.js";
import { printOptionalToken } from "./miscellaneous.js";
+2 -1
View File
@@ -16,7 +16,8 @@ import {
hasComment,
} from "../utilities/comments.js";
import { createTypeCheckFunction } from "../utilities/create-type-check-function.js";
import { isNextLineEmpty, shouldPrintComma } from "../utilities/utilities.js";
import { isNextLineEmpty } from "../utilities/is-next-line-empty.js";
import { shouldPrintComma } from "../utilities/should-print-comma.js";
import { shouldHugTheOnlyParameter } from "./function-parameters.js";
/*
+1 -1
View File
@@ -17,7 +17,7 @@ import isNonEmptyArray from "../../utilities/is-non-empty-array.js";
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import { createTypeCheckFunction } from "../utilities/create-type-check-function.js";
import { isMemberExpression } from "../utilities/node-types.js";
import { stripChainElementWrappers } from "../utilities/utilities.js";
import { stripChainElementWrappers } from "../utilities/strip-chain-element-wrappers.js";
import { printAssignment } from "./assignment.js";
import { printClassMemberDecorators } from "./decorators.js";
import { printMethod } from "./function.js";
+2 -2
View File
@@ -5,9 +5,9 @@ import {
replaceEndOfLine,
} from "../../document/index.js";
import { locEnd, locStart } from "../loc.js";
import isBlockComment from "../utilities/is-block-comment.js";
import { isBlockComment } from "../utilities/is-block-comment.js";
import isIndentableBlockComment from "../utilities/is-indentable-block-comment.js";
import isLineComment from "../utilities/is-line-comment.js";
import { isLineComment } from "../utilities/is-line-comment.js";
/**
@import {Doc} from "../../document/index.js"
+1 -1
View File
@@ -9,12 +9,12 @@ import { printDanglingComments } from "../../main/comments/print.js";
import UnexpectedNodeError from "../../utilities/unexpected-node-error.js";
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import { isMeaningfulEmptyStatement } from "../utilities/is-meaningful-empty-statement.js";
import { isMethod } from "../utilities/is-method.js";
import {
isArrayExpression,
isLiteral,
isObjectExpression,
} from "../utilities/node-types.js";
import { isMethod } from "../utilities/utilities.js";
import { printArray } from "./array.js";
import { printArrowFunction } from "./arrow-function.js";
import {
+2 -2
View File
@@ -4,9 +4,9 @@ import * as assert from "#universal/assert";
import { replaceEndOfLine } from "../../document/index.js";
import printNumber from "../../utilities/print-number.js";
import printString from "../../utilities/print-string.js";
import getRaw from "../utilities/get-raw.js";
import { getRaw } from "../utilities/get-raw.js";
import isFlowKeywordType from "../utilities/is-flow-keyword-type.js";
import { isMethod } from "../utilities/utilities.js";
import { isMethod } from "../utilities/is-method.js";
import { printArray } from "./array.js";
import { printArrayType } from "./array-type.js";
import { printBinaryCastExpression } from "./cast-expression.js";
+10 -10
View File
@@ -11,22 +11,22 @@ import {
} from "../../document/index.js";
import isNonEmptyArray from "../../utilities/is-non-empty-array.js";
import { hasComment } from "../utilities/comments.js";
import {
getFunctionParameters,
hasRestParameter,
iterateFunctionParametersPath,
} from "../utilities/function-parameters.js";
import { isFlowObjectTypePropertyAFunction } from "../utilities/is-flow-object-type-property-a-function.js";
import { isNextLineEmpty } from "../utilities/is-next-line-empty.js";
import { isSimpleType } from "../utilities/is-simple-type.js";
import { isTypeAnnotationAFunction } from "../utilities/is-type-annotation-a-function.js";
import {
isArrayExpression,
isObjectExpression,
isObjectType,
} from "../utilities/node-types.js";
import { shouldPrintComma } from "../utilities/should-print-comma.js";
import { isTestCall } from "../utilities/test-libraries.js";
import {
getFunctionParameters,
hasRestParameter,
isFlowObjectTypePropertyAFunction,
isNextLineEmpty,
isSimpleType,
isTypeAnnotationAFunction,
iterateFunctionParametersPath,
shouldPrintComma,
} from "../utilities/utilities.js";
import { printDanglingCommentsInList } from "./miscellaneous.js";
/** @import AstPath from "../../common/ast-path.js" */
+1 -1
View File
@@ -1,6 +1,6 @@
import { group } from "../../document/index.js";
import { hasSameLocStart } from "../loc.js";
import { isFlowObjectTypePropertyAFunction } from "../utilities/utilities.js";
import { isFlowObjectTypePropertyAFunction } from "../utilities/is-flow-object-type-property-a-function.js";
import { printClassMemberSemicolon } from "./class.js";
import {
printFunctionParameters,
+3 -5
View File
@@ -1,12 +1,10 @@
import * as assert from "#universal/assert";
import { group } from "../../document/index.js";
import { getCallArguments } from "../utilities/call-arguments.js";
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import { getFunctionParameters } from "../utilities/function-parameters.js";
import { isMethod } from "../utilities/is-method.js";
import { isCallExpression } from "../utilities/node-types.js";
import {
getCallArguments,
getFunctionParameters,
isMethod,
} from "../utilities/utilities.js";
import {
printFunctionParameters,
shouldBreakFunctionParameters,
+1 -1
View File
@@ -1,7 +1,7 @@
import { group, hardline } from "../../document/index.js";
import { printDanglingComments } from "../../main/comments/print.js";
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import { needsHardlineAfterDanglingComment } from "../utilities/utilities.js";
import { needsHardlineAfterDanglingComment } from "../utilities/needs-hardline-after-dangling-comment.js";
import { adjustClause, printIfStatementCondition } from "./miscellaneous.js";
/**
+1 -1
View File
@@ -5,7 +5,7 @@ import {
join,
softline,
} from "../../document/index.js";
import { shouldPrintComma } from "../utilities/utilities.js";
import { shouldPrintComma } from "../utilities/should-print-comma.js";
import { printClassMemberSemicolon } from "./class.js";
import { printTypeAnnotationProperty } from "./type-annotation.js";
+1 -1
View File
@@ -11,7 +11,7 @@ import needsParentheses from "../parentheses/needs-parentheses.js";
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import { createTypeCheckFunction } from "../utilities/create-type-check-function.js";
import isIgnored from "../utilities/is-ignored.js";
import { isIifeCalleeOrTaggedTemplateExpressionTag } from "../utilities/utilities.js";
import { isIifeCalleeOrTaggedTemplateExpressionTag } from "../utilities/is-iife-callee-or-tagged-template-expression-tag.js";
import { printAngular } from "./angular.js";
import { printDecorators } from "./decorators.js";
import { printEstree } from "./estree.js";
+1 -1
View File
@@ -1,6 +1,6 @@
import { group, indent, line } from "../../document/index.js";
import { hasLeadingOwnLineComment } from "../utilities/has-leading-own-line-comment.js";
import { isObjectType } from "../utilities/node-types.js";
import { hasLeadingOwnLineComment } from "../utilities/utilities.js";
// `TSIntersectionType` and `IntersectionTypeAnnotation`
function printIntersectionType(path, options, print) {
+2 -2
View File
@@ -23,7 +23,7 @@ import UnexpectedNodeError from "../../utilities/unexpected-node-error.js";
import needsParentheses from "../parentheses/needs-parentheses.js";
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import { createTypeCheckFunction } from "../utilities/create-type-check-function.js";
import getRaw from "../utilities/get-raw.js";
import { getRaw } from "../utilities/get-raw.js";
import { isMeaningfulJsxText } from "../utilities/is-meaningful-jsx-text.js";
import { jsxWhitespace } from "../utilities/jsx-whitespace.js";
import {
@@ -34,7 +34,7 @@ import {
isObjectExpression,
isStringLiteral,
} from "../utilities/node-types.js";
import { stripChainElementWrappers } from "../utilities/utilities.js";
import { stripChainElementWrappers } from "../utilities/strip-chain-element-wrappers.js";
/**
@import AstPath from "../../common/ast-path.js";
+1 -1
View File
@@ -2,7 +2,7 @@ import isEs5IdentifierName from "is-es5-identifier-name";
import { printComments } from "../../main/comments/print.js";
import printNumber from "../../utilities/print-number.js";
import printString from "../../utilities/print-string.js";
import getRaw from "../utilities/get-raw.js";
import { getRaw } from "../utilities/get-raw.js";
import { isNumericLiteral, isStringLiteral } from "../utilities/node-types.js";
/**
+1 -1
View File
@@ -12,7 +12,7 @@ import hasNewlineInRange from "../../utilities/has-newline-in-range.js";
import { locEnd, locStart } from "../loc.js";
import { CommentCheckFlags, getComments } from "../utilities/comments.js";
import getTextWithoutComments from "../utilities/get-text-without-comments.js";
import isLineComment from "../utilities/is-line-comment.js";
import { isLineComment } from "../utilities/is-line-comment.js";
import { printClassMemberSemicolon } from "./class.js";
/**
+2 -4
View File
@@ -15,10 +15,8 @@ import {
import needsParentheses from "../parentheses/needs-parentheses.js";
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import { createTypeCheckFunction } from "../utilities/create-type-check-function.js";
import {
hasLeadingOwnLineComment,
isNextLineEmpty,
} from "../utilities/utilities.js";
import { hasLeadingOwnLineComment } from "../utilities/has-leading-own-line-comment.js";
import { isNextLineEmpty } from "../utilities/is-next-line-empty.js";
/*
- `MatchExpression` (Flow)
+4 -6
View File
@@ -14,18 +14,16 @@ import isNextLineEmptyAfterIndex from "../../utilities/is-next-line-empty.js";
import { locEnd } from "../loc.js";
import needsParentheses from "../parentheses/needs-parentheses.js";
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import { isLongCurriedCallExpression } from "../utilities/is-long-curried-call-expression.js";
import { isMemberish } from "../utilities/is-memberish.js";
import { isNextLineEmpty } from "../utilities/is-next-line-empty.js";
import { isSimpleCallArgument } from "../utilities/is-simple-call-argument.js";
import {
isCallExpression,
isFunctionOrArrowExpression,
isMemberExpression,
isNumericLiteral,
} from "../utilities/node-types.js";
import {
isLongCurriedCallExpression,
isMemberish,
isNextLineEmpty,
isSimpleCallArgument,
} from "../utilities/utilities.js";
import { printBindExpressionCallee } from "./bind-expression.js";
import printCallArguments from "./call-arguments.js";
import { printMemberLookup } from "./member.js";
+2 -4
View File
@@ -5,16 +5,14 @@ import {
lineSuffixBoundary,
softline,
} from "../../document/index.js";
import { getCallArguments } from "../utilities/call-arguments.js";
import {
isCallExpression,
isChainElementWrapper,
isMemberExpression,
isNumericLiteral,
} from "../utilities/node-types.js";
import {
getCallArguments,
stripChainElementWrappers,
} from "../utilities/utilities.js";
import { stripChainElementWrappers } from "../utilities/strip-chain-element-wrappers.js";
import { printOptionalToken } from "./miscellaneous.js";
const isCallExpressionWithArguments = (node) =>
+3 -5
View File
@@ -15,12 +15,10 @@ import { locEnd, locStart } from "../loc.js";
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import { createTypeCheckFunction } from "../utilities/create-type-check-function.js";
import getTextWithoutComments from "../utilities/get-text-without-comments.js";
import { isShorthandSpecifier } from "../utilities/is-shorthand-specifier.js";
import { needsHardlineAfterDanglingComment } from "../utilities/needs-hardline-after-dangling-comment.js";
import { isStringLiteral } from "../utilities/node-types.js";
import {
isShorthandSpecifier,
needsHardlineAfterDanglingComment,
shouldPrintComma,
} from "../utilities/utilities.js";
import { shouldPrintComma } from "../utilities/should-print-comma.js";
import { printDecoratorsBeforeExport } from "./decorators.js";
import { printDeclareToken } from "./miscellaneous.js";
import { printObject } from "./object.js";
+2 -1
View File
@@ -19,8 +19,9 @@ import {
} from "../utilities/comments.js";
import { createTypeCheckFunction } from "../utilities/create-type-check-function.js";
import getTextWithoutComments from "../utilities/get-text-without-comments.js";
import { isNextLineEmpty } from "../utilities/is-next-line-empty.js";
import { isObjectType } from "../utilities/node-types.js";
import { isNextLineEmpty, shouldPrintComma } from "../utilities/utilities.js";
import { shouldPrintComma } from "../utilities/should-print-comma.js";
import { shouldHugTheOnlyParameter } from "./function-parameters.js";
import {
printDanglingCommentsInList,
+1 -1
View File
@@ -1,5 +1,5 @@
import { hardline } from "../../document/index.js";
import { isNextLineEmpty } from "../utilities/utilities.js";
import { isNextLineEmpty } from "../utilities/is-next-line-empty.js";
/**
* @import {Doc} from "../../document/index.js"
+1 -1
View File
@@ -7,7 +7,7 @@ import {
} from "../../document/index.js";
import { printDanglingComments } from "../../main/comments/print.js";
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import { isNextLineEmpty } from "../utilities/utilities.js";
import { isNextLineEmpty } from "../utilities/is-next-line-empty.js";
import { printStatementSequence } from "./statement-sequence.js";
function printSwitchStatement(path, options, print) {
+1 -1
View File
@@ -25,7 +25,7 @@ import {
isBinaryish,
isMemberExpression,
} from "../utilities/node-types.js";
import { stripChainElementWrappers } from "../utilities/utilities.js";
import { stripChainElementWrappers } from "../utilities/strip-chain-element-wrappers.js";
/**
* @import {Doc} from "../../document/index.js"
+3 -5
View File
@@ -17,7 +17,9 @@ import {
getComments,
hasComment,
} from "../utilities/comments.js";
import isBlockComment from "../utilities/is-block-comment.js";
import { isBlockComment } from "../utilities/is-block-comment.js";
import { isLoneShortArgument } from "../utilities/is-lone-short-argument.js";
import { isSimpleExpressionByNodeCount } from "../utilities/is-simple-expression-by-node-count.js";
import {
isBinaryCastExpression,
isCallExpression,
@@ -27,10 +29,6 @@ import {
isMemberExpression,
isReturnOrThrowStatement,
} from "../utilities/node-types.js";
import {
isLoneShortArgument,
isSimpleExpressionByNodeCount,
} from "../utilities/utilities.js";
import { printTernaryOld } from "./ternary-old.js";
/**
+1 -1
View File
@@ -2,7 +2,7 @@ import { indent, softline } from "../../document/index.js";
import hasNewline from "../../utilities/has-newline.js";
import { locEnd, locStart } from "../loc.js";
import { hasComment } from "../utilities/comments.js";
import isBlockComment from "../utilities/is-block-comment.js";
import { isBlockComment } from "../utilities/is-block-comment.js";
function printTryStatement(path, options, print) {
const { node } = path;
+1 -1
View File
@@ -1,6 +1,6 @@
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import { isSimpleType } from "../utilities/is-simple-type.js";
import { isObjectType, isUnionType } from "../utilities/node-types.js";
import { isSimpleType } from "../utilities/utilities.js";
import { shouldHugUnionType } from "./union-type.js";
/**
+2 -4
View File
@@ -13,12 +13,10 @@ import { printDanglingComments } from "../../main/comments/print.js";
import hasNewline from "../../utilities/has-newline.js";
import { locEnd } from "../loc.js";
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import { getFunctionParameters } from "../utilities/function-parameters.js";
import { isObjectType } from "../utilities/node-types.js";
import { shouldPrintComma } from "../utilities/should-print-comma.js";
import { isTestCall } from "../utilities/test-libraries.js";
import {
getFunctionParameters,
shouldPrintComma,
} from "../utilities/utilities.js";
import { isArrowFunctionVariableDeclarator } from "./assignment.js";
import {
printTypeAnnotationProperty,
+2 -4
View File
@@ -14,15 +14,13 @@ import {
import needsParentheses from "../parentheses/needs-parentheses.js";
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import { createTypeCheckFunction } from "../utilities/create-type-check-function.js";
import { hasLeadingOwnLineComment } from "../utilities/has-leading-own-line-comment.js";
import {
isConditionalType,
isTupleType,
isTypeAlias,
} from "../utilities/node-types.js";
import {
hasLeadingOwnLineComment,
shouldUnionTypePrintOwnComments,
} from "../utilities/utilities.js";
import { shouldUnionTypePrintOwnComments } from "../utilities/should-union-type-print-own-comments.js";
/**
@import {Doc} from "../../document/index.js";
+1 -1
View File
@@ -9,7 +9,7 @@ import { insertPragma } from "./pragma.js";
import { printComment } from "./print/comment.js";
import { printEstree } from "./print/index.js";
import getVisitorKeys from "./traverse/get-visitor-keys.js";
import isBlockComment from "./utilities/is-block-comment.js";
import { isBlockComment } from "./utilities/is-block-comment.js";
import hasPrettierIgnore from "./utilities/is-ignored.js";
const features = {
+2 -2
View File
@@ -1,10 +1,10 @@
import needsParentheses from "../parentheses/needs-parentheses.js";
import { shouldPrintParamsWithoutParens } from "../print/function.js";
import { isJsxElement } from "../utilities/node-types.js";
import {
getLeftSidePathName,
hasNakedLeftSide,
} from "../utilities/utilities.js";
} from "../utilities/left-side.js";
import { isJsxElement } from "../utilities/node-types.js";
function shouldExpressionStatementPrintLeadingSemicolon(path, options) {
if (options.semi) {
+1 -1
View File
@@ -1,7 +1,7 @@
import type { ESTree as MeriyahESTree } from "meriyah";
import type * as Babel from "@babel/types";
import type { NGTree } from "angular-estree-parser";
import type * as TSESTree from "./typescript-estree.ts";
import type * as TSESTree from "./typescript-estree.js";
import type * as FlowESTree from "./flow-estree.js";
import type * as Babel from "./babel.js";
@@ -0,0 +1,89 @@
/**
@import {
Node,
NodeMap,
} from "../types/estree.js";
@typedef {
| NodeMap["NewExpression"]
| NodeMap["ImportExpression"]
| NodeMap["OptionalCallExpression"]
| NodeMap["CallExpression"]
| NodeMap["TSImportType"]
| NodeMap["TSExternalModuleReference"]
} CallLikeNode
*/
const callArgumentsCache = new WeakMap();
/**
@param {CallLikeNode} node
*/
function getCallArguments(node) {
if (callArgumentsCache.has(node)) {
return callArgumentsCache.get(node);
}
let args;
if (node.type === "ImportExpression" || node.type === "TSImportType") {
args = [node.source];
if (node.options) {
args.push(node.options);
}
} else if (node.type === "TSExternalModuleReference") {
args = [node.expression];
} else {
args = node.arguments;
}
callArgumentsCache.set(node, args);
return args;
}
function iterateCallArgumentsPath(path, iteratee) {
const { node } = path;
if (node.type === "ImportExpression" || node.type === "TSImportType") {
path.call(() => iteratee(path, 0), "source");
if (node.options) {
path.call(() => iteratee(path, 1), "options");
}
} else if (node.type === "TSExternalModuleReference") {
path.call(() => iteratee(path, 0), "expression");
} else {
path.each(iteratee, "arguments");
}
}
/**
@param {CallLikeNode} node
@param {number} index
*/
function getCallArgumentSelector(node, index) {
if (node.type === "ImportExpression" || node.type === "TSImportType") {
if (index === 0 || index === (node.options ? -2 : -1)) {
return ["source"];
}
if (node.options && (index === 1 || index === -1)) {
return ["options"];
}
throw new RangeError("Invalid argument index");
} else if (node.type === "TSExternalModuleReference") {
if (index === 0 || index === -1) {
return ["expression"];
}
} else {
if (index < 0) {
index = node.arguments.length + index;
}
if (index >= 0 && index < node.arguments.length) {
return ["arguments", index];
}
}
/* c8 ignore next */
throw new RangeError("Invalid argument index");
}
export { getCallArguments, getCallArgumentSelector, iterateCallArgumentsPath };
+2 -2
View File
@@ -1,6 +1,6 @@
import isNonEmptyArray from "../../utilities/is-non-empty-array.js";
import isBlockComment from "./is-block-comment.js";
import isLineComment from "./is-line-comment.js";
import { isBlockComment } from "./is-block-comment.js";
import { isLineComment } from "./is-line-comment.js";
import { isPrettierIgnoreComment } from "./is-prettier-ignore-comment.js";
/**
@@ -0,0 +1,47 @@
const functionParametersCache = new WeakMap();
function getFunctionParameters(node) {
if (functionParametersCache.has(node)) {
return functionParametersCache.get(node);
}
const parameters = [];
if (node.this) {
parameters.push(node.this);
}
parameters.push(...node.params);
if (node.rest) {
parameters.push(node.rest);
}
functionParametersCache.set(node, parameters);
return parameters;
}
function iterateFunctionParametersPath(path, iteratee) {
const { node } = path;
let index = 0;
const callback = () => iteratee(path, index++);
if (node.this) {
path.call(callback, "this");
}
path.each(callback, "params");
if (node.rest) {
path.call(callback, "rest");
}
}
function hasRestParameter(node) {
if (node.rest) {
return true;
}
const parameters = getFunctionParameters(node);
return parameters.at(-1)?.type === "RestElement";
}
export {
getFunctionParameters,
hasRestParameter,
iterateFunctionParametersPath,
};
@@ -0,0 +1,24 @@
const PRECEDENCE = new Map(
[
["|>"],
["??"],
["||"],
["&&"],
["|"],
["^"],
["&"],
["==", "===", "!=", "!=="],
["<", ">", "<=", ">=", "in", "instanceof"],
[">>", "<<", ">>>"],
["+", "-"],
["*", "/", "%"],
["**"],
].flatMap((operators, index) =>
operators.map((operator) => [operator, index]),
),
);
function getPrecedence(operator) {
return PRECEDENCE.get(operator);
}
export { getPrecedence };
+1 -1
View File
@@ -2,4 +2,4 @@ function getRaw(node) {
return node.extra?.raw ?? node.raw;
}
export default getRaw;
export { getRaw };
@@ -0,0 +1,35 @@
import hasNewline from "../../utilities/has-newline.js";
import { locEnd } from "../loc.js";
import { CommentCheckFlags, hasComment } from "./comments.js";
import { hasNodeIgnoreComment } from "./has-node-ignore-comment.js";
import { isJsxElement } from "./node-types.js";
/**
@import {
Node,
NodeMap,
Comment,
NumericLiteral,
StringLiteral,
RegExpLiteral,
BigIntLiteral,
} from "../types/estree.js";
@import AstPath from "../../common/ast-path.js";
*/
/**
* @param {string} text
* @param {Node} node
* @returns {boolean}
*/
function hasLeadingOwnLineComment(text, node) {
if (isJsxElement(node)) {
return hasNodeIgnoreComment(node);
}
return hasComment(node, CommentCheckFlags.Leading, (comment) =>
hasNewline(text, locEnd(comment)),
);
}
export { hasLeadingOwnLineComment };
+19
View File
@@ -0,0 +1,19 @@
import { hasDescendant } from "../../utilities/ast.js";
import getVisitorKeys from "../traverse/get-visitor-keys.js";
/**
@import {
Node,
} from "../types/estree.js";
*/
/**
* @param {Node} node
* @param {(node: Node) => boolean} predicate
* @returns {boolean}
*/
function hasNode(node, predicate) {
return predicate(node) || hasDescendant(node, { getVisitorKeys, predicate });
}
export { hasNode };
@@ -0,0 +1,17 @@
/**
@import {
Node,
} from "../types/estree.js";
*/
/**
* @param {Node} node
* @returns {boolean}
*/
const isTsAsConstExpression = (node) =>
node?.type === "TSAsExpression" &&
node.typeAnnotation.type === "TSTypeReference" &&
node.typeAnnotation.typeName.type === "Identifier" &&
node.typeAnnotation.typeName.name === "const";
export { isTsAsConstExpression };
@@ -0,0 +1,12 @@
import { bitshiftOperators } from "./should-flatten.js";
function isBitwiseOperator(operator) {
return (
Boolean(bitshiftOperators[operator]) ||
operator === "|" ||
operator === "^" ||
operator === "&"
);
}
export { isBitwiseOperator };
@@ -15,4 +15,4 @@ const isBlockComment = createTypeCheckFunction([
"MultiLine",
]);
export default isBlockComment;
export { isBlockComment };
@@ -0,0 +1,22 @@
/**
@import {
Node,
} from "../types/estree.js";
*/
/**
* @param {Node} node
* @returns {boolean}
*/
function isBooleanTypeCoercion(node) {
return (
node.type === "CallExpression" &&
// @ts-expect-error -- expected
!node.optional &&
node.arguments.length === 1 &&
node.callee.type === "Identifier" &&
node.callee.name === "Boolean"
);
}
export { isBooleanTypeCoercion };
@@ -0,0 +1,25 @@
/**
@import {
Node,
} from "../types/estree.js";
*/
/**
* @param {Node} node
* @returns {boolean}
*/
function isFlowObjectTypePropertyAFunction(node) {
return (
(node.type === "ObjectTypeProperty" ||
node.type === "ObjectTypeInternalSlot") &&
!node.static &&
!node.method &&
// @ts-expect-error -- exists on `ObjectTypeProperty` but not `ObjectTypeInternalSlot`
node.kind !== "get" &&
// @ts-expect-error -- exists on `ObjectTypeProperty` but not `ObjectTypeInternalSlot`
node.kind !== "set" &&
node.value.type === "FunctionTypeAnnotation"
);
}
export { isFlowObjectTypePropertyAFunction };
@@ -0,0 +1,33 @@
import { getCallArguments } from "./call-arguments.js";
import { isCallExpression, isFunctionOrArrowExpression } from "./node-types.js";
import { stripChainElementWrappers } from "./strip-chain-element-wrappers.js";
// Logic to check for args with multiple anonymous functions. For instance,
// the following call should be split on multiple lines for readability:
// source.pipe(map((x) => x + x), filter((x) => x % 2 === 0))
function isFunctionCompositionArguments(args) {
if (args.length <= 1) {
return false;
}
let count = 0;
for (let arg of args) {
if (isFunctionOrArrowExpression(arg)) {
count += 1;
if (count > 1) {
return true;
}
} else {
arg = stripChainElementWrappers(arg);
if (isCallExpression(arg)) {
for (const childArg of getCallArguments(arg)) {
if (isFunctionOrArrowExpression(childArg)) {
return true;
}
}
}
}
}
return false;
}
export { isFunctionCompositionArguments };
@@ -0,0 +1,13 @@
import { isCallExpression } from "./node-types.js";
function isIifeCalleeOrTaggedTemplateExpressionTag(path) {
const { node } = path;
return (
(node.type === "FunctionExpression" ||
node.type === "ArrowFunctionExpression") &&
((path.key === "callee" && isCallExpression(path.parent)) ||
(path.key === "tag" && path.parent.type === "TaggedTemplateExpression"))
);
}
export { isIifeCalleeOrTaggedTemplateExpressionTag };
@@ -1,4 +1,4 @@
import isBlockComment from "./is-block-comment.js";
import { isBlockComment } from "./is-block-comment.js";
function isIndentableBlockCommentInternal(comment) {
/*
+1 -1
View File
@@ -18,4 +18,4 @@ const isLineComment = createTypeCheckFunction([
"InterpreterDirective",
]);
export default isLineComment;
export { isLineComment };
@@ -0,0 +1,71 @@
import printString from "../../utilities/print-string.js";
import { hasComment } from "./comments.js";
import { getRaw } from "./get-raw.js";
import { isSignedNumericLiteral } from "./is-signed-numeric-literal.js";
import { isLiteral, isStringLiteral } from "./node-types.js";
/**
@import {
Node,
} from "../types/estree.js";
*/
const LONE_SHORT_ARGUMENT_THRESHOLD_RATE = 0.25;
/**
* @param {Node} node
* @returns {boolean}
*/
function isLoneShortArgument(node, options) {
const { printWidth } = options;
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 printString(getRaw(node), options).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);
}
export { isLoneShortArgument };
@@ -0,0 +1,37 @@
import { isCallExpression } from "./node-types.js";
/**
@import {
Node,
NodeMap,
Comment,
NumericLiteral,
StringLiteral,
RegExpLiteral,
BigIntLiteral,
} from "../types/estree.js";
@import AstPath from "../../common/ast-path.js";
*/
// Logic to determine if a call is a “long curried function call”.
// See https://github.com/prettier/prettier/issues/1420.
//
// `connect(a, b, c)(d)`
// In the above call expression, the second call is the parent node and the
// first call is the current node.
/**
* @param {AstPath} path
* @returns {boolean}
*/
function isLongCurriedCallExpression(path) {
const { node, parent, key } = path;
return (
key === "callee" &&
isCallExpression(node) &&
isCallExpression(parent) &&
parent.arguments.length > 0 &&
node.arguments.length > parent.arguments.length
);
}
export { isLongCurriedCallExpression };
@@ -1,4 +1,4 @@
import getRaw from "./get-raw.js";
import { getRaw } from "./get-raw.js";
import { jsxWhitespace } from "./jsx-whitespace.js";
/**
+20
View File
@@ -0,0 +1,20 @@
import { isMemberExpression } from "./node-types.js";
/**
@import {
Node,
} from "../types/estree.js";
*/
/**
* @param {Node} node
* @returns {boolean}
*/
function isMemberish(node) {
return (
isMemberExpression(node) ||
(node.type === "BindExpression" && Boolean(node.object))
);
}
export { isMemberish };
+9
View File
@@ -0,0 +1,9 @@
function isMethod(node) {
return (
(node.method && node.kind === "init") ||
node.kind === "get" ||
node.kind === "set"
);
}
export { isMethod };
@@ -0,0 +1,29 @@
import isNextLineEmptyAfterIndex from "../../utilities/is-next-line-empty.js";
import { locEnd, locEndWithFullText } from "../loc.js";
/**
@import {
Node,
} from "../types/estree.js";
*/
/**
* @param {Node} node
* @returns {boolean}
*/
const isNextLineEmpty = (node, { originalText }) => {
const end = locEnd(node);
if (isNextLineEmptyAfterIndex(originalText, end)) {
return true;
}
const endWithSemicolon = locEndWithFullText(node);
if (endWithSemicolon === end) {
return false;
}
return isNextLineEmptyAfterIndex(originalText, endWithSemicolon);
};
export { isNextLineEmpty };
@@ -0,0 +1,15 @@
/**
@import {
Node,
} from "../types/estree.js";
*/
/**
* @param {Node} node
* @returns {boolean}
*/
function isNullishCoalescing(node) {
return node.type === "LogicalExpression" && node.operator === "??";
}
export { isNullishCoalescing };
@@ -0,0 +1,20 @@
import { isMethod } from "./is-method.js";
/**
@import {
Node,
} from "../types/estree.js";
*/
/**
* @param {Node} node
* @returns {boolean}
*/
function isObjectProperty(node) {
return (
node?.type === "ObjectProperty" ||
(node?.type === "Property" && !isMethod(node))
);
}
export { isObjectProperty };
@@ -0,0 +1,53 @@
import { hasSameLoc } from "../loc.js";
import { getRaw } from "./get-raw.js";
import { isStringLiteral } from "./node-types.js";
/**
@import {
Node,
} from "../types/estree.js";
*/
/**
* @param {Node} specifier
* @returns {boolean}
*/
function isShorthandSpecifier(specifier) {
if (
specifier.type !== "ImportSpecifier" &&
specifier.type !== "ExportSpecifier"
) {
return false;
}
const {
local,
// @ts-expect-error -- FIXME
[specifier.type === "ImportSpecifier" ? "imported" : "exported"]:
importedOrExported,
} = specifier;
if (
local.type !== importedOrExported.type ||
!hasSameLoc(local, importedOrExported)
) {
return false;
}
if (isStringLiteral(local)) {
return (
local.value === importedOrExported.value &&
getRaw(local) === getRaw(importedOrExported)
);
}
switch (local.type) {
case "Identifier":
return local.name === importedOrExported.name;
default:
/* c8 ignore next */
return false;
}
}
export { isShorthandSpecifier };
@@ -0,0 +1,23 @@
import { isNumericLiteral } from "./node-types.js";
/**
@import {
Node,
NodeMap,
NumericLiteral,
} from "../types/estree.js";
*/
/**
@param {Node} node
@returns {node is NodeMap["UnaryExpression"] & {operator: "+" | "-", argument: NumericLiteral}}
*/
function isSignedNumericLiteral(node) {
return (
node.type === "UnaryExpression" &&
(node.operator === "+" || node.operator === "-") &&
isNumericLiteral(node.argument)
);
}
export { isSignedNumericLiteral };
@@ -0,0 +1,111 @@
import getStringWidth from "../../utilities/get-string-width.js";
import { getCallArguments } from "./call-arguments.js";
import { createTypeCheckFunction } from "./create-type-check-function.js";
import {
isArrayExpression,
isCallLikeExpression,
isLiteral,
isMemberExpression,
isObjectExpression,
isRegExpLiteral,
} from "./node-types.js";
import { stripChainElementWrappers } from "./strip-chain-element-wrappers.js";
/**
@import {
Node,
} from "../types/estree.js";
*/
const simpleCallArgumentUnaryOperators = new Set(["!", "-", "+", "~"]);
const isSingleWordType = createTypeCheckFunction([
"Identifier",
"ThisExpression",
"Super",
"PrivateName",
"PrivateIdentifier",
]);
/**
* @param {Node} node
* @param {number} depth
* @returns {boolean}
*/
function isSimpleCallArgument(node, depth = 2) {
if (depth <= 0) {
return false;
}
const isChildSimple = (child) => isSimpleCallArgument(child, depth - 1);
node = stripChainElementWrappers(node);
if (isRegExpLiteral(node)) {
return (
// @ts-expect-error -- safe
getStringWidth(node.pattern ?? node.regex.pattern) <= 5
);
}
if (
isLiteral(node) ||
isSingleWordType(node) ||
node.type === "ArgumentPlaceholder"
) {
return true;
}
if (node.type === "TemplateLiteral") {
return (
node.quasis.every((element) => !element.value.raw.includes("\n")) &&
node.expressions.every(isChildSimple)
);
}
if (isObjectExpression(node)) {
return node.properties.every(
(property) =>
// @ts-expect-error -- FIXME
!property.computed &&
// @ts-expect-error -- FIXME
(property.shorthand ||
// @ts-expect-error -- FIXME
(property.value && isChildSimple(property.value))),
);
}
if (isArrayExpression(node)) {
return node.elements.every((x) => x === null || isChildSimple(x));
}
if (isCallLikeExpression(node)) {
if (
node.type === "ImportExpression" ||
isSimpleCallArgument(node.callee, depth)
) {
const args = getCallArguments(node);
return args.length <= depth && args.every(isChildSimple);
}
return false;
}
if (isMemberExpression(node)) {
return (
isSimpleCallArgument(node.object, depth) &&
isSimpleCallArgument(node.property, depth)
);
}
if (
(node.type === "UnaryExpression" &&
simpleCallArgumentUnaryOperators.has(node.operator)) ||
node.type === "UpdateExpression"
) {
return isSimpleCallArgument(node.argument, depth);
}
return false;
}
export { isSimpleCallArgument };
@@ -0,0 +1,30 @@
import isObject from "../../utilities/is-object.js";
function getExpressionInnerNodeCount(node, maxCount) {
let count = 0;
for (const k in node) {
const prop = node[k];
if (isObject(prop) && typeof prop.type === "string") {
count++;
count += getExpressionInnerNodeCount(prop, maxCount - count);
}
// Bail early to protect against bad performance.
if (count > maxCount) {
return count;
}
}
return count;
}
/**
* 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;
}
export { isSimpleExpressionByNodeCount };
@@ -0,0 +1,15 @@
import { createTypeCheckFunction } from "./create-type-check-function.js";
const isSimpleTypeAnnotation = createTypeCheckFunction([
"TSThisType",
// literals
"NullLiteralTypeAnnotation",
"BooleanLiteralTypeAnnotation",
"StringLiteralTypeAnnotation",
"BigIntLiteralTypeAnnotation",
"NumberLiteralTypeAnnotation",
"TSLiteralType",
"TSTemplateLiteralType",
]);
export { isSimpleTypeAnnotation };
@@ -0,0 +1,25 @@
import isFlowKeywordType from "./is-flow-keyword-type.js";
import { isSimpleTypeAnnotation } from "./is-simple-type-annotation.js";
import isTsKeywordType from "./is-ts-keyword-type.js";
/**
@import {
Node,
} from "../types/estree.js";
*/
/**
* @param {Node} node
* @returns {boolean}
*/
function isSimpleType(node) {
return (
isTsKeywordType(node) ||
isFlowKeywordType(node) ||
isSimpleTypeAnnotation(node) ||
(node.type === "GenericTypeAnnotation" && !node.typeParameters) ||
(node.type === "TSTypeReference" && !node.typeArguments)
);
}
export { isSimpleType };
@@ -0,0 +1,32 @@
import hasNewline from "../../utilities/has-newline.js";
import { locStart } from "../loc.js";
import { templateLiteralHasNewLines } from "./template-literal-has-new-lines.js";
/**
@import {
Node,
NodeMap,
Comment,
NumericLiteral,
StringLiteral,
RegExpLiteral,
BigIntLiteral,
} from "../types/estree.js";
@import AstPath from "../../common/ast-path.js";
*/
/**
* @param {NodeMap["TemplateLiteral"] | NodeMap["TaggedTemplateExpression"]} node
* @param {string} text
* @returns {boolean}
*/
function isTemplateOnItsOwnLine(node, text) {
return (
((node.type === "TemplateLiteral" && templateLiteralHasNewLines(node)) ||
(node.type === "TaggedTemplateExpression" &&
templateLiteralHasNewLines(node.quasi))) &&
!hasNewline(text, locStart(node), { backwards: true })
);
}
export { isTemplateOnItsOwnLine };
@@ -0,0 +1,15 @@
import { hasSameLocStart } from "../loc.js";
// Hack to differentiate between the following two which have the same ast
// declare function f(a): void;
// var f: (a) => void;
function isTypeAnnotationAFunction(node) {
return (
(node.type === "TypeAnnotation" || node.type === "TSTypeAnnotation") &&
node.typeAnnotation.type === "FunctionTypeAnnotation" &&
!node.static &&
!hasSameLocStart(node, node.typeAnnotation)
);
}
export { isTypeAnnotationAFunction };
@@ -1,4 +1,4 @@
import isBlockComment from "./is-block-comment.js";
import { isBlockComment } from "./is-block-comment.js";
/**
@import {Comment} from "../types/estree.js"
@@ -26,4 +26,4 @@ function isTypeCastComment(comment) {
return cache.get(comment);
}
export default isTypeCastComment;
export { isTypeCastComment };
+86
View File
@@ -0,0 +1,86 @@
import {
isBinaryCastExpression,
isCallExpression,
isChainElementWrapper,
isMemberExpression,
} from "./node-types.js";
/**
@import {
Node,
NodeMap,
Comment,
NumericLiteral,
StringLiteral,
RegExpLiteral,
BigIntLiteral,
} from "../types/estree.js";
@import AstPath from "../../common/ast-path.js";
*/
/**
* @param {Node} node
* @returns {boolean}
*/
function hasNakedLeftSide(node) {
return (
node.type === "AssignmentExpression" ||
node.type === "BinaryExpression" ||
node.type === "LogicalExpression" ||
node.type === "NGPipeExpression" ||
node.type === "ConditionalExpression" ||
isCallExpression(node) ||
isMemberExpression(node) ||
node.type === "SequenceExpression" ||
node.type === "TaggedTemplateExpression" ||
node.type === "BindExpression" ||
(node.type === "UpdateExpression" && !node.prefix) ||
isBinaryCastExpression(node) ||
isChainElementWrapper(node)
);
}
function getLeftSide(node) {
if (node.expressions) {
return node.expressions[0];
}
return (
node.left ??
node.test ??
node.callee ??
node.object ??
node.tag ??
node.argument ??
node.expression
);
}
function getLeftSidePathName(node) {
if (node.expressions) {
return ["expressions", 0];
}
if (node.left) {
return ["left"];
}
if (node.test) {
return ["test"];
}
if (node.object) {
return ["object"];
}
if (node.callee) {
return ["callee"];
}
if (node.tag) {
return ["tag"];
}
if (node.argument) {
return ["argument"];
}
if (node.expression) {
return ["expression"];
}
throw new Error("Unexpected node has no left side.");
}
export { getLeftSide, getLeftSidePathName, hasNakedLeftSide };
@@ -0,0 +1,24 @@
import { CommentCheckFlags, getComments, hasComment } from "./comments.js";
import { isBlockComment } from "./is-block-comment.js";
/**
@import {
Node,
} from "../types/estree.js";
*/
/**
* @param {Node} node
* @returns {boolean}
*/
function needsHardlineAfterDanglingComment(node) {
if (!hasComment(node)) {
return false;
}
const lastDanglingComment = getComments(node, CommentCheckFlags.Dangling).at(
-1,
);
return lastDanglingComment && !isBlockComment(lastDanglingComment);
}
export { needsHardlineAfterDanglingComment };
@@ -1,12 +1,9 @@
import hasNewlineInRange from "../../utilities/has-newline-in-range.js";
import { locEnd, locStart } from "../loc.js";
import { hasLeadingOwnLineComment } from "../utilities/has-leading-own-line-comment.js";
import { CommentCheckFlags, hasComment } from "./comments.js";
import { getLeftSide, hasNakedLeftSide } from "./left-side.js";
import { isJsxElement } from "./node-types.js";
import {
getLeftSide,
hasLeadingOwnLineComment,
hasNakedLeftSide,
} from "./utilities.js";
// This recurses the return argument, looking for the first token
// (the leftmost leaf node) and, if it (or its parents) has any
@@ -1,6 +1,6 @@
import { shouldExpressionStatementPrintLeadingSemicolon } from "../semicolon/semicolon.js";
import { CommentCheckFlags, getComments } from "./comments.js";
import isTypeCastComment from "./is-type-cast-comment.js";
import { isTypeCastComment } from "./is-type-cast-comment.js";
function shouldExpressionStatementPrintOwnComments(path, options) {
if (!shouldExpressionStatementPrintLeadingSemicolon(path, options)) {
@@ -0,0 +1,62 @@
import { getPrecedence } from "./get-precedence.js";
const equalityOperators = {
"==": true,
"!=": true,
"===": true,
"!==": true,
};
const multiplicativeOperators = {
"*": true,
"/": true,
"%": true,
};
const bitshiftOperators = {
">>": true,
">>>": true,
"<<": true,
};
function shouldFlatten(parentOp, nodeOp) {
if (getPrecedence(nodeOp) !== getPrecedence(parentOp)) {
return false;
}
// ** is right-associative
// x ** y ** z --> x ** (y ** z)
if (parentOp === "**") {
return false;
}
// x == y == z --> (x == y) == z
if (equalityOperators[parentOp] && equalityOperators[nodeOp]) {
return false;
}
// x * y % z --> (x * y) % z
if (
(nodeOp === "%" && multiplicativeOperators[parentOp]) ||
(parentOp === "%" && multiplicativeOperators[nodeOp])
) {
return false;
}
// x * y / z --> (x * y) / z
// x / y * z --> (x / y) * z
if (
nodeOp !== parentOp &&
multiplicativeOperators[nodeOp] &&
multiplicativeOperators[parentOp]
) {
return false;
}
// x << y << z --> (x << y) << z
if (bitshiftOperators[parentOp] && bitshiftOperators[nodeOp]) {
return false;
}
return true;
}
export { bitshiftOperators, shouldFlatten };
@@ -0,0 +1,13 @@
/**
* @param {any} options
* @param {("es5" | "all")} [level]
* @returns {boolean}
*/
function shouldPrintComma(options, level = "es5") {
return (
(options.trailingComma === "es5" && level === "es5") ||
(options.trailingComma === "all" && (level === "all" || level === "es5"))
);
}
export { shouldPrintComma };
@@ -0,0 +1,16 @@
import { isIntersectionType, isUnionType } from "./node-types.js";
function shouldUnionTypePrintOwnComments({ key, parent }) {
if (
// If it's `types` of union type, parent will print comment for it
(key === "types" && isUnionType(parent)) ||
// Inside intersection type let the comment print outside of parentheses
(key === "types" && isIntersectionType(parent))
) {
return false;
}
return true;
}
export { shouldUnionTypePrintOwnComments };
@@ -0,0 +1,68 @@
/**
@import {
Node,
} from "../types/estree.js";
*/
/**
* Tests if the leftmost node of the expression matches the predicate. E.g.,
* used to check whether an expression statement needs to be wrapped in extra
* parentheses because it starts with:
*
* - `{`
* - `function`, `class`, or `do {}`
* - `let[`
*
* Will be overzealous if there already are necessary grouping parentheses.
*
* @param {Node} node
* @param {(leftmostNode: Node) => boolean} predicate
* @returns {boolean}
*/
function startsWithNoLookaheadToken(node, predicate) {
switch (node.type) {
case "BinaryExpression":
case "LogicalExpression":
case "AssignmentExpression":
case "NGPipeExpression":
return startsWithNoLookaheadToken(node.left, predicate);
case "MemberExpression":
case "OptionalMemberExpression":
return startsWithNoLookaheadToken(node.object, predicate);
case "TaggedTemplateExpression":
if (node.tag.type === "FunctionExpression") {
// IIFEs are always already parenthesized
return false;
}
return startsWithNoLookaheadToken(node.tag, predicate);
case "CallExpression":
case "OptionalCallExpression":
if (node.callee.type === "FunctionExpression") {
// IIFEs are always already parenthesized
return false;
}
return startsWithNoLookaheadToken(node.callee, predicate);
case "ConditionalExpression":
return startsWithNoLookaheadToken(node.test, predicate);
case "UpdateExpression":
return (
!node.prefix && startsWithNoLookaheadToken(node.argument, predicate)
);
case "BindExpression":
return node.object && startsWithNoLookaheadToken(node.object, predicate);
case "SequenceExpression":
return startsWithNoLookaheadToken(node.expressions[0], predicate);
case "ChainExpression":
case "TSNonNullExpression":
case "TSSatisfiesExpression":
case "TSAsExpression":
case "AsExpression":
case "AsConstExpression":
case "SatisfiesExpression":
return startsWithNoLookaheadToken(node.expression, predicate);
default:
return predicate(node);
}
}
export { startsWithNoLookaheadToken };
@@ -0,0 +1,22 @@
import { isChainElementWrapper } from "./node-types.js";
/**
@import {
Node,
NodeMap,
} from "../types/estree.js";
*/
/**
@param {Node} node
@returns {Exclude<Node, NodeMap["ChainExpression"] | NodeMap["TSNonNullExpression"]>}
*/
function stripChainElementWrappers(node) {
while (isChainElementWrapper(node)) {
node = node.expression;
}
return node;
}
export { stripChainElementWrappers };
@@ -0,0 +1,22 @@
/**
@import {
Node,
NodeMap,
Comment,
NumericLiteral,
StringLiteral,
RegExpLiteral,
BigIntLiteral,
} from "../types/estree.js";
@import AstPath from "../../common/ast-path.js";
*/
/**
* @param {NodeMap["TemplateLiteral"]} template
* @returns {boolean}
*/
function templateLiteralHasNewLines(template) {
return template.quasis.some((quasi) => quasi.value.raw.includes("\n"));
}
export { templateLiteralHasNewLines };
+2 -1
View File
@@ -1,3 +1,5 @@
import { getCallArguments } from "./call-arguments.js";
import { getFunctionParameters } from "./function-parameters.js";
import { isNodeMatches } from "./is-node-matches.js";
import {
isCallExpression,
@@ -5,7 +7,6 @@ import {
isNumericLiteral,
isStringLiteral,
} from "./node-types.js";
import { getCallArguments, getFunctionParameters } from "./utilities.js";
/**
@import {
-920
View File
@@ -1,920 +0,0 @@
import { hasDescendant } from "../../utilities/ast.js";
import getStringWidth from "../../utilities/get-string-width.js";
import hasNewline from "../../utilities/has-newline.js";
import isNextLineEmptyAfterIndex from "../../utilities/is-next-line-empty.js";
import isObject from "../../utilities/is-object.js";
import printString from "../../utilities/print-string.js";
import {
hasSameLoc,
hasSameLocStart,
locEnd,
locEndWithFullText,
locStart,
} from "../loc.js";
import getVisitorKeys from "../traverse/get-visitor-keys.js";
import { CommentCheckFlags, getComments, hasComment } from "./comments.js";
import { createTypeCheckFunction } from "./create-type-check-function.js";
import getRaw from "./get-raw.js";
import { hasNodeIgnoreComment } from "./has-node-ignore-comment.js";
import isBlockComment from "./is-block-comment.js";
import isFlowKeywordType from "./is-flow-keyword-type.js";
import isTsKeywordType from "./is-ts-keyword-type.js";
import {
isArrayExpression,
isBinaryCastExpression,
isCallExpression,
isCallLikeExpression,
isChainElementWrapper,
isFunctionOrArrowExpression,
isIntersectionType,
isJsxElement,
isLiteral,
isMemberExpression,
isNumericLiteral,
isObjectExpression,
isRegExpLiteral,
isStringLiteral,
isUnionType,
} from "./node-types.js";
/**
@import {
Node,
NodeMap,
Comment,
NumericLiteral,
StringLiteral,
RegExpLiteral,
BigIntLiteral,
} from "../types/estree.js";
@import AstPath from "../../common/ast-path.js";
*/
/**
* @param {Node} node
* @param {(node: Node) => boolean} predicate
* @returns {boolean}
*/
function hasNode(node, predicate) {
return predicate(node) || hasDescendant(node, { getVisitorKeys, predicate });
}
/**
* @param {Node} node
* @returns {boolean}
*/
function hasNakedLeftSide(node) {
return (
node.type === "AssignmentExpression" ||
node.type === "BinaryExpression" ||
node.type === "LogicalExpression" ||
node.type === "NGPipeExpression" ||
node.type === "ConditionalExpression" ||
isCallExpression(node) ||
isMemberExpression(node) ||
node.type === "SequenceExpression" ||
node.type === "TaggedTemplateExpression" ||
node.type === "BindExpression" ||
(node.type === "UpdateExpression" && !node.prefix) ||
isBinaryCastExpression(node) ||
isChainElementWrapper(node)
);
}
function getLeftSide(node) {
if (node.expressions) {
return node.expressions[0];
}
return (
node.left ??
node.test ??
node.callee ??
node.object ??
node.tag ??
node.argument ??
node.expression
);
}
function getLeftSidePathName(node) {
if (node.expressions) {
return ["expressions", 0];
}
if (node.left) {
return ["left"];
}
if (node.test) {
return ["test"];
}
if (node.object) {
return ["object"];
}
if (node.callee) {
return ["callee"];
}
if (node.tag) {
return ["tag"];
}
if (node.argument) {
return ["argument"];
}
if (node.expression) {
return ["expression"];
}
throw new Error("Unexpected node has no left side.");
}
/**
* @param {Node} node
* @returns {boolean}
*/
function isNullishCoalescing(node) {
return node.type === "LogicalExpression" && node.operator === "??";
}
/**
@param {Node} node
@returns {node is NodeMap["UnaryExpression"] & {operator: "+" | "-", argument: NumericLiteral}}
*/
function isSignedNumericLiteral(node) {
return (
node.type === "UnaryExpression" &&
(node.operator === "+" || node.operator === "-") &&
isNumericLiteral(node.argument)
);
}
const isSingleWordType = createTypeCheckFunction([
"Identifier",
"ThisExpression",
"Super",
"PrivateName",
"PrivateIdentifier",
]);
function isMethod(node) {
return (
(node.method && node.kind === "init") ||
node.kind === "get" ||
node.kind === "set"
);
}
/**
* @param {Node} node
* @returns {boolean}
*/
function isFlowObjectTypePropertyAFunction(node) {
return (
(node.type === "ObjectTypeProperty" ||
node.type === "ObjectTypeInternalSlot") &&
!node.static &&
!node.method &&
// @ts-expect-error -- exists on `ObjectTypeProperty` but not `ObjectTypeInternalSlot`
node.kind !== "get" &&
// @ts-expect-error -- exists on `ObjectTypeProperty` but not `ObjectTypeInternalSlot`
node.kind !== "set" &&
node.value.type === "FunctionTypeAnnotation"
);
}
// Hack to differentiate between the following two which have the same ast
// declare function f(a): void;
// var f: (a) => void;
function isTypeAnnotationAFunction(node) {
return (
(node.type === "TypeAnnotation" || node.type === "TSTypeAnnotation") &&
node.typeAnnotation.type === "FunctionTypeAnnotation" &&
!node.static &&
!hasSameLocStart(node, node.typeAnnotation)
);
}
/**
* @param {Node} node
* @returns {boolean}
*/
function isMemberish(node) {
return (
isMemberExpression(node) ||
(node.type === "BindExpression" && Boolean(node.object))
);
}
const isSimpleTypeAnnotation = createTypeCheckFunction([
"TSThisType",
// literals
"NullLiteralTypeAnnotation",
"BooleanLiteralTypeAnnotation",
"StringLiteralTypeAnnotation",
"BigIntLiteralTypeAnnotation",
"NumberLiteralTypeAnnotation",
"TSLiteralType",
"TSTemplateLiteralType",
]);
/**
* @param {Node} node
* @returns {boolean}
*/
function isSimpleType(node) {
return (
isTsKeywordType(node) ||
isFlowKeywordType(node) ||
isSimpleTypeAnnotation(node) ||
(node.type === "GenericTypeAnnotation" && !node.typeParameters) ||
(node.type === "TSTypeReference" && !node.typeArguments)
);
}
/**
* 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 (isObject(prop) && 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, options) {
const { printWidth } = options;
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 printString(getRaw(node), options).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);
}
/**
* @param {string} text
* @param {Node} node
* @returns {boolean}
*/
function hasLeadingOwnLineComment(text, node) {
if (isJsxElement(node)) {
return hasNodeIgnoreComment(node);
}
return hasComment(node, CommentCheckFlags.Leading, (comment) =>
hasNewline(text, locEnd(comment)),
);
}
/**
* @param {NodeMap["TemplateLiteral"]} template
* @returns {boolean}
*/
function templateLiteralHasNewLines(template) {
return template.quasis.some((quasi) => quasi.value.raw.includes("\n"));
}
/**
* @param {NodeMap["TemplateLiteral"] | NodeMap["TaggedTemplateExpression"]} node
* @param {string} text
* @returns {boolean}
*/
function isTemplateOnItsOwnLine(node, text) {
return (
((node.type === "TemplateLiteral" && templateLiteralHasNewLines(node)) ||
(node.type === "TaggedTemplateExpression" &&
templateLiteralHasNewLines(node.quasi))) &&
!hasNewline(text, locStart(node), { backwards: true })
);
}
/**
* @param {Node} node
* @returns {boolean}
*/
function needsHardlineAfterDanglingComment(node) {
if (!hasComment(node)) {
return false;
}
const lastDanglingComment = getComments(node, CommentCheckFlags.Dangling).at(
-1,
);
return lastDanglingComment && !isBlockComment(lastDanglingComment);
}
// Logic to check for args with multiple anonymous functions. For instance,
// the following call should be split on multiple lines for readability:
// source.pipe(map((x) => x + x), filter((x) => x % 2 === 0))
function isFunctionCompositionArgs(args) {
if (args.length <= 1) {
return false;
}
let count = 0;
for (let arg of args) {
if (isFunctionOrArrowExpression(arg)) {
count += 1;
if (count > 1) {
return true;
}
} else {
arg = stripChainElementWrappers(arg);
if (isCallExpression(arg)) {
for (const childArg of getCallArguments(arg)) {
if (isFunctionOrArrowExpression(childArg)) {
return true;
}
}
}
}
}
return false;
}
// Logic to determine if a call is a “long curried function call”.
// See https://github.com/prettier/prettier/issues/1420.
//
// `connect(a, b, c)(d)`
// In the above call expression, the second call is the parent node and the
// first call is the current node.
/**
* @param {AstPath} path
* @returns {boolean}
*/
function isLongCurriedCallExpression(path) {
const { node, parent, key } = path;
return (
key === "callee" &&
isCallExpression(node) &&
isCallExpression(parent) &&
parent.arguments.length > 0 &&
node.arguments.length > parent.arguments.length
);
}
const simpleCallArgumentUnaryOperators = new Set(["!", "-", "+", "~"]);
/**
* @param {any} node
* @param {number} depth
* @returns {boolean}
*/
function isSimpleCallArgument(node, depth = 2) {
if (depth <= 0) {
return false;
}
const isChildSimple = (child) => isSimpleCallArgument(child, depth - 1);
node = stripChainElementWrappers(node);
if (isRegExpLiteral(node)) {
return (
// @ts-expect-error -- safe
getStringWidth(node.pattern ?? node.regex.pattern) <= 5
);
}
if (
isLiteral(node) ||
isSingleWordType(node) ||
node.type === "ArgumentPlaceholder"
) {
return true;
}
if (node.type === "TemplateLiteral") {
return (
node.quasis.every((element) => !element.value.raw.includes("\n")) &&
node.expressions.every(isChildSimple)
);
}
if (isObjectExpression(node)) {
return node.properties.every(
(property) =>
// @ts-expect-error -- FIXME
!property.computed &&
// @ts-expect-error -- FIXME
(property.shorthand ||
// @ts-expect-error -- FIXME
(property.value && isChildSimple(property.value))),
);
}
if (isArrayExpression(node)) {
return node.elements.every((x) => x === null || isChildSimple(x));
}
if (isCallLikeExpression(node)) {
if (
node.type === "ImportExpression" ||
isSimpleCallArgument(node.callee, depth)
) {
const args = getCallArguments(node);
return args.length <= depth && args.every(isChildSimple);
}
return false;
}
if (isMemberExpression(node)) {
return (
isSimpleCallArgument(node.object, depth) &&
isSimpleCallArgument(node.property, depth)
);
}
if (
(node.type === "UnaryExpression" &&
simpleCallArgumentUnaryOperators.has(node.operator)) ||
node.type === "UpdateExpression"
) {
return isSimpleCallArgument(node.argument, depth);
}
return false;
}
/**
* @param {any} options
* @param {("es5" | "all")} [level]
* @returns {boolean}
*/
function shouldPrintComma(options, level = "es5") {
return (
(options.trailingComma === "es5" && level === "es5") ||
(options.trailingComma === "all" && (level === "all" || level === "es5"))
);
}
/**
* Tests if the leftmost node of the expression matches the predicate. E.g.,
* used to check whether an expression statement needs to be wrapped in extra
* parentheses because it starts with:
*
* - `{`
* - `function`, `class`, or `do {}`
* - `let[`
*
* Will be overzealous if there already are necessary grouping parentheses.
*
* @param {Node} node
* @param {(leftmostNode: Node) => boolean} predicate
* @returns {boolean}
*/
function startsWithNoLookaheadToken(node, predicate) {
switch (node.type) {
case "BinaryExpression":
case "LogicalExpression":
case "AssignmentExpression":
case "NGPipeExpression":
return startsWithNoLookaheadToken(node.left, predicate);
case "MemberExpression":
case "OptionalMemberExpression":
return startsWithNoLookaheadToken(node.object, predicate);
case "TaggedTemplateExpression":
if (node.tag.type === "FunctionExpression") {
// IIFEs are always already parenthesized
return false;
}
return startsWithNoLookaheadToken(node.tag, predicate);
case "CallExpression":
case "OptionalCallExpression":
if (node.callee.type === "FunctionExpression") {
// IIFEs are always already parenthesized
return false;
}
return startsWithNoLookaheadToken(node.callee, predicate);
case "ConditionalExpression":
return startsWithNoLookaheadToken(node.test, predicate);
case "UpdateExpression":
return (
!node.prefix && startsWithNoLookaheadToken(node.argument, predicate)
);
case "BindExpression":
return node.object && startsWithNoLookaheadToken(node.object, predicate);
case "SequenceExpression":
return startsWithNoLookaheadToken(node.expressions[0], predicate);
case "ChainExpression":
case "TSNonNullExpression":
case "TSSatisfiesExpression":
case "TSAsExpression":
case "AsExpression":
case "AsConstExpression":
case "SatisfiesExpression":
return startsWithNoLookaheadToken(node.expression, predicate);
default:
return predicate(node);
}
}
const equalityOperators = {
"==": true,
"!=": true,
"===": true,
"!==": true,
};
const multiplicativeOperators = {
"*": true,
"/": true,
"%": true,
};
const bitshiftOperators = {
">>": true,
">>>": true,
"<<": true,
};
function shouldFlatten(parentOp, nodeOp) {
if (getPrecedence(nodeOp) !== getPrecedence(parentOp)) {
return false;
}
// ** is right-associative
// x ** y ** z --> x ** (y ** z)
if (parentOp === "**") {
return false;
}
// x == y == z --> (x == y) == z
if (equalityOperators[parentOp] && equalityOperators[nodeOp]) {
return false;
}
// x * y % z --> (x * y) % z
if (
(nodeOp === "%" && multiplicativeOperators[parentOp]) ||
(parentOp === "%" && multiplicativeOperators[nodeOp])
) {
return false;
}
// x * y / z --> (x * y) / z
// x / y * z --> (x / y) * z
if (
nodeOp !== parentOp &&
multiplicativeOperators[nodeOp] &&
multiplicativeOperators[parentOp]
) {
return false;
}
// x << y << z --> (x << y) << z
if (bitshiftOperators[parentOp] && bitshiftOperators[nodeOp]) {
return false;
}
return true;
}
const PRECEDENCE = new Map(
[
["|>"],
["??"],
["||"],
["&&"],
["|"],
["^"],
["&"],
["==", "===", "!=", "!=="],
["<", ">", "<=", ">=", "in", "instanceof"],
[">>", "<<", ">>>"],
["+", "-"],
["*", "/", "%"],
["**"],
].flatMap((operators, index) =>
operators.map((operator) => [operator, index]),
),
);
function getPrecedence(operator) {
return PRECEDENCE.get(operator);
}
function isBitwiseOperator(operator) {
return (
Boolean(bitshiftOperators[operator]) ||
operator === "|" ||
operator === "^" ||
operator === "&"
);
}
function hasRestParameter(node) {
if (node.rest) {
return true;
}
const parameters = getFunctionParameters(node);
return parameters.at(-1)?.type === "RestElement";
}
const functionParametersCache = new WeakMap();
function getFunctionParameters(node) {
if (functionParametersCache.has(node)) {
return functionParametersCache.get(node);
}
const parameters = [];
if (node.this) {
parameters.push(node.this);
}
parameters.push(...node.params);
if (node.rest) {
parameters.push(node.rest);
}
functionParametersCache.set(node, parameters);
return parameters;
}
function iterateFunctionParametersPath(path, iteratee) {
const { node } = path;
let index = 0;
const callback = () => iteratee(path, index++);
if (node.this) {
path.call(callback, "this");
}
path.each(callback, "params");
if (node.rest) {
path.call(callback, "rest");
}
}
const callArgumentsCache = new WeakMap();
function getCallArguments(node) {
if (callArgumentsCache.has(node)) {
return callArgumentsCache.get(node);
}
let args;
if (node.type === "ImportExpression" || node.type === "TSImportType") {
args = [node.source];
if (node.options) {
args.push(node.options);
}
} else if (node.type === "TSExternalModuleReference") {
args = [node.expression];
} else {
args = node.arguments;
}
callArgumentsCache.set(node, args);
return args;
}
function iterateCallArgumentsPath(path, iteratee) {
const { node } = path;
if (node.type === "ImportExpression" || node.type === "TSImportType") {
path.call(() => iteratee(path, 0), "source");
if (node.options) {
path.call(() => iteratee(path, 1), "options");
}
} else if (node.type === "TSExternalModuleReference") {
path.call(() => iteratee(path, 0), "expression");
} else {
path.each(iteratee, "arguments");
}
}
function getCallArgumentSelector(node, index) {
if (node.type === "ImportExpression" || node.type === "TSImportType") {
if (index === 0 || index === (node.options ? -2 : -1)) {
return ["source"];
}
if (node.options && (index === 1 || index === -1)) {
return ["options"];
}
throw new RangeError("Invalid argument index");
} else if (node.type === "TSExternalModuleReference") {
if (index === 0 || index === -1) {
return ["expression"];
}
} else {
if (index < 0) {
index = node.arguments.length + index;
}
if (index >= 0 && index < node.arguments.length) {
return ["arguments", index];
}
}
/* c8 ignore next */
throw new RangeError("Invalid argument index");
}
/**
* @param {Node} node
* @returns {boolean}
*/
const isNextLineEmpty = (node, { originalText }) => {
const end = locEnd(node);
if (isNextLineEmptyAfterIndex(originalText, end)) {
return true;
}
const endWithSemicolon = locEndWithFullText(node);
if (endWithSemicolon === end) {
return false;
}
return isNextLineEmptyAfterIndex(originalText, endWithSemicolon);
};
function isObjectProperty(node) {
return (
node &&
(node.type === "ObjectProperty" ||
(node.type === "Property" && !isMethod(node)))
);
}
const isTsAsConstExpression = (node) =>
node?.type === "TSAsExpression" &&
node.typeAnnotation.type === "TSTypeReference" &&
node.typeAnnotation.typeName.type === "Identifier" &&
node.typeAnnotation.typeName.name === "const";
function shouldUnionTypePrintOwnComments({ key, parent }) {
if (
// If it's `types` of union type, parent will print comment for it
(key === "types" && isUnionType(parent)) ||
// Inside intersection type let the comment print outside of parentheses
(key === "types" && isIntersectionType(parent))
) {
return false;
}
return true;
}
/**
@returns {boolean}
*/
function isBooleanTypeCoercion(node) {
return (
node.type === "CallExpression" &&
!node.optional &&
node.arguments.length === 1 &&
node.callee.type === "Identifier" &&
node.callee.name === "Boolean"
);
}
function isShorthandSpecifier(specifier) {
if (
specifier.type !== "ImportSpecifier" &&
specifier.type !== "ExportSpecifier"
) {
return false;
}
const {
local,
[specifier.type === "ImportSpecifier" ? "imported" : "exported"]:
importedOrExported,
} = specifier;
if (
local.type !== importedOrExported.type ||
!hasSameLoc(local, importedOrExported)
) {
return false;
}
if (isStringLiteral(local)) {
return (
local.value === importedOrExported.value &&
getRaw(local) === getRaw(importedOrExported)
);
}
switch (local.type) {
case "Identifier":
return local.name === importedOrExported.name;
default:
/* c8 ignore next */
return false;
}
}
function isIifeCalleeOrTaggedTemplateExpressionTag(path) {
const { node } = path;
return (
(node.type === "FunctionExpression" ||
node.type === "ArrowFunctionExpression") &&
((path.key === "callee" && isCallExpression(path.parent)) ||
(path.key === "tag" && path.parent.type === "TaggedTemplateExpression"))
);
}
/**
@param {Node} node
@returns {Exclude<Node, NodeMap["ChainExpression"] | NodeMap["TSNonNullExpression"]>}
*/
function stripChainElementWrappers(node) {
while (isChainElementWrapper(node)) {
node = node.expression;
}
return node;
}
export {
getCallArguments,
getCallArgumentSelector,
getFunctionParameters,
getLeftSide,
getLeftSidePathName,
getPrecedence,
hasLeadingOwnLineComment,
hasNakedLeftSide,
hasNode,
hasRestParameter,
isBitwiseOperator,
isBooleanTypeCoercion,
isFlowObjectTypePropertyAFunction,
isFunctionCompositionArgs,
isIifeCalleeOrTaggedTemplateExpressionTag,
isLoneShortArgument,
isLongCurriedCallExpression,
isMemberish,
isMethod,
isNextLineEmpty,
isNullishCoalescing,
isObjectProperty,
isShorthandSpecifier,
isSignedNumericLiteral,
isSimpleCallArgument,
isSimpleExpressionByNodeCount,
isSimpleType,
isTemplateOnItsOwnLine,
isTsAsConstExpression,
isTypeAnnotationAFunction,
iterateCallArgumentsPath,
iterateFunctionParametersPath,
needsHardlineAfterDanglingComment,
shouldFlatten,
shouldPrintComma,
shouldUnionTypePrintOwnComments,
startsWithNoLookaheadToken,
stripChainElementWrappers,
};