8000 feat(eslint-plugin): sort members alphabetically (#263) · shishkin/typescript-eslint@485e902 · GitHub
[go: up one dir, main page]

Skip to content

Commit 485e902

Browse files
timkrautbradzacher
andauthored
feat(eslint-plugin): sort members alphabetically (typescript-eslint#263)
Co-authored-by: Brad Zacher <brad.zacher@gmail.com>
1 parent 1f0ff41 commit 485e902

File tree

4 files changed

+2958
-494
lines changed

4 files changed

+2958
-494
lines changed

packages/eslint-plugin/docs/rules/member-ordering.md

Lines changed: 151 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,54 @@
11
# Require a consistent member declaration order (`member-ordering`)
22

3-
A consistent ordering of fields, methods and constructors can make interfaces, type literals, classes and class
4-
expressions easier to read, navigate and edit.
3+
A consistent ordering of fields, methods and constructors can make interfaces, type literals, classes and class expressions easier to read, navigate and edit.
54

65
## Rule Details
76

8-
This rule aims to standardize the way class declarations, class expressions, interfaces and type literals are structured.
7+
This rule aims to standardize the way class declarations, class expressions, interfaces and type literals are structured and ordered.
98

10-
It allows to group members by their type (e.g. `public-static-field`, `protected-static-field`, `private-static-field`, `public-instance-field`, ...). By default, their order is the same inside `classes`, `classExpressions`, `interfaces` and `typeLiterals` (note: not all member types apply to `interfaces` and `typeLiterals`). It is possible to define the order for any of those individually or to change the default order for all of them by setting the `default` option.
9+
### Grouping and sorting member groups
10+
11+
It allows to group members by their type (e.g. `public-static-field`, `protected-static-field`, `private-static-field`, `public-instance-field`, ...) and enforce a certain order for these groups. By default, their order is the same inside `classes`, `classExpressions`, `interfaces` and `typeLiterals` (note: not all member types apply to `interfaces` and `typeLiterals`). It is possible to define the order for any of those individually or to change the default order for all of them by setting the `default` option.
12+
13+
### Sorting members
14+
15+
Besides grouping the members and sorting their groups, this rule also allows to sort the members themselves (e.g. `a`, `b`, `c`, ...). You have 2 options: Sort all of them while ignoring their type or sort them while respecting their types (e.g. sort all fields in an interface alphabetically).
1116

1217
## Options
1318

19+
These options allow to specify how to group the members and sort their groups.
20+
21+
- Sort groups, don't enforce member order: Use `memberTypes`
22+
- Sort members, don't enforce group order: Use `order`
23+
- Sort members within groups: Use `memberTypes` and `order`
24+
1425
```ts
26+
type TypeOptions<T> =
27+
| {
28+
memberTypes: Array<T> | 'never',
29+
order?: 'alphabetically' | 'as-written',
30+
}
31+
| {
32+
order: 'alphabetically',
33+
};
34+
1535
{
16-
default?: Array<MemberType> | never
17-
classes?: Array<MemberType> | never
18-
classExpressions?: Array<MemberType> | never
36+
default?: TypeOptions<MemberTypes>,
37+
38+
classes?: TypeOptions<MemberTypes>,
39+
classExpressions?: TypeOptions<MemberTypes>,
1940

20-
interfaces?: ['signature' | 'field' | 'method' | 'constructor'] | never
21-
typeLiterals?: ['signature' | 'field' | 'method' | 'constructor'] | never
41+
interfaces?: TypeOptions<'signature' | 'field' | 'method' | 'constructor'>,
42+
typeLiterals?: TypeOptions<'signature' | 'field' | 'method' | 'constructor'>,
2243
}
2344
```
2445

2546
See below for the possible definitions of `MemberType`.
2647

48+
### Deprecated syntax
49+
50+
Note: There is a deprecated syntax to specify the member types as an array.
51+
2752
### Member types (granular form)
2853

2954
There are multiple ways to specify the member types. The most explicit and granular form is the following:
@@ -138,62 +163,72 @@ The third grouping option is to ignore both scope and accessibility.
138163

139164
The default configuration looks as follows:
140165

141-
```json
166+
```json5
142167
{
143-
"default": [
144-
"signature",
168+
default: [
169+
// Index signature
170+
'signature',
145171

146-
"public-static-field",
147-
"protected-static-field",
148-
"private-static-field",
172+
// Fields
173+
'public-static-field',
174+
'protected-static-field',
175+
'private-static-field',
149176

150-
"public-instance-field",
151-
"protected-instance-field",
152-
"private-instance-field",
177+
'public-instance-field',
178+
'protected-instance-field',
179+
'private-instance-field',
153180

154-
"public-abstract-field",
155-
"protected-abstract-field",
156-
"private-abstract-field",
181+
'public-abstract-field',
182+
'protected-abstract-field',
183+
'private-abstract-field',
157184

158-
"public-field",
159-
"protected-field",
160-
"private-field",
185+
'public-field',
186+
'protected-field',
187+
'private-field',
161188

162-
"static-field",
163-
"instance-field",
164-
"abstract-field",
189+
'static-field',
190+
'instance-field',
191+
'abstract-field',
165192

166-
"field",
193+
'field',
167194

168-
"constructor",
195+
// Constructors
196+
'public-constructor',
197+
'protected-constructor',
198+
'private-constructor',
169199

170-
"public-static-method",
171-
"protected-static-method",
172-
"private-static-method",
200+
'constructor',
173201

174-
"public-instance-method",
175-
"protected-instance-method",
176-
"private-instance-method",
202+
// Methods
203+
'public-static-method',
204+
'protected-static-method',
205+
'private-static-method',
177206

178-
"public-abstract-method",
179-
"protected-abstract-method",
180-
"private-abstract-method",
207+
'public-instance-method',
208+
'protected-instance-method',
209+
'private-instance-method',
181210

182-
"public-method",
183-
"protected-method",
184-
"private-method",
211+
'public-abstract-method',
212+
'protected-abstract-method',
213+
'private-abstract-method',
185214

186-
"static-method",
187-
"instance-method",
188-
"abstract-method",
215+
'public-method',
216+
'protected-method',
217+
'private-method',
189218

190-
"method"
191-
]
219+
'static-method',
220+
'instance-method',
221+
'abstract-method',
222+
223+
'method',
224+
],
192225
}
193226
```
194227

195228
Note: The default configuration contains member group types which contain other member types (see above). This is intentional to provide better error messages.
196229

230+
Note: By default, the members are not sorted. If you want to sort them alphabetically, you have to provide a custom configuration.
231+
197232
## Examples
198233

199234
### Custom `default` configuration
@@ -448,7 +483,7 @@ const foo = class {
448483
};
449484
```
450485

451-
Issue: Public static fields should come first, followed by static fields and instance fields.
486+
Note: Public static fields should come first, followed by static fields and instance fields.
452487

453488
##### Correct examples
454489

@@ -542,21 +577,19 @@ class Foo {
542577

543578
##### Correct example
544579

545-
Examples of **correct** code for `{ "classes": [...] }` option:
546-
547580
```ts
548581
class Foo {
549582
private C: string; // (irrelevant)
550583

551584
public D: string; // (irrelevant)
552585

553-
public static E: string; // -> public static field
586+
public B(): void {} // -> public instance method
554587

555588
constructor() {} // (irrelevant)
556589

557590
public static A(): void {} // (irrelevant)
558591

559-
public B(): void {} // -> public instance method
592+
public static E: string; // -> public static field
560593
}
561594
```
562595

@@ -712,6 +745,73 @@ type Foo = {
712745
};
713746
```
714747

748+
### Sorting alphabetically within member groups
749+
750+
It is possible to sort all members within a group alphabetically.
751+
752+
#### Configuration: `{ default: { memberTypes: <Default Order>, order: 'alphabetically' } }`
753+
754+
This will apply the default order (see above) and enforce an alphabetic order within each group.
755+
756+
##### Incorrect examples
757+
758+
```ts
759+
interface Foo {
760+
a: x;
761+
b: x;
762+
c: x;
763+
764+
new (): Bar;
765+
(): Baz;
766+
767+
a(): void;
768+
b(): void;
769+
c(): void;
770+
771+
// Wrong group order, should be placed before all field definitions
772+
[a: string]: number;
773+
}
774+
```
775+
776+
```ts
777+
interface Foo {
778+
[a: string]: number;
779+
780+
a: x;
781+
b: x;
782+
c: x;
783+
784+
new (): Bar;
785+
(): Baz;
786+
787+
// Wrong alphabetic order within group
788+
c(): void;
789+
b(): void;
790+
a(): void;
791+
}
792+
```
793+
794+
### Sorting alphabetically while ignoring member groups
795+
796+
It is also possible to sort all members and ignore the member groups completely.
797+
798+
#### Configuration: `{ default: { memberTypes: 'never', order: 'alphabetically' } }`
799+
800+
##### Incorrect example
801+
802+
```ts
803+
interface Foo {
804+
b(): void;
805+
a: b;
806+
807+
[a: string]: number; // Order doesn't matter (no sortable identifier)
808+
new (): Bar; // Order doesn't matter (no sortable identifier)
809+
(): Baz; // Order doesn't matter (no sortable identifier)
810+
}
811+
```
812+
813+
Note: Wrong alphabetic order `b(): void` should come after `a: b`.
814+
715815
## When Not To Use It
716816

717817
If you don't care about the general structure of your classes and interfaces, then you will not need this rule.

0 commit comments

Comments
 (0)
0