1+ /** @internal */
2+ namespace ts {
3+ export function createGetSymbolWalker (
4+ getRestTypeOfSignature : ( sig : Signature ) => Type ,
5+ getReturnTypeOfSignature : ( sig : Signature ) => Type ,
6+ getBaseTypes : ( type : Type ) => Type [ ] ,
7+ resolveStructuredTypeMembers : ( type : ObjectType ) => ResolvedType ,
8+ getTypeOfSymbol : ( sym : Symbol ) => Type ,
9+ getResolvedSymbol : ( node : Node ) => Symbol ,
10+ getIndexTypeOfStructuredType : ( type : Type , kind : IndexKind ) => Type ,
11+ getConstraintFromTypeParameter : ( typeParameter : TypeParameter ) => Type ,
12+ getFirstIdentifier : ( node : EntityNameOrEntityNameExpression ) => Identifier ) {
13+
14+ return getSymbolWalker ;
15+
16+ function getSymbolWalker ( accept : ( symbol : Symbol ) => boolean = ( ) => true ) : SymbolWalker {
17+ const visitedTypes = createMap < Type > ( ) ; // Key is id as string
18+ const visitedSymbols = createMap < Symbol > ( ) ; // Key is id as string
19+
20+ return {
21+ walkType : type => {
22+ visitedTypes . clear ( ) ;
23+ visitedSymbols . clear ( ) ;
24+ visitType ( type ) ;
25+ return { visitedTypes : arrayFrom ( visitedTypes . values ( ) ) , visitedSymbols : arrayFrom ( visitedSymbols . values ( ) ) } ;
26+ } ,
27+ walkSymbol : symbol => {
28+ visitedTypes . clear ( ) ;
29+ visitedSymbols . clear ( ) ;
30+ visitSymbol ( symbol ) ;
31+ return { visitedTypes : arrayFrom ( visitedTypes . values ( ) ) , visitedSymbols : arrayFrom ( visitedSymbols . values ( ) ) } ;
32+ } ,
33+ } ;
34+
35+ function visitType ( type : Type ) : void {
36+ if ( ! type ) {
37+ return ;
38+ }
39+
40+ const typeIdString = type . id . toString ( ) ;
41+ if ( visitedTypes . has ( typeIdString ) ) {
42+ return ;
43+ }
44+ visitedTypes . set ( typeIdString , type ) ;
45+
46+ // Reuse visitSymbol to visit the type's symbol,
47+ // but be sure to bail on recuring into the type if accept declines the symbol.
48+ const shouldBail = visitSymbol ( type . symbol ) ;
49+ if ( shouldBail ) return ;
50+
51+ // Visit the type's related types, if any
52+ if ( type . flags & TypeFlags . Object ) {
53+ const objectType = type as ObjectType ;
54+ const objectFlags = objectType . objectFlags ;
55+ if ( objectFlags & ObjectFlags . Reference ) {
56+ visitTypeReference ( type as TypeReference ) ;
57+ }
58+ if ( objectFlags & ObjectFlags . Mapped ) {
59+ visitMappedType ( type as MappedType ) ;
60+ }
61+ if ( objectFlags & ( ObjectFlags . Class | ObjectFlags . Interface ) ) {
62+ visitInterfaceType ( type as InterfaceType ) ;
63+ }
64+ if ( objectFlags & ( ObjectFlags . Tuple | ObjectFlags . Anonymous ) ) {
65+ visitObjectType ( objectType ) ;
66+ }
67+ }
68+ if ( type . flags & TypeFlags . TypeParameter ) {
69+ visitTypeParameter ( type as TypeParameter ) ;
70+ }
71+ if ( type . flags & TypeFlags . UnionOrIntersection ) {
72+ visitUnionOrIntersectionType ( type as UnionOrIntersectionType ) ;
73+ }
74+ if ( type . flags & TypeFlags . Index ) {
75+ visitIndexType ( type as IndexType ) ;
76+ }
77+ if ( type . flags & TypeFlags . IndexedAccess ) {
78+ visitIndexedAccessType ( type as IndexedAccessType ) ;
79+ }
80+ }
81+
82+ function visitTypeList ( types : Type [ ] ) : void {
83+ if ( ! types ) {
84+ return ;
85+ }
86+ for ( let i = 0 ; i < types . length ; i ++ ) {
87+ visitType ( types [ i ] ) ;
88+ }
89+ }
90+
91+ function visitTypeReference ( type : TypeReference ) : void {
92+ visitType ( type . target ) ;
93+ visitTypeList ( type . typeArguments ) ;
94+ }
95+
96+ function visitTypeParameter ( type : TypeParameter ) : void {
97+ visitType ( getConstraintFromTypeParameter ( type ) ) ;
98+ }
99+
100+ function visitUnionOrIntersectionType ( type : UnionOrIntersectionType ) : void {
101+ visitTypeList ( type . types ) ;
102+ }
103+
104+ function visitIndexType ( type : IndexType ) : void {
105+ visitType ( type . type ) ;
106+ }
107+
108+ function visitIndexedAccessType ( type : IndexedAccessType ) : void {
109+ visitType ( type . objectType ) ;
110+ visitType ( type . indexType ) ;
111+ visitType ( type . constraint ) ;
112+ }
113+
114+ function visitMappedType ( type : MappedType ) : void {
115+ visitType ( type . typeParameter ) ;
116+ visitType ( type . constraintType ) ;
117+ visitType ( type . templateType ) ;
118+ visitType ( type . modifiersType ) ;
119+ }
120+
121+ function visitSignature ( signature : Signature ) : void {
122+ if ( signature . typePredicate ) {
123+ visitType ( signature . typePredicate . type ) ;
124+ }
125+ visitTypeList ( signature . typeParameters ) ;
126+
127+ for ( const parameter of signature . parameters ) {
128+ visitSymbol ( parameter ) ;
129+ }
130+ visitType ( getRestTypeOfSignature ( signature ) ) ;
131+ visitType ( getReturnTypeOfSignature ( signature ) ) ;
132+ }
133+
134+ function visitInterfaceType ( interfaceT : InterfaceType ) : void {
135+ visitObjectType ( interfaceT ) ;
136+ visitTypeList ( interfaceT . typeParameters ) ;
137+ visitTypeList ( getBaseTypes ( interfaceT ) ) ;
138+ visitType ( interfaceT . thisType ) ;
139+ }
140+
141+ function visitObjectType ( type : ObjectType ) : void {
142+ const stringIndexType = getIndexTypeOfStructuredType ( type , IndexKind . String ) ;
143+ visitType ( stringIndexType ) ;
144+ const numberIndexType = getIndexTypeOfStructuredType ( type , IndexKind . Number ) ;
145+ visitType ( numberIndexType ) ;
146+
147+ // The two checks above *should* have already resolved the type (if needed), so this should be cached
148+ const resolved = resolveStructuredTypeMembers ( type ) ;
149+ for ( const signature of resolved . callSignatures ) {
150+ visitSignature ( signature ) ;
151+ }
152+ for ( const signature of resolved . constructSignatures ) {
153+ visitSignature ( signature ) ;
154+ }
155+ for ( const p of resolved . properties ) {
156+ visitSymbol ( p ) ;
157+ }
158+ }
159+
160+ function visitSymbol ( symbol : Symbol ) : boolean {
161+ if ( ! symbol ) {
162+ return ;
163+ }
164+ const symbolIdString = getSymbolId ( symbol ) . toString ( ) ;
165+ if ( visitedSymbols . has ( symbolIdString ) ) {
166+ return ;
167+ }
168+ visitedSymbols . set ( symbolIdString , symbol ) ;
169+ if ( ! accept ( symbol ) ) {
170+ return true ;
171+ }
172+ const t = getTypeOfSymbol ( symbol ) ;
173+ visitType ( t ) ; // Should handle members on classes and such
174+ if ( symbol . flags & SymbolFlags . HasExports ) {
175+ symbol . exports . forEach ( visitSymbol ) ;
176+ }
177+ forEach ( symbol . declarations , d => {
178+ // Type queries are too far resolved when we just visit the symbol's type
179+ // (their type resolved directly to the member deeply referenced)
180+ // So to get the intervening symbols, we need to check if there's a type
181+ // query node on any of the symbol's declarations and get symbols there
182+ if ( ( d as any ) . type && ( d as any ) . type . kind === SyntaxKind . TypeQuery ) {
183+ const query = ( d as any ) . type as TypeQueryNode ;
184+ const entity = getResolvedSymbol ( getFirstIdentifier ( query . exprName ) ) ;
185+ visitSymbol ( entity ) ;
186+ }
187+ } ) ;
188+ }
189+ }
190+ }
191+ }
0 commit comments