diff --git a/rules/sort-array-includes.ts b/rules/sort-array-includes.ts index 6fc52a676..eb9ec70ac 100644 --- a/rules/sort-array-includes.ts +++ b/rules/sort-array-includes.ts @@ -27,6 +27,7 @@ import { getEslintDisabledLines } from '../utils/get-eslint-disabled-lines' import { singleCustomGroupJsonSchema } from './sort-array-includes.types' import { isNodeEslintDisabled } from '../utils/is-node-eslint-disabled' import { hasPartitionComment } from '../utils/is-partition-comment' +import { createNodeIndexMap } from '../utils/create-node-index-map' import { sortNodesByGroups } from '../utils/sort-nodes-by-groups' import { getCommentsBefore } from '../utils/get-comments-before' import { customGroupMatches } from './sort-array-includes-utils' @@ -168,12 +169,14 @@ export let sortArray = ({ let sourceCode = getSourceCode(context) let settings = getSettings(context.settings) + let matchedContextOptions = getMatchingContextOptions({ nodeNames: elements .filter(element => element !== null) .map(element => getNodeName({ sourceCode, element })), contextOptions: context.options, }) + let completeOptions = complete( matchedContextOptions[0], settings, @@ -198,6 +201,7 @@ export let sortArray = ({ ruleName: context.id, sourceCode, }) + let formattedMembers: SortArrayIncludesSortingNode[][] = elements.reduce( ( accumulator: SortArrayIncludesSortingNode[][], @@ -218,11 +222,13 @@ export let sortArray = ({ selector = 'literal' } - for (let predefinedGroup of generatePredefinedGroups({ + let predefinedGroups = generatePredefinedGroups({ cache: cachedGroupsByModifiersAndSelectors, selectors: [selector], modifiers: [], - })) { + }) + + for (let predefinedGroup of predefinedGroups) { defineGroup(predefinedGroup) } @@ -236,7 +242,10 @@ export let sortArray = ({ }) ) { defineGroup(customGroup.groupName, true) - // If the custom group is not referenced in the `groups` option, it will be ignored + /** + * If the custom group is not referenced in the `groups` option, it + * will be ignored + */ if (getGroup() === customGroup.groupName) { break } @@ -245,23 +254,22 @@ export let sortArray = ({ let sortingNode: SortArrayIncludesSortingNode = { isEslintDisabled: isNodeEslintDisabled(element, eslintDisabledLines), - name: getNodeName({ sourceCode, element }), size: rangeToDiff(element, sourceCode), group: getGroup(), node: element, groupKind, + name, } let lastSortingNode = accumulator.at(-1)?.at(-1) if ( - (options.partitionByComment && - hasPartitionComment( - options.partitionByComment, - getCommentsBefore({ - node: element, - sourceCode, - }), - )) || + hasPartitionComment( + options.partitionByComment, + getCommentsBefore({ + node: element, + sourceCode, + }), + ) || (options.partitionByNewLine && lastSortingNode && getLinesBetween(sourceCode, lastSortingNode, sortingNode)) @@ -303,21 +311,25 @@ export let sortArray = ({ ignoreEslintDisabledNodes, }), ) + let sortedNodes = sortNodesIgnoringEslintDisabledNodes(false) let sortedNodesExcludingEslintDisabled = sortNodesIgnoringEslintDisabledNodes(true) + let nodeIndexMap = createNodeIndexMap(sortedNodes) + pairwise(nodes, (left, right) => { - let indexOfLeft = sortedNodes.indexOf(left) - let indexOfRight = sortedNodes.indexOf(right) + let leftIndex = nodeIndexMap.get(left)! + let rightIndex = nodeIndexMap.get(right)! + let leftNumber = getGroupNumber(options.groups, left) let rightNumber = getGroupNumber(options.groups, right) let indexOfRightExcludingEslintDisabled = sortedNodesExcludingEslintDisabled.indexOf(right) if ( - indexOfLeft < indexOfRight && - indexOfLeft < indexOfRightExcludingEslintDisabled + leftIndex < rightIndex && + leftIndex < indexOfRightExcludingEslintDisabled ) { return } diff --git a/rules/sort-classes.ts b/rules/sort-classes.ts index db3fd280f..663b279f6 100644 --- a/rules/sort-classes.ts +++ b/rules/sort-classes.ts @@ -494,12 +494,14 @@ export default createEslintRule({ selectors.push('property') } - for (let officialGroup of generatePredefinedGroups({ + let predefinedGroups = generatePredefinedGroups({ cache: cachedGroupsByModifiersAndSelectors, selectors, modifiers, - })) { - defineGroup(officialGroup) + }) + + for (let predefinedGroup of predefinedGroups) { + defineGroup(predefinedGroup) } for (let customGroup of options.customGroups) { @@ -553,14 +555,13 @@ export default createEslintRule({ (options.partitionByNewLine && lastMember && getLinesBetween(sourceCode, lastMember, sortingNode)) || - (options.partitionByComment && - hasPartitionComment( - options.partitionByComment, - getCommentsBefore({ - node: member, - sourceCode, - }), - )) + hasPartitionComment( + options.partitionByComment, + getCommentsBefore({ + node: member, + sourceCode, + }), + ) ) { accumulator.push([]) } diff --git a/rules/sort-decorators.ts b/rules/sort-decorators.ts index a868e31d5..b55e9e418 100644 --- a/rules/sort-decorators.ts +++ b/rules/sort-decorators.ts @@ -19,6 +19,7 @@ import { validateGroupsConfiguration } from '../utils/validate-groups-configurat import { getEslintDisabledLines } from '../utils/get-eslint-disabled-lines' import { isNodeEslintDisabled } from '../utils/is-node-eslint-disabled' import { hasPartitionComment } from '../utils/is-partition-comment' +import { createNodeIndexMap } from '../utils/create-node-index-map' import { sortNodesByGroups } from '../utils/sort-nodes-by-groups' import { getCommentsBefore } from '../utils/get-comments-before' import { getNodeDecorators } from '../utils/get-node-decorators' @@ -218,7 +219,6 @@ let sortDecorators = ( let formattedMembers: SortDecoratorsSortingNode[][] = decorators.reduce( (accumulator: SortDecoratorsSortingNode[][], decorator) => { if ( - options.partitionByComment && hasPartitionComment( options.partitionByComment, getCommentsBefore({ @@ -259,16 +259,19 @@ let sortDecorators = ( let sortedNodes = sortNodesExcludingEslintDisabled(false) let sortedNodesExcludingEslintDisabled = sortNodesExcludingEslintDisabled(true) + let nodes = formattedMembers.flat() + let nodeIndexMap = createNodeIndexMap(sortedNodes) + pairwise(nodes, (left, right) => { - let indexOfLeft = sortedNodes.indexOf(left) - let indexOfRight = sortedNodes.indexOf(right) + let leftIndex = nodeIndexMap.get(left)! + let rightIndex = nodeIndexMap.get(right)! let indexOfRightExcludingEslintDisabled = sortedNodesExcludingEslintDisabled.indexOf(right) if ( - indexOfLeft < indexOfRight && - indexOfLeft < indexOfRightExcludingEslintDisabled + leftIndex < rightIndex && + leftIndex < indexOfRightExcludingEslintDisabled ) { return } diff --git a/rules/sort-enums.ts b/rules/sort-enums.ts index 3d3250c85..3386f943a 100644 --- a/rules/sort-enums.ts +++ b/rules/sort-enums.ts @@ -21,6 +21,7 @@ import { validateCustomSortConfiguration } from '../utils/validate-custom-sort-c import { getEslintDisabledLines } from '../utils/get-eslint-disabled-lines' import { isNodeEslintDisabled } from '../utils/is-node-eslint-disabled' import { hasPartitionComment } from '../utils/is-partition-comment' +import { createNodeIndexMap } from '../utils/create-node-index-map' import { getCommentsBefore } from '../utils/get-comments-before' import { createEslintRule } from '../utils/create-eslint-rule' import { getLinesBetween } from '../utils/get-lines-between' @@ -96,37 +97,35 @@ export default createEslintRule({ enumName: string, ): string[] => { let dependencies: string[] = [] + let stack: TSESTree.Node[] = [expression] - let checkNode = (nodeValue: TSESTree.Node): void => { + while (stack.length) { + let node = stack.pop()! if ( - nodeValue.type === 'MemberExpression' && - nodeValue.object.type === 'Identifier' && - nodeValue.object.name === enumName && - nodeValue.property.type === 'Identifier' + node.type === 'MemberExpression' && + node.object.type === 'Identifier' && + node.object.name === enumName && + node.property.type === 'Identifier' ) { - dependencies.push(nodeValue.property.name) - } else if (nodeValue.type === 'Identifier') { - dependencies.push(nodeValue.name) + dependencies.push(node.property.name) + } else if (node.type === 'Identifier') { + dependencies.push(node.name) } - if ('left' in nodeValue) { - checkNode(nodeValue.left) + if ('left' in node) { + stack.push(node.left) } - - if ('right' in nodeValue) { - checkNode(nodeValue.right) + if ('right' in node) { + stack.push(node.right) } - - if ('expressions' in nodeValue) { - for (let currentExpression of nodeValue.expressions) { - checkNode(currentExpression) - } + if ('expressions' in node) { + stack.push(...node.expressions) } } - checkNode(expression) return dependencies } + let formattedMembers: SortEnumsSortingNode[][] = members.reduce( (accumulator: SortEnumsSortingNode[][], member) => { let dependencies: string[] = [] @@ -154,14 +153,13 @@ export default createEslintRule({ } if ( - (options.partitionByComment && - hasPartitionComment( - options.partitionByComment, - getCommentsBefore({ - node: member, - sourceCode, - }), - )) || + hasPartitionComment( + options.partitionByComment, + getCommentsBefore({ + node: member, + sourceCode, + }), + ) || (options.partitionByNewLine && lastSortingNode && getLinesBetween(sourceCode, lastSortingNode, sortingNode)) @@ -176,11 +174,13 @@ export default createEslintRule({ ) let sortingNodes = formattedMembers.flat() + let isNumericEnum = sortingNodes.every( sortingNode => sortingNode.numericValue !== null && !Number.isNaN(sortingNode.numericValue), ) + let compareOptions: CompareOptions = { // Get the enum value rather than the name if needed nodeValueGetter: @@ -195,7 +195,10 @@ export default createEslintRule({ return '' } : null, - // If the enum is numeric, and we sort by value, always use the `natural` sort type, which will correctly sort them. + /** + * If the enum is numeric, and we sort by value, always use the + * `natural` sort type, which will correctly sort them. + */ type: isNumericEnum && (options.forceNumericSort || options.sortByValue) ? 'natural' @@ -220,18 +223,22 @@ export default createEslintRule({ ignoreEslintDisabledNodes, }, ) + let sortedNodes = sortNodesIgnoringEslintDisabledNodes(false) let sortedNodesExcludingEslintDisabled = sortNodesIgnoringEslintDisabledNodes(true) + let nodeIndexMap = createNodeIndexMap(sortedNodes) + pairwise(sortingNodes, (left, right) => { - let indexOfLeft = sortedNodes.indexOf(left) - let indexOfRight = sortedNodes.indexOf(right) + let leftIndex = nodeIndexMap.get(left)! + let rightIndex = nodeIndexMap.get(right)! + let indexOfRightExcludingEslintDisabled = sortedNodesExcludingEslintDisabled.indexOf(right) if ( - indexOfLeft < indexOfRight && - indexOfLeft < indexOfRightExcludingEslintDisabled + leftIndex < rightIndex && + leftIndex < indexOfRightExcludingEslintDisabled ) { return } diff --git a/rules/sort-exports.ts b/rules/sort-exports.ts index 0a7aff295..ca5325aff 100644 --- a/rules/sort-exports.ts +++ b/rules/sort-exports.ts @@ -15,6 +15,7 @@ import { import { validateCustomSortConfiguration } from '../utils/validate-custom-sort-configuration' import { getEslintDisabledLines } from '../utils/get-eslint-disabled-lines' import { isNodeEslintDisabled } from '../utils/is-node-eslint-disabled' +import { createNodeIndexMap } from '../utils/create-node-index-map' import { hasPartitionComment } from '../utils/is-partition-comment' import { getCommentsBefore } from '../utils/get-comments-before' import { createEslintRule } from '../utils/create-eslint-rule' @@ -136,18 +137,22 @@ export default createEslintRule({ ignoreEslintDisabledNodes, }), ) + let sortedNodes = sortNodesExcludingEslintDisabled(false) let sortedNodesExcludingEslintDisabled = sortNodesExcludingEslintDisabled(true) + let nodeIndexMap = createNodeIndexMap(sortedNodes) + pairwise(nodes, (left, right) => { - let indexOfLeft = sortedNodes.indexOf(left) - let indexOfRight = sortedNodes.indexOf(right) + let leftIndex = nodeIndexMap.get(left)! + let rightIndex = nodeIndexMap.get(right)! + let indexOfRightExcludingEslintDisabled = sortedNodesExcludingEslintDisabled.indexOf(right) if ( - indexOfLeft < indexOfRight && - indexOfLeft < indexOfRightExcludingEslintDisabled + leftIndex < rightIndex && + leftIndex < indexOfRightExcludingEslintDisabled ) { return } diff --git a/rules/sort-heritage-clauses.ts b/rules/sort-heritage-clauses.ts index d1454dcfa..2cf18a71d 100644 --- a/rules/sort-heritage-clauses.ts +++ b/rules/sort-heritage-clauses.ts @@ -17,6 +17,7 @@ import { validateCustomSortConfiguration } from '../utils/validate-custom-sort-c import { validateGroupsConfiguration } from '../utils/validate-groups-configuration' import { getEslintDisabledLines } from '../utils/get-eslint-disabled-lines' import { isNodeEslintDisabled } from '../utils/is-node-eslint-disabled' +import { createNodeIndexMap } from '../utils/create-node-index-map' import { sortNodesByGroups } from '../utils/sort-nodes-by-groups' import { createEslintRule } from '../utils/create-eslint-rule' import { getGroupNumber } from '../utils/get-group-number' @@ -122,7 +123,7 @@ let sortHeritageClauses = ( | TSESTree.TSClassImplements[] | undefined, ): void => { - if (!heritageClauses || !isSortable(heritageClauses)) { + if (!isSortable(heritageClauses)) { return } let sourceCode = getSourceCode(context) @@ -131,7 +132,7 @@ let sortHeritageClauses = ( sourceCode, }) - let nodes: SortingNode[] = heritageClauses.map(heritageClause => { + let nodes: SortingNode[] = heritageClauses!.map(heritageClause => { let name = getHeritageClauseExpressionName(heritageClause.expression) let { setCustomGroups, getGroup } = useGroups(options) @@ -153,18 +154,22 @@ let sortHeritageClauses = ( ignoreEslintDisabledNodes: boolean, ): SortingNode[] => sortNodesByGroups(nodes, options, { ignoreEslintDisabledNodes }) + let sortedNodes = sortNodesExcludingEslintDisabled(false) let sortedNodesExcludingEslintDisabled = sortNodesExcludingEslintDisabled(true) + let nodeIndexMap = createNodeIndexMap(sortedNodes) + pairwise(nodes, (left, right) => { - let indexOfLeft = sortedNodes.indexOf(left) - let indexOfRight = sortedNodes.indexOf(right) + let leftIndex = nodeIndexMap.get(left)! + let rightIndex = nodeIndexMap.get(right)! + let indexOfRightExcludingEslintDisabled = sortedNodesExcludingEslintDisabled.indexOf(right) if ( - indexOfLeft < indexOfRight && - indexOfLeft < indexOfRightExcludingEslintDisabled + leftIndex < rightIndex && + leftIndex < indexOfRightExcludingEslintDisabled ) { return } diff --git a/rules/sort-imports.ts b/rules/sort-imports.ts index 5ca40c4d6..4513c8827 100644 --- a/rules/sort-imports.ts +++ b/rules/sort-imports.ts @@ -24,6 +24,7 @@ import { getOptionsWithCleanGroups } from '../utils/get-options-with-clean-group import { getEslintDisabledLines } from '../utils/get-eslint-disabled-lines' import { isNodeEslintDisabled } from '../utils/is-node-eslint-disabled' import { getTypescriptImport } from '../utils/get-typescript-import' +import { createNodeIndexMap } from '../utils/create-node-index-map' import { hasPartitionComment } from '../utils/is-partition-comment' import { sortNodesByGroups } from '../utils/sort-nodes-by-groups' import { getCommentsBefore } from '../utils/get-comments-before' @@ -181,8 +182,10 @@ export default createEslintRule, MESSAGE_ID>({ return group.every(isSideEffectOnlyGroup) } - // Ensure that if `sortSideEffects: false`, no side effect group is in a - // Nested group with non-side-effect groups. + /** + * Ensure that if `sortSideEffects: false`, no side effect group is in a + * nested group with non-side-effect groups. + */ if (!options.sortSideEffects) { let hasInvalidGroup = options.groups .filter(group => Array.isArray(group)) @@ -214,11 +217,18 @@ export default createEslintRule, MESSAGE_ID>({ /* Avoid matching on named imports without specifiers */ !/\}\s*from\s+/u.test(sourceCode.getText(node)) + let styleExtensions = [ + '.less', + '.scss', + '.sass', + '.styl', + '.pcss', + '.css', + '.sss', + ] let isStyle = (value: string): boolean => { let [cleanedValue] = value.split('?') - return ['.less', '.scss', '.sass', '.styl', '.pcss', '.css', '.sss'].some( - extension => cleanedValue.endsWith(extension), - ) + return styleExtensions.some(extension => cleanedValue.endsWith(extension)) } let flatGroups = new Set(options.groups.flat()) @@ -455,27 +465,28 @@ export default createEslintRule, MESSAGE_ID>({ let formattedMembers: SortImportsSortingNode[][] = [[]] for (let sortingNode of nodes) { - let lastSortingNode = formattedMembers.at(-1)?.at(-1) + let lastGroup = formattedMembers.at(-1) + let lastSortingNode = lastGroup?.at(-1) if ( - (options.partitionByComment && - hasPartitionComment( - options.partitionByComment, - getCommentsBefore({ - node: sortingNode.node, - sourceCode, - }), - )) || + hasPartitionComment( + options.partitionByComment, + getCommentsBefore({ + node: sortingNode.node, + sourceCode, + }), + ) || (options.partitionByNewLine && lastSortingNode && getLinesBetween(sourceCode, lastSortingNode, sortingNode)) || (lastSortingNode && hasContentBetweenNodes(lastSortingNode, sortingNode)) ) { - formattedMembers.push([]) + lastGroup = [] + formattedMembers.push(lastGroup) } - formattedMembers.at(-1)!.push(sortingNode) + lastGroup!.push(sortingNode) } for (let nodeList of formattedMembers) { @@ -493,24 +504,28 @@ export default createEslintRule, MESSAGE_ID>({ isNodeIgnored: node => node.isIgnored, ignoreEslintDisabledNodes, }) + let sortedNodes = sortNodesExcludingEslintDisabled(false) let sortedNodesExcludingEslintDisabled = sortNodesExcludingEslintDisabled(true) + let nodeIndexMap = createNodeIndexMap(sortedNodes) + pairwise(nodeList, (left, right) => { let leftNumber = getGroupNumber(options.groups, left) let rightNumber = getGroupNumber(options.groups, right) - let indexOfLeft = sortedNodes.indexOf(left) - let indexOfRight = sortedNodes.indexOf(right) + let leftIndex = nodeIndexMap.get(left)! + let rightIndex = nodeIndexMap.get(right)! + let indexOfRightExcludingEslintDisabled = sortedNodesExcludingEslintDisabled.indexOf(right) let messageIds: MESSAGE_ID[] = [] if ( - indexOfLeft > indexOfRight || - indexOfLeft >= indexOfRightExcludingEslintDisabled + leftIndex > rightIndex || + leftIndex >= indexOfRightExcludingEslintDisabled ) { messageIds.push( leftNumber === rightNumber diff --git a/rules/sort-intersection-types.ts b/rules/sort-intersection-types.ts index aacdc0355..068618db7 100644 --- a/rules/sort-intersection-types.ts +++ b/rules/sort-intersection-types.ts @@ -17,6 +17,7 @@ import { validateCustomSortConfiguration } from '../utils/validate-custom-sort-c import { validateGroupsConfiguration } from '../utils/validate-groups-configuration' import { getEslintDisabledLines } from '../utils/get-eslint-disabled-lines' import { isNodeEslintDisabled } from '../utils/is-node-eslint-disabled' +import { createNodeIndexMap } from '../utils/create-node-index-map' import { hasPartitionComment } from '../utils/is-partition-comment' import { sortNodesByGroups } from '../utils/sort-nodes-by-groups' import { getCommentsBefore } from '../utils/get-comments-before' @@ -179,7 +180,8 @@ export default createEslintRule({ break } - let lastSortingNode = accumulator.at(-1)?.at(-1) + let lastGroup = accumulator.at(-1) + let lastSortingNode = lastGroup?.at(-1) let sortingNode: SortingNode = { isEslintDisabled: isNodeEslintDisabled(type, eslintDisabledLines), size: rangeToDiff(type, sourceCode), @@ -188,23 +190,23 @@ export default createEslintRule({ node: type, } if ( - (options.partitionByComment && - hasPartitionComment( - options.partitionByComment, - getCommentsBefore({ - tokenValueToIgnoreBefore: '&', - node: type, - sourceCode, - }), - )) || + hasPartitionComment( + options.partitionByComment, + getCommentsBefore({ + tokenValueToIgnoreBefore: '&', + node: type, + sourceCode, + }), + ) || (options.partitionByNewLine && lastSortingNode && getLinesBetween(sourceCode, lastSortingNode, sortingNode)) ) { - accumulator.push([]) + lastGroup = [] + accumulator.push(lastGroup) } - accumulator.at(-1)?.push(sortingNode) + lastGroup?.push(sortingNode) return accumulator }, @@ -216,24 +218,28 @@ export default createEslintRule({ ignoreEslintDisabledNodes: boolean, ): SortingNode[] => sortNodesByGroups(nodes, options, { ignoreEslintDisabledNodes }) + let sortedNodes = sortNodesExcludingEslintDisabled(false) let sortedNodesExcludingEslintDisabled = sortNodesExcludingEslintDisabled(true) + let nodeIndexMap = createNodeIndexMap(sortedNodes) + pairwise(nodes, (left, right) => { let leftNumber = getGroupNumber(options.groups, left) let rightNumber = getGroupNumber(options.groups, right) - let indexOfLeft = sortedNodes.indexOf(left) - let indexOfRight = sortedNodes.indexOf(right) + let leftIndex = nodeIndexMap.get(left)! + let rightIndex = nodeIndexMap.get(right)! + let indexOfRightExcludingEslintDisabled = sortedNodesExcludingEslintDisabled.indexOf(right) let messageIds: MESSAGE_ID[] = [] if ( - indexOfLeft > indexOfRight || - indexOfLeft >= indexOfRightExcludingEslintDisabled + leftIndex > rightIndex || + leftIndex >= indexOfRightExcludingEslintDisabled ) { messageIds.push( leftNumber === rightNumber diff --git a/rules/sort-jsx-props.ts b/rules/sort-jsx-props.ts index c84ed3244..e71351b75 100644 --- a/rules/sort-jsx-props.ts +++ b/rules/sort-jsx-props.ts @@ -16,6 +16,7 @@ import { validateCustomSortConfiguration } from '../utils/validate-custom-sort-c import { validateGroupsConfiguration } from '../utils/validate-groups-configuration' import { getEslintDisabledLines } from '../utils/get-eslint-disabled-lines' import { isNodeEslintDisabled } from '../utils/is-node-eslint-disabled' +import { createNodeIndexMap } from '../utils/create-node-index-map' import { sortNodesByGroups } from '../utils/sort-nodes-by-groups' import { createEslintRule } from '../utils/create-eslint-rule' import { getGroupNumber } from '../utils/get-group-number' @@ -118,9 +119,7 @@ export default createEslintRule, MESSAGE_ID>({ if (attribute.value === null) { defineGroup('shorthand') - } - - if (attribute.loc.start.line !== attribute.loc.end.line) { + } else if (attribute.loc.start.line !== attribute.loc.end.line) { defineGroup('multiline') } @@ -151,14 +150,17 @@ export default createEslintRule, MESSAGE_ID>({ let sortedNodesExcludingEslintDisabled = sortNodesExcludingEslintDisabled(true) + let nodeIndexMap = createNodeIndexMap(sortedNodes) + pairwise(nodes, (left, right) => { - let indexOfLeft = sortedNodes.indexOf(left) - let indexOfRight = sortedNodes.indexOf(right) + let leftIndex = nodeIndexMap.get(left)! + let rightIndex = nodeIndexMap.get(right)! + let indexOfRightExcludingEslintDisabled = sortedNodesExcludingEslintDisabled.indexOf(right) if ( - indexOfLeft < indexOfRight && - indexOfLeft < indexOfRightExcludingEslintDisabled + leftIndex < rightIndex && + leftIndex < indexOfRightExcludingEslintDisabled ) { return } diff --git a/rules/sort-maps.ts b/rules/sort-maps.ts index 446fc51de..bff24e9e2 100644 --- a/rules/sort-maps.ts +++ b/rules/sort-maps.ts @@ -15,6 +15,7 @@ import { import { validateCustomSortConfiguration } from '../utils/validate-custom-sort-configuration' import { getEslintDisabledLines } from '../utils/get-eslint-disabled-lines' import { isNodeEslintDisabled } from '../utils/is-node-eslint-disabled' +import { createNodeIndexMap } from '../utils/create-node-index-map' import { hasPartitionComment } from '../utils/is-partition-comment' import { getCommentsBefore } from '../utils/get-comments-before' import { createEslintRule } from '../utils/create-eslint-rule' @@ -126,14 +127,13 @@ export default createEslintRule({ } if ( - (options.partitionByComment && - hasPartitionComment( - options.partitionByComment, - getCommentsBefore({ - node: element, - sourceCode, - }), - )) || + hasPartitionComment( + options.partitionByComment, + getCommentsBefore({ + node: element, + sourceCode, + }), + ) || (options.partitionByNewLine && lastSortingNode && getLinesBetween(sourceCode, lastSortingNode, sortingNode)) @@ -153,14 +153,17 @@ export default createEslintRule({ let sortedNodesExcludingEslintDisabled = sortNodesExcludingEslintDisabled(true) + let nodeIndexMap = createNodeIndexMap(sortedNodes) + pairwise(nodes, (left, right) => { - let indexOfLeft = sortedNodes.indexOf(left) - let indexOfRight = sortedNodes.indexOf(right) + let leftIndex = nodeIndexMap.get(left)! + let rightIndex = nodeIndexMap.get(right)! + let indexOfRightExcludingEslintDisabled = sortedNodesExcludingEslintDisabled.indexOf(right) if ( - indexOfLeft < indexOfRight && - indexOfLeft < indexOfRightExcludingEslintDisabled + leftIndex < rightIndex && + leftIndex < indexOfRightExcludingEslintDisabled ) { return } diff --git a/rules/sort-modules.ts b/rules/sort-modules.ts index 2edf0457e..867c0a3fc 100644 --- a/rules/sort-modules.ts +++ b/rules/sort-modules.ts @@ -39,6 +39,7 @@ import { getCustomGroupsCompareOptions } from '../utils/get-custom-groups-compar import { generatePredefinedGroups } from '../utils/generate-predefined-groups' import { getEslintDisabledLines } from '../utils/get-eslint-disabled-lines' import { isNodeEslintDisabled } from '../utils/is-node-eslint-disabled' +import { createNodeIndexMap } from '../utils/create-node-index-map' import { hasPartitionComment } from '../utils/is-partition-comment' import { sortNodesByGroups } from '../utils/sort-nodes-by-groups' import { getNewlinesErrors } from '../utils/get-newlines-errors' @@ -314,12 +315,12 @@ let analyzeModule = ({ } let { defineGroup, getGroup } = useGroups(options) - for (let officialGroup of generatePredefinedGroups({ + for (let predefinedGroup of generatePredefinedGroups({ cache: cachedGroupsByModifiersAndSelectors, selectors: [selector], modifiers, })) { - defineGroup(officialGroup) + defineGroup(predefinedGroup) } for (let customGroup of options.customGroups) { if ( @@ -345,22 +346,21 @@ let analyzeModule = ({ dependencyName: name, group: getGroup(), dependencies, - node, name, + node, } let lastSortingNode = formattedNodes.at(-1)?.at(-1) if ( (options.partitionByNewLine && lastSortingNode && getLinesBetween(sourceCode, lastSortingNode, sortingNode)) || - (options.partitionByComment && - hasPartitionComment( - options.partitionByComment, - getCommentsBefore({ - sourceCode, - node, - }), - )) + hasPartitionComment( + options.partitionByComment, + getCommentsBefore({ + sourceCode, + node, + }), + ) ) { formattedNodes.push([]) } @@ -390,12 +390,15 @@ let analyzeModule = ({ sortNodesIgnoringEslintDisabledNodes(true) let nodes = formattedNodes.flat() + let nodeIndexMap = createNodeIndexMap(sortedNodes) + pairwise(nodes, (left, right) => { let leftNumber = getGroupNumber(options.groups, left) let rightNumber = getGroupNumber(options.groups, right) - let indexOfLeft = sortedNodes.indexOf(left) - let indexOfRight = sortedNodes.indexOf(right) + let leftIndex = nodeIndexMap.get(left)! + let rightIndex = nodeIndexMap.get(right)! + let indexOfRightExcludingEslintDisabled = sortedNodesExcludingEslintDisabled.indexOf(right) @@ -406,8 +409,8 @@ let analyzeModule = ({ ) if ( firstUnorderedNodeDependentOnRight || - indexOfLeft > indexOfRight || - indexOfLeft >= indexOfRightExcludingEslintDisabled + leftIndex > rightIndex || + leftIndex >= indexOfRightExcludingEslintDisabled ) { if (firstUnorderedNodeDependentOnRight) { messageIds.push('unexpectedModulesDependencyOrder') diff --git a/rules/sort-named-exports.ts b/rules/sort-named-exports.ts index 07a9d305e..f8a20b3cc 100644 --- a/rules/sort-named-exports.ts +++ b/rules/sort-named-exports.ts @@ -15,6 +15,7 @@ import { import { validateCustomSortConfiguration } from '../utils/validate-custom-sort-configuration' import { getEslintDisabledLines } from '../utils/get-eslint-disabled-lines' import { isNodeEslintDisabled } from '../utils/is-node-eslint-disabled' +import { createNodeIndexMap } from '../utils/create-node-index-map' import { hasPartitionComment } from '../utils/is-partition-comment' import { getCommentsBefore } from '../utils/get-comments-before' import { createEslintRule } from '../utils/create-eslint-rule' @@ -103,14 +104,13 @@ export default createEslintRule({ name, } if ( - (options.partitionByComment && - hasPartitionComment( - options.partitionByComment, - getCommentsBefore({ - node: specifier, - sourceCode, - }), - )) || + hasPartitionComment( + options.partitionByComment, + getCommentsBefore({ + node: specifier, + sourceCode, + }), + ) || (options.partitionByNewLine && lastSortingNode && getLinesBetween(sourceCode, lastSortingNode, sortingNode)) @@ -145,18 +145,22 @@ export default createEslintRule({ ignoreEslintDisabledNodes, }), ) + let sortedNodes = sortNodesExcludingEslintDisabled(false) let sortedNodesExcludingEslintDisabled = sortNodesExcludingEslintDisabled(true) + let nodeIndexMap = createNodeIndexMap(sortedNodes) + pairwise(nodes, (left, right) => { - let indexOfLeft = sortedNodes.indexOf(left) - let indexOfRight = sortedNodes.indexOf(right) + let leftIndex = nodeIndexMap.get(left)! + let rightIndex = nodeIndexMap.get(right)! + let indexOfRightExcludingEslintDisabled = sortedNodesExcludingEslintDisabled.indexOf(right) if ( - indexOfLeft < indexOfRight && - indexOfLeft < indexOfRightExcludingEslintDisabled + leftIndex < rightIndex && + leftIndex < indexOfRightExcludingEslintDisabled ) { return } diff --git a/rules/sort-named-imports.ts b/rules/sort-named-imports.ts index a3bdce20e..2aaa68bc6 100644 --- a/rules/sort-named-imports.ts +++ b/rules/sort-named-imports.ts @@ -15,6 +15,7 @@ import { import { validateCustomSortConfiguration } from '../utils/validate-custom-sort-configuration' import { getEslintDisabledLines } from '../utils/get-eslint-disabled-lines' import { isNodeEslintDisabled } from '../utils/is-node-eslint-disabled' +import { createNodeIndexMap } from '../utils/create-node-index-map' import { hasPartitionComment } from '../utils/is-partition-comment' import { getCommentsBefore } from '../utils/get-comments-before' import { createEslintRule } from '../utils/create-eslint-rule' @@ -112,14 +113,13 @@ export default createEslintRule({ } if ( - (options.partitionByComment && - hasPartitionComment( - options.partitionByComment, - getCommentsBefore({ - node: specifier, - sourceCode, - }), - )) || + hasPartitionComment( + options.partitionByComment, + getCommentsBefore({ + node: specifier, + sourceCode, + }), + ) || (options.partitionByNewLine && lastSortingNode && getLinesBetween(sourceCode, lastSortingNode, sortingNode)) @@ -154,18 +154,22 @@ export default createEslintRule({ ignoreEslintDisabledNodes, }), ) + let sortedNodes = sortNodesExcludingEslintDisabled(false) let sortedNodesExcludingEslintDisabled = sortNodesExcludingEslintDisabled(true) + let nodeIndexMap = createNodeIndexMap(sortedNodes) + pairwise(nodes, (left, right) => { - let indexOfLeft = sortedNodes.indexOf(left) - let indexOfRight = sortedNodes.indexOf(right) + let leftIndex = nodeIndexMap.get(left)! + let rightIndex = nodeIndexMap.get(right)! + let indexOfRightExcludingEslintDisabled = sortedNodesExcludingEslintDisabled.indexOf(right) if ( - indexOfLeft < indexOfRight && - indexOfLeft < indexOfRightExcludingEslintDisabled + leftIndex < rightIndex && + leftIndex < indexOfRightExcludingEslintDisabled ) { return } diff --git a/rules/sort-object-types.ts b/rules/sort-object-types.ts index b62a8a545..199ae0e92 100644 --- a/rules/sort-object-types.ts +++ b/rules/sort-object-types.ts @@ -33,6 +33,7 @@ import { isNodeEslintDisabled } from '../utils/is-node-eslint-disabled' import { allModifiers, allSelectors } from './sort-object-types.types' import { hasPartitionComment } from '../utils/is-partition-comment' import { isNodeFunctionType } from '../utils/is-node-function-type' +import { createNodeIndexMap } from '../utils/create-node-index-map' import { sortNodesByGroups } from '../utils/sort-nodes-by-groups' import { getCommentsBefore } from '../utils/get-comments-before' import { makeNewlinesFixes } from '../utils/make-newlines-fixes' @@ -262,7 +263,8 @@ export let sortObjectTypeElements = ({ return accumulator } - let lastSortingNode = accumulator.at(-1)?.at(-1) + let lastGroup = accumulator.at(-1) + let lastSortingNode = lastGroup?.at(-1) let { setCustomGroups, defineGroup, getGroup } = useGroups(options) @@ -283,8 +285,9 @@ export let sortObjectTypeElements = ({ } if ( - !selectors.includes('index-signature') && - !selectors.includes('method') + !(['index-signature', 'method']).some(selector => + selectors.includes(selector), + ) ) { selectors.push('property') } @@ -297,11 +300,13 @@ export let sortObjectTypeElements = ({ modifiers.push('required') } - for (let predefinedGroup of generatePredefinedGroups({ + let predefinedGroups = generatePredefinedGroups({ cache: cachedGroupsByModifiersAndSelectors, selectors, modifiers, - })) { + }) + + for (let predefinedGroup of predefinedGroups) { defineGroup(predefinedGroup) } @@ -317,7 +322,10 @@ export let sortObjectTypeElements = ({ }) ) { defineGroup(customGroup.groupName, true) - // If the custom group is not referenced in the `groups` option, it will be ignored + /** + * If the custom group is not referenced in the `groups` option, it + * will be ignored + */ if (getGroup() === customGroup.groupName) { break } @@ -355,10 +363,11 @@ export let sortObjectTypeElements = ({ lastSortingNode && getLinesBetween(sourceCode, lastSortingNode, sortingNode)) ) { - accumulator.push([]) + lastGroup = [] + accumulator.push(lastGroup) } - accumulator.at(-1)?.push(sortingNode) + lastGroup?.push(sortingNode) return accumulator }, @@ -394,20 +403,23 @@ export let sortObjectTypeElements = ({ let sortedNodesExcludingEslintDisabled = sortNodesExcludingEslintDisabled(true) + let nodeIndexMap = createNodeIndexMap(sortedNodes) + pairwise(nodes, (left, right) => { let leftNumber = getGroupNumber(options.groups, left) let rightNumber = getGroupNumber(options.groups, right) - let indexOfLeft = sortedNodes.indexOf(left) - let indexOfRight = sortedNodes.indexOf(right) + let leftIndex = nodeIndexMap.get(left)! + let rightIndex = nodeIndexMap.get(right)! + let indexOfRightExcludingEslintDisabled = sortedNodesExcludingEslintDisabled.indexOf(right) let messageIds: MessageIds[] = [] if ( - indexOfLeft > indexOfRight || - indexOfLeft >= indexOfRightExcludingEslintDisabled + leftIndex > rightIndex || + leftIndex >= indexOfRightExcludingEslintDisabled ) { messageIds.push( leftNumber === rightNumber diff --git a/rules/sort-objects.ts b/rules/sort-objects.ts index 767b28212..ebe0d0479 100644 --- a/rules/sort-objects.ts +++ b/rules/sort-objects.ts @@ -27,6 +27,7 @@ import { validateGroupsConfiguration } from '../utils/validate-groups-configurat import { getMatchingContextOptions } from '../utils/get-matching-context-options' import { getEslintDisabledLines } from '../utils/get-eslint-disabled-lines' import { isNodeEslintDisabled } from '../utils/is-node-eslint-disabled' +import { createNodeIndexMap } from '../utils/create-node-index-map' import { hasPartitionComment } from '../utils/is-partition-comment' import { sortNodesByGroups } from '../utils/sort-nodes-by-groups' import { getCommentsBefore } from '../utils/get-comments-before' @@ -369,14 +370,13 @@ export default createEslintRule({ lastProperty, propertySortingNode, )) || - (options.partitionByComment && - hasPartitionComment( - options.partitionByComment, - getCommentsBefore({ - node: property, - sourceCode, - }), - )) + hasPartitionComment( + options.partitionByComment, + getCommentsBefore({ + node: property, + sourceCode, + }), + ) ) { accumulator.push([]) } @@ -411,14 +411,18 @@ export default createEslintRule({ let sortedNodes = sortNodesIgnoringEslintDisabledNodes(false) let sortedNodesExcludingEslintDisabled = sortNodesIgnoringEslintDisabledNodes(true) + let nodes = formattedMembers.flat() + let nodeIndexMap = createNodeIndexMap(sortedNodes) + pairwise(nodes, (left, right) => { let leftNumber = getGroupNumber(options.groups, left) let rightNumber = getGroupNumber(options.groups, right) - let indexOfLeft = sortedNodes.indexOf(left) - let indexOfRight = sortedNodes.indexOf(right) + let leftIndex = nodeIndexMap.get(left)! + let rightIndex = nodeIndexMap.get(right)! + let indexOfRightExcludingEslintDisabled = sortedNodesExcludingEslintDisabled.indexOf(right) @@ -428,8 +432,8 @@ export default createEslintRule({ | undefined if ( - indexOfLeft > indexOfRight || - indexOfLeft >= indexOfRightExcludingEslintDisabled + leftIndex > rightIndex || + leftIndex >= indexOfRightExcludingEslintDisabled ) { firstUnorderedNodeDependentOnRight = getFirstUnorderedNodeDependentOn( right, diff --git a/rules/sort-switch-case.ts b/rules/sort-switch-case.ts index c9964e362..69fd50d46 100644 --- a/rules/sort-switch-case.ts +++ b/rules/sort-switch-case.ts @@ -13,6 +13,7 @@ import { } from '../utils/common-json-schemas' import { validateCustomSortConfiguration } from '../utils/validate-custom-sort-configuration' import { makeCommentAfterFixes } from '../utils/make-comment-after-fixes' +import { createNodeIndexMap } from '../utils/create-node-index-map' import { createEslintRule } from '../utils/create-eslint-rule' import { getSourceCode } from '../utils/get-source-code' import { rangeToDiff } from '../utils/range-to-diff' @@ -106,10 +107,13 @@ export default createEslintRule({ (node, index) => node !== caseNodesSortingNodeGroup[index], ) + let nodeIndexMap = createNodeIndexMap(sortedCaseNameSortingNodes) + pairwise(caseNodesSortingNodeGroup, (left, right) => { - let indexOfLeft = sortedCaseNameSortingNodes.indexOf(left) - let indexOfRight = sortedCaseNameSortingNodes.indexOf(right) - if (indexOfLeft < indexOfRight) { + let leftIndex = nodeIndexMap.get(left)! + let rightIndex = nodeIndexMap.get(right)! + + if (leftIndex < rightIndex) { return } @@ -326,15 +330,12 @@ let reduceCaseSortingNodes = ( ) let caseHasBreakOrReturn = (caseNode: TSESTree.SwitchCase): boolean => { - if (caseNode.consequent.length === 0) { - return false - } - if (caseNode.consequent[0]?.type === 'BlockStatement') { - return caseNode.consequent[0].body.some(statementIsBreakOrReturn) - } - return caseNode.consequent.some(currentConsequent => - statementIsBreakOrReturn(currentConsequent), - ) + let statements = + caseNode.consequent[0]?.type === 'BlockStatement' + ? caseNode.consequent[0].body + : caseNode.consequent + + return statements.some(statementIsBreakOrReturn) } let statementIsBreakOrReturn = ( diff --git a/rules/sort-union-types.ts b/rules/sort-union-types.ts index d10801eab..d7521faed 100644 --- a/rules/sort-union-types.ts +++ b/rules/sort-union-types.ts @@ -17,6 +17,7 @@ import { validateCustomSortConfiguration } from '../utils/validate-custom-sort-c import { validateGroupsConfiguration } from '../utils/validate-groups-configuration' import { getEslintDisabledLines } from '../utils/get-eslint-disabled-lines' import { isNodeEslintDisabled } from '../utils/is-node-eslint-disabled' +import { createNodeIndexMap } from '../utils/create-node-index-map' import { hasPartitionComment } from '../utils/is-partition-comment' import { sortNodesByGroups } from '../utils/sort-nodes-by-groups' import { getCommentsBefore } from '../utils/get-comments-before' @@ -179,7 +180,8 @@ export default createEslintRule({ break } - let lastSortingNode = accumulator.at(-1)?.at(-1) + let lastGroup = accumulator.at(-1) + let lastSortingNode = lastGroup?.at(-1) let sortingNode: SortingNode = { isEslintDisabled: isNodeEslintDisabled(type, eslintDisabledLines), size: rangeToDiff(type, sourceCode), @@ -188,23 +190,23 @@ export default createEslintRule({ node: type, } if ( - (options.partitionByComment && - hasPartitionComment( - options.partitionByComment, - getCommentsBefore({ - tokenValueToIgnoreBefore: '|', - node: type, - sourceCode, - }), - )) || + hasPartitionComment( + options.partitionByComment, + getCommentsBefore({ + tokenValueToIgnoreBefore: '|', + node: type, + sourceCode, + }), + ) || (options.partitionByNewLine && lastSortingNode && getLinesBetween(sourceCode, lastSortingNode, sortingNode)) ) { - accumulator.push([]) + lastGroup = [] + accumulator.push(lastGroup) } - accumulator.at(-1)?.push(sortingNode) + lastGroup?.push(sortingNode) return accumulator }, [[]], @@ -219,20 +221,23 @@ export default createEslintRule({ let sortedNodesExcludingEslintDisabled = sortNodesExcludingEslintDisabled(true) + let nodeIndexMap = createNodeIndexMap(sortedNodes) + pairwise(nodes, (left, right) => { let leftNumber = getGroupNumber(options.groups, left) let rightNumber = getGroupNumber(options.groups, right) - let indexOfLeft = sortedNodes.indexOf(left) - let indexOfRight = sortedNodes.indexOf(right) + let leftIndex = nodeIndexMap.get(left)! + let rightIndex = nodeIndexMap.get(right)! + let indexOfRightExcludingEslintDisabled = sortedNodesExcludingEslintDisabled.indexOf(right) let messageIds: MESSAGE_ID[] = [] if ( - indexOfLeft > indexOfRight || - indexOfLeft >= indexOfRightExcludingEslintDisabled + leftIndex > rightIndex || + leftIndex >= indexOfRightExcludingEslintDisabled ) { messageIds.push( leftNumber === rightNumber diff --git a/rules/sort-variable-declarations.ts b/rules/sort-variable-declarations.ts index 872f13dcd..c2f575cf9 100644 --- a/rules/sort-variable-declarations.ts +++ b/rules/sort-variable-declarations.ts @@ -19,6 +19,7 @@ import { import { validateCustomSortConfiguration } from '../utils/validate-custom-sort-configuration' import { getEslintDisabledLines } from '../utils/get-eslint-disabled-lines' import { isNodeEslintDisabled } from '../utils/is-node-eslint-disabled' +import { createNodeIndexMap } from '../utils/create-node-index-map' import { hasPartitionComment } from '../utils/is-partition-comment' import { getCommentsBefore } from '../utils/get-comments-before' import { createEslintRule } from '../utils/create-eslint-rule' @@ -200,14 +201,13 @@ export default createEslintRule({ name, } if ( - (options.partitionByComment && - hasPartitionComment( - options.partitionByComment, - getCommentsBefore({ - node: declaration, - sourceCode, - }), - )) || + hasPartitionComment( + options.partitionByComment, + getCommentsBefore({ + node: declaration, + sourceCode, + }), + ) || (options.partitionByNewLine && lastSortingNode && getLinesBetween(sourceCode, lastSortingNode, sortingNode)) @@ -238,16 +238,20 @@ export default createEslintRule({ let sortedNodes = sortNodesIgnoringEslintDisabledNodes(false) let sortedNodesExcludingEslintDisabled = sortNodesIgnoringEslintDisabledNodes(true) + let nodes = formattedMembers.flat() + let nodeIndexMap = createNodeIndexMap(sortedNodes) + pairwise(nodes, (left, right) => { - let indexOfLeft = sortedNodes.indexOf(left) - let indexOfRight = sortedNodes.indexOf(right) + let leftIndex = nodeIndexMap.get(left)! + let rightIndex = nodeIndexMap.get(right)! + let indexOfRightExcludingEslintDisabled = sortedNodesExcludingEslintDisabled.indexOf(right) if ( - indexOfLeft < indexOfRight && - indexOfLeft < indexOfRightExcludingEslintDisabled + leftIndex < rightIndex && + leftIndex < indexOfRightExcludingEslintDisabled ) { return } diff --git a/utils/create-node-index-map.ts b/utils/create-node-index-map.ts new file mode 100644 index 000000000..f606f57a4 --- /dev/null +++ b/utils/create-node-index-map.ts @@ -0,0 +1,13 @@ +import type { TSESTree } from '@typescript-eslint/types' + +import type { SortingNode } from '../typings' + +export let createNodeIndexMap = ( + nodes: SortingNode[], +): Map => { + let nodeIndexMap = new Map, number>() + for (let [index, node] of nodes.entries()) { + nodeIndexMap.set(node, index) + } + return nodeIndexMap +} diff --git a/utils/is-partition-comment.ts b/utils/is-partition-comment.ts index 0a95ce911..50a570d36 100644 --- a/utils/is-partition-comment.ts +++ b/utils/is-partition-comment.ts @@ -7,7 +7,7 @@ export let isPartitionComment = ( partitionComment: string[] | boolean | string, comment: string, ): boolean => { - if (getEslintDisabledRules(comment)) { + if (getEslintDisabledRules(comment) || !partitionComment) { return false } return ( diff --git a/utils/pairwise.ts b/utils/pairwise.ts index 414c78cb6..ee3b62d9e 100644 --- a/utils/pairwise.ts +++ b/utils/pairwise.ts @@ -11,8 +11,6 @@ export let pairwise = ( let left = nodes.at(i - 1) let right = nodes.at(i) - if (left && right) { - callback(left, right, i - 1) - } + callback(left!, right!, i - 1) } } diff --git a/utils/validate-groups-configuration.ts b/utils/validate-groups-configuration.ts index c47535472..31af72784 100644 --- a/utils/validate-groups-configuration.ts +++ b/utils/validate-groups-configuration.ts @@ -37,10 +37,18 @@ export let validateNoDuplicatedGroups = ( groups: (string[] | string)[], ): void => { let flattenGroups = groups.flat() - let duplicatedGroups = flattenGroups.filter( - (group, index) => flattenGroups.indexOf(group) !== index, - ) - if (duplicatedGroups.length) { - throw new Error(`Duplicated group(s): ${duplicatedGroups.join(', ')}`) + let seenGroups = new Set() + let duplicatedGroups = new Set() + + for (let group of flattenGroups) { + if (seenGroups.has(group)) { + duplicatedGroups.add(group) + } else { + seenGroups.add(group) + } + } + + if (duplicatedGroups.size > 0) { + throw new Error(`Duplicated group(s): ${[...duplicatedGroups].join(', ')}`) } }