@@ -63,6 +63,8 @@ function visitBlockStatements(
63
63
// 'oIndex' is the original statement index; 'uIndex' is the updated statement index
64
64
for ( let oIndex = 0 , uIndex = 0 ; oIndex < statements . length - 1 ; oIndex ++ , uIndex ++ ) {
65
65
const currentStatement = statements [ oIndex ] ;
66
+ let newStatement : ts . Statement | undefined ;
67
+ let oldStatementsLength = 0 ;
66
68
67
69
// these can't contain an enum declaration
68
70
if ( currentStatement . kind === ts . SyntaxKind . ImportDeclaration ) {
@@ -79,53 +81,47 @@ function visitBlockStatements(
79
81
// * not be last statement
80
82
// * be a variable statement
81
83
// * have only one declaration
82
- // * have an ClassExpression as a initializer
84
+ // * have an ClassExpression or BinaryExpression and a right
85
+ // of kind ClassExpression as a initializer
83
86
if ( ts . isVariableStatement ( currentStatement )
84
87
&& currentStatement . declarationList . declarations . length === 1 ) {
85
88
86
89
const variableDeclaration = currentStatement . declarationList . declarations [ 0 ] ;
90
+ const initializer = variableDeclaration . initializer ;
87
91
if ( ts . isIdentifier ( variableDeclaration . name ) ) {
88
92
const name = variableDeclaration . name . text ;
89
93
90
- if ( ! variableDeclaration . initializer ) {
94
+ if ( ! initializer ) {
91
95
const iife = findTs2_3EnumIife ( name , statements [ oIndex + 1 ] ) ;
92
96
if ( iife ) {
93
- // found an enum
94
- if ( ! updatedStatements ) {
95
- updatedStatements = statements . slice ( ) ;
96
- }
97
97
// update IIFE and replace variable statement and old IIFE
98
- updatedStatements . splice ( uIndex , 2 , updateEnumIife (
98
+ oldStatementsLength = 2 ;
99
+ newStatement = updateEnumIife (
99
100
currentStatement ,
100
101
iife [ 0 ] ,
101
102
iife [ 1 ] ,
102
- ) ) ;
103
+ ) ;
103
104
// skip IIFE statement
104
105
oIndex ++ ;
105
- continue ;
106
106
}
107
- } else if ( ts . isObjectLiteralExpression ( variableDeclaration . initializer )
108
- && variableDeclaration . initializer . properties . length === 0 ) {
107
+ } else if ( ts . isObjectLiteralExpression ( initializer )
108
+ && initializer . properties . length === 0 ) {
109
109
const enumStatements = findTs2_2EnumStatements ( name , statements , oIndex + 1 ) ;
110
110
if ( enumStatements . length > 0 ) {
111
- // found an enum
112
- if ( ! updatedStatements ) {
113
- updatedStatements = statements . slice ( ) ;
114
- }
115
111
// create wrapper and replace variable statement and enum member statements
116
- updatedStatements . splice ( uIndex , enumStatements . length + 1 , createWrappedEnum (
112
+ oldStatementsLength = enumStatements . length + 1 ;
113
+ newStatement = createWrappedEnum (
117
114
name ,
118
115
currentStatement ,
119
116
enumStatements ,
120
- variableDeclaration . initializer ,
121
- ) ) ;
117
+ initializer ,
118
+ ) ;
122
119
// skip enum member declarations
123
120
oIndex += enumStatements . length ;
124
- continue ;
125
121
}
126
- } else if ( ts . isObjectLiteralExpression ( variableDeclaration . initializer )
127
- && variableDeclaration . initializer . properties . length !== 0 ) {
128
- const literalPropertyCount = variableDeclaration . initializer . properties . length ;
122
+ } else if ( ts . isObjectLiteralExpression ( initializer )
123
+ && initializer . properties . length !== 0 ) {
124
+ const literalPropertyCount = initializer . properties . length ;
129
125
130
126
// tsickle es2015 enums first statement is an export declaration
131
127
const isPotentialEnumExport = ts . isExportDeclaration ( statements [ oIndex + 1 ] ) ;
@@ -136,42 +132,61 @@ function visitBlockStatements(
136
132
137
133
const enumStatements = findEnumNameStatements ( name , statements , oIndex + 1 ) ;
138
134
if ( enumStatements . length === literalPropertyCount ) {
139
- // found an enum
140
- if ( ! updatedStatements ) {
141
- updatedStatements = statements . slice ( ) ;
142
- }
143
135
// create wrapper and replace variable statement and enum member statements
144
- const deleteCount = enumStatements . length + ( isPotentialEnumExport ? 2 : 1 ) ;
145
- updatedStatements . splice ( uIndex , deleteCount , createWrappedEnum (
136
+ oldStatementsLength = enumStatements . length + ( isPotentialEnumExport ? 2 : 1 ) ;
137
+ newStatement = createWrappedEnum (
146
138
name ,
147
139
currentStatement ,
148
140
enumStatements ,
149
- variableDeclaration . initializer ,
141
+ initializer ,
150
142
isPotentialEnumExport ,
151
- ) ) ;
143
+ ) ;
152
144
// skip enum member declarations
153
145
oIndex += enumStatements . length ;
154
- continue ;
155
146
}
156
- } else if ( ts . isClassExpression ( variableDeclaration . initializer ) ) {
157
- const classStatements = findClassExpressionStatements ( name , statements , oIndex ) ;
147
+ } else if (
148
+ ts . isClassExpression ( initializer )
149
+ || (
150
+ ts . isBinaryExpression ( initializer )
151
+ && ts . isClassExpression ( initializer . right )
152
+ )
153
+ ) {
154
+ const classStatements = findClassStatements ( name , statements , oIndex ) ;
158
155
if ( ! classStatements ) {
159
156
continue ;
160
157
}
161
158
162
- if ( ! updatedStatements ) {
163
- updatedStatements = [ ...statements ] ;
164
- }
165
-
166
- updatedStatements . splice ( uIndex , classStatements . length , createWrappedClass (
167
- name ,
159
+ oldStatementsLength = classStatements . length ;
160
+ newStatement = createWrappedClass (
161
+ variableDeclaration ,
168
162
classStatements ,
169
- ) ) ;
163
+ ) ;
170
164
171
165
oIndex += classStatements . length - 1 ;
172
- continue ;
173
166
}
174
167
}
168
+ } else if ( ts . isClassDeclaration ( currentStatement ) ) {
169
+ const name = ( currentStatement . name as ts . Identifier ) . text ;
170
+ const classStatements = findClassStatements ( name , statements , oIndex ) ;
171
+ if ( ! classStatements ) {
172
+ continue ;
173
+ }
174
+
175
+ oldStatementsLength = classStatements . length ;
176
+ newStatement = createWrappedClass (
177
+ currentStatement ,
178
+ classStatements ,
179
+ ) ;
180
+
181
+ oIndex += classStatements . length - 1 ;
182
+ }
183
+
184
+ if ( newStatement ) {
185
+ if ( ! updatedStatements ) {
186
+ updatedStatements = [ ...statements ] ;
187
+ }
188
+
189
+ updatedStatements . splice ( uIndex , oldStatementsLength , newStatement ) ;
175
190
}
176
191
177
192
const result = ts . visitNode ( currentStatement , visitor ) ;
@@ -433,7 +448,7 @@ function updateHostNode(
433
448
}
434
449
435
450
/**
436
- * Find class expression statements.
451
+ * Find class expression or declaration statements.
437
452
*
438
453
* The classExpressions block to wrap in an iife must
439
454
* - end with an ExpressionStatement
@@ -445,36 +460,63 @@ function updateHostNode(
445
460
Foo = __decorate([]);
446
461
```
447
462
*/
448
- function findClassExpressionStatements (
463
+ function findClassStatements (
449
464
name : string ,
450
465
statements : ts . NodeArray < ts . Statement > ,
451
466
statementIndex : number ,
452
467
) : ts . Statement [ ] | undefined {
453
- let index = statementIndex + 1 ;
454
- let statement = statements [ index ] ;
468
+ let count = 1 ;
469
+
470
+ for ( let index = statementIndex + 1 ; index < statements . length ; ++ index ) {
471
+ const statement = statements [ index ] ;
472
+ if ( ! ts . isExpressionStatement ( statement ) ) {
473
+ break ;
474
+ }
455
475
456
- while ( ts . isExpressionStatement ( statement ) ) {
457
476
const expression = statement . expression ;
477
+
458
478
if ( ts . isCallExpression ( expression ) ) {
459
- // Ex:
460
- // __decorate([propDecorator()], FooClass, "propertyName", void 0);
461
- // __decorate$1([propDecorator()], FooClass, "propertyName", void 0);
462
- const callExpression = expression . expression ;
463
- if ( ! ts . isIdentifier ( callExpression ) || ! / ^ _ _ d e c o r a t e ( \$ \d + ) ? $ / . test ( callExpression . text ) ) {
464
- break ;
479
+ // Ex:
480
+ // setClassMetadata(FooClass, [{}], void 0);
481
+ // __decorate([propDecorator()], FooClass.prototype, "propertyName", void 0);
482
+ // __decorate([propDecorator()], FooClass, "propertyName", void 0);
483
+ // __decorate$1([propDecorator()], FooClass, "propertyName", void 0);
484
+ const args = expression . arguments ;
485
+
486
+ if ( args . length > 2 ) {
487
+ const isReferenced = args . some ( arg => {
488
+ const potentialIdentifier = ts . isPropertyAccessExpression ( arg ) ? arg . expression : arg ;
489
+
490
+ return ts . isIdentifier ( potentialIdentifier ) && potentialIdentifier . text === name ;
491
+ } ) ;
492
+
493
+ if ( isReferenced ) {
494
+ count ++ ;
495
+ continue ;
496
+ }
497
+ }
498
+ } else if ( ts . isBinaryExpression ( expression ) ) {
499
+ const node = ts . isBinaryExpression ( expression . left )
500
+ ? expression . left . left
501
+ : expression . left ;
502
+
503
+ const leftExpression = ts . isPropertyAccessExpression ( node )
504
+ // Static Properties // Ex: Foo.bar = 'value';
505
+ ? node . expression
506
+ // Ex: FooClass = __decorate([Component()], FooClass);
507
+ : node ;
508
+
509
+ if ( ts . isIdentifier ( leftExpression ) && leftExpression . text === name ) {
510
+ count ++ ;
511
+ continue ;
465
512
}
466
513
}
467
514
468
- if (
469
- ts . isBinaryExpression ( expression )
470
- && ts . isIdentifier ( expression . left )
471
- && expression . left . getText ( ) === name
472
- ) {
473
- // Ex: FooClass = __decorate([Component()], FooClass);
474
- return statements . slice ( statementIndex , index + 1 ) ;
475
- }
515
+ break ;
516
+ }
476
517
477
- statement = statements [ ++ index ] ;
518
+ if ( count > 1 ) {
519
+ return statements . slice ( statementIndex , statementIndex + count ) ;
478
520
}
479
521
480
522
return undefined ;
@@ -573,18 +615,33 @@ function createWrappedEnum(
573
615
}
574
616
575
617
function createWrappedClass (
576
- name : string ,
618
+ hostNode : ts . ClassDeclaration | ts . VariableDeclaration ,
577
619
statements : ts . Statement [ ] ,
578
620
) : ts . Statement {
621
+ const name = ( hostNode . name as ts . Identifier ) . text ;
622
+
623
+ const updatedStatements = [ ...statements ] ;
624
+
625
+ if ( ts . isClassDeclaration ( hostNode ) ) {
626
+ updatedStatements [ 0 ] = ts . createClassDeclaration (
627
+ hostNode . decorators ,
628
+ undefined ,
629
+ hostNode . name ,
630
+ hostNode . typeParameters ,
631
+ hostNode . heritageClauses ,
632
+ hostNode . members ,
633
+ ) ;
634
+ }
635
+
579
636
const pureIife = addPureComment (
580
637
ts . createImmediatelyInvokedArrowFunction ( [
581
- ...statements ,
638
+ ...updatedStatements ,
582
639
ts . createReturn ( ts . createIdentifier ( name ) ) ,
583
640
] ) ,
584
641
) ;
585
642
586
643
return ts . createVariableStatement (
587
- undefined ,
644
+ hostNode . modifiers ,
588
645
ts . createVariableDeclarationList ( [
589
646
ts . createVariableDeclaration ( name , undefined , pureIife ) ,
590
647
] ,
0 commit comments