@@ -5,8 +5,9 @@ import MagicString from 'magic-string';
5
5
* Collects all imports and module-level declarations to then find out which interfaces/types are hoistable.
6
6
*/
7
7
export class HoistableInterfaces {
8
- private import_value_set : Set < string > = new Set ( ) ;
9
- private import_type_set : Set < string > = new Set ( ) ;
8
+ private module_types : Set < string > = new Set ( ) ;
9
+ private disallowed_types = new Set < string > ( ) ;
10
+ private disallowed_values = new Set < string > ( ) ;
10
11
private interface_map : Map <
11
12
string ,
12
13
{ type_deps : Set < string > ; value_deps : Set < string > ; node : ts . Node }
@@ -18,6 +19,7 @@ export class HoistableInterfaces {
18
19
value_deps : new Set < string > ( )
19
20
} ;
20
21
22
+ /** should be called before analyzeInstanceScriptNode */
21
23
analyzeModuleScriptNode ( node : ts . Node ) {
22
24
// Handle Import Declarations
23
25
if ( ts . isImportDeclaration ( node ) && node . importClause ) {
@@ -30,9 +32,7 @@ export class HoistableInterfaces {
30
32
node . importClause . namedBindings . elements . forEach ( ( element ) => {
31
33
const import_name = element . name . text ;
32
34
if ( is_type_only || element . isTypeOnly ) {
33
- this . import_type_set . add ( import_name ) ;
34
- } else {
35
- this . import_value_set . add ( import_name ) ;
35
+ this . module_types . add ( import_name ) ;
36
36
}
37
37
} ) ;
38
38
}
@@ -41,9 +41,7 @@ export class HoistableInterfaces {
41
41
if ( node . importClause . name ) {
42
42
const default_import = node . importClause . name . text ;
43
43
if ( is_type_only ) {
44
- this . import_type_set . add ( default_import ) ;
45
- } else {
46
- this . import_value_set . add ( default_import ) ;
44
+ this . module_types . add ( default_import ) ;
47
45
}
48
46
}
49
47
@@ -54,40 +52,17 @@ export class HoistableInterfaces {
54
52
) {
55
53
const namespace_import = node . importClause . namedBindings . name . text ;
56
54
if ( is_type_only ) {
57
- this . import_type_set . add ( namespace_import ) ;
58
- } else {
59
- this . import_value_set . add ( namespace_import ) ;
55
+ this . module_types . add ( namespace_import ) ;
60
56
}
61
57
}
62
58
}
63
59
64
- // Handle top-level declarations
65
- if ( ts . isVariableStatement ( node ) ) {
66
- node . declarationList . declarations . forEach ( ( declaration ) => {
67
- if ( ts . isIdentifier ( declaration . name ) ) {
68
- this . import_value_set . add ( declaration . name . text ) ;
69
- }
70
- } ) ;
71
- }
72
-
73
- if ( ts . isFunctionDeclaration ( node ) && node . name ) {
74
- this . import_value_set . add ( node . name . text ) ;
75
- }
76
-
77
- if ( ts . isClassDeclaration ( node ) && node . name ) {
78
- this . import_value_set . add ( node . name . text ) ;
79
- }
80
-
81
- if ( ts . isEnumDeclaration ( node ) ) {
82
- this . import_value_set . add ( node . name . text ) ;
83
- }
84
-
85
60
if ( ts . isTypeAliasDeclaration ( node ) ) {
86
- this . import_type_set . add ( node . name . text ) ;
61
+ this . module_types . add ( node . name . text ) ;
87
62
}
88
63
89
64
if ( ts . isInterfaceDeclaration ( node ) ) {
90
- this . import_type_set . add ( node . name . text ) ;
65
+ this . module_types . add ( node . name . text ) ;
91
66
}
92
67
}
93
68
@@ -103,9 +78,7 @@ export class HoistableInterfaces {
103
78
node . importClause . namedBindings . elements . forEach ( ( element ) => {
104
79
const import_name = element . name . text ;
105
80
if ( is_type_only ) {
106
- this . import_type_set . add ( import_name ) ;
107
- } else {
108
- this . import_value_set . add ( import_name ) ;
81
+ this . module_types . add ( import_name ) ;
109
82
}
110
83
} ) ;
111
84
}
@@ -114,9 +87,7 @@ export class HoistableInterfaces {
114
87
if ( node . importClause . name ) {
115
88
const default_import = node . importClause . name . text ;
116
89
if ( is_type_only ) {
117
- this . import_type_set . add ( default_import ) ;
118
- } else {
119
- this . import_value_set . add ( default_import ) ;
90
+ this . module_types . add ( default_import ) ;
120
91
}
121
92
}
122
93
@@ -127,9 +98,7 @@ export class HoistableInterfaces {
127
98
) {
128
99
const namespace_import = node . importClause . namedBindings . name . text ;
129
100
if ( is_type_only ) {
130
- this . import_type_set . add ( namespace_import ) ;
131
- } else {
132
- this . import_value_set . add ( namespace_import ) ;
101
+ this . module_types . add ( namespace_import ) ;
133
102
}
134
103
}
135
104
}
@@ -167,9 +136,9 @@ export class HoistableInterfaces {
167
136
}
168
137
} ) ;
169
138
170
- if ( this . import_type_set . has ( interface_name ) ) {
171
- // shadowed; delete because we can't hoist
172
- this . import_type_set . delete ( interface_name ) ;
139
+ if ( this . module_types . has ( interface_name ) ) {
140
+ // shadowed; we can't hoist
141
+ this . disallowed_types . add ( interface_name ) ;
173
142
} else {
174
143
this . interface_map . set ( interface_name , {
175
144
type_deps : type_dependencies ,
@@ -193,9 +162,9 @@ export class HoistableInterfaces {
193
162
generics
194
163
) ;
195
164
196
- if ( this . import_type_set . has ( alias_name ) ) {
197
- // shadowed; delete because we can't hoist
198
- this . import_type_set . delete ( alias_name ) ;
165
+ if ( this . module_types . has ( alias_name ) ) {
166
+ // shadowed; we can't hoist
167
+ this . disallowed_types . add ( alias_name ) ;
199
168
} else {
200
169
this . interface_map . set ( alias_name , {
201
170
type_deps : type_dependencies ,
@@ -209,29 +178,21 @@ export class HoistableInterfaces {
209
178
if ( ts . isVariableStatement ( node ) ) {
210
179
node . declarationList . declarations . forEach ( ( declaration ) => {
211
180
if ( ts . isIdentifier ( declaration . name ) ) {
212
- this . import_value_set . delete ( declaration . name . text ) ;
181
+ this . disallowed_values . add ( declaration . name . text ) ;
213
182
}
214
183
} ) ;
215
184
}
216
185
217
186
if ( ts . isFunctionDeclaration ( node ) && node . name ) {
218
- this . import_value_set . delete ( node . name . text ) ;
187
+ this . disallowed_values . add ( node . name . text ) ;
219
188
}
220
189
221
190
if ( ts . isClassDeclaration ( node ) && node . name ) {
222
- this . import_value_set . delete ( node . name . text ) ;
191
+ this . disallowed_values . add ( node . name . text ) ;
223
192
}
224
193
225
194
if ( ts . isEnumDeclaration ( node ) ) {
226
- this . import_value_set . delete ( node . name . text ) ;
227
- }
228
-
229
- if ( ts . isTypeAliasDeclaration ( node ) ) {
230
- this . import_type_set . delete ( node . name . text ) ;
231
- }
232
-
233
- if ( ts . isInterfaceDeclaration ( node ) ) {
234
- this . import_type_set . delete ( node . name . text ) ;
195
+ this . disallowed_values . add ( node . name . text ) ;
235
196
}
236
197
}
237
198
@@ -281,13 +242,26 @@ export class HoistableInterfaces {
281
242
continue ;
282
243
}
283
244
284
- const can_hoist = [ ...deps . type_deps , ...deps . value_deps ] . every ( ( dep ) => {
285
- return (
286
- this . import_type_set . has ( dep ) ||
287
- this . import_value_set . has ( dep ) ||
288
- hoistable_interfaces . has ( dep )
289
- ) ;
290
- } ) ;
245
+ let can_hoist = true ;
246
+
247
+ for ( const dep of deps . type_deps ) {
248
+ if ( this . disallowed_types . has ( dep ) ) {
249
+ this . disallowed_types . add ( interface_name ) ;
250
+ can_hoist = false ;
251
+ break ;
252
+ }
253
+ if ( this . interface_map . has ( dep ) && ! hoistable_interfaces . has ( dep ) ) {
254
+ can_hoist = false ;
255
+ }
256
+ }
257
+
258
+ for ( const dep of deps . value_deps ) {
259
+ if ( this . disallowed_values . has ( dep ) ) {
260
+ this . disallowed_types . add ( interface_name ) ;
261
+ can_hoist = false ;
262
+ break ;
263
+ }
264
+ }
291
265
292
266
if ( can_hoist ) {
293
267
hoistable_interfaces . set ( interface_name , deps . node ) ;
@@ -301,11 +275,7 @@ export class HoistableInterfaces {
301
275
...this . props_interface . type_deps ,
302
276
...this . props_interface . value_deps
303
277
] . every ( ( dep ) => {
304
- return (
305
- this . import_type_set . has ( dep ) ||
306
- this . import_value_set . has ( dep ) ||
307
- hoistable_interfaces . has ( dep )
308
- ) ;
278
+ return ! this . disallowed_types . has ( dep ) && ! this . disallowed_values . has ( dep ) ;
309
279
} ) ;
310
280
311
281
if ( can_hoist ) {
@@ -328,7 +298,7 @@ export class HoistableInterfaces {
328
298
if ( ! this . props_interface . name ) return ;
329
299
330
300
for ( const generic of generics ) {
331
- this . import_type_set . delete ( generic ) ;
301
+ this . disallowed_types . add ( generic ) ;
332
302
}
333
303
334
304
const hoistable = this . determineHoistableInterfaces ( ) ;
@@ -362,8 +332,8 @@ export class HoistableInterfaces {
362
332
}
363
333
}
364
334
365
- getAllowedValues ( ) {
366
- return this . import_value_set ;
335
+ isAllowedReference ( reference : string ) {
336
+ return ! this . disallowed_values . has ( reference ) ;
367
337
}
368
338
369
339
/**
0 commit comments