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