Skip to content

Commit

Permalink
fix(sort-classes): fix dependency detection regression
Browse files Browse the repository at this point in the history
  • Loading branch information
hugop95 authored Feb 11, 2025
1 parent 00a8080 commit df40df4
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 84 deletions.
152 changes: 73 additions & 79 deletions rules/sort-classes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -332,8 +332,74 @@ export default createEslintRule<SortClassesOptions, MESSAGE_ID>({
let selectors: Selector[] = []
let addSafetySemicolonWhenInline: boolean = true
switch (member.type) {
case 'TSAbstractPropertyDefinition':
case 'PropertyDefinition':
/**
* Member is necessarily a property similarly to above for methods,
* prioritize 'static', 'declare', 'decorated', 'abstract',
* 'override' and 'readonly' over accessibility modifiers.
*/
if ('static' in member && member.static) {
modifiers.push('static')
}

if ('declare' in member && member.declare) {
modifiers.push('declare')
}

if (member.type === 'TSAbstractPropertyDefinition') {
modifiers.push('abstract')
}

if (decorated) {
modifiers.push('decorated')
}

if ('override' in member && member.override) {
modifiers.push('override')
}

if ('readonly' in member && member.readonly) {
modifiers.push('readonly')
}

if (
'accessibility' in member &&
member.accessibility === 'protected'
) {
modifiers.push('protected')
} else if (
('accessibility' in member &&
member.accessibility === 'private') ||
isPrivateHash
) {
modifiers.push('private')
} else {
modifiers.push('public')
}

if ('optional' in member && member.optional) {
modifiers.push('optional')
}

if (
member.value?.type === 'ArrowFunctionExpression' ||
member.value?.type === 'FunctionExpression'
) {
if (member.value.async) {
modifiers.push('async')
}
selectors.push('function-property')
} else if (member.value) {
memberValue = sourceCode.getText(member.value)
dependencies = extractDependencies(member.value, member.static)
}

selectors.push('property')
break

case 'TSAbstractMethodDefinition':
case 'MethodDefinition': {
case 'MethodDefinition':
/**
* By putting the static modifier before accessibility modifiers, we
* prioritize 'static' over those in cases like:
Expand Down Expand Up @@ -389,9 +455,9 @@ export default createEslintRule<SortClassesOptions, MESSAGE_ID>({
selectors.push('method')

break
}

case 'TSAbstractAccessorProperty':
case 'AccessorProperty': {
case 'AccessorProperty':
if (member.static) {
modifiers.push('static')
}
Expand All @@ -418,8 +484,8 @@ export default createEslintRule<SortClassesOptions, MESSAGE_ID>({
selectors.push('accessor-property')

break
}
case 'TSIndexSignature': {

case 'TSIndexSignature':
if (member.static) {
modifiers.push('static')
}
Expand All @@ -431,87 +497,15 @@ export default createEslintRule<SortClassesOptions, MESSAGE_ID>({
selectors.push('index-signature')

break
}
case 'StaticBlock': {

case 'StaticBlock':
addSafetySemicolonWhenInline = false

selectors.push('static-block')

dependencies = extractDependencies(member, true)

break
}
default: {
/**
* Member is necessarily a property similarly to above for methods,
* prioritize 'static', 'declare', 'decorated', 'abstract',
* 'override' and 'readonly' over accessibility modifiers.
*/
if ('static' in member && member.static) {
modifiers.push('static')
}

if ('declare' in member && member.declare) {
modifiers.push('declare')
}

if (member.type === 'TSAbstractPropertyDefinition') {
modifiers.push('abstract')
}

if (decorated) {
modifiers.push('decorated')
}

if ('override' in member && member.override) {
modifiers.push('override')
}

if ('readonly' in member && member.readonly) {
modifiers.push('readonly')
}

if (
'accessibility' in member &&
member.accessibility === 'protected'
) {
modifiers.push('protected')
} else if (
('accessibility' in member &&
member.accessibility === 'private') ||
isPrivateHash
) {
modifiers.push('private')
} else {
modifiers.push('public')
}

if ('optional' in member && member.optional) {
modifiers.push('optional')
}

if ('value' in member && member.value) {
if (
member.value.type === 'ArrowFunctionExpression' ||
member.value.type === 'FunctionExpression'
) {
if (member.value.async) {
modifiers.push('async')
}
selectors.push('function-property')
} else {
memberValue = sourceCode.getText(member.value)
}
if (member.value.type !== 'TSEmptyBodyFunctionExpression') {
dependencies = extractDependencies(
member.value,
member.static,
)
}
}

selectors.push('property')
}
}

let predefinedGroups = generatePredefinedGroups({
Expand Down
7 changes: 2 additions & 5 deletions rules/sort-maps.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { TSESLint } from '@typescript-eslint/utils'

import { TSESTree } from '@typescript-eslint/types'
import type { TSESTree } from '@typescript-eslint/types'

import type { SortingNode } from '../types/sorting-node'
import type { Options } from './sort-maps/types'
Expand Down Expand Up @@ -83,9 +82,7 @@ export default createEslintRule<Options, MESSAGE_ID>({
let matchedContextOptions = getMatchingContextOptions({
nodeNames: elements
.filter(
element =>
element !== null &&
element.type !== TSESTree.AST_NODE_TYPES.SpreadElement,
element => element !== null && element.type !== 'SpreadElement',
)
.map(element => getNodeName({ sourceCode, element })),
contextOptions: context.options,
Expand Down
13 changes: 13 additions & 0 deletions test/rules/sort-classes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2784,6 +2784,19 @@ describe(ruleName, () => {
},
],
},
{
code: dedent`
class MyClass {
a = () => this.b()
b = () => null
}
`,
options: [
{
...options,
},
],
},
],
invalid: [],
},
Expand Down

0 comments on commit df40df4

Please sign in to comment.