154 lines
4.9 KiB
JavaScript
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 }
|