Files

154 lines
4.9 KiB
JavaScript

import { isGroupWithOverridesOption } from './is-group-with-overrides-option.js'
import { getGroupIndex } from './get-group-index.js'
import { getCommentsBefore } from './get-comments-before.js'
import { getCommentAboveThatShouldExist } from './get-comment-above-that-should-exist.js'
/**
* Generates fixes for adding or removing comment separators above groups.
*
* Processes sorted nodes to ensure that comment separators defined in the
* groups configuration are properly placed. This includes:
*
* - Adding missing comment separators above groups
* - Removing auto-generated comments that are no longer needed
* - Ensuring comments are in the correct position after sorting.
*
* The function handles the first node specially (checking if it needs a
* comment) and then processes pairs of adjacent nodes to determine comment
* placement.
*
* @example
*
* ```ts
* // Configuration with commentAbove
* const groups = ['imports', { commentAbove: 'Components' }, 'components']
*
* // Will add '// Components' comment above the components group
* // Will remove any misplaced auto-generated comments
* ```
*
* @param params - Parameters for generating fixes.
* @returns Array of ESLint fix operations to apply.
*/
function makeCommentAboveFixes({ sortedNodes, sourceCode, options, fixer }) {
let allAutoAddedComments = new Set(
options.groups
.filter(group => isGroupWithOverridesOption(group))
.map(({ commentAbove }) => commentAbove)
.filter(comment => comment !== void 0),
)
let fixes = []
let firstNodeFixes = makeCommentAboveFix({
nextSortedSortingNode: sortedNodes[0],
sortedSortingNode: null,
allAutoAddedComments,
sourceCode,
options,
fixer,
})
fixes.push(...firstNodeFixes)
for (let i = 0; i < sortedNodes.length - 1; i++) {
let sortedSortingNode = sortedNodes.at(i)
let nodeFixes = makeCommentAboveFix({
nextSortedSortingNode: sortedNodes.at(i + 1),
allAutoAddedComments,
sortedSortingNode,
sourceCode,
options,
fixer,
})
fixes.push(...nodeFixes)
}
return fixes
}
/**
* Creates fixes for comment placement between two adjacent nodes.
*
* Determines whether a comment separator should exist between two nodes based
* on their group indices and configuration. Handles:
*
* - Adding a new comment if required but missing
* - Removing outdated auto-generated comments
* - Preserving manually added comments.
*
* The function checks if the next node should have a comment above it based on
* the groups configuration, then ensures the comment state matches the expected
* state.
*
* @param params - Parameters for creating fixes.
* @param params.sortedSortingNode - Previous node in sorted order (null for
* first node).
* @param params.nextSortedSortingNode - Current node to potentially add comment
* above.
* @param params.allAutoAddedComments - Set of all auto-generated comment texts.
* @param params.sourceCode - ESLint source code object.
* @param params.options - Groups and configuration options.
* @param params.fixer - ESLint fixer for creating fixes.
* @returns Array of fixes to add/remove comments.
*/
function makeCommentAboveFix({
nextSortedSortingNode,
allAutoAddedComments,
sortedSortingNode,
sourceCode,
options,
fixer,
}) {
let leftGroupIndex =
sortedSortingNode ? getGroupIndex(options.groups, sortedSortingNode) : -1
let rightGroupIndex = getGroupIndex(options.groups, nextSortedSortingNode)
let commentAboveThatShouldExist = getCommentAboveThatShouldExist({
options: {
...options,
groups: options.groups,
},
sortingNode: nextSortedSortingNode,
rightGroupIndex,
leftGroupIndex,
sourceCode,
})
let commentsBefore = getCommentsBefore({
node: nextSortedSortingNode.node,
sourceCode,
})
let autoAddedCommentsAboveToRemove = commentsBefore
.filter(
comment =>
!commentAboveThatShouldExist?.comment ||
comment.value.slice(1) !== commentAboveThatShouldExist.comment,
)
.filter(
comment =>
comment.type === 'Line' &&
allAutoAddedComments.has(comment.value.slice(1)),
)
let fixes = []
for (let autoAddedCommentAboveToRemove of autoAddedCommentsAboveToRemove) {
let nextToken = sourceCode.getTokenAfter(autoAddedCommentAboveToRemove)
fixes.push(
fixer.removeRange([
autoAddedCommentAboveToRemove.range[0],
nextToken.range[0],
]),
)
}
if (commentAboveThatShouldExist && !commentAboveThatShouldExist.exists) {
let nodeToPutCommentBefore
if (
!sourceCode.getTokenBefore(nextSortedSortingNode.node) ||
!commentsBefore[0]
) {
nodeToPutCommentBefore = nextSortedSortingNode.node
} else {
;[nodeToPutCommentBefore] = commentsBefore
}
fixes.push(
fixer.insertTextBeforeRange(
nodeToPutCommentBefore.range,
`// ${commentAboveThatShouldExist.comment}\n`,
),
)
}
return fixes
}
export { makeCommentAboveFixes }