From 0449e9f891f575e778e112663c0ba52bc3a18a69 Mon Sep 17 00:00:00 2001 From: Lakshya Khera Date: Sun, 15 Nov 2020 21:10:32 +0530 Subject: [PATCH 1/4] fix(eslint-plugin): fixed circular reference issue --- .../src/rules/consistent-indexed-object-style.ts | 7 +++++-- .../tests/rules/consistent-indexed-object-style.test.ts | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts b/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts index c1b86bf8c61f..338db71c1091 100644 --- a/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts +++ b/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts @@ -94,13 +94,16 @@ export default createRule({ if (!valueType) { return; } - + const value = sourceCode.getText(valueType.typeAnnotation); + const name = node.parent?.id?.name; + if (value.includes(name)) { + return; + } context.report({ node, messageId: 'preferRecord', fix(fixer) { const key = sourceCode.getText(keyType.typeAnnotation); - const value = sourceCode.getText(valueType.typeAnnotation); return fixer.replaceText( node, `${prefix}Record<${key}, ${value}>${postfix}`, diff --git a/packages/eslint-plugin/tests/rules/consistent-indexed-object-style.test.ts b/packages/eslint-plugin/tests/rules/consistent-indexed-object-style.test.ts index ebedccf424a7..f41cb1240100 100644 --- a/packages/eslint-plugin/tests/rules/consistent-indexed-object-style.test.ts +++ b/packages/eslint-plugin/tests/rules/consistent-indexed-object-style.test.ts @@ -76,7 +76,8 @@ interface Foo { []; } `, - + 'type Foo = { [key: string]: string | Foo };', + 'type Foo = { [key: string]: Foo };', // 'index-signature' // Unhandled type { From b930c212e03218d513bae73a744265be503334be Mon Sep 17 00:00:00 2001 From: Lakshya Khera Date: Sun, 15 Nov 2020 22:57:45 +0530 Subject: [PATCH 2/4] fix(eslint-plugin): fixed bug --- .../src/rules/consistent-indexed-object-style.ts | 3 ++- .../tests/rules/consistent-indexed-object-style.test.ts | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts b/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts index 338db71c1091..b889d341fd95 100644 --- a/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts +++ b/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts @@ -96,7 +96,8 @@ export default createRule({ } const value = sourceCode.getText(valueType.typeAnnotation); const name = node.parent?.id?.name; - if (value.includes(name)) { + const valueArray = value.split('|').map(v => v.trim()); + if (valueArray.indexOf(name) != -1) { return; } context.report({ diff --git a/packages/eslint-plugin/tests/rules/consistent-indexed-object-style.test.ts b/packages/eslint-plugin/tests/rules/consistent-indexed-object-style.test.ts index f41cb1240100..ee4a13d426bc 100644 --- a/packages/eslint-plugin/tests/rules/consistent-indexed-object-style.test.ts +++ b/packages/eslint-plugin/tests/rules/consistent-indexed-object-style.test.ts @@ -173,6 +173,11 @@ type Foo = Record; output: 'type Foo = Record;', errors: [{ messageId: 'preferRecord', line: 1, column: 12 }], }, + { + code: 'type Foo = { [key: string]: AnotherFoo };', + output: 'type Foo = Record;', + errors: [{ messageId: 'preferRecord', line: 1, column: 12 }], + }, // Generic { From 7d07483e39d499f661ebb58666b0961de9b56eb8 Mon Sep 17 00:00:00 2001 From: Lakshya Khera Date: Mon, 16 Nov 2020 14:25:40 +0530 Subject: [PATCH 3/4] fix(eslint-plugin): fixed bugs using scope analysis --- .../rules/consistent-indexed-object-style.ts | 41 ++++++++++++++++--- .../consistent-indexed-object-style.test.ts | 16 ++++++++ 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts b/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts index b889d341fd95..0cfda7d45754 100644 --- a/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts +++ b/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts @@ -94,16 +94,47 @@ export default createRule({ if (!valueType) { return; } - const value = sourceCode.getText(valueType.typeAnnotation); - const name = node.parent?.id?.name; - const valueArray = value.split('|').map(v => v.trim()); - if (valueArray.indexOf(name) != -1) { - return; + const scope = context.getScope(); + if (scope.block.type == AST_NODE_TYPES.Program) { + const body = scope.block.body[0]; + if (body.type == AST_NODE_TYPES.TSTypeAliasDeclaration) { + const name = body?.id.name; + const memberTypes = member.typeAnnotation?.typeAnnotation; + if (memberTypes) { + if (memberTypes.type == AST_NODE_TYPES.TSTypeReference) { + const memberType = memberTypes.typeName; + if ( + memberType.type == AST_NODE_TYPES.Identifier && + memberType.name == name + ) { + return; + } + } else if (memberTypes.type == AST_NODE_TYPES.TSUnionType) { + const membersArray = memberTypes.types; + let flag = false; + membersArray.forEach((m: TSESTree.Node) => { + if (m.type == AST_NODE_TYPES.TSTypeReference) { + if ( + m.typeName.type == AST_NODE_TYPES.Identifier && + m.typeName.name == name + ) { + flag = true; + } + } + }); + if (flag) { + return; + } + } + } + } } + context.report({ node, messageId: 'preferRecord', fix(fixer) { + const value = sourceCode.getText(valueType.typeAnnotation); const key = sourceCode.getText(keyType.typeAnnotation); return fixer.replaceText( node, diff --git a/packages/eslint-plugin/tests/rules/consistent-indexed-object-style.test.ts b/packages/eslint-plugin/tests/rules/consistent-indexed-object-style.test.ts index ee4a13d426bc..ada62733c29e 100644 --- a/packages/eslint-plugin/tests/rules/consistent-indexed-object-style.test.ts +++ b/packages/eslint-plugin/tests/rules/consistent-indexed-object-style.test.ts @@ -78,6 +78,7 @@ interface Foo { `, 'type Foo = { [key: string]: string | Foo };', 'type Foo = { [key: string]: Foo };', + // 'index-signature' // Unhandled type { @@ -173,6 +174,21 @@ type Foo = Record; output: 'type Foo = Record;', errors: [{ messageId: 'preferRecord', line: 1, column: 12 }], }, + { + code: 'type T = { [k: string]: AT };', + output: 'type T = Record;', + errors: [{ messageId: 'preferRecord', line: 1, column: 10 }], + }, + { + code: 'type T = { [k: string]: TA };', + output: 'type T = Record;', + errors: [{ messageId: 'preferRecord', line: 1, column: 10 }], + }, + { + code: 'type T = { [k: string]: A.T };', + output: 'type T = Record;', + errors: [{ messageId: 'preferRecord', line: 1, column: 10 }], + }, { code: 'type Foo = { [key: string]: AnotherFoo };', output: 'type Foo = Record;', From b760395af3e266f548d012481c591efcf243f369 Mon Sep 17 00:00:00 2001 From: Lakshya Khera Date: Mon, 16 Nov 2020 14:33:32 +0530 Subject: [PATCH 4/4] fix(eslint-plugin): refactored code --- .../rules/consistent-indexed-object-style.ts | 51 +++++++++---------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts b/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts index 0cfda7d45754..5f8fe91cba3e 100644 --- a/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts +++ b/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts @@ -94,37 +94,36 @@ export default createRule({ if (!valueType) { return; } + const scope = context.getScope(); - if (scope.block.type == AST_NODE_TYPES.Program) { + if ( + scope.block.type == AST_NODE_TYPES.Program && + scope.block.body[0].type == AST_NODE_TYPES.TSTypeAliasDeclaration + ) { const body = scope.block.body[0]; - if (body.type == AST_NODE_TYPES.TSTypeAliasDeclaration) { - const name = body?.id.name; - const memberTypes = member.typeAnnotation?.typeAnnotation; - if (memberTypes) { - if (memberTypes.type == AST_NODE_TYPES.TSTypeReference) { - const memberType = memberTypes.typeName; + const name = body?.id.name; + const memberTypes = member.typeAnnotation?.typeAnnotation; + if (memberTypes) { + if ( + memberTypes.type == AST_NODE_TYPES.TSTypeReference && + memberTypes.typeName.type == AST_NODE_TYPES.Identifier && + memberTypes.typeName.name == name + ) { + return; + } else if (memberTypes.type == AST_NODE_TYPES.TSUnionType) { + const membersArray = memberTypes.types; + let flag = false; + membersArray.forEach((m: TSESTree.Node) => { if ( - memberType.type == AST_NODE_TYPES.Identifier && - memberType.name == name + m.type == AST_NODE_TYPES.TSTypeReference && + m.typeName.type == AST_NODE_TYPES.Identifier && + m.typeName.name == name ) { - return; - } - } else if (memberTypes.type == AST_NODE_TYPES.TSUnionType) { - const membersArray = memberTypes.types; - let flag = false; - membersArray.forEach((m: TSESTree.Node) => { - if (m.type == AST_NODE_TYPES.TSTypeReference) { - if ( - m.typeName.type == AST_NODE_TYPES.Identifier && - m.typeName.name == name - ) { - flag = true; - } - } - }); - if (flag) { - return; + flag = true; } + }); + if (flag) { + return; } } }