Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5f093ac

Browse files
hsmitty93JamesHenry
authored andcommitted
feat(eslint-plugin): Support abstract members in member-ordering rule (typescript-eslint#395) (typescript-eslint#1004)
1 parent 1918024 commit 5f093ac

File tree

4 files changed

+195
-13
lines changed

4 files changed

+195
-13
lines changed

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

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ There are multiple ways to specify the member types. The most explicit and granu
3737
'public-instance-field',
3838
'protected-instance-field',
3939
'private-instance-field',
40+
'public-abstract-field',
41+
'protected-abstract-field',
42+
'private-abstract-field',
4043

4144
// Constructors
4245
'public-constructor',
@@ -50,14 +53,17 @@ There are multiple ways to specify the member types. The most explicit and granu
5053
'public-instance-method',
5154
'protected-instance-method',
5255
'private-instance-method',
56+
'public-abstract-method',
57+
'protected-abstract-method',
58+
'private-abstract-method',
5359
]
5460
```
5561

5662
Note: If you only specify some of the possible types, the non-specified ones can have any particular order. This means that they can be placed before, within or after the specified types and the linter won't complain about it.
5763

5864
### Member group types (with accessibility, ignoring scope)
5965

60-
It is also possible to group member types by their accessibility (`static`, `instance`), ignoring their scope.
66+
It is also possible to group member types by their accessibility (`static`, `instance`, `abstract`), ignoring their scope.
6167

6268
```json5
6369
[
@@ -85,13 +91,15 @@ Another option is to group the member types by their scope (`public`, `protected
8591
// Fields
8692
'static-field', // = ['public-static-field', 'protected-static-field', 'private-static-field'])
8793
'instance-field', // = ['public-instance-field', 'protected-instance-field', 'private-instance-field'])
94+
'abstract-field', // = ['public-abstract-field', 'protected-abstract-field', 'private-abstract-field'])
8895

8996
// Constructors
9097
'constructor', // = ['public-constructor', 'protected-constructor', 'private-constructor'])
9198

9299
// Methods
93100
'static-method', // = ['public-static-method', 'protected-static-method', 'private-static-method'])
94-
'instance-method', // = ['public-instance-method', 'protected-instance-method', 'private-instance-method']
101+
'instance-method', // = ['public-instance-method', 'protected-instance-method', 'private-instance-method'])
102+
'abstract-method', // = ['public-abstract-method', 'protected-abstract-method', 'private-abstract-method'])
95103
]
96104
```
97105

@@ -102,13 +110,15 @@ The third grouping option is to ignore both scope and accessibility.
102110
```json5
103111
[
104112
// Fields
105-
'field', // = ['public-static-field', 'protected-static-field', 'private-static-field', 'public-instance-field', 'protected-instance-field', 'private-instance-field'])
113+
'field', // = ['public-static-field', 'protected-static-field', 'private-static-field', 'public-instance-field', 'protected-instance-field', 'private-instance-field',
114+
// 'public-abstract-field', 'protected-abstract-field', private-abstract-field'])
106115

107116
// Constructors
108117
// Only the accessibility of constructors is configurable. See above.
109118

110119
// Methods
111-
'method', // = ['public-static-method', 'protected-static-method', 'private-static-method', 'public-instance-method', 'protected-instance-method', 'private-instance-method'])
120+
'method', // = ['public-static-method', 'protected-static-method', 'private-static-method', 'public-instance-method', 'protected-instance-method', 'private-instance-method',
121+
// 'public-abstract-method', 'protected-abstract-method', 'private-abstract-method'])
112122
]
113123
```
114124

@@ -127,12 +137,17 @@ The default configuration looks as follows:
127137
"protected-instance-field",
128138
"private-instance-field",
129139

140+
"public-abstract-field",
141+
"protected-abstract-field",
142+
"private-abstract-field",
143+
130144
"public-field",
131145
"protected-field",
132146
"private-field",
133147

134148
"static-field",
135149
"instance-field",
150+
"abstract-field",
136151

137152
"field",
138153

@@ -146,12 +161,17 @@ The default configuration looks as follows:
146161
"protected-instance-method",
147162
"private-instance-method",
148163

164+
"public-abstract-method",
165+
"protected-abstract-method",
166+
"private-abstract-method",
167+
149168
"public-method",
150169
"protected-method",
151170
"private-method",
152171

153172
"static-method",
154173
"instance-method",
174+
"abstract-method",
155175

156176
"method"
157177
]

packages/eslint-plugin/src/rules/member-ordering.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ const allMemberTypes = ['field', 'method', 'constructor'].reduce<string[]>(
2424
all.push(`${accessibility}-${type}`); // e.g. `public-field`
2525

2626
if (type !== 'constructor') {
27-
// There is no `static-constructor` or `instance-constructor
28-
['static', 'instance'].forEach(scope => {
27+
// There is no `static-constructor` or `instance-constructor or `abstract-constructor`
28+
['static', 'instance', 'abstract'].forEach(scope => {
2929
if (!all.includes(`${scope}-${type}`)) {
3030
all.push(`${scope}-${type}`);
3131
}
@@ -138,12 +138,17 @@ export default util.createRule<Options, MessageIds>({
138138
'protected-instance-field',
139139
'private-instance-field',
140140

141+
'public-abstract-field',
142+
'protected-abstract-field',
143+
'private-abstract-field',
144+
141145
'public-field',
142146
'protected-field',
143147
'private-field',
144148

145149
'static-field',
146150
'instance-field',
151+
'abstract-field',
147152

148153
'field',
149154

@@ -157,12 +162,17 @@ export default util.createRule<Options, MessageIds>({
157162
'protected-instance-method',
158163
'private-instance-method',
159164

165+
'public-abstract-method',
166+
'protected-abstract-method',
167+
'private-abstract-method',
168+
160169
'public-method',
161170
'protected-method',
162171
'private-method',
163172

164173
'static-method',
165174
'instance-method',
175+
'abstract-method',
166176

167177
'method',
168178
],
@@ -185,15 +195,15 @@ export default util.createRule<Options, MessageIds>({
185195
): string | null {
186196
// TODO: add missing TSCallSignatureDeclaration
187197
// TODO: add missing TSIndexSignature
188-
// TODO: add missing TSAbstractClassProperty
189-
// TODO: add missing TSAbstractMethodDefinition
190198
switch (node.type) {
199+
case AST_NODE_TYPES.TSAbstractMethodDefinition:
191200
case AST_NODE_TYPES.MethodDefinition:
192201
return node.kind;
193202
case AST_NODE_TYPES.TSMethodSignature:
194203
return 'method';
195204
case AST_NODE_TYPES.TSConstructSignatureDeclaration:
196205
return 'constructor';
206+
case AST_NODE_TYPES.TSAbstractClassProperty:
197207
case AST_NODE_TYPES.ClassProperty:
198208
return node.value && functionExpressions.includes(node.value.type)
199209
? 'method'
@@ -215,8 +225,10 @@ export default util.createRule<Options, MessageIds>({
215225
switch (node.type) {
216226
case AST_NODE_TYPES.TSPropertySignature:
217227
case AST_NODE_TYPES.TSMethodSignature:
228+
case AST_NODE_TYPES.TSAbstractClassProperty:
218229
case AST_NODE_TYPES.ClassProperty:
219230
return util.getNameFromPropertyName(node.key);
231+
case AST_NODE_TYPES.TSAbstractMethodDefinition:
220232
case AST_NODE_TYPES.MethodDefinition:
221233
return node.kind === 'constructor'
222234
? 'constructor'
@@ -268,7 +280,16 @@ export default util.createRule<Options, MessageIds>({
268280
return order.length - 1;
269281
}
270282

271-
const scope = 'static' in node && node.static ? 'static' : 'instance';
283+
const abstract =
284+
node.type === 'TSAbstractClassProperty' ||
285+
node.type === 'TSAbstractMethodDefinition';
286+
287+
const scope =
288+
'static' in node && node.static
289+
? 'static'
290+
: abstract
291+
? 'abstract'
292+
: 'instance';
272293
const accessibility =
273294
'accessibility' in node && node.accessibility
274295
? node.accessibility

packages/eslint-plugin/src/util/misc.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,10 @@ export function findFirstResult<T, U>(
9696
* or ClassProperty node, with handling for computed property names.
9797
*/
9898
export function getNameFromClassMember(
99-
methodDefinition: TSESTree.MethodDefinition | TSESTree.ClassProperty,
99+
methodDefinition:
100+
| TSESTree.MethodDefinition
101+
| TSESTree.ClassProperty
102+
| TSESTree.TSAbstractMethodDefinition,
100103
sourceCode: TSESLint.SourceCode,
101104
): string {
102105
if (keyCanBeReadAsPropertyName(methodDefinition.key)) {

packages/eslint-plugin/tests/rules/member-ordering.test.ts

Lines changed: 141 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,12 +1211,45 @@ type Foo = {
12111211
`,
12121212
options: [{ default: ['method', 'constructor', 'field'] }],
12131213
},
1214-
`
1214+
{
1215+
code: `
12151216
abstract class Foo {
12161217
B: string;
12171218
abstract A: () => {}
12181219
}
12191220
`,
1221+
},
1222+
{
1223+
code: `
1224+
interface Foo {
1225+
public B: string;
1226+
[A:string]: number;
1227+
}
1228+
`,
1229+
},
1230+
{
1231+
code: `
1232+
abstract class Foo {
1233+
private static C: string;
1234+
B: string;
1235+
private D: string;
1236+
protected static F(): {};
1237+
public E(): {};
1238+
public abstract A = () => {};
1239+
protected abstract G(): void;
1240+
}
1241+
`,
1242+
},
1243+
{
1244+
code: `
1245+
abstract class Foo {
1246+
protected typeChecker: (data: any) => boolean;
1247+
public abstract required: boolean;
1248+
abstract verify(): void;
1249+
}
1250+
`,
1251+
options: [{ classes: ['field', 'constructor', 'method'] }],
1252+
},
12201253
],
12211254
invalid: [
12221255
{
@@ -3319,7 +3352,7 @@ type Foo = {
33193352
{
33203353
code: `
33213354
abstract class Foo {
3322-
abstract A: () => {}
3355+
abstract A = () => {};
33233356
B: string;
33243357
}
33253358
`,
@@ -3328,12 +3361,117 @@ abstract class Foo {
33283361
messageId: 'incorrectOrder',
33293362
data: {
33303363
name: 'B',
3331-
rank: 'method',
3364+
rank: 'public abstract method',
33323365
},
33333366
line: 4,
33343367
column: 5,
33353368
},
33363369
],
33373370
},
3371+
{
3372+
code: `
3373+
abstract class Foo {
3374+
abstract A: () => {};
3375+
B: string;
3376+
public C() {};
3377+
private D() {};
3378+
abstract E() {};
3379+
}
3380+
`,
3381+
errors: [
3382+
{
3383+
messageId: 'incorrectOrder',
3384+
data: {
3385+
name: 'B',
3386+
rank: 'public abstract field',
3387+
},
3388+
line: 4,
3389+
column: 5,
3390+
},
3391+
],
3392+
},
3393+
{
3394+
code: `
3395+
abstract class Foo {
3396+
B: string;
3397+
abstract C = () => {};
3398+
abstract A: () => {};
3399+
}
3400+
`,
3401+
options: [{ default: ['method', 'constructor', 'field'] }],
3402+
errors: [
3403+
{
3404+
messageId: 'incorrectOrder',
3405+
data: {
3406+
name: 'C',
3407+
rank: 'field',
3408+
},
3409+
line: 4,
3410+
column: 5,
3411+
},
3412+
],
3413+
},
3414+
{
3415+
code: `
3416+
class Foo {
3417+
C: number;
3418+
[A:string]: number;
3419+
public static D(): {};
3420+
private static [B:string]: number;
3421+
}
3422+
`,
3423+
options: [
3424+
{
3425+
default: [
3426+
'field',
3427+
'method',
3428+
'public-static-method',
3429+
'private-static-method',
3430+
],
3431+
},
3432+
],
3433+
errors: [
3434+
{
3435+
messageId: 'incorrectOrder',
3436+
data: {
3437+
name: 'D',
3438+
rank: 'private static method',
3439+
},
3440+
line: 5,
3441+
column: 5,
3442+
},
3443+
],
3444+
},
3445+
{
3446+
code: `
3447+
abstract class Foo {
3448+
abstract B: string;
3449+
abstract A(): void;
3450+
public C(): {};
3451+
3452+
}
3453+
`,
3454+
options: [{ default: ['method', 'constructor', 'field'] }],
3455+
errors: [
3456+
{
3457+
messageId: 'incorrectOrder',
3458+
data: {
3459+
name: 'A',
3460+
rank: 'field',
3461+
},
3462+
line: 4,
3463+
column: 5,
3464+
},
3465+
{
3466+
messageId: 'incorrectOrder',
3467+
data: {
3468+
name: 'C',
3469+
rank: 'field',
3470+
},
3471+
line: 5,
3472+
column: 5,
3473+
},
3474+
],
3475+
},
33383476
],
33393477
});

0 commit comments

Comments
 (0)