eslint-plugin-perfectionist
Version:
ESLint plugin for sorting various data such as objects, imports, types, enums, JSX props, etc.
224 lines (223 loc) • 7.54 kB
JavaScript
import { computeDependenciesOutsideFunctionsBySortingNode } from '../../utils/compute-dependencies-outside-functions-by-sorting-node.js'
import { populateSortingNodeGroupsWithDependencies } from '../../utils/populate-sorting-node-groups-with-dependencies.js'
import { validateNewlinesAndPartitionConfiguration } from '../../utils/validate-newlines-and-partition-configuration.js'
import { buildOptionsByGroupIndexComputer } from '../../utils/build-options-by-group-index-computer.js'
import { validateCustomSortConfiguration } from '../../utils/validate-custom-sort-configuration.js'
import { validateGroupsConfiguration } from '../../utils/validate-groups-configuration.js'
import { generatePredefinedGroups } from '../../utils/generate-predefined-groups.js'
import { sortNodesByDependencies } from '../../utils/sort-nodes-by-dependencies.js'
import { getEslintDisabledLines } from '../../utils/get-eslint-disabled-lines.js'
import { doesCustomGroupMatch } from '../../utils/does-custom-group-match.js'
import { isNodeEslintDisabled } from '../../utils/is-node-eslint-disabled.js'
import { sortNodesByGroups } from '../../utils/sort-nodes-by-groups.js'
import { reportAllErrors } from '../../utils/report-all-errors.js'
import { shouldPartition } from '../../utils/should-partition.js'
import { computeGroup } from '../../utils/compute-group.js'
import { rangeToDiff } from '../../utils/range-to-diff.js'
import { getSettings } from '../../utils/get-settings.js'
import { isSortable } from '../../utils/is-sortable.js'
import { complete } from '../../utils/complete.js'
import { isNodeOnSingleLine } from '../../utils/is-node-on-single-line.js'
import {
DEPENDENCY_ORDER_ERROR_ID,
EXTRA_SPACING_ERROR_ID,
GROUP_ORDER_ERROR_ID,
MISSED_SPACING_ERROR_ID,
ORDER_ERROR_ID,
allModifiers,
allSelectors,
} from './types.js'
import { computePropertyOrVariableDeclaratorName } from './compute-property-or-variable-declarator-name.js'
import { computeMatchedContextOptions } from './compute-matched-context-options.js'
import { comparatorByOptionsComputer } from './comparator-by-options-computer.js'
import { computeDependencyNames } from './compute-dependency-names.js'
import { computeDependencies } from './compute-dependencies.js'
import { isStyleComponent } from './is-style-component.js'
import { computeNodeValue } from './compute-node-value.js'
import { AST_NODE_TYPES } from '@typescript-eslint/utils'
/**
* Cache computed groups by modifiers and selectors for performance.
*/
var cachedGroupsByModifiersAndSelectors = /* @__PURE__ */ new Map()
var defaultOptions = {
useExperimentalDependencyDetection: true,
fallbackSort: { type: 'unsorted' },
newlinesInside: 'newlinesBetween',
partitionByComputedKey: false,
partitionByNewLine: false,
partitionByComment: false,
newlinesBetween: 'ignore',
specialCharacters: 'keep',
styledComponents: true,
useConfigurationIf: {},
type: 'alphabetical',
ignoreCase: true,
customGroups: [],
locales: 'en-US',
sortBy: 'name',
alphabet: '',
order: 'asc',
groups: [],
}
function sortObject({ matchedAstSelectors, context, node }) {
if (!isSortable(node.properties)) {
return
}
let { sourceCode, id } = context
let settings = getSettings(context.settings)
let isDestructuredObject = node.type === AST_NODE_TYPES.ObjectPattern
let options = complete(
computeMatchedContextOptions({
isDestructuredObject,
matchedAstSelectors,
nodeObject: node,
sourceCode,
context,
}),
settings,
defaultOptions,
)
validateCustomSortConfiguration(options)
validateGroupsConfiguration({
selectors: allSelectors,
modifiers: allModifiers,
options,
})
validateNewlinesAndPartitionConfiguration(options)
if (!options.styledComponents && isStyleComponent(node)) {
return
}
let eslintDisabledLines = getEslintDisabledLines({
ruleName: id,
sourceCode,
})
let optionsByGroupIndexComputer = buildOptionsByGroupIndexComputer(options)
let sortingNodeGroups = [[]]
for (let property of node.properties) {
if (
property.type === AST_NODE_TYPES.SpreadElement ||
property.type === AST_NODE_TYPES.RestElement
) {
sortingNodeGroups.push([])
continue
}
if (
options.partitionByComputedKey &&
!isDestructuredObject &&
property.computed
) {
sortingNodeGroups.push([])
continue
}
let lastSortingNode = sortingNodeGroups.at(-1)?.at(-1)
let selectors = []
let modifiers = []
if (
property.value.type === AST_NODE_TYPES.ArrowFunctionExpression ||
property.value.type === AST_NODE_TYPES.FunctionExpression
) {
selectors.push('method')
} else {
selectors.push('property')
}
selectors.push('member')
if (!isNodeOnSingleLine(property)) {
modifiers.push('multiline')
}
let name = computePropertyOrVariableDeclaratorName({
node: property,
sourceCode,
})
let dependencyNames = [name]
if (isDestructuredObject) {
dependencyNames = [...new Set(computeDependencyNames(property.value))]
}
let value = computeNodeValue({
isDestructuredObject,
sourceCode,
property,
})
let group = computeGroup({
customGroupMatcher: customGroup =>
doesCustomGroupMatch({
elementValue: value,
elementName: name,
customGroup,
selectors,
modifiers,
}),
predefinedGroups: generatePredefinedGroups({
cache: cachedGroupsByModifiersAndSelectors,
selectors,
modifiers,
}),
options,
})
let sortingNode = {
dependencies:
options.useExperimentalDependencyDetection ?
[]
: computeDependencies(property),
isEslintDisabled: isNodeEslintDisabled(property, eslintDisabledLines),
size: rangeToDiff(property, sourceCode),
value: value ?? '',
dependencyNames,
node: property,
group,
name,
}
if (
shouldPartition({
lastSortingNode,
sortingNode,
sourceCode,
options,
})
) {
sortingNodeGroups.push([])
}
sortingNodeGroups.at(-1).push({
...sortingNode,
partitionId: sortingNodeGroups.length,
})
}
if (options.useExperimentalDependencyDetection) {
sortingNodeGroups = populateSortingNodeGroupsWithDependencies({
dependenciesBySortingNode:
computeDependenciesOutsideFunctionsBySortingNode({
sortingNodes: sortingNodeGroups.flat(),
sourceCode,
}),
sortingNodeGroups,
})
}
let sortingNodes = sortingNodeGroups.flat()
reportAllErrors({
availableMessageIds: {
missedSpacingBetweenMembers: MISSED_SPACING_ERROR_ID,
unexpectedDependencyOrder: DEPENDENCY_ORDER_ERROR_ID,
extraSpacingBetweenMembers: EXTRA_SPACING_ERROR_ID,
unexpectedGroupOrder: GROUP_ORDER_ERROR_ID,
unexpectedOrder: ORDER_ERROR_ID,
},
sortNodesExcludingEslintDisabled,
nodes: sortingNodes,
options,
context,
})
function sortNodesExcludingEslintDisabled(ignoreEslintDisabledNodes) {
return sortNodesByDependencies(
sortingNodeGroups.flatMap(nodes =>
sortNodesByGroups({
comparatorByOptionsComputer,
optionsByGroupIndexComputer,
ignoreEslintDisabledNodes,
groups: options.groups,
nodes,
}),
),
{ ignoreEslintDisabledNodes },
)
}
}
export { defaultOptions, sortObject }