eslint-plugin-perfectionist
Version:
ESLint plugin for sorting various data such as objects, imports, types, enums, JSX props, etc.
130 lines (129 loc) • 4.75 kB
JavaScript
import { UnreachableCaseError } from '../../utils/unreachable-case-error.js'
import { computeDependenciesBySortingNode as computeDependenciesBySortingNode$1 } from '../../utils/compute-dependencies-by-sorting-node.js'
import { computeParentNodesWithTypes } from '../../utils/compute-parent-nodes-with-types.js'
import { doesSortingNodeHaveOneOfDependencyNames } from '../../utils/does-sorting-node-have-one-of-dependency-names.js'
import { isPropertyOrAccessorNode } from './is-property-or-accessor-node.js'
import { isArrowFunctionNode } from './is-arrow-function-node.js'
import { AST_NODE_TYPES } from '@typescript-eslint/utils'
function computeDependenciesBySortingNode({
dependencyDetection,
sortingNodes,
sourceCode,
}) {
return computeDependenciesBySortingNode$1({
additionalIdentifierDependenciesComputer:
buildAdditionalIdentifierDependenciesComputer({ sortingNodes }),
shouldIgnoreSortingNodeComputer:
buildShouldIgnoreSortingNodeComputer(dependencyDetection),
shouldIgnoreIdentifierComputer:
buildShouldIgnoreIdentifierComputer(dependencyDetection),
sortingNodes,
sourceCode,
})
}
function buildShouldIgnoreIdentifierComputer(dependencyDetection) {
return ({ referencingSortingNode, identifier }) => {
switch (dependencyDetection) {
case 'soft':
return false
case 'hard':
return !isInRelevantClassContext()
/* v8 ignore next 2 -- @preserve Exhaustive guard. */
default:
throw new UnreachableCaseError(dependencyDetection)
}
function isInRelevantClassContext() {
let relevantParentNodes = computeParentNodesWithTypes({
allowedTypes: [
AST_NODE_TYPES.ClassBody,
AST_NODE_TYPES.PropertyDefinition,
AST_NODE_TYPES.AccessorProperty,
AST_NODE_TYPES.MethodDefinition,
AST_NODE_TYPES.ArrowFunctionExpression,
],
maxParent: referencingSortingNode.node,
consecutiveOnly: false,
node: identifier,
})
let firstClassBodyParent = relevantParentNodes.findIndex(
parentNode => parentNode.type === AST_NODE_TYPES.ClassBody,
)
if (firstClassBodyParent < 0) {
return true
}
let searchStaticMethodsAndFunctionProperties = relevantParentNodes[
firstClassBodyParent
].body.some(
classElement =>
classElement.type === AST_NODE_TYPES.StaticBlock ||
(classElement.static &&
isPropertyOrAccessorNode(classElement) &&
!isArrowFunctionNode(classElement)),
)
return relevantParentNodes
.slice(0, firstClassBodyParent)
.every(otherParent =>
isClassElementRelevant(
otherParent,
searchStaticMethodsAndFunctionProperties,
),
)
}
function isClassElementRelevant(
classElement,
searchStaticMethodsAndFunctionProperties,
) {
if (
classElement.type !== AST_NODE_TYPES.MethodDefinition &&
!isArrowFunctionNode(classElement)
) {
return true
}
return classElement.static && searchStaticMethodsAndFunctionProperties
}
}
}
function buildAdditionalIdentifierDependenciesComputer({ sortingNodes }) {
return ({ referencingSortingNode, reference }) => {
let relatedIdentifiers = [
...computeMemberExpressionIdentifiers(),
...computeQualifiedNameIdentifiers(),
]
return sortingNodes.filter(sortingNode =>
doesSortingNodeHaveOneOfDependencyNames(sortingNode, relatedIdentifiers),
)
function computeMemberExpressionIdentifiers() {
return computeParentNodesWithTypes({
allowedTypes: [AST_NODE_TYPES.MemberExpression],
maxParent: referencingSortingNode.node,
node: reference.identifier,
consecutiveOnly: true,
})
.map(node => node.property)
.filter(property => property.type === AST_NODE_TYPES.Identifier)
.map(property => property.name)
}
function computeQualifiedNameIdentifiers() {
return computeParentNodesWithTypes({
allowedTypes: [AST_NODE_TYPES.TSQualifiedName],
maxParent: referencingSortingNode.node,
node: reference.identifier,
consecutiveOnly: true,
}).map(node => node.right.name)
}
}
}
function buildShouldIgnoreSortingNodeComputer(dependencyDetection) {
return sortingNode => {
switch (dependencyDetection) {
case 'hard':
return sortingNode.dependencyDetection !== 'hard'
case 'soft':
return false
/* v8 ignore next 2 -- @preserve Exhaustive guard. */
default:
throw new UnreachableCaseError(dependencyDetection)
}
}
}
export { computeDependenciesBySortingNode }