Files
routie/frontend/node_modules/eslint-plugin-perfectionist/dist/utils/get-node-range.js
T

119 lines
3.4 KiB
JavaScript

import { getEslintDisabledRules } from './get-eslint-disabled-rules.js'
import { isPartitionComment } from './is-partition-comment.js'
import { getCommentsBefore } from './get-comments-before.js'
import { ASTUtils } from '@typescript-eslint/utils'
/**
* Determines the complete range of a node including its associated comments.
*
* Calculates the full range that should be considered when moving or analyzing
* a node. This includes:
*
* - The node itself
* - Parentheses surrounding the node (if any)
* - Preceding comments that "belong" to the node.
*
* The function intelligently determines which comments should be included by:
*
* - Including comments directly above the node (no empty lines between)
* - Stopping at partition comments (used to separate sections)
* - Stopping at ESLint disable/enable comments
* - Optionally excluding the highest block comment (e.g., file headers).
*
* @example
*
* ```ts
* // Source code:
* // This comment belongs to the function
* // So does this one
* function foo() {}
*
* const range = getNodeRange({ node: functionNode, sourceCode })
* // Returns range including both comments
* ```
*
* @example
*
* ```ts
* // Source code:
* /* File header comment *\/
* // Function comment
* function bar() { }
*
* const range = getNodeRange({
* node: functionNode,
* sourceCode,
* ignoreHighestBlockComment: true
* });
* // Returns range including line comment but not block comment
* ```
*
* @param params - Parameters for range calculation.
* @returns Tuple of [start, end] positions including relevant comments.
*/
function getNodeRange({
ignoreHighestBlockComment,
sourceCode,
options,
node,
}) {
let start = node.range.at(0)
let end = node.range.at(1)
if (ASTUtils.isParenthesized(node, sourceCode)) {
let bodyOpeningParen = sourceCode.getTokenBefore(
node,
ASTUtils.isOpeningParenToken,
)
let bodyClosingParen = sourceCode.getTokenAfter(
node,
ASTUtils.isClosingParenToken,
)
start = bodyOpeningParen.range.at(0)
end = bodyClosingParen.range.at(1)
}
let comments = getCommentsBefore({
sourceCode,
node,
})
let highestBlockComment = comments.find(comment => comment.type === 'Block')
/**
* Iterate on all comments starting from the bottom until we reach the last of
* the comments, a newline between comments, a partition comment, or a
* eslint-disable comment.
*/
let relevantTopComment
for (let i = comments.length - 1; i >= 0; i--) {
let comment = comments[i]
let eslintDisabledRules = getEslintDisabledRules(comment.value)
if (
isPartitionComment({
partitionByComment: options?.partitionByComment ?? false,
comment,
}) ||
eslintDisabledRules?.eslintDisableDirective === 'eslint-disable' ||
eslintDisabledRules?.eslintDisableDirective === 'eslint-enable'
) {
break
}
/**
* Check for newlines between comments or between the first comment and the
* node.
*/
let previousCommentOrNodeStartLine =
i === comments.length - 1 ?
node.loc.start.line
: comments[i + 1].loc.start.line
if (comment.loc.end.line !== previousCommentOrNodeStartLine - 1) {
break
}
if (ignoreHighestBlockComment && comment === highestBlockComment) {
break
}
relevantTopComment = comment
}
if (relevantTopComment) {
start = relevantTopComment.range.at(0)
}
return [start, end]
}
export { getNodeRange }