Skip to content

Commit a4f85b8

Browse files
authored
fix(eslint-plugin): [no-empty-interface] disable autofix for declaration merging with class (#5920)
* fix(eslint-plugin): [no-empty-interface] disable autofix for declaration merging with class * fix comment * fix lint * Apply review
1 parent 7a10707 commit a4f85b8

File tree

2 files changed

+109
-10
lines changed

2 files changed

+109
-10
lines changed

packages/eslint-plugin/src/rules/no-empty-interface.ts

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { TSESLint } from '@typescript-eslint/utils';
2+
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
23

34
import * as util from '../util';
45

@@ -73,29 +74,39 @@ export default util.createRule<Options, MessageIds>({
7374
)}${typeParam} = ${sourceCode.getText(extend[0])}`,
7475
);
7576
};
77+
const scope = context.getScope();
7678

77-
// Check if interface is within ambient declaration
78-
let useAutoFix = true;
79-
if (util.isDefinitionFile(filename)) {
80-
const scope = context.getScope();
81-
if (scope.type === 'tsModule' && scope.block.declare) {
82-
useAutoFix = false;
83-
}
84-
}
79+
const mergedWithClassDeclaration = scope.set
80+
.get(node.id.name)
81+
?.defs?.some(
82+
def => def.node.type === AST_NODE_TYPES.ClassDeclaration,
83+
);
84+
85+
const isInAmbientDeclaration = !!(
86+
util.isDefinitionFile(filename) &&
87+
scope.type === 'tsModule' &&
88+
scope.block.declare
89+
);
90+
91+
const useAutoFix = !(
92+
isInAmbientDeclaration || mergedWithClassDeclaration
93+
);
8594

8695
context.report({
8796
node: node.id,
8897
messageId: 'noEmptyWithSuper',
8998
...(useAutoFix
9099
? { fix }
91-
: {
100+
: !mergedWithClassDeclaration
101+
? {
92102
suggest: [
93103
{
94104
messageId: 'noEmptyWithSuper',
95105
fix,
96106
},
97107
],
98-
}),
108+
}
109+
: null),
99110
});
100111
}
101112
}

packages/eslint-plugin/tests/rules/no-empty-interface.test.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,18 @@ interface Bar extends Foo {}
3434
`,
3535
options: [{ allowSingleExtends: true }],
3636
},
37+
{
38+
code: `
39+
interface Foo {
40+
props: string;
41+
}
42+
43+
interface Bar extends Foo {}
44+
45+
class Bar {}
46+
`,
47+
options: [{ allowSingleExtends: true }],
48+
},
3749
],
3850
invalid: [
3951
{
@@ -58,6 +70,82 @@ interface Bar extends Foo {}
5870
},
5971
{
6072
code: `
73+
interface Foo {
74+
props: string;
75+
}
76+
77+
interface Bar extends Foo {}
78+
79+
class Baz {}
80+
`,
81+
output: `
82+
interface Foo {
83+
props: string;
84+
}
85+
86+
type Bar = Foo
87+
88+
class Baz {}
89+
`,
90+
options: [{ allowSingleExtends: false }],
91+
errors: [
92+
{
93+
messageId: 'noEmptyWithSuper',
94+
line: 6,
95+
column: 11,
96+
},
97+
],
98+
},
99+
{
100+
code: `
101+
interface Foo {
102+
props: string;
103+
}
104+
105+
interface Bar extends Foo {}
106+
107+
class Bar {}
108+
`,
109+
options: [{ allowSingleExtends: false }],
110+
errors: [
111+
{
112+
messageId: 'noEmptyWithSuper',
113+
line: 6,
114+
column: 11,
115+
},
116+
],
117+
output: null,
118+
},
119+
{
120+
code: `
121+
interface Foo {
122+
props: string;
123+
}
124+
125+
interface Bar extends Foo {}
126+
127+
const bar = class Bar {};
128+
`,
129+
output: `
130+
interface Foo {
131+
props: string;
132+
}
133+
134+
type Bar = Foo
135+
136+
const bar = class Bar {};
137+
`,
138+
options: [{ allowSingleExtends: false }],
139+
errors: [
140+
{
141+
messageId: 'noEmptyWithSuper',
142+
line: 6,
143+
column: 11,
144+
},
145+
],
146+
},
147+
{
148+
code: `
61149
interface Foo {
62150
name: string;
63151
}

0 commit comments

Comments
 (0)