@@ -104,54 +104,38 @@ function visitBlockStatements(
104
104
// skip IIFE statement
105
105
oIndex ++ ;
106
106
}
107
- } else if ( ts . isObjectLiteralExpression ( initializer )
108
- && initializer . properties . length === 0 ) {
109
- const enumStatements = findTs2_2EnumStatements ( name , statements , oIndex + 1 ) ;
110
- if ( enumStatements . length > 0 ) {
111
- // create wrapper and replace variable statement and enum member statements
112
- oldStatementsLength = enumStatements . length + 1 ;
113
- newStatement = createWrappedEnum (
114
- name ,
115
- currentStatement ,
116
- enumStatements ,
117
- initializer ,
118
- ) ;
119
- // skip enum member declarations
120
- oIndex += enumStatements . length ;
121
- }
122
- } else if ( ts . isObjectLiteralExpression ( initializer )
123
- && initializer . properties . length !== 0 ) {
124
- const literalPropertyCount = initializer . properties . length ;
125
-
107
+ } else if ( ts . isObjectLiteralExpression ( initializer ) ) {
126
108
// tsickle es2015 enums first statement is an export declaration
127
109
const isPotentialEnumExport = ts . isExportDeclaration ( statements [ oIndex + 1 ] ) ;
128
110
if ( isPotentialEnumExport ) {
129
111
// skip the export
130
- oIndex ++ ;
112
+ oIndex ++ ;
131
113
}
132
114
133
- const enumStatements = findEnumNameStatements ( name , statements , oIndex + 1 ) ;
134
- if ( enumStatements . length === literalPropertyCount ) {
135
- // create wrapper and replace variable statement and enum member statements
136
- oldStatementsLength = enumStatements . length + ( isPotentialEnumExport ? 2 : 1 ) ;
137
- newStatement = createWrappedEnum (
138
- name ,
139
- currentStatement ,
140
- enumStatements ,
141
- initializer ,
142
- isPotentialEnumExport ,
143
- ) ;
144
- // skip enum member declarations
145
- oIndex += enumStatements . length ;
115
+ const enumStatements = findStatements ( name , statements , oIndex + 1 ) ;
116
+ if ( ! enumStatements ) {
117
+ continue ;
146
118
}
119
+
120
+ // create wrapper and replace variable statement and enum member statements
121
+ oldStatementsLength = enumStatements . length + ( isPotentialEnumExport ? 2 : 1 ) ;
122
+ newStatement = createWrappedEnum (
123
+ name ,
124
+ currentStatement ,
125
+ enumStatements ,
126
+ initializer ,
127
+ isPotentialEnumExport ,
128
+ ) ;
129
+ // skip enum member declarations
130
+ oIndex += enumStatements . length ;
147
131
} else if (
148
132
ts . isClassExpression ( initializer )
149
133
|| (
150
134
ts . isBinaryExpression ( initializer )
151
135
&& ts . isClassExpression ( initializer . right )
152
136
)
153
137
) {
154
- const classStatements = findClassStatements ( name , statements , oIndex ) ;
138
+ const classStatements = findStatements ( name , statements , oIndex ) ;
155
139
if ( ! classStatements ) {
156
140
continue ;
157
141
}
@@ -167,7 +151,7 @@ function visitBlockStatements(
167
151
}
168
152
} else if ( ts . isClassDeclaration ( currentStatement ) ) {
169
153
const name = ( currentStatement . name as ts . Identifier ) . text ;
170
- const classStatements = findClassStatements ( name , statements , oIndex ) ;
154
+ const classStatements = findStatements ( name , statements , oIndex ) ;
171
155
if ( ! classStatements ) {
172
156
continue ;
173
157
}
@@ -215,31 +199,43 @@ function findTs2_3EnumIife(
215
199
return null ;
216
200
}
217
201
218
- let expression = statement . expression ;
219
- while ( ts . isParenthesizedExpression ( expression ) ) {
220
- expression = expression . expression ;
221
- }
222
-
202
+ const expression = statement . expression ;
223
203
if ( ! expression || ! ts . isCallExpression ( expression ) || expression . arguments . length !== 1 ) {
224
204
return null ;
225
205
}
226
206
227
207
const callExpression = expression ;
228
- let exportExpression ;
208
+ let exportExpression : ts . Expression | undefined ;
229
209
230
- let argument = expression . arguments [ 0 ] ;
231
- if ( ! ts . isBinaryExpression ( argument ) ) {
210
+ if ( ! ts . isParenthesizedExpression ( callExpression . expression ) ) {
211
+ return null ;
212
+ }
213
+
214
+ const functionExpression = callExpression . expression . expression ;
215
+ if ( ! ts . isFunctionExpression ( functionExpression ) ) {
216
+ return null ;
217
+ }
218
+
219
+ // The name of the parameter can be different than the name of the enum if it was renamed
220
+ // due to scope hoisting.
221
+ const parameter = functionExpression . parameters [ 0 ] ;
222
+ if ( ! ts . isIdentifier ( parameter . name ) ) {
232
223
return null ;
233
224
}
225
+ const parameterName = parameter . name . text ;
234
226
235
- if ( ! ts . isIdentifier ( argument . left ) || argument . left . text !== name ) {
227
+ let argument = callExpression . arguments [ 0 ] ;
228
+ if (
229
+ ! ts . isBinaryExpression ( argument )
230
+ || ! ts . isIdentifier ( argument . left )
231
+ || argument . left . text !== name
232
+ ) {
236
233
return null ;
237
234
}
238
235
239
236
let potentialExport = false ;
240
237
if ( argument . operatorToken . kind === ts . SyntaxKind . FirstAssignment ) {
241
- if ( ! ts . isBinaryExpression ( argument . right )
242
- || argument . right . operatorToken . kind !== ts . SyntaxKind . BarBarToken ) {
238
+ if ( ts . isBinaryExpression ( argument . right ) && argument . right . operatorToken . kind !== ts . SyntaxKind . BarBarToken ) {
243
239
return null ;
244
240
}
245
241
@@ -259,177 +255,25 @@ function findTs2_3EnumIife(
259
255
exportExpression = argument . left ;
260
256
}
261
257
262
- expression = expression . expression ;
263
- while ( ts . isParenthesizedExpression ( expression ) ) {
264
- expression = expression . expression ;
265
- }
266
-
267
- if ( ! expression || ! ts . isFunctionExpression ( expression ) || expression . parameters . length !== 1 ) {
268
- return null ;
269
- }
270
-
271
- const parameter = expression . parameters [ 0 ] ;
272
- if ( ! ts . isIdentifier ( parameter . name ) ) {
273
- return null ;
274
- }
275
-
276
- // The name of the parameter can be different than the name of the enum if it was renamed
277
- // due to scope hoisting.
278
- const parameterName = parameter . name . text ;
279
-
280
- // In TS 2.3 enums, the IIFE contains only expressions with a certain format.
281
- // If we find any that is different, we ignore the whole thing.
282
- for ( let bodyIndex = 0 ; bodyIndex < expression . body . statements . length ; ++ bodyIndex ) {
283
- const bodyStatement = expression . body . statements [ bodyIndex ] ;
284
-
285
- if ( ! ts . isExpressionStatement ( bodyStatement ) || ! bodyStatement . expression ) {
286
- return null ;
287
- }
288
-
289
- if ( ! ts . isBinaryExpression ( bodyStatement . expression )
290
- || bodyStatement . expression . operatorToken . kind !== ts . SyntaxKind . FirstAssignment ) {
291
- return null ;
292
- }
293
-
294
- const assignment = bodyStatement . expression . left ;
295
- const value = bodyStatement . expression . right ;
296
- if ( ! ts . isElementAccessExpression ( assignment ) || ! ts . isStringLiteral ( value ) ) {
297
- return null ;
298
- }
299
-
300
- if ( ! ts . isIdentifier ( assignment . expression ) || assignment . expression . text !== parameterName ) {
301
- return null ;
302
- }
303
-
304
- const memberArgument = assignment . argumentExpression ;
305
- // String enum
306
- if ( ts . isStringLiteral ( memberArgument ) ) {
307
- return [ callExpression , exportExpression ] ;
308
- }
309
-
310
- // Non string enums
311
- if ( ! ts . isBinaryExpression ( memberArgument )
312
- || memberArgument . operatorToken . kind !== ts . SyntaxKind . FirstAssignment ) {
313
- return null ;
314
- }
315
-
316
- if ( ! ts . isElementAccessExpression ( memberArgument . left ) ) {
317
- return null ;
318
- }
319
-
320
- if ( ! ts . isIdentifier ( memberArgument . left . expression )
321
- || memberArgument . left . expression . text !== parameterName ) {
322
- return null ;
258
+ // Go through all the statements and check that all match the name
259
+ for ( const statement of functionExpression . body . statements ) {
260
+ if (
261
+ ! ts . isExpressionStatement ( statement )
262
+ || ! ts . isBinaryExpression ( statement . expression )
263
+ || ! ts . isElementAccessExpression ( statement . expression . left )
264
+ ) {
265
+ return null
323
266
}
324
267
325
- if ( ! memberArgument . left . argumentExpression
326
- || ! ts . isStringLiteral ( memberArgument . left . argumentExpression ) ) {
327
- return null ;
328
- }
329
-
330
- if ( memberArgument . left . argumentExpression . text !== value . text ) {
268
+ const leftExpression = statement . expression . left . expression ;
269
+ if ( ! ts . isIdentifier ( leftExpression ) || leftExpression . text !== parameterName ) {
331
270
return null ;
332
271
}
333
272
}
334
273
335
274
return [ callExpression , exportExpression ] ;
336
275
}
337
276
338
- // TS 2.2 enums have statements after the variable declaration, with index statements followed
339
- // by value statements.
340
- function findTs2_2EnumStatements (
341
- name : string ,
342
- statements : ts . NodeArray < ts . Statement > ,
343
- statementOffset : number ,
344
- ) : ts . Statement [ ] {
345
- const enumValueStatements : ts . Statement [ ] = [ ] ;
346
- const memberNames : string [ ] = [ ] ;
347
-
348
- let index = statementOffset ;
349
- for ( ; index < statements . length ; ++ index ) {
350
- // Ensure all statements are of the expected format and using the right identifer.
351
- // When we find a statement that isn't part of the enum, return what we collected so far.
352
- const current = statements [ index ] ;
353
- if ( ! ts . isExpressionStatement ( current ) || ! ts . isBinaryExpression ( current . expression ) ) {
354
- break ;
355
- }
356
-
357
- const property = current . expression . left ;
358
- if ( ! property || ! ts . isPropertyAccessExpression ( property ) ) {
359
- break ;
360
- }
361
-
362
- if ( ! ts . isIdentifier ( property . expression ) || property . expression . text !== name ) {
363
- break ;
364
- }
365
-
366
- memberNames . push ( property . name . text ) ;
367
- enumValueStatements . push ( current ) ;
368
- }
369
-
370
- if ( enumValueStatements . length === 0 ) {
371
- return [ ] ;
372
- }
373
-
374
- const enumNameStatements = findEnumNameStatements ( name , statements , index , memberNames ) ;
375
- if ( enumNameStatements . length !== enumValueStatements . length ) {
376
- return [ ] ;
377
- }
378
-
379
- return enumValueStatements . concat ( enumNameStatements ) ;
380
- }
381
-
382
- // Tsickle enums have a variable statement with indexes, followed by value statements.
383
- // See https://github.com/angular/devkit/issues/229#issuecomment-338512056 fore more information.
384
- function findEnumNameStatements (
385
- name : string ,
386
- statements : ts . NodeArray < ts . Statement > ,
387
- statementOffset : number ,
388
- memberNames ?: string [ ] ,
389
- ) : ts . Statement [ ] {
390
- const enumStatements : ts . Statement [ ] = [ ] ;
391
-
392
- for ( let index = statementOffset ; index < statements . length ; ++ index ) {
393
- // Ensure all statements are of the expected format and using the right identifer.
394
- // When we find a statement that isn't part of the enum, return what we collected so far.
395
- const current = statements [ index ] ;
396
- if ( ! ts . isExpressionStatement ( current ) || ! ts . isBinaryExpression ( current . expression ) ) {
397
- break ;
398
- }
399
-
400
- const access = current . expression . left ;
401
- const value = current . expression . right ;
402
- if ( ! access || ! ts . isElementAccessExpression ( access ) || ! value || ! ts . isStringLiteral ( value ) ) {
403
- break ;
404
- }
405
-
406
- if ( memberNames && ! memberNames . includes ( value . text ) ) {
407
- break ;
408
- }
409
-
410
- if ( ! ts . isIdentifier ( access . expression ) || access . expression . text !== name ) {
411
- break ;
412
- }
413
-
414
- if ( ! access . argumentExpression || ! ts . isPropertyAccessExpression ( access . argumentExpression ) ) {
415
- break ;
416
- }
417
-
418
- const enumExpression = access . argumentExpression . expression ;
419
- if ( ! ts . isIdentifier ( enumExpression ) || enumExpression . text !== name ) {
420
- break ;
421
- }
422
-
423
- if ( value . text !== access . argumentExpression . name . text ) {
424
- break ;
425
- }
426
-
427
- enumStatements . push ( current ) ;
428
- }
429
-
430
- return enumStatements ;
431
- }
432
-
433
277
function updateHostNode (
434
278
hostNode : ts . VariableStatement ,
435
279
expression : ts . Expression ,
@@ -456,7 +300,7 @@ function updateHostNode(
456
300
}
457
301
458
302
/**
459
- * Find class expression or declaration statements.
303
+ * Find enums, class expression or declaration statements.
460
304
*
461
305
* The classExpressions block to wrap in an iife must
462
306
* - end with an ExpressionStatement
@@ -468,7 +312,7 @@ function updateHostNode(
468
312
Foo = __decorate([]);
469
313
```
470
314
*/
471
- function findClassStatements (
315
+ function findStatements (
472
316
name : string ,
473
317
statements : ts . NodeArray < ts . Statement > ,
474
318
statementIndex : number ,
@@ -484,11 +328,11 @@ function findClassStatements(
484
328
const expression = statement . expression ;
485
329
486
330
if ( ts . isCallExpression ( expression ) ) {
487
- // Ex:
488
- // setClassMetadata(FooClass, [{}], void 0);
489
- // __decorate([propDecorator()], FooClass.prototype, "propertyName", void 0);
490
- // __decorate([propDecorator()], FooClass, "propertyName", void 0);
491
- // __decorate$1([propDecorator()], FooClass, "propertyName", void 0);
331
+ // Ex:
332
+ // setClassMetadata(FooClass, [{}], void 0);
333
+ // __decorate([propDecorator()], FooClass.prototype, "propertyName", void 0);
334
+ // __decorate([propDecorator()], FooClass, "propertyName", void 0);
335
+ // __decorate$1([propDecorator()], FooClass, "propertyName", void 0);
492
336
const args = expression . arguments ;
493
337
494
338
if ( args . length > 2 ) {
@@ -508,8 +352,9 @@ function findClassStatements(
508
352
? expression . left . left
509
353
: expression . left ;
510
354
511
- const leftExpression = ts . isPropertyAccessExpression ( node )
355
+ const leftExpression = ts . isPropertyAccessExpression ( node ) || ts . isElementAccessExpression ( node )
512
356
// Static Properties // Ex: Foo.bar = 'value';
357
+ // ENUM Property // Ex: ChangeDetectionStrategy[ChangeDetectionStrategy.Default] = "Default";
513
358
? node . expression
514
359
// Ex: FooClass = __decorate([Component()], FooClass);
515
360
: node ;
0 commit comments