From 7b5ea1d438d56c4f5aadcc82d97c1ad091bf56b7 Mon Sep 17 00:00:00 2001 From: cherryblossom <31467609+cherryblossom000@users.noreply.github.com> Date: Sun, 1 Nov 2020 15:11:51 +1100 Subject: [PATCH] fix(eslint-plugin): [no-shadow] ignore module augmentation (fixes #2724) --- .../eslint-plugin/docs/rules/no-shadow.md | 2 +- packages/eslint-plugin/src/rules/no-shadow.ts | 16 +++++++ .../tests/rules/no-shadow.test.ts | 43 +++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin/docs/rules/no-shadow.md b/packages/eslint-plugin/docs/rules/no-shadow.md index ed241b807882..bcb40d4fb5a0 100644 --- a/packages/eslint-plugin/docs/rules/no-shadow.md +++ b/packages/eslint-plugin/docs/rules/no-shadow.md @@ -3,7 +3,7 @@ ## Rule Details This rule extends the base [`eslint/no-shadow`](https://eslint.org/docs/rules/no-shadow) rule. -It adds support for TypeScript's `this` parameters, and adds options for TypeScript features. +It adds support for TypeScript's `this` parameters and global augmentation, and adds options for TypeScript features. ## How to use diff --git a/packages/eslint-plugin/src/rules/no-shadow.ts b/packages/eslint-plugin/src/rules/no-shadow.ts index 05761572b216..1d1f894b651f 100644 --- a/packages/eslint-plugin/src/rules/no-shadow.ts +++ b/packages/eslint-plugin/src/rules/no-shadow.ts @@ -3,6 +3,7 @@ import { TSESLint, AST_NODE_TYPES, } from '@typescript-eslint/experimental-utils'; +import { ScopeType } from '@typescript-eslint/scope-manager'; import * as util from '../util'; type MessageIds = 'noShadow'; @@ -67,6 +68,16 @@ export default util.createRule({ }, ], create(context, [options]) { + /** + * Check if a scope is a TypeScript module augmenting the global namespace. + */ + function isGlobalAugmentation(scope: TSESLint.Scope.Scope): boolean { + return ( + (scope.type === ScopeType.tsModule && !!scope.block.global) || + (!!scope.upper && isGlobalAugmentation(scope.upper)) + ); + } + /** * Check if variable is a `this` parameter. */ @@ -261,6 +272,11 @@ export default util.createRule({ * @param {Scope} scope Fixme */ function checkForShadows(scope: TSESLint.Scope.Scope): void { + // ignore global augmentation + if (isGlobalAugmentation(scope)) { + return; + } + const variables = scope.variables; for (const variable of variables) { diff --git a/packages/eslint-plugin/tests/rules/no-shadow.test.ts b/packages/eslint-plugin/tests/rules/no-shadow.test.ts index d7c81d834492..abc78ee5f3ec 100644 --- a/packages/eslint-plugin/tests/rules/no-shadow.test.ts +++ b/packages/eslint-plugin/tests/rules/no-shadow.test.ts @@ -116,6 +116,49 @@ type Fn = (Foo: string) => typeof Foo; Foo: 'writable', }, }, + // https://github.com/typescript-eslint/typescript-eslint/issues/2724 + { + code: ` + declare global { + interface ArrayConstructor {} + } + export {}; + `, + options: [{ builtinGlobals: true }], + }, + ` + declare global { + const a: string; + + namespace Foo { + const a: number; + } + } + export {}; + `, + { + code: ` + declare global { + type A = 'foo'; + + namespace Foo { + type A = 'bar'; + } + } + export {}; + `, + options: [{ ignoreTypeValueShadow: false }], + }, + { + code: ` + declare global { + const foo: string; + type Fn = (foo: number) => void; + } + export {}; + `, + options: [{ ignoreFunctionTypeParameterNameValueShadow: false }], + }, ], invalid: [ {