10000 feat(eslint-plugin): add extension [no-dupe-class-members] (#1492) · Bertrand/typescript-eslint@b22424e · GitHub
[go: up one dir, main page]

Skip to content

Commit b22424e

Browse files
authored
feat(eslint-plugin): add extension [no-dupe-class-members] (typescript-eslint#1492)
1 parent 9e7d161 commit b22424e

File tree

7 files changed

+158
-0
lines changed

7 files changed

+158
-0
lines changed

packages/eslint-plugin/README.md

Lines changed: 1 addition & 10000 ; 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ In these cases, we create what we call an extension rule; a rule within our plug
173173
| [`@typescript-eslint/func-call-spacing`](./docs/rules/func-call-spacing.md) | Require or disallow spacing between function identifiers and their invocations | | :wrench: | |
174174
| [`@typescript-eslint/indent`](./docs/rules/indent.md) | Enforce consistent indentation | | :wrench: | |
175175
| [`@typescript-eslint/no-array-constructor`](./docs/rules/no-array-constructor.md) | Disallow generic `Array` constructors | :heavy_check_mark: | :wrench: | |
176+
| [`@typescript-eslint/no-dupe-class-members`](./docs/rules/no-dupe-class-members.md) | Disallow duplicate class members | | | |
176177
| [`@typescript-eslint/no-empty-function`](./docs/rules/no-empty-function.md) | Disallow empty functions | :heavy_check_mark: | | |
177178
| [`@typescript-eslint/no-extra-parens`](./docs/rules/no-extra-parens.md) | Disallow unnecessary parentheses | | :wrench: | |
178179
| [`@typescript-eslint/no-extra-semi`](./docs/rules/no-extra-semi.md) | Disallow unnecessary semicolons | | :wrench: | |
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Disallow duplicate class members (`no-dupe-class-members`)
2+
3+
## Rule Details
4+
5+
This rule extends the base [`eslint/no-no-dupe-class-members`](https://eslint.org/docs/rules/no-no-dupe-class-members) rule.
6+
It adds support for TypeScript's method overload definitions.
7+
8+
## How to use
9+
10+
```cjson
11+
{
12+
// note you must disable the base rule as it can report incorrect errors
13+
"no-no-dupe-class-members": "off",
14+
"@typescript-eslint/no-no-dupe-class-members": ["error"]
15+
}
16+
```
17+
18+
<sup>Taken with ❤️ [from ESLint core](https://github.com/eslint/eslint/blob/master/docs/rules/no-no-dupe-class-members.md)</sup>

packages/eslint-plugin/src/configs/all.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
"@typescript-eslint/naming-convention": "error",
2727
"no-array-constructor": "off",
2828
"@typescript-eslint/no-array-constructor": "error",
29+
"no-dupe-class-members": "off",
30+
"@typescript-eslint/no-dupe-class-members": "error",
2931
"@typescript-eslint/no-dynamic-delete": "error",
3032
"no-empty-function": "off",
3133
"@typescript-eslint/no-empty-function": "error",

packages/eslint-plugin/src/rules/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import memberNaming from './member-naming';
2323
import memberOrdering from './member-ordering';
2424
import namingConvention from './naming-convention';
2525
import noArrayConstructor from './no-array-constructor';
26+
import noDupeClassMembers from './no-dupe-class-members';
2627
import noDynamicDelete from './no-dynamic-delete';
2728
import noEmptyFunction from './no-empty-function';
2829
import noEmptyInterface from './no-empty-interface';
@@ -110,6 +111,7 @@ export default {
110111
'member-ordering': memberOrdering,
111112
'naming-convention': namingConvention,
112113
'no-array-constructor': noArrayConstructor,
114+
'no-dupe-class-members': noDupeClassMembers,
113115
'no-dynamic-delete': noDynamicDelete,
114116
'no-empty-function': noEmptyFunction,
115117
'no-empty-interface': noEmptyInterface,
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { AST_NODE_TYPES } from '@typescript-eslint/experimental-utils';
2+
import baseRule from 'eslint/lib/rules/no-dupe-class-members';
3+
import * as util from '../util';
4+
5+
type Options = util.InferOptionsTypeFromRule<typeof baseRule>;
6+
type MessageIds = util.InferMessageIdsTypeFromRule<typeof baseRule>;
7+
8+
export default util.createRule<Options, MessageIds>({
9+
name: 'no-dupe-class-members',
10+
meta: {
11+
type: 'problem',
12+
docs: {
13+
description: 'Disallow duplicate class members',
14+
category: 'Possible Errors',
15+
recommended: false,
16+
extendsBaseRule: true,
17+
},
18+
schema: baseRule.meta.schema,
19+
messages: baseRule.meta.messages,
20+
},
21+
defaultOptions: [],
22+
create(context) {
23+
const rules = baseRule.create(context);
24+
25+
return {
26+
...rules,
27+
MethodDefinition(node): void {
28+
if (node.computed) {
29+
return;
30+
}
31+
32+
if (node.value.type === AST_NODE_TYPES.TSEmptyBodyFunctionExpression) {
33+
return;
34+
}
35+
36+
return rules.MethodDefinition(node);
37+
},
38+
};
39+
},
40+
});
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import rule from '../../src/rules/no-dupe-class-members';
2+
import { RuleTester } from '../RuleTester';
3+
4+
const ruleTester = new RuleTester({
5+
parser: '@typescript-eslint/parser',
6+
});
7+
8+
ruleTester.run('no-dupe-class-members', rule, {
9+
valid: [
10+
'class A { foo() {} bar() {} }',
11+
'class A { static foo() {} foo() {} }',
12+
'class A { get foo() {} set foo(value) {} }',
13+
'class A { static foo() {} get foo() {} set foo(value) {} }',
14+
'class A { foo() { } } class B { foo() { } }',
15+
'class A { [foo]() {} foo() {} }',
16+
"class A { 'foo'() {} 'bar'() {} baz() {} }",
17+
"class A { *'foo'() {} *'bar'() {} *baz() {} }",
18+
"class A { get 'foo'() {} get 'bar'() {} get baz() {} }",
19+
'class A { 1() {} 2() {} }',
20+
`
21+
class Foo {
22+
foo(a: string): string;
23+
foo(a: number): number;
24+
foo(a: any): any {}
25+
}
26+
`,
27+
],
28+
invalid: [
29+
{
30+
code: 'class A { foo() {} foo() {} }',
31+
errors: [
32+
{ line: 1, column: 20, messageId: 'unexpected', data: { name: 'foo' } },
33+
],
34+
},
35+
{
36+
code: '!class A { foo() {} foo() {} };',
37+
errors: [
38+
{ line: 1, column: 21, messageId: 'unexpected', data: { name: 'foo' } },
39+
],
40+
},
41+
{
42+
code: "class A { 'foo'() {} 'foo'() {} }",
43+
errors: [
44+
{ line: 1, column: 22, messageId: 'unexpected', data: { name: 'foo' } },
45+
],
46+
},
47+
{
48+
code: 'class A { 10() {} 1e1() {} }',
49+
errors: [
50+
{ line: 1, column: 19, messageId: 'unexpected', data: { name: '10' } },
51+
],
52+
},
53+
{
54+
code: 'class A { foo() {} foo() {} foo() {} }',
55+
errors: [
56+
{ line: 1, column: 20, messageId: 'unexpected', data: { name: 'foo' } },
57+
{ line: 1, column: 29, messageId: 'unexpected', data: { name: 'foo' } },
58+
],
59+
},
60+
{
61+
code: 'class A { static foo() {} static foo() {} }',
62+
errors: [
63+
{ line: 1, column: 27, messageId: 'unexpected', data: { name: 'foo' } },
64+
],
65+
},
66+
{
67+
code: 'class A { foo() {} get foo() {} }',
68+
errors: [
69+
{ line: 1, column: 20, messageId: 'unexpected', data: { name: 'foo' } },
70+
],
71+
},
72+
{
73+
code: 'class A { set foo(value) {} foo() {} }',
74+
errors: [
75+
{ line: 1, column: 29, messageId: 'unexpected', data: { name: 'foo' } },
76+
],
77+
},
78+
],
79+
});

packages/eslint-plugin/typings/eslint-rules.d.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,22 @@ declare module 'eslint/lib/rules/indent' {
142142
export = rule;
143143
}
144144

145+
declare module 'eslint/lib/rules/no-dupe-class-members' {
146+
import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils';
147+
148+
const rule: TSESLint.RuleModule<
149+
'unexpected',
150+
[],
151+
{
152+
Program(): void;
153+
ClassBody(): void;
154+
'ClassBody:exit'(): void;
155+
MethodDefinition(node: TSESTree.MethodDefinition): void;
156+
}
157+
>;
158+
export = rule;
159+
}
160+
145161
declare module 'eslint/lib/rules/no-dupe-args' {
146162
import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils';
147163

0 commit comments

Comments
 (0)
0