Extract logic related to js node location (#18849)

This commit is contained in:
fisker Cheung authored and GitHub committed 2026-02-03 08:59:13 +08:00
1 parent f0a706d88b
commit 6f1d135768
43 files changed
+186 -144

No files matched your search

@@ -1,5 +1,5 @@
import { addLeadingComment } from "../../../main/comments/utilities.js";
import { locStart } from "../../loc.js";
import { locStart } from "../../location/index.js";
import { stripComments } from "../../utilities/strip-comments.js";
function handleForXStatementComments({
@@ -5,7 +5,7 @@ import {
} from "../../../main/comments/utilities.js";
import getNextNonSpaceNonCommentCharacter from "../../../utilities/get-next-non-space-non-comment-character.js";
import hasNewlineInRange from "../../../utilities/has-newline-in-range.js";
import { locEnd, locStart } from "../../loc.js";
import { locEnd, locStart } from "../../location/index.js";
import { stripComments } from "../../utilities/strip-comments.js";
import { isSingleLineComment } from "./utilities.js";
@@ -3,7 +3,7 @@ import {
addTrailingComment,
} from "../../../main/comments/utilities.js";
import getNextNonSpaceNonCommentCharacter from "../../../utilities/get-next-non-space-non-comment-character.js";
import { locEnd } from "../../loc.js";
import { locEnd } from "../../location/index.js";
/**
@import {CommentContext} from "../handle-comments.js"
+1 -1
View File
@@ -3,7 +3,7 @@ import {
addLeadingComment,
} from "../../../main/comments/utilities.js";
import hasNewlineInRange from "../../../utilities/has-newline-in-range.js";
import { locEnd, locStart } from "../../loc.js";
import { locEnd, locStart } from "../../location/index.js";
import { isLineComment } from "../../utilities/comment-types.js";
/**
+1 -1
View File
@@ -8,7 +8,7 @@ import getNextNonSpaceNonCommentCharacterIndex from "../../utilities/get-next-no
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 { locEnd, locStart } from "../location/index.js";
import { getCallArguments } from "../utilities/call-arguments.js";
import { isInsideCallOrNewExpressionParentheses } from "../utilities/call-or-new-expression-parentheses.js";
import { isBlockComment, isLineComment } from "../utilities/comment-types.js";
-107
View File
@@ -1,107 +0,0 @@
/**
@import {Node, Comment} from "./types/estree.js";
*/
const isIndex = (value) => Number.isInteger(value) && value >= 0;
function locStart(node) {
const start = node.range?.[0] ?? node.start;
/* c8 ignore next 3 */
if (process.env.NODE_ENV !== "production" && !isIndex(start)) {
throw new TypeError("Can't not locate node.");
}
// Handle nodes with decorators. They should start at the first decorator
const firstDecorator = (node.declaration?.decorators ?? node.decorators)?.[0];
if (firstDecorator) {
return Math.min(locStart(firstDecorator), start);
}
return start;
}
/**
@param {Node | Comment} node
@return {number}
*/
function locEnd(node) {
if (node.type === "BreakStatement" || node.type === "ContinueStatement") {
const start = locStart(node);
return node.label
? locEnd(node.label)
: start +
(node.type === "BreakStatement" ? "break".length : "continue".length);
}
if (node.type === "DebuggerStatement") {
return locStart(node) + "debugger".length;
}
if (node.type === "VariableDeclaration") {
const lastDeclaration = node.declarations.at(-1);
return locEnd(lastDeclaration);
}
if (node.type === "IfStatement") {
return locEnd(node.alternate ?? node.consequent);
}
if (
(node.type === "ExpressionStatement" ||
node.type === "Directive" ||
node.type === "ImportDeclaration" ||
node.type === "ExportDefaultDeclaration" ||
node.type === "ExportNamedDeclaration" ||
node.type === "ExportAllDeclaration" ||
node.type === "ReturnStatement" ||
node.type === "ThrowStatement") &&
node.__contentEnd
) {
return node.__contentEnd;
}
return locEndWithFullText(node);
}
function locEndWithFullText(node) {
const end = node.range?.[1] ?? node.end;
/* c8 ignore next 3 */
if (process.env.NODE_ENV !== "production" && !isIndex(end)) {
throw new TypeError("Can't not locate node.");
}
return end;
}
/**
* @param {Node} nodeA
* @param {Node} nodeB
* @returns {boolean}
*/
function hasSameLocStart(nodeA, nodeB) {
const nodeAStart = locStart(nodeA);
return isIndex(nodeAStart) && nodeAStart === locStart(nodeB);
}
/**
* @param {Node} nodeA
* @param {Node} nodeB
* @returns {boolean}
*/
function hasSameLocEnd(nodeA, nodeB) {
const nodeAEnd = locEnd(nodeA);
return isIndex(nodeAEnd) && nodeAEnd === locEnd(nodeB);
}
/**
* @param {Node} nodeA
* @param {Node} nodeB
* @returns {boolean}
*/
function hasSameLoc(nodeA, nodeB) {
return hasSameLocStart(nodeA, nodeB) && hasSameLocEnd(nodeA, nodeB);
}
export { hasSameLoc, hasSameLocStart, locEnd, locEndWithFullText, locStart };
+38
View File
@@ -0,0 +1,38 @@
import { locEnd } from "./end.js";
import { isIndex } from "./is-index.js";
import { locStart } from "./start.js";
/**
@import {Node, Comment} from "../types/estree.js";
*/
/**
* @param {Node} nodeA
* @param {Node} nodeB
* @returns {boolean}
*/
function hasSameLocStart(nodeA, nodeB) {
const nodeAStart = locStart(nodeA);
return isIndex(nodeAStart) && nodeAStart === locStart(nodeB);
}
/**
* @param {Node} nodeA
* @param {Node} nodeB
* @returns {boolean}
*/
function hasSameLocEnd(nodeA, nodeB) {
const nodeAEnd = locEnd(nodeA);
return isIndex(nodeAEnd) && nodeAEnd === locEnd(nodeB);
}
/**
* @param {Node} nodeA
* @param {Node} nodeB
* @returns {boolean}
*/
function hasSameLoc(nodeA, nodeB) {
return hasSameLocStart(nodeA, nodeB) && hasSameLocEnd(nodeA, nodeB);
}
export { hasSameLoc, hasSameLocStart };
@@ -0,0 +1,23 @@
import { isIndex } from "./is-index.js";
/**
@import {Node, Comment} from "../types/estree.js";
*/
/**
@param {Node | Comment} node
@return {number}
*/
function locEndWithFullText(node) {
// @ts-expect-error -- safe
const end = node.range?.[1] ?? node.end;
/* c8 ignore next 3 */
if (process.env.NODE_ENV !== "production" && !isIndex(end)) {
throw new TypeError("Can't not locate node.");
}
return end;
}
export { locEndWithFullText };
+51
View File
@@ -0,0 +1,51 @@
import { locEndWithFullText } from "./end-with-full-text.js";
import { locStart } from "./start.js";
/**
@import {Node, Comment} from "../types/estree.js";
*/
/**
@param {Node | Comment} node
@return {number}
*/
function locEnd(node) {
if (node.type === "BreakStatement" || node.type === "ContinueStatement") {
const start = locStart(node);
return node.label
? locEnd(node.label)
: start +
(node.type === "BreakStatement" ? "break".length : "continue".length);
}
if (node.type === "DebuggerStatement") {
return locStart(node) + "debugger".length;
}
if (node.type === "VariableDeclaration") {
const lastDeclaration = node.declarations.at(-1);
return locEnd(lastDeclaration);
}
if (node.type === "IfStatement") {
return locEnd(node.alternate ?? node.consequent);
}
if (
(node.type === "ExpressionStatement" ||
node.type === "Directive" ||
node.type === "ImportDeclaration" ||
node.type === "ExportDefaultDeclaration" ||
node.type === "ExportNamedDeclaration" ||
node.type === "ExportAllDeclaration" ||
node.type === "ReturnStatement" ||
node.type === "ThrowStatement") &&
node.__contentEnd
) {
return node.__contentEnd;
}
return locEndWithFullText(node);
}
export { locEnd };
+4
View File
@@ -0,0 +1,4 @@
export { hasSameLoc, hasSameLocStart } from "./comparison.js";
export { locEnd } from "./end.js";
export { locEndWithFullText } from "./end-with-full-text.js";
export { locStart } from "./start.js";
+3
View File
@@ -0,0 +1,3 @@
const isIndex = (value) => Number.isInteger(value) && value >= 0;
export { isIndex };
+30
View File
@@ -0,0 +1,30 @@
import { isIndex } from "./is-index.js";
/**
@import {Node, Comment} from "../types/estree.js";
*/
/**
@param {Node | Comment} node
@return {number}
*/
function locStart(node) {
// @ts-expect-error -- safe
const start = node.range?.[0] ?? node.start;
/* c8 ignore next 3 */
if (process.env.NODE_ENV !== "production" && !isIndex(start)) {
throw new TypeError("Can't not locate node.");
}
// Handle nodes with decorators. They should start at the first decorator
// @ts-expect-error -- safe
const firstDecorator = (node.declaration?.decorators ?? node.decorators)?.[0];
if (firstDecorator) {
return Math.min(locStart(firstDecorator), start);
}
return start;
}
export { locStart };
+1 -1
View File
@@ -5,7 +5,7 @@ import {
parseTemplateBindings,
} from "angular-estree-parser";
import createError from "../../common/parser-create-error.js";
import { locEnd, locStart } from "../loc.js";
import { locEnd, locStart } from "../location/index.js";
import wrapExpression from "./utilities/wrap-expression.js";
/**
+1 -1
View File
@@ -1,6 +1,6 @@
import * as assert from "#universal/assert";
import { commentsPropertyInOptions } from "../../../constants.js";
import { locEnd, locEndWithFullText, locStart } from "../../loc.js";
import { locEnd, locEndWithFullText, locStart } from "../../location/index.js";
import {
isBlockComment,
isLineComment,
@@ -1,4 +1,4 @@
import { locEnd, locStart } from "../../loc.js";
import { locEnd, locStart } from "../../location/index.js";
import {
isBlockComment,
isLineComment,
@@ -1,4 +1,4 @@
import { locEnd, locStart } from "../../loc.js";
import { locEnd, locStart } from "../../location/index.js";
import { hasIgnorePragma, hasPragma } from "../../pragma.js";
function createParser(options) {
+1 -1
View File
@@ -12,7 +12,7 @@ import hasNewline from "../../utilities/has-newline.js";
import isNextLineEmptyAfterIndex from "../../utilities/is-next-line-empty.js";
import skipInlineComment from "../../utilities/skip-inline-comment.js";
import skipTrailingComment from "../../utilities/skip-trailing-comment.js";
import { locEnd, locStart } from "../loc.js";
import { locEnd, locStart } from "../location/index.js";
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import { isSignedNumericLiteral } from "../utilities/is-signed-numeric-literal.js";
import {
+1 -1
View File
@@ -9,7 +9,7 @@ import {
import { printDanglingComments } from "../../main/comments/print.js";
import hasNewline from "../../utilities/has-newline.js";
import hasNewlineInRange from "../../utilities/has-newline-in-range.js";
import { locEnd, locStart } from "../loc.js";
import { locEnd, locStart } from "../location/index.js";
import { iterateClassMembersPath } from "../utilities/class-members.js";
import {
CommentCheckFlags,
+1 -1
View File
@@ -1,7 +1,7 @@
import { hardline, indent, line } from "../../document/index.js";
import hasNewline from "../../utilities/has-newline.js";
import hasNewlineInRange from "../../utilities/has-newline-in-range.js";
import { locEnd, locStart } from "../loc.js";
import { locEnd, locStart } from "../location/index.js";
import {
CommentCheckFlags,
getComments,
+1 -1
View File
@@ -4,7 +4,7 @@ import {
markAsRoot,
replaceEndOfLine,
} from "../../document/index.js";
import { locEnd, locStart } from "../loc.js";
import { locEnd, locStart } from "../location/index.js";
import { isBlockComment, isLineComment } from "../utilities/comment-types.js";
import isIndentableBlockComment from "../utilities/is-indentable-block-comment.js";
+1 -1
View File
@@ -7,7 +7,7 @@ import {
} from "../../document/index.js";
import hasNewline from "../../utilities/has-newline.js";
import isNonEmptyArray from "../../utilities/is-non-empty-array.js";
import { hasSameLocStart, locEnd } from "../loc.js";
import { hasSameLocStart, locEnd } from "../location/index.js";
import isIgnored from "../utilities/is-ignored.js";
import { isExportDeclaration } from "../utilities/node-types.js";
+1 -1
View File
@@ -1,5 +1,5 @@
import { group } from "../../document/index.js";
import { hasSameLocStart } from "../loc.js";
import { hasSameLocStart } from "../location/index.js";
import { isFlowObjectTypePropertyAFunction } from "../utilities/is-flow-object-type-property-a-function.js";
import { printClassMemberSemicolon } from "./class.js";
import {
+1 -1
View File
@@ -1,7 +1,7 @@
import { group, hardline } from "../../document/index.js";
import { printDanglingComments } from "../../main/comments/print.js";
import hasNewline from "../../utilities/has-newline.js";
import { locEnd, locStart } from "../loc.js";
import { locEnd, locStart } from "../location/index.js";
import { CommentCheckFlags, getComments } from "../utilities/comments.js";
import { isPreviousLineEmpty } from "../utilities/is-previous-line-empty.js";
import { needsHardlineAfterDanglingComment } from "../utilities/needs-hardline-after-dangling-comment.js";
+1 -1
View File
@@ -1,6 +1,6 @@
import { indent, softline } from "../../document/index.js";
import isNonEmptyArray from "../../utilities/is-non-empty-array.js";
import { locEnd, locStart } from "../loc.js";
import { locEnd, locStart } from "../location/index.js";
import { shouldExpressionStatementPrintLeadingSemicolon } from "../semicolon/semicolon.js";
function printIgnored(path, options /* , print*/) {
+1 -1
View File
@@ -9,7 +9,7 @@ import {
import { printDanglingComments } from "../../main/comments/print.js";
import hasNewline from "../../utilities/has-newline.js";
import hasNewlineInRange from "../../utilities/has-newline-in-range.js";
import { locEnd, locStart } from "../loc.js";
import { locEnd, locStart } from "../location/index.js";
import { isLineComment } from "../utilities/comment-types.js";
import { CommentCheckFlags, getComments } from "../utilities/comments.js";
import { stripComments } from "../utilities/strip-comments.js";
+1 -1
View File
@@ -11,7 +11,7 @@ import {
import { printComments } from "../../main/comments/print.js";
import getNextNonSpaceNonCommentCharacterIndex from "../../utilities/get-next-non-space-non-comment-character-index.js";
import isNextLineEmptyAfterIndex from "../../utilities/is-next-line-empty.js";
import { locEnd } from "../loc.js";
import { locEnd } from "../location/index.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";
+1 -1
View File
@@ -10,7 +10,7 @@ import {
import { printDanglingComments } from "../../main/comments/print.js";
import isNonEmptyArray from "../../utilities/is-non-empty-array.js";
import UnexpectedNodeError from "../../utilities/unexpected-node-error.js";
import { locEnd, locStart } from "../loc.js";
import { locEnd, locStart } from "../location/index.js";
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import { createTypeCheckFunction } from "../utilities/create-type-check-function.js";
import { isShorthandSpecifier } from "../utilities/is-shorthand-specifier.js";
+1 -1
View File
@@ -10,7 +10,7 @@ import { printDanglingComments } from "../../main/comments/print.js";
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 { locEnd, locStart } from "../location/index.js";
import {
CommentCheckFlags,
getComments,
+1 -1
View File
@@ -14,7 +14,7 @@ import {
import getIndentSize from "../../utilities/get-indent-size.js";
import getStringWidth from "../../utilities/get-string-width.js";
import hasNewlineInRange from "../../utilities/has-newline-in-range.js";
import { locEnd, locStart } from "../loc.js";
import { locEnd, locStart } from "../location/index.js";
import {
CommentCheckFlags,
getComments,
+1 -1
View File
@@ -10,7 +10,7 @@ import {
} from "../../document/index.js";
import { printDanglingComments } from "../../main/comments/print.js";
import hasNewlineInRange from "../../utilities/has-newline-in-range.js";
import { locEnd, locStart } from "../loc.js";
import { locEnd, locStart } from "../location/index.js";
import needsParentheses from "../parentheses/needs-parentheses.js";
import { isBlockComment } from "../utilities/comment-types.js";
import {
+1 -1
View File
@@ -1,6 +1,6 @@
import { indent, softline } from "../../document/index.js";
import hasNewline from "../../utilities/has-newline.js";
import { locEnd, locStart } from "../loc.js";
import { locEnd, locStart } from "../location/index.js";
import { isBlockComment } from "../utilities/comment-types.js";
import { hasComment } from "../utilities/comments.js";
+1 -1
View File
@@ -10,7 +10,7 @@ import {
} from "../../document/index.js";
import { printDanglingComments } from "../../main/comments/print.js";
import hasNewline from "../../utilities/has-newline.js";
import { locEnd } from "../loc.js";
import { locEnd } from "../location/index.js";
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import { getFunctionParameters } from "../utilities/function-parameters.js";
import { isObjectType } from "../utilities/node-types.js";
+1 -1
View File
@@ -3,7 +3,7 @@ import handleComments from "./comments/handle-comments.js";
import isGap from "./comments/is-gap.js";
import willPrintOwnComments from "./comments/will-print-own-comments.js";
import embed from "./embed/index.js";
import { locEndWithFullText, locStart } from "./loc.js";
import { locEndWithFullText, locStart } from "./location/index.js";
import { massageAstNode } from "./massage-ast/index.js";
import { insertPragma } from "./pragma.js";
import { printComment } from "./print/comment.js";
@@ -1,4 +1,4 @@
import { locEnd, locStart } from "../loc.js";
import { locEnd, locStart } from "../location/index.js";
import { stripComments } from "./strip-comments.js";
/**
@@ -36,7 +36,7 @@ function getCallOrNewExpressionClosingParenthesisIndex(
/**
@param {CallOrNewExpression} callOrNewExpression
@returns {number | void}
@returns {number | undefined}
*/
function getCallOrNewExpressionOpeningParenthesisIndex(
callOrNewExpression,
+1 -1
View File
@@ -1,5 +1,5 @@
import isNonEmptyArray from "../../utilities/is-non-empty-array.js";
import { locStart } from "../loc.js";
import { locStart } from "../location/index.js";
/**
@import AstPath from "../../common/ast-path.js";
@@ -1,5 +1,5 @@
import hasNewline from "../../utilities/has-newline.js";
import { locEnd } from "../loc.js";
import { locEnd } from "../location/index.js";
import { CommentCheckFlags, hasComment } from "./comments.js";
import { hasNodeIgnoreComment } from "./has-node-ignore-comment.js";
import { isJsxElement } from "./node-types.js";
@@ -1,5 +1,5 @@
import isNextLineEmptyAfterIndex from "../../utilities/is-next-line-empty.js";
import { locEnd, locEndWithFullText } from "../loc.js";
import { locEnd, locEndWithFullText } from "../location/index.js";
/**
@import {
@@ -1,5 +1,5 @@
import isPreviousLineEmptyBeforeIndex from "../../utilities/is-previous-line-empty.js";
import { locStart } from "../loc.js";
import { locStart } from "../location/index.js";
/**
@import {
@@ -1,4 +1,4 @@
import { hasSameLoc } from "../loc.js";
import { hasSameLoc } from "../location/index.js";
import { getRaw } from "./get-raw.js";
import { isStringLiteral } from "./node-types.js";
@@ -1,5 +1,5 @@
import hasNewline from "../../utilities/has-newline.js";
import { locStart } from "../loc.js";
import { locStart } from "../location/index.js";
import { templateLiteralHasNewLines } from "./template-literal-has-new-lines.js";
/**
@@ -1,4 +1,4 @@
import { hasSameLocStart } from "../loc.js";
import { hasSameLocStart } from "../location/index.js";
// Hack to differentiate between the following two which have the same ast
// declare function f(a): void;
@@ -1,5 +1,5 @@
import hasNewlineInRange from "../../utilities/has-newline-in-range.js";
import { locEnd, locStart } from "../loc.js";
import { locEnd, locStart } from "../location/index.js";
import { hasLeadingOwnLineComment } from "../utilities/has-leading-own-line-comment.js";
import { CommentCheckFlags, hasComment } from "./comments.js";
import { getLeftSide, hasNakedLeftSide } from "./left-side.js";
+1 -1
View File
@@ -1,6 +1,6 @@
import { commentsPropertyInOptions } from "../../constants.js";
import replaceNonLineBreaksWithSpace from "../../utilities/replace-non-line-breaks-with-space.js";
import { locEnd, locStart } from "../loc.js";
import { locEnd, locStart } from "../location/index.js";
/**
@import {Node, Comment} from "../types/estree.js"