Skip to content
Permalink
Browse files

fix(eslint-plugin): [consistent-type-definitions] remove fixer when t…

…he interface is within a global module declaration (#2739)
  • Loading branch information
ddubrava committed Nov 14, 2020
1 parent 9441d50 commit 2326238738c95acfc14c17f9b16798f1de6d267f
@@ -1,4 +1,5 @@
import {
AST_NODE_TYPES,
AST_TOKEN_TYPES,
TSESLint,
TSESTree,
@@ -31,6 +32,21 @@ export default util.createRule({
create(context, [option]) {
const sourceCode = context.getSourceCode();

/**
* Iterates from the highest parent to the currently traversed node
* to determine whether any node in tree is globally declared module declaration
*/
function isCurrentlyTraversedNodeWithinModuleDeclaration(): boolean {
return context
.getAncestors()
.some(
node =>
node.type === AST_NODE_TYPES.TSModuleDeclaration &&
node.declare &&
node.global,
);
}

return {
"TSTypeAliasDeclaration[typeAnnotation.type='TSTypeLiteral']"(
node: TSESTree.TSTypeAliasDeclaration,
@@ -73,32 +89,41 @@ export default util.createRule({
context.report({
node: node.id,
messageId: 'typeOverInterface',
fix(fixer) {
const typeNode = node.typeParameters ?? node.id;
const fixes: TSESLint.RuleFix[] = [];
/**
* remove automatically fix when the interface is within a declare global
* @see {@link https://github.com/typescript-eslint/typescript-eslint/issues/2707}
*/
fix: isCurrentlyTraversedNodeWithinModuleDeclaration()
? null
: (fixer): TSESLint.RuleFix[] => {
const typeNode = node.typeParameters ?? node.id;
const fixes: TSESLint.RuleFix[] = [];

const firstToken = sourceCode.getFirstToken(node);
if (firstToken) {
fixes.push(fixer.replaceText(firstToken, 'type'));
fixes.push(
fixer.replaceTextRange(
[typeNode.range[1], node.body.range[0]],
' = ',
),
);
}
const firstToken = sourceCode.getFirstToken(node);
if (firstToken) {
fixes.push(fixer.replaceText(firstToken, 'type'));
fixes.push(
fixer.replaceTextRange(
[typeNode.range[1], node.body.range[0]],
' = ',
),
);
}

if (node.extends) {
node.extends.forEach(heritage => {
const typeIdentifier = sourceCode.getText(heritage);
fixes.push(
fixer.insertTextAfter(node.body, ` & ${typeIdentifier}`),
);
});
}
if (node.extends) {
node.extends.forEach(heritage => {
const typeIdentifier = sourceCode.getText(heritage);
fixes.push(
fixer.insertTextAfter(
node.body,
` & ${typeIdentifier}`,
),
);
});
}

return fixes;
},
return fixes;
},
});
}
},
@@ -197,5 +197,89 @@ export type W<T> = {
},
],
},
{
code: `
namespace JSX {
interface Array<T> {
foo(x: (x: number) => T): T[];
}
}
`,
output: noFormat`
namespace JSX {
type Array<T> = {
foo(x: (x: number) => T): T[];
}
}
`,
options: ['type'],
errors: [
{
messageId: 'typeOverInterface',
line: 3,
column: 13,
},
],
},
{
code: `
global {
interface Array<T> {
foo(x: (x: number) => T): T[];
}
}
`,
output: noFormat`
global {
type Array<T> = {
foo(x: (x: number) => T): T[];
}
}
`,
options: ['type'],
errors: [
{
messageId: 'typeOverInterface',
line: 3,
column: 13,
},
],
},
{
code: `
declare global {
interface Array<T> {
foo(x: (x: number) => T): T[];
}
}
`,
output: null,
options: ['type'],
errors: [
{
messageId: 'typeOverInterface',
line: 3,
column: 13,
},
],
},
{
code: `
declare global {
namespace Foo {
interface Bar {}
}
}
`,
output: null,
options: ['type'],
errors: [
{
messageId: 'typeOverInterface',
line: 4,
column: 15,
},
],
},
],
});

0 comments on commit 2326238

Please sign in to comment.