Skip to content

Commit 41b92d3

Browse files
authored
feat: add property-function groups in sort-class rule
1 parent 8e15730 commit 41b92d3

File tree

3 files changed

+140
-1
lines changed

3 files changed

+140
-1
lines changed

docs/content/rules/sort-classes.mdx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,13 +232,17 @@ The `abstract` modifier is incompatible with the `static`, `private` and `decora
232232
`constructor`, `get-method` and `set-method` elements will also be matched as `method`.
233233

234234
#### Properties
235-
- Selector: `property`.
235+
- Selectors: `function-property`, `property`.
236236
- Modifiers: `static`, `declare`, `abstract`, `decorated`, `override`, `readonly`, `protected`, `private`, `public`.
237237
- Example: `readonly-decorated-property`.
238238

239239
The `abstract` modifier is incompatible with the `static`, `private` and `decorated` modifiers.
240+
240241
The `declare` modifier is incompatible with the `override` and `decorated` modifiers.
241242

243+
The `function-property` selector will match properties whose values are defined functions or arrow-functions.
244+
As such, the `declare` and `abstract` modifiers are incompatible with this selector.
245+
242246
#### Index-signatures
243247
- Selector: `index-signature`.
244248
- Modifiers: `static`, `readonly`.
@@ -317,6 +321,12 @@ abstract class Example extends BaseExample {
317321
@SomeDecorator
318322
private _value: number;
319323

324+
// private-function-property
325+
private arrowProperty = () => {};
326+
327+
// private-function-property
328+
private functionProperty = function() {};
329+
320330
// 'private-property'
321331
private name: string;
322332

rules/sort-classes.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export type Modifier =
4343
| StaticModifier
4444

4545
type ConstructorSelector = 'constructor'
46+
type FunctionPropertySelector = 'function-property'
4647
type PropertySelector = 'property'
4748
type MethodSelector = 'method'
4849
type GetMethodSelector = 'get-method'
@@ -52,6 +53,7 @@ type StaticBlockSelector = 'static-block'
5253
type AccessorPropertySelector = 'accessor-property'
5354
export type Selector =
5455
| AccessorPropertySelector
56+
| FunctionPropertySelector
5557
| IndexSignatureSelector
5658
| ConstructorSelector
5759
| StaticBlockSelector
@@ -84,6 +86,8 @@ type MethodOrGetMethodOrSetMethodSelector =
8486

8587
type ConstructorGroup =
8688
`${PublicOrProtectedOrPrivateModifierPrefix}${ConstructorSelector}`
89+
type FunctionPropertyGroup =
90+
`${PublicOrProtectedOrPrivateModifierPrefix}${StaticModifierPrefix}${OverrideModifierPrefix}${ReadonlyModifierPrefix}${DecoratedModifierPrefix}${FunctionPropertySelector}`
8791
type DeclarePropertyGroup =
8892
`${DeclareModifierPrefix}${PublicOrProtectedOrPrivateModifierPrefix}${StaticOrAbstractModifierPrefix}${ReadonlyModifierPrefix}${PropertySelector}`
8993
type NonDeclarePropertyGroup =
@@ -105,6 +109,7 @@ type Group =
105109
| MethodOrGetMethodOrSetMethodGroup
106110
| NonDeclarePropertyGroup
107111
| AccessorPropertyGroup
112+
| FunctionPropertyGroup
108113
| DeclarePropertyGroup
109114
| IndexSignatureGroup
110115
| ConstructorGroup
@@ -474,6 +479,13 @@ export default createEslintRule<Options, MESSAGE_ID>({
474479
modifiers.push('public')
475480
}
476481

482+
if (
483+
member.value?.type === 'ArrowFunctionExpression' ||
484+
member.value?.type === 'FunctionExpression'
485+
) {
486+
selectors.push('function-property')
487+
}
488+
477489
selectors.push('property')
478490
}
479491
for (let officialGroup of generateOfficialGroups(

test/sort-classes.test.ts

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,10 @@ describe(ruleName, () => {
185185
186186
static readonly [key: string]: string;
187187
188+
private n = function() {};
189+
190+
private m = () => {};
191+
188192
declare private static readonly l;
189193
190194
private k = 'k';
@@ -241,6 +245,10 @@ describe(ruleName, () => {
241245
242246
declare private static readonly l;
243247
248+
private m = () => {};
249+
250+
private n = function() {};
251+
244252
static readonly [key: string]: string;
245253
246254
static {}
@@ -263,6 +271,7 @@ describe(ruleName, () => {
263271
'protected-property',
264272
'private-property',
265273
'declare-private-static-readonly-property',
274+
'function-property',
266275
'static-readonly-index-signature',
267276
'static-block',
268277
],
@@ -283,6 +292,22 @@ describe(ruleName, () => {
283292
data: {
284293
left: 'static readonly [key: string]',
285294
leftGroup: 'static-readonly-index-signature',
295+
right: 'n',
296+
rightGroup: 'function-property',
297+
},
298+
},
299+
{
300+
messageId: 'unexpectedClassesOrder',
301+
data: {
302+
left: 'n',
303+
right: 'm',
304+
},
305+
},
306+
{
307+
messageId: 'unexpectedClassesGroupOrder',
308+
data: {
309+
left: 'm',
310+
leftGroup: 'function-property',
286311
right: 'l',
287312
rightGroup: 'declare-private-static-readonly-property',
288313
},
@@ -1020,6 +1045,98 @@ describe(ruleName, () => {
10201045
}
10211046
})
10221047

1048+
describe('property selectors priority', () => {
1049+
ruleTester.run(
1050+
`${ruleName}(${type}): prioritize function property over property`,
1051+
rule,
1052+
{
1053+
valid: [],
1054+
invalid: [
1055+
{
1056+
code: dedent`
1057+
export class Class {
1058+
1059+
a = function() {}
1060+
1061+
z: string;
1062+
}
1063+
`,
1064+
output: dedent`
1065+
export class Class {
1066+
1067+
z: string;
1068+
1069+
a = function() {}
1070+
}
1071+
`,
1072+
options: [
1073+
{
1074+
...options,
1075+
groups: ['property', 'function-property'],
1076+
},
1077+
],
1078+
errors: [
1079+
{
1080+
messageId: 'unexpectedClassesGroupOrder',
1081+
data: {
1082+
left: 'a',
1083+
leftGroup: 'function-property',
1084+
right: 'z',
1085+
rightGroup: 'property',
1086+
},
1087+
},
1088+
],
1089+
},
1090+
],
1091+
},
1092+
)
1093+
1094+
ruleTester.run(
1095+
`${ruleName}(${type}): prioritize function property over property for arrow functions`,
1096+
rule,
1097+
{
1098+
valid: [],
1099+
invalid: [
1100+
{
1101+
code: dedent`
1102+
export class Class {
1103+
1104+
a = () => {}
1105+
1106+
z: string;
1107+
}
1108+
`,
1109+
output: dedent`
1110+
export class Class {
1111+
1112+
z: string;
1113+
1114+
a = () => {}
1115+
}
1116+
`,
1117+
options: [
1118+
{
1119+
...options,
1120+
groups: ['property', 'function-property'],
1121+
},
1122+
],
1123+
errors: [
1124+
{
1125+
messageId: 'unexpectedClassesGroupOrder',
1126+
data: {
1127+
left: 'a',
1128+
leftGroup: 'function-property',
1129+
right: 'z',
1130+
rightGroup: 'property',
1131+
},
1132+
},
1133+
],
1134+
},
1135+
],
1136+
},
1137+
)
1138+
})
1139+
10231140
describe('property modifiers priority', () => {
10241141
ruleTester.run(
10251142
`${ruleName}(${type}): prioritize static over declare`,

0 commit comments

Comments
 (0)