Skip to content

Commit

Permalink
feat(sort-classes): add async modifier
Browse files Browse the repository at this point in the history
  • Loading branch information
hugop95 authored and azat-io committed Nov 19, 2024
1 parent 9f9f5c1 commit be0b68f
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 32 deletions.
6 changes: 4 additions & 2 deletions docs/content/rules/sort-classes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ Predefined groups are characterized by a single selector and potentially multipl

#### Methods
- Selectors: `get-method`, `set-method`, `method`.
- Modifiers: `static`, `abstract`, `decorated`, `override`, `protected`, `private`, `public`, `optional`.
- Modifiers: `static`, `abstract`, `decorated`, `override`, `protected`, `private`, `public`, `optional`, `async`.
- Example: `private-static-accessor-property`, `protected-abstract-override-method` or `static-get-method`.

The `optional` modifier is incompatible with the `get-method` and `set-method` selectors.
Expand All @@ -339,7 +339,7 @@ The `abstract` modifier is incompatible with the `static`, `private` and `decora

#### Properties
- Selectors: `function-property`, `property`.
- Modifiers: `static`, `declare`, `abstract`, `decorated`, `override`, `readonly`, `protected`, `private`, `public`, `optional`.
- Modifiers: `static`, `declare`, `abstract`, `decorated`, `override`, `readonly`, `protected`, `private`, `public`, `optional`, `async`.
- Example: `readonly-decorated-property`.

The `abstract` modifier is incompatible with the `static`, `private` and `decorated` modifiers.
Expand All @@ -349,6 +349,8 @@ The `declare` modifier is incompatible with the `override` and `decorated` modif
The `function-property` selector will match properties whose values are defined functions or arrow-functions.
As such, the `declare` and `abstract` modifiers are incompatible with this selector.

The `async` modifier is reserved for the `function-property` selector.

#### Index-signatures
- Selector: `index-signature`.
- Modifiers: `static`, `readonly`.
Expand Down
24 changes: 11 additions & 13 deletions rules/sort-classes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,10 @@ export default createEslintRule<SortClassesOptions, MESSAGE_ID>({
modifiers.push('optional')
}

if (member.value.async) {
modifiers.push('async')
}

if (member.kind === 'constructor') {
selectors.push('constructor')
}
Expand Down Expand Up @@ -544,26 +548,20 @@ export default createEslintRule<SortClassesOptions, MESSAGE_ID>({
modifiers.push('optional')
}

let isFunctionProperty =
if (
member.value?.type === 'ArrowFunctionExpression' ||
member.value?.type === 'FunctionExpression'
if (isFunctionProperty) {
) {
if (member.value.async) {
modifiers.push('async')
}
selectors.push('function-property')
}

if (!isFunctionProperty && member.value) {
} else if (member.value) {
memberValue = sourceCode.getText(member.value)
dependencies = extractDependencies(member.value, member.static)
}

selectors.push('property')

if (
member.type === 'PropertyDefinition' &&
member.value &&
!isFunctionProperty
) {
dependencies = extractDependencies(member.value, member.static)
}
}

for (let officialGroup of generatePredefinedGroups({
Expand Down
18 changes: 12 additions & 6 deletions rules/sort-classes.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ type PublicOrProtectedOrPrivateModifier =
| ProtectedModifier
| PrivateModifier
| PublicModifier
type AsyncModifier = 'async'
type StaticModifier = 'static'
type AbstractModifier = 'abstract'
type OverrideModifier = 'override'
Expand All @@ -23,6 +24,7 @@ export type Modifier =
| ReadonlyModifier
| DeclareModifier
| StaticModifier
| AsyncModifier

type ConstructorSelector = 'constructor'
type FunctionPropertySelector = 'function-property'
Expand Down Expand Up @@ -50,6 +52,7 @@ type PublicOrProtectedOrPrivateModifierPrefix = WithDashSuffixOrEmpty<
ProtectedModifier | PrivateModifier | PublicModifier
>

type AsyncModifierPrefix = WithDashSuffixOrEmpty<AsyncModifier>
type OverrideModifierPrefix = WithDashSuffixOrEmpty<OverrideModifier>
type OptionalModifierPrefix = WithDashSuffixOrEmpty<OptionalModifier>
type ReadonlyModifierPrefix = WithDashSuffixOrEmpty<ReadonlyModifier>
Expand All @@ -67,13 +70,13 @@ type GetMethodOrSetMethodSelector = GetMethodSelector | SetMethodSelector
type ConstructorGroup =
`${PublicOrProtectedOrPrivateModifierPrefix}${ConstructorSelector}`
type FunctionPropertyGroup =
`${PublicOrProtectedOrPrivateModifierPrefix}${StaticModifierPrefix}${OverrideModifierPrefix}${ReadonlyModifierPrefix}${DecoratedModifierPrefix}${FunctionPropertySelector}`
`${PublicOrProtectedOrPrivateModifierPrefix}${StaticModifierPrefix}${OverrideModifierPrefix}${ReadonlyModifierPrefix}${DecoratedModifierPrefix}${AsyncModifierPrefix}${FunctionPropertySelector}`
type DeclarePropertyGroup =
`${DeclareModifierPrefix}${PublicOrProtectedOrPrivateModifierPrefix}${StaticOrAbstractModifierPrefix}${ReadonlyModifierPrefix}${OptionalModifierPrefix}${PropertySelector}`
type NonDeclarePropertyGroup =
`${PublicOrProtectedOrPrivateModifierPrefix}${StaticOrAbstractModifierPrefix}${OverrideModifierPrefix}${ReadonlyModifierPrefix}${DecoratedModifierPrefix}${OptionalModifierPrefix}${PropertySelector}`
type MethodGroup =
`${PublicOrProtectedOrPrivateModifierPrefix}${StaticOrAbstractModifierPrefix}${OverrideModifierPrefix}${DecoratedModifierPrefix}${OptionalModifierPrefix}${MethodSelector}`
`${PublicOrProtectedOrPrivateModifierPrefix}${StaticOrAbstractModifierPrefix}${OverrideModifierPrefix}${DecoratedModifierPrefix}${AsyncModifierPrefix}${OptionalModifierPrefix}${MethodSelector}`
type GetMethodOrSetMethodGroup =
`${PublicOrProtectedOrPrivateModifierPrefix}${StaticOrAbstractModifierPrefix}${OverrideModifierPrefix}${DecoratedModifierPrefix}${GetMethodOrSetMethodSelector}`
type AccessorPropertyGroup =
Expand Down Expand Up @@ -121,17 +124,19 @@ interface AllowedModifiersPerSelector {
| OverrideModifier
| OptionalModifier
| StaticModifier
'accessor-property':
| AsyncModifier
'function-property':
| PublicOrProtectedOrPrivateModifier
| DecoratedModifier
| AbstractModifier
| OverrideModifier
| ReadonlyModifier
| StaticModifier
'function-property':
| AsyncModifier
'accessor-property':
| PublicOrProtectedOrPrivateModifier
| DecoratedModifier
| AbstractModifier
| OverrideModifier
| ReadonlyModifier
| StaticModifier
'set-method':
| PublicOrProtectedOrPrivateModifier
Expand Down Expand Up @@ -213,6 +218,7 @@ export let allSelectors: Selector[] = [
]

export let allModifiers: Modifier[] = [
'async',
'protected',
'private',
'public',
Expand Down
112 changes: 101 additions & 11 deletions test/sort-classes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,17 +189,17 @@ describe(ruleName, () => {
code: dedent`
abstract class Class {
p?(): void;
async p?(): Promise<void>;
o?;
static {}
static readonly [key: string]: string;
private n = function() {};
private n = async function() {};
private m = () => {};
private m = async () => {};
declare private static readonly l;
Expand Down Expand Up @@ -257,17 +257,17 @@ describe(ruleName, () => {
declare private static readonly l;
private m = () => {};
private m = async () => {};
private n = function() {};
private n = async function() {};
static readonly [key: string]: string;
static {}
o?;
p?(): void;
async p?(): Promise<void>;
}
`,
options: [
Expand All @@ -287,11 +287,11 @@ describe(ruleName, () => {
'protected-property',
'private-property',
'declare-private-static-readonly-property',
'function-property',
'async-function-property',
'static-readonly-index-signature',
'static-block',
'public-optional-property',
'public-optional-method',
'public-optional-async-method',
],
},
],
Expand All @@ -300,7 +300,7 @@ describe(ruleName, () => {
messageId: 'unexpectedClassesGroupOrder',
data: {
left: 'p',
leftGroup: 'public-optional-method',
leftGroup: 'public-optional-async-method',
right: 'o',
rightGroup: 'public-optional-property',
},
Expand Down Expand Up @@ -329,7 +329,7 @@ describe(ruleName, () => {
left: 'static readonly [key: string]',
leftGroup: 'static-readonly-index-signature',
right: 'n',
rightGroup: 'function-property',
rightGroup: 'async-function-property',
},
},
{
Expand All @@ -343,7 +343,7 @@ describe(ruleName, () => {
messageId: 'unexpectedClassesGroupOrder',
data: {
left: 'm',
leftGroup: 'function-property',
leftGroup: 'async-function-property',
right: 'l',
rightGroup: 'declare-private-static-readonly-property',
},
Expand Down Expand Up @@ -926,6 +926,51 @@ describe(ruleName, () => {
},
)
}

ruleTester.run(
`${ruleName}(${type}): prioritize optional over async`,
rule,
{
valid: [],
invalid: [
{
code: dedent`
export class Class {
a: string;
async z?(): Promise<string>;
}
`,
output: dedent`
export class Class {
async z?(): Promise<string>;
a: string;
}
`,
options: [
{
...options,
groups: [`optional-method`, 'property', 'async-method'],
},
],
errors: [
{
messageId: 'unexpectedClassesGroupOrder',
data: {
left: 'a',
leftGroup: 'property',
right: 'z',
rightGroup: `optional-method`,
},
},
],
},
],
},
)
})

describe(`${ruleName}(${type}): accessor modifiers priority`, () => {
Expand Down Expand Up @@ -1596,6 +1641,51 @@ describe(ruleName, () => {
},
)
}

ruleTester.run(
`${ruleName}(${type}): prioritize optional over async`,
rule,
{
valid: [],
invalid: [
{
code: dedent`
export class Class {
a(): void {}
z?: Promise<string> = async () => {};
}
`,
output: dedent`
export class Class {
z?: Promise<string> = async () => {};
a(): void {}
}
`,
options: [
{
...options,
groups: ['optional-property', 'method', `async-property`],
},
],
errors: [
{
messageId: 'unexpectedClassesGroupOrder',
data: {
left: 'a',
leftGroup: 'method',
right: 'z',
rightGroup: `optional-property`,
},
},
],
},
],
},
)
})

ruleTester.run(
Expand Down

0 comments on commit be0b68f

Please sign in to comment.