@@ -63,6 +63,8 @@ function visitBlockStatements(
6363 // 'oIndex' is the original statement index; 'uIndex' is the updated statement index
6464 for ( let oIndex = 0 , uIndex = 0 ; oIndex < statements . length - 1 ; oIndex ++ , uIndex ++ ) {
6565 const currentStatement = statements [ oIndex ] ;
66+ let newStatement : ts . Statement | undefined ;
67+ let oldStatementsLength = 0 ;
6668
6769 // these can't contain an enum declaration
6870 if ( currentStatement . kind === ts . SyntaxKind . ImportDeclaration ) {
@@ -79,53 +81,47 @@ function visitBlockStatements(
7981 // * not be last statement
8082 // * be a variable statement
8183 // * 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
8386 if ( ts . isVariableStatement ( currentStatement )
8487 && currentStatement . declarationList . declarations . length === 1 ) {
8588
8689 const variableDeclaration = currentStatement . declarationList . declarations [ 0 ] ;
90+ const initializer = variableDeclaration . initializer ;
8791 if ( ts . isIdentifier ( variableDeclaration . name ) ) {
8892 const name = variableDeclaration . name . text ;
8993
90- if ( ! variableDeclaration . initializer ) {
94+ if ( ! initializer ) {
9195 const iife = findTs2_3EnumIife ( name , statements [ oIndex + 1 ] ) ;
9296 if ( iife ) {
93- // found an enum
94- if ( ! updatedStatements ) {
95- updatedStatements = statements . slice ( ) ;
96- }
9797 // update IIFE and replace variable statement and old IIFE
98- updatedStatements . splice ( uIndex , 2 , updateEnumIife (
98+ oldStatementsLength = 2 ;
99+ newStatement = updateEnumIife (
99100 currentStatement ,
100101 iife [ 0 ] ,
101102 iife [ 1 ] ,
102- ) ) ;
103+ ) ;
103104 // skip IIFE statement
104105 oIndex ++ ;
105- continue ;
106106 }
107- } else if ( ts . isObjectLiteralExpression ( variableDeclaration . initializer )
108- && variableDeclaration . initializer . properties . length === 0 ) {
107+ } else if ( ts . isObjectLiteralExpression ( initializer )
108+ && initializer . properties . length === 0 ) {
109109 const enumStatements = findTs2_2EnumStatements ( name , statements , oIndex + 1 ) ;
110110 if ( enumStatements . length > 0 ) {
111- // found an enum
112- if ( ! updatedStatements ) {
113- updatedStatements = statements . slice ( ) ;
114- }
115111 // 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 (
117114 name ,
118115 currentStatement ,
119116 enumStatements ,
120- variableDeclaration . initializer ,
121- ) ) ;
117+ initializer ,
118+ ) ;
122119 // skip enum member declarations
123120 oIndex += enumStatements . length ;
124- continue ;
125121 }
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 ;
129125
130126 // tsickle es2015 enums first statement is an export declaration
131127 const isPotentialEnumExport = ts . isExportDeclaration ( statements [ oIndex + 1 ] ) ;
@@ -136,42 +132,61 @@ function visitBlockStatements(
136132
137133 const enumStatements = findEnumNameStatements ( name , statements , oIndex + 1 ) ;
138134 if ( enumStatements . length === literalPropertyCount ) {
139- // found an enum
140- if ( ! updatedStatements ) {
141- updatedStatements = statements . slice ( ) ;
142- }
143135 // 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 (
146138 name ,
147139 currentStatement ,
148140 enumStatements ,
149- variableDeclaration . initializer ,
141+ initializer ,
150142 isPotentialEnumExport ,
151- ) ) ;
143+ ) ;
152144 // skip enum member declarations
153145 oIndex += enumStatements . length ;
154- continue ;
155146 }
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 ) ;
158155 if ( ! classStatements ) {
159156 continue ;
160157 }
161158
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 ,
168162 classStatements ,
169- ) ) ;
163+ ) ;
170164
171165 oIndex += classStatements . length - 1 ;
172- continue ;
173166 }
174167 }
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 ) ;
175190 }
176191
177192 const result = ts . visitNode ( currentStatement , visitor ) ;
@@ -433,7 +448,7 @@ function updateHostNode(
433448}
434449
435450/**
436- * Find class expression statements.
451+ * Find class expression or declaration statements.
437452 *
438453 * The classExpressions block to wrap in an iife must
439454 * - end with an ExpressionStatement
@@ -445,36 +460,63 @@ function updateHostNode(
445460 Foo = __decorate([]);
446461 ```
447462 */
448- function findClassExpressionStatements (
463+ function findClassStatements (
449464 name : string ,
450465 statements : ts . NodeArray < ts . Statement > ,
451466 statementIndex : number ,
452467) : 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+ }
455475
456- while ( ts . isExpressionStatement ( statement ) ) {
457476 const expression = statement . expression ;
477+
458478 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 ;
465512 }
466513 }
467514
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+ }
476517
477- statement = statements [ ++ index ] ;
518+ if ( count > 1 ) {
519+ return statements . slice ( statementIndex , statementIndex + count ) ;
478520 }
479521
480522 return undefined ;
@@ -573,18 +615,33 @@ function createWrappedEnum(
573615}
574616
575617function createWrappedClass (
576- name : string ,
618+ hostNode : ts . ClassDeclaration | ts . VariableDeclaration ,
577619 statements : ts . Statement [ ] ,
578620) : 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+
579636 const pureIife = addPureComment (
580637 ts . createImmediatelyInvokedArrowFunction ( [
581- ...statements ,
638+ ...updatedStatements ,
582639 ts . createReturn ( ts . createIdentifier ( name ) ) ,
583640 ] ) ,
584641 ) ;
585642
586643 return ts . createVariableStatement (
587- undefined ,
644+ hostNode . modifiers ,
588645 ts . createVariableDeclarationList ( [
589646 ts . createVariableDeclaration ( name , undefined , pureIife ) ,
590647 ] ,
0 commit comments