Skip to content

Commit 62b2278

Browse files
authored
fix(eslint-plugin): [no-empty-interface] use suggestion fixer for ambient contexts (#1880)
1 parent fd75424 commit 62b2278

File tree

2 files changed

+78
-12
lines changed

2 files changed

+78
-12
lines changed

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

+42-12
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
import * as util from '../util';
2+
import {
3+
AST_NODE_TYPES,
4+
TSESLint,
5+
} from '@typescript-eslint/experimental-utils';
26

37
type Options = [
48
{
@@ -43,6 +47,7 @@ export default util.createRule<Options, MessageIds>({
4347
return {
4448
TSInterfaceDeclaration(node): void {
4549
const sourceCode = context.getSourceCode();
50+
const filename = context.getFilename();
4651

4752
if (node.body.body.length !== 0) {
4853
// interface contains members --> Nothing to report
@@ -58,21 +63,46 @@ export default util.createRule<Options, MessageIds>({
5863
} else if (extend.length === 1) {
5964
// interface extends exactly 1 interface --> Report depending on rule setting
6065
if (!allowSingleExtends) {
66+
const fix = (fixer: TSESLint.RuleFixer): TSESLint.RuleFix => {
67+
let typeParam = '';
68+
if (node.typeParameters) {
69+
typeParam = sourceCode.getText(node.typeParameters);
70+
}
71+
return fixer.replaceText(
72+
node,
73+
`type ${sourceCode.getText(
74+
node.id,
75+
)}${typeParam} = ${sourceCode.getText(extend[0])}`,
76+
);
77+
};
78+
79+
// Check if interface is within ambient declaration
80+
let useAutoFix = true;
81+
if (util.isDefinitionFile(filename)) {
82+
const scope = context.getScope();
83+
if (
84+
scope.block.parent &&
85+
scope.block.parent.type ===
86+
AST_NODE_TYPES.TSModuleDeclaration &&
87+
scope.block.parent.declare
88+
) {
89+
useAutoFix = false;
90+
}
91+
}
92+
6193
context.report({
6294
node: node.id,
6395
messageId: 'noEmptyWithSuper',
64-
fix: fixer => {
65-
let typeParam = '';
66-
if (node.typeParameters) {
67-
typeParam = sourceCode.getText(node.typeParameters);
68-
}
69-
return fixer.replaceText(
70-
node,
71-
`type ${sourceCode.getText(
72-
node.id,
73-
)}${typeParam} = ${sourceCode.getText(extend[0])}`,
74-
);
75-
},
96+
...(useAutoFix
97+
? { fix }
98+
: {
99+
suggest: [
100+
{
101+
messageId: 'noEmptyWithSuper',
102+
fix,
103+
},
104+
],
105+
}),
76106
});
77107
}
78108
}

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

+36
Original file line numberDiff line numberDiff line change
@@ -148,5 +148,41 @@ type Foo<T> = Bar<T>
148148
},
149149
],
150150
},
151+
{
152+
filename: 'test.d.ts',
153+
code: `
154+
declare module FooBar {
155+
type Baz = typeof baz;
156+
export interface Bar extends Baz {}
157+
}
158+
`.trimRight(),
159+
errors: [
160+
{
161+
messageId: 'noEmptyWithSuper',
162+
line: 4,
163+
column: 20,
164+
endLine: 4,
165+
endColumn: 23,
166+
suggestions: [
167+
{
168+
messageId: 'noEmptyWithSuper',
169+
output: noFormat`
170+
declare module FooBar {
171+
type Baz = typeof baz;
172+
export type Bar = Baz
173+
}
174+
`.trimRight(),
175+
},
176+
],
177+
},
178+
],
179+
// output matches input because a suggestion was made
180+
output: `
181+
declare module FooBar {
182+
type Baz = typeof baz;
183+
export interface Bar extends Baz {}
184+
}
185+
`.trimRight(),
186+
},
151187
],
152188
});

0 commit comments

Comments
 (0)