11import type { ScopeManager , Scope } from "eslint-scope" ;
22import type * as ESTree from "estree" ;
33import type { TSESTree } from "@typescript-eslint/types" ;
4+ import type { Scope as TSScope } from "@typescript-eslint/scope-manager" ;
45import type { Context , ScriptsSourceCode } from "." ;
56import type {
67 Comment ,
@@ -20,19 +21,19 @@ import {
2021 removeReference ,
2122 removeScope ,
2223} from "../scope" ;
23- import { traverseNodes } from "../traverse" ;
24+ import { getKeys , traverseNodes , getNodes } from "../traverse" ;
2425import { UniqueIdGenerator } from "./unique" ;
2526
2627type TSAsExpression = {
2728 type : "TSAsExpression" ;
2829 expression : ESTree . Expression ;
29- typeAnnotation : TSParenthesizedType | ESTree . Node ;
30+ typeAnnotation : TSParenthesizedType | TSESTree . TypeNode ;
3031} ;
3132
3233// TS ESLint v4 Node
3334type TSParenthesizedType = {
3435 type : "TSParenthesizedType" ;
35- typeAnnotation : ESTree . Node ;
36+ typeAnnotation : TSESTree . TypeNode ;
3637} ;
3738
3839export type ScriptLetCallback < E extends ESTree . Node > = (
@@ -167,30 +168,10 @@ export class ScriptLetContext {
167168 }
168169
169170 if ( isTS ) {
170- const blockNode =
171- tsAs ! . typeAnnotation . type === "TSParenthesizedType"
172- ? tsAs ! . typeAnnotation . typeAnnotation
173- : tsAs ! . typeAnnotation ;
174- const targetScopes = [ result . getScope ( blockNode ) ] ;
175- let targetBlockNode : TSESTree . Node | TSParenthesizedType =
176- blockNode as any ;
177- while (
178- targetBlockNode . type === "TSConditionalType" ||
179- targetBlockNode . type === "TSParenthesizedType"
180- ) {
181- if ( targetBlockNode . type === "TSParenthesizedType" ) {
182- targetBlockNode = targetBlockNode . typeAnnotation as any ;
183- continue ;
184- }
185- // TSConditionalType's `falseType` may not be a child scope.
186- const falseType : TSESTree . TypeNode = targetBlockNode . falseType ;
187- const falseTypeScope = result . getScope ( falseType as any ) ;
188- if ( ! targetScopes . includes ( falseTypeScope ) ) {
189- targetScopes . push ( falseTypeScope ) ;
190- }
191- targetBlockNode = falseType ;
192- }
193- for ( const scope of targetScopes ) {
171+ for ( const scope of extractTypeNodeScopes (
172+ tsAs ! . typeAnnotation ,
173+ result
174+ ) ) {
194175 removeScope ( result . scopeManager , scope ) ;
195176 }
196177 this . remapNodes (
@@ -1039,3 +1020,44 @@ function getNodeToScope(
10391020
10401021 return nodeToScope ;
10411022}
1023+
1024+ /** Extract the type scope of the given node. */
1025+ function extractTypeNodeScopes (
1026+ node : TSESTree . TypeNode | TSParenthesizedType ,
1027+ result : ScriptLetCallbackOption
1028+ ) : Iterable < Scope > {
1029+ const scopes = new Set < Scope > ( ) ;
1030+ for ( const scope of iterateTypeNodeScopes ( node ) ) {
1031+ scopes . add ( scope ) ;
1032+ }
1033+
1034+ return scopes ;
1035+
1036+ /** Iterate the type scope of the given node. */
1037+ function * iterateTypeNodeScopes (
1038+ node : TSESTree . TypeNode | TSParenthesizedType
1039+ ) : Iterable < Scope > {
1040+ if ( node . type === "TSParenthesizedType" ) {
1041+ // Skip TSParenthesizedType.
1042+ yield * iterateTypeNodeScopes ( node . typeAnnotation ) ;
1043+ } else if ( node . type === "TSConditionalType" ) {
1044+ yield result . getScope ( node as any ) ;
1045+ // `falseType` of `TSConditionalType` is sibling scope.
1046+ const falseType : TSESTree . TypeNode = node . falseType ;
1047+ yield * iterateTypeNodeScopes ( falseType ) ;
1048+ } else if (
1049+ node . type === "TSFunctionType" ||
1050+ node . type === "TSMappedType" ||
1051+ node . type === "TSConstructorType"
1052+ ) {
1053+ yield result . getScope ( node as any ) ;
1054+ } else {
1055+ const typeNode : Exclude < TSESTree . TypeNode , TSScope [ "block" ] > = node ;
1056+ for ( const key of getKeys ( typeNode , result . visitorKeys ) ) {
1057+ for ( const child of getNodes ( typeNode , key ) ) {
1058+ yield * iterateTypeNodeScopes ( child as TSESTree . TypeNode ) ;
1059+ }
1060+ }
1061+ }
1062+ }
1063+ }
0 commit comments