UNPKG

eslint-plugin-perfectionist

Version:

ESLint plugin for sorting various data such as objects, imports, types, enums, JSX props, etc.

216 lines (215 loc) 7.05 kB
import { UnreachableCaseError } from '../../utils/unreachable-case-error.js' import { isArrowFunctionNode } from './is-arrow-function-node.js' import { getEnumMembers } from '../../utils/get-enum-members.js' import { AST_NODE_TYPES } from '@typescript-eslint/utils' /** * Computes the dependencies of a given AST node. * * @deprecated - To remove when experimental dependency detection is the only * option. * @param node - The AST node to analyze. * @param dependencyDetection - The dependency detection strategy. Hard * dependencies consider dependencies impacting compilation, while soft * dependencies also consider type references. * @returns The names of the dependencies. */ function computeDependencies(node, dependencyDetection) { let dependencies = [] checkNode(node) return dependencies function checkNode(nodeToCheck, options) { switch (dependencyDetection.type) { case 'hard': if ( (nodeToCheck.type === AST_NODE_TYPES.MethodDefinition || isArrowFunctionNode(nodeToCheck)) && (!nodeToCheck.static || !dependencyDetection.searchStaticMethodsAndFunctionProperties) ) { return } break case 'soft': checkNodesForSoftDependencies() break /* v8 ignore next 2 -- @preserve Exhaustive guard. */ default: throw new UnreachableCaseError(dependencyDetection) } checkNodesForCommonDependencies() function checkNodesForCommonDependencies() { if ( !options?.ignoreNextIdentifier && nodeToCheck.type === AST_NODE_TYPES.Identifier ) { dependencies.push(nodeToCheck.name) } if ('alternate' in nodeToCheck && nodeToCheck.alternate) { checkNode(nodeToCheck.alternate) } if ('argument' in nodeToCheck && nodeToCheck.argument) { checkNode(nodeToCheck.argument) } if ('arguments' in nodeToCheck) { traverseNode(nodeToCheck.arguments) } if ( 'body' in nodeToCheck && nodeToCheck.body && nodeToCheck.type !== AST_NODE_TYPES.TSEnumDeclaration ) { traverseNode(nodeToCheck.body) } if ('callee' in nodeToCheck) { checkNode(nodeToCheck.callee) } if ('consequent' in nodeToCheck) { traverseNode(nodeToCheck.consequent) } if ('declarations' in nodeToCheck) { traverseNode(nodeToCheck.declarations) } if ('decorators' in nodeToCheck) { traverseNode(nodeToCheck.decorators) } if ('elements' in nodeToCheck) { traverseNode( nodeToCheck.elements.filter(currentNode => currentNode !== null), ) } if ( 'expression' in nodeToCheck && typeof nodeToCheck.expression !== 'boolean' ) { checkNode(nodeToCheck.expression) } if ('expressions' in nodeToCheck) { traverseNode(nodeToCheck.expressions) } if ('init' in nodeToCheck && nodeToCheck.init) { checkNode(nodeToCheck.init) } if ('initializer' in nodeToCheck && nodeToCheck.initializer) { checkNode(nodeToCheck.initializer) } if ('left' in nodeToCheck) { checkNode(nodeToCheck.left) } if (nodeToCheck.type === AST_NODE_TYPES.TSEnumDeclaration) { traverseNode(getEnumMembers(nodeToCheck)) } else if ('members' in nodeToCheck) { traverseNode(nodeToCheck.members) } if ('object' in nodeToCheck) { checkNode(nodeToCheck.object) } if ('properties' in nodeToCheck) { traverseNode(nodeToCheck.properties) } if ('property' in nodeToCheck) { checkNode(nodeToCheck.property) } if ('right' in nodeToCheck) { checkNode(nodeToCheck.right) } if ('superClass' in nodeToCheck && nodeToCheck.superClass) { checkNode(nodeToCheck.superClass) } if ('test' in nodeToCheck && nodeToCheck.test) { checkNode(nodeToCheck.test) } if ( 'value' in nodeToCheck && nodeToCheck.value && typeof nodeToCheck.value === 'object' && 'type' in nodeToCheck.value ) { checkNode(nodeToCheck.value) } } function checkNodesForSoftDependencies() { if ('checkType' in nodeToCheck) { checkNode(nodeToCheck.checkType) } if ('constraint' in nodeToCheck && nodeToCheck.constraint) { checkNode(nodeToCheck.constraint) } if ('declaration' in nodeToCheck && nodeToCheck.declaration) { checkNode(nodeToCheck.declaration) } if ('elementTypes' in nodeToCheck) { traverseNode(nodeToCheck.elementTypes) } if ('elementType' in nodeToCheck) { checkNode(nodeToCheck.elementType) } if ('extends' in nodeToCheck) { traverseNode(nodeToCheck.extends) } if ('extendsType' in nodeToCheck) { checkNode(nodeToCheck.extendsType) } if ('exprName' in nodeToCheck) { checkNode(nodeToCheck.exprName) } if ('falseType' in nodeToCheck) { checkNode(nodeToCheck.falseType) } if ('key' in nodeToCheck) { checkNode(nodeToCheck.key, { ignoreNextIdentifier: true }) } if ('id' in nodeToCheck && nodeToCheck.id) { checkNode(nodeToCheck.id) } if ('implements' in nodeToCheck) { traverseNode(nodeToCheck.implements) } if ('indexType' in nodeToCheck) { checkNode(nodeToCheck.indexType) } if ('name' in nodeToCheck && typeof nodeToCheck.name !== 'string') { checkNode(nodeToCheck.name) } if ('objectType' in nodeToCheck) { checkNode(nodeToCheck.objectType) } if ('params' in nodeToCheck) { traverseNode(nodeToCheck.params, { ignoreNextIdentifier: true }) } if ('returnType' in nodeToCheck && nodeToCheck.returnType) { checkNode(nodeToCheck.returnType) } if ('trueType' in nodeToCheck) { checkNode(nodeToCheck.trueType) } if ('typeAnnotation' in nodeToCheck && nodeToCheck.typeAnnotation) { checkNode(nodeToCheck.typeAnnotation) } if ('typeArguments' in nodeToCheck && nodeToCheck.typeArguments) { checkNode(nodeToCheck.typeArguments) } if ('typeName' in nodeToCheck) { checkNode(nodeToCheck.typeName) } if ('typeParameters' in nodeToCheck && nodeToCheck.typeParameters) { traverseNode(nodeToCheck.typeParameters) } if ('typeParameter' in nodeToCheck) { checkNode(nodeToCheck.typeParameter) } if ('types' in nodeToCheck) { traverseNode(nodeToCheck.types) } } } function traverseNode(nodeToTraverse, options) { if (Array.isArray(nodeToTraverse)) { for (let nodeItem of nodeToTraverse) { traverseNode(nodeItem, options) } } else { checkNode(nodeToTraverse, options) } } } export { computeDependencies }