Skip to content

Commit

Permalink
perf: improve rules performance
Browse files Browse the repository at this point in the history
  • Loading branch information
azat-io authored Dec 19, 2024
1 parent aa18f1a commit 42ac82d
Show file tree
Hide file tree
Showing 22 changed files with 356 additions and 241 deletions.
44 changes: 28 additions & 16 deletions rules/sort-array-includes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -168,12 +169,14 @@ export let sortArray = <MessageIds extends string>({

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,
Expand All @@ -198,6 +201,7 @@ export let sortArray = <MessageIds extends string>({
ruleName: context.id,
sourceCode,
})

let formattedMembers: SortArrayIncludesSortingNode[][] = elements.reduce(
(
accumulator: SortArrayIncludesSortingNode[][],
Expand All @@ -218,11 +222,13 @@ export let sortArray = <MessageIds extends string>({
selector = 'literal'
}

for (let predefinedGroup of generatePredefinedGroups({
let predefinedGroups = generatePredefinedGroups({
cache: cachedGroupsByModifiersAndSelectors,
selectors: [selector],
modifiers: [],
})) {
})

for (let predefinedGroup of predefinedGroups) {
defineGroup(predefinedGroup)
}

Expand All @@ -236,7 +242,10 @@ export let sortArray = <MessageIds extends string>({
})
) {
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
}
Expand All @@ -245,23 +254,22 @@ export let sortArray = <MessageIds extends string>({

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))
Expand Down Expand Up @@ -303,21 +311,25 @@ export let sortArray = <MessageIds extends string>({
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
}
Expand Down
23 changes: 12 additions & 11 deletions rules/sort-classes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -494,12 +494,14 @@ export default createEslintRule<SortClassesOptions, MESSAGE_ID>({
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) {
Expand Down Expand Up @@ -553,14 +555,13 @@ export default createEslintRule<SortClassesOptions, MESSAGE_ID>({
(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([])
}
Expand Down
13 changes: 8 additions & 5 deletions rules/sort-decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -218,7 +219,6 @@ let sortDecorators = (
let formattedMembers: SortDecoratorsSortingNode[][] = decorators.reduce(
(accumulator: SortDecoratorsSortingNode[][], decorator) => {
if (
options.partitionByComment &&
hasPartitionComment(
options.partitionByComment,
getCommentsBefore({
Expand Down Expand Up @@ -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
}
Expand Down
71 changes: 39 additions & 32 deletions rules/sort-enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -96,37 +97,35 @@ export default createEslintRule<Options, MESSAGE_ID>({
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[] = []
Expand Down Expand Up @@ -154,14 +153,13 @@ export default createEslintRule<Options, MESSAGE_ID>({
}

if (
(options.partitionByComment &&
hasPartitionComment(
options.partitionByComment,
getCommentsBefore({
node: member,
sourceCode,
}),
)) ||
hasPartitionComment(
options.partitionByComment,
getCommentsBefore({
node: member,
sourceCode,
}),
) ||
(options.partitionByNewLine &&
lastSortingNode &&
getLinesBetween(sourceCode, lastSortingNode, sortingNode))
Expand All @@ -176,11 +174,13 @@ export default createEslintRule<Options, MESSAGE_ID>({
)

let sortingNodes = formattedMembers.flat()

let isNumericEnum = sortingNodes.every(
sortingNode =>
sortingNode.numericValue !== null &&
!Number.isNaN(sortingNode.numericValue),
)

let compareOptions: CompareOptions<SortEnumsSortingNode> = {
// Get the enum value rather than the name if needed
nodeValueGetter:
Expand All @@ -195,7 +195,10 @@ export default createEslintRule<Options, MESSAGE_ID>({
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'
Expand All @@ -220,18 +223,22 @@ export default createEslintRule<Options, MESSAGE_ID>({
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
}
Expand Down
13 changes: 9 additions & 4 deletions rules/sort-exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -136,18 +137,22 @@ export default createEslintRule<Options, MESSAGE_ID>({
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
}
Expand Down
Loading

0 comments on commit 42ac82d

Please sign in to comment.