@@ -12,6 +12,7 @@ import { collectDeepNodes } from '../helpers/ast-utils';
12
12
export function testScrubFile ( content : string ) {
13
13
const markers = [
14
14
'decorators' ,
15
+ '__decorate' ,
15
16
'propDecorators' ,
16
17
'ctorParameters' ,
17
18
] ;
@@ -68,6 +69,9 @@ export function getScrubFileTransformer(program: ts.Program): ts.TransformerFact
68
69
if ( isDecoratorAssignmentExpression ( exprStmt ) ) {
69
70
nodes . push ( ...pickDecorationNodesToRemove ( exprStmt , ngMetadata , checker ) ) ;
70
71
}
72
+ if ( isDecorateAssignmentExpression ( exprStmt ) ) {
73
+ nodes . push ( ...pickDecorateNodesToRemove ( exprStmt , ngMetadata , checker ) ) ;
74
+ }
71
75
if ( isPropDecoratorAssignmentExpression ( exprStmt ) ) {
72
76
nodes . push ( ...pickPropDecorationNodesToRemove ( exprStmt , ngMetadata , checker ) ) ;
73
77
}
@@ -99,7 +103,7 @@ export function getScrubFileTransformer(program: ts.Program): ts.TransformerFact
99
103
100
104
export function expect < T extends ts . Node > ( node : ts . Node , kind : ts . SyntaxKind ) : T {
101
105
if ( node . kind !== kind ) {
102
- throw new Error ( 'Invalid! ' ) ;
106
+ throw new Error ( 'Invalid node type. ' ) ;
103
107
}
104
108
105
109
return node as T ;
@@ -158,6 +162,7 @@ function isAngularCoreSpecifier(node: ts.ImportSpecifier): boolean {
158
162
return angularSpecifiers . indexOf ( nameOfSpecifier ( node ) ) !== - 1 ;
159
163
}
160
164
165
+ // Check if assignment is `Clazz.decorators = [...];`.
161
166
function isDecoratorAssignmentExpression ( exprStmt : ts . ExpressionStatement ) : boolean {
162
167
if ( exprStmt . expression . kind !== ts . SyntaxKind . BinaryExpression ) {
163
168
return false ;
@@ -183,6 +188,46 @@ function isDecoratorAssignmentExpression(exprStmt: ts.ExpressionStatement): bool
183
188
return true ;
184
189
}
185
190
191
+ // Check if assignment is `Clazz = __decorate([...], Clazz)`.
192
+ function isDecorateAssignmentExpression ( exprStmt : ts . ExpressionStatement ) : boolean {
193
+ if ( exprStmt . expression . kind !== ts . SyntaxKind . BinaryExpression ) {
194
+ return false ;
195
+ }
196
+ const expr = exprStmt . expression as ts . BinaryExpression ;
197
+ if ( expr . left . kind !== ts . SyntaxKind . Identifier ) {
198
+ return false ;
199
+ }
200
+ if ( expr . right . kind !== ts . SyntaxKind . CallExpression ) {
201
+ return false ;
202
+ }
203
+ const classIdent = expr . left as ts . Identifier ;
204
+ const callExpr = expr . right as ts . CallExpression ;
205
+ if ( callExpr . expression . kind !== ts . SyntaxKind . Identifier ) {
206
+ return false ;
207
+ }
208
+ const callExprIdent = callExpr . expression as ts . Identifier ;
209
+ // node.text on a name that starts with two underscores will return three instead.
210
+ if ( callExprIdent . text !== '___decorate' ) {
211
+ return false ;
212
+ }
213
+ if ( callExpr . arguments . length !== 2 ) {
214
+ return false ;
215
+ }
216
+ if ( callExpr . arguments [ 1 ] . kind !== ts . SyntaxKind . Identifier ) {
217
+ return false ;
218
+ }
219
+ const classArg = callExpr . arguments [ 1 ] as ts . Identifier ;
220
+ if ( classIdent . text !== classArg . text ) {
221
+ return false ;
222
+ }
223
+ if ( callExpr . arguments [ 0 ] . kind !== ts . SyntaxKind . ArrayLiteralExpression ) {
224
+ return false ;
225
+ }
226
+
227
+ return true ;
228
+ }
229
+
230
+ // Check if assignment is `Clazz.propDecorators = [...];`.
186
231
function isPropDecoratorAssignmentExpression ( exprStmt : ts . ExpressionStatement ) : boolean {
187
232
if ( exprStmt . expression . kind !== ts . SyntaxKind . BinaryExpression ) {
188
233
return false ;
@@ -208,6 +253,7 @@ function isPropDecoratorAssignmentExpression(exprStmt: ts.ExpressionStatement):
208
253
return true ;
209
254
}
210
255
256
+ // Check if assignment is `Clazz.ctorParameters = [...];`.
211
257
function isCtorParamsAssignmentExpression ( exprStmt : ts . ExpressionStatement ) : boolean {
212
258
if ( exprStmt . expression . kind !== ts . SyntaxKind . BinaryExpression ) {
213
259
return false ;
@@ -243,6 +289,8 @@ function isCtorParamsWhitelistedService(exprStmt: ts.ExpressionStatement): boole
243
289
return platformWhitelist . indexOf ( serviceId . text ) !== - 1 ;
244
290
}
245
291
292
+ // Remove Angular decorators from`Clazz.decorators = [...];`, or expression itself if all are
293
+ // removed.
246
294
function pickDecorationNodesToRemove (
247
295
exprStmt : ts . ExpressionStatement ,
248
296
ngMetadata : ts . Node [ ] ,
@@ -261,6 +309,38 @@ function pickDecorationNodesToRemove(
261
309
return ( elements . length > ngDecorators . length ) ? ngDecorators : [ exprStmt ] ;
262
310
}
263
311
312
+ // Remove Angular decorators from `Clazz = __decorate([...], Clazz)`, or expression itself if all
313
+ // are removed.
314
+ function pickDecorateNodesToRemove (
315
+ exprStmt : ts . ExpressionStatement ,
316
+ ngMetadata : ts . Node [ ] ,
317
+ checker : ts . TypeChecker ,
318
+ ) : ts . Node [ ] {
319
+
320
+ const expr = expect < ts . BinaryExpression > ( exprStmt . expression , ts . SyntaxKind . BinaryExpression ) ;
321
+ const callExpr = expect < ts . CallExpression > ( expr . right , ts . SyntaxKind . CallExpression ) ;
322
+ const arrLiteral = expect < ts . ArrayLiteralExpression > ( callExpr . arguments [ 0 ] ,
323
+ ts . SyntaxKind . ArrayLiteralExpression ) ;
324
+ if ( ! arrLiteral . elements . every ( ( elem ) => elem . kind === ts . SyntaxKind . CallExpression ) ) {
325
+ return [ ] ;
326
+ }
327
+ const elements = arrLiteral . elements as ts . NodeArray < ts . CallExpression > ;
328
+ const ngDecoratorCalls = elements . filter ( ( el ) => {
329
+ if ( el . expression . kind !== ts . SyntaxKind . Identifier ) {
330
+ return false ;
331
+ }
332
+ const id = el . expression as ts . Identifier ;
333
+
334
+ return identifierIsMetadata ( id , ngMetadata , checker ) ;
335
+ } ) ;
336
+
337
+ // If all decorators are metadata decorators then return the whole `Class = __decorate([...])'`
338
+ // statement so that it is removed in entirety
339
+ return ( elements . length === ngDecoratorCalls . length ) ? [ exprStmt ] : ngDecoratorCalls ;
340
+ }
341
+
342
+ // Remove Angular decorators from`Clazz.propDecorators = [...];`, or expression itself if all
343
+ // are removed.
264
344
function pickPropDecorationNodesToRemove (
265
345
exprStmt : ts . ExpressionStatement ,
266
346
ngMetadata : ts . Node [ ] ,
0 commit comments