diff --git a/packages/angular_devkit/build_optimizer/src/transforms/scrub-file.ts b/packages/angular_devkit/build_optimizer/src/transforms/scrub-file.ts index 99ed37996862..2af38ec80f5b 100644 --- a/packages/angular_devkit/build_optimizer/src/transforms/scrub-file.ts +++ b/packages/angular_devkit/build_optimizer/src/transforms/scrub-file.ts @@ -206,11 +206,23 @@ function isDecorateAssignmentExpression( if (expr.left.kind !== ts.SyntaxKind.Identifier) { return false; } - if (expr.right.kind !== ts.SyntaxKind.CallExpression) { + const classIdent = expr.left as ts.Identifier; + let callExpr: ts.CallExpression; + + if (expr.right.kind === ts.SyntaxKind.CallExpression) { + callExpr = expr.right as ts.CallExpression; + } else if (expr.right.kind === ts.SyntaxKind.BinaryExpression) { + // `Clazz = Clazz_1 = __decorate([...], Clazz)` can be found when there are static property + // accesses. + const innerExpr = expr.right as ts.BinaryExpression; + if (innerExpr.left.kind !== ts.SyntaxKind.Identifier + || innerExpr.right.kind !== ts.SyntaxKind.CallExpression) { + return false; + } + callExpr = innerExpr.right as ts.CallExpression; + } else { return false; } - const classIdent = expr.left as ts.Identifier; - const callExpr = expr.right as ts.CallExpression; if (!isTslibHelper(callExpr, '__decorate', tslibImports, checker)) { return false; @@ -372,9 +384,20 @@ function pickDecorateNodesToRemove( const expr = expect(exprStmt.expression, ts.SyntaxKind.BinaryExpression); const classId = expect(expr.left, ts.SyntaxKind.Identifier); - const callExpr = expect(expr.right, ts.SyntaxKind.CallExpression); + let callExpr: ts.CallExpression; + + if (expr.right.kind === ts.SyntaxKind.CallExpression) { + callExpr = expect(expr.right, ts.SyntaxKind.CallExpression); + } else if (expr.right.kind === ts.SyntaxKind.BinaryExpression) { + const innerExpr = expr.right as ts.BinaryExpression; + callExpr = expect(innerExpr.right, ts.SyntaxKind.CallExpression); + } else { + return []; + } + const arrLiteral = expect(callExpr.arguments[0], ts.SyntaxKind.ArrayLiteralExpression); + if (!arrLiteral.elements.every((elem) => elem.kind === ts.SyntaxKind.CallExpression)) { return []; } diff --git a/packages/angular_devkit/build_optimizer/src/transforms/scrub-file_spec.ts b/packages/angular_devkit/build_optimizer/src/transforms/scrub-file_spec.ts index 5e324c75aace..accfff1a566e 100644 --- a/packages/angular_devkit/build_optimizer/src/transforms/scrub-file_spec.ts +++ b/packages/angular_devkit/build_optimizer/src/transforms/scrub-file_spec.ts @@ -138,6 +138,48 @@ describe('scrub-file', () => { expect(tags.oneLine`${transform(input)}`).toEqual(tags.oneLine`${output}`); }); + it('removes constructor parameter metadata when static properties are present', () => { + const output = tags.stripIndent` + import { Injectable } from '@angular/core'; + import { Logger } from 'another-lib'; + var GaService = (function () { + function GaService(logger) { + this.logger = logger; + } + GaService_1 = GaService; + GaService.prototype.initializeGa = function () { + console.log(GaService_1.initializeDelay); + }; + GaService.initializeDelay = 1000; + return GaService; + var GaService_1; + }()); + `; + const input = tags.stripIndent` + import { Injectable } from '@angular/core'; + import { Logger } from 'another-lib'; + var GaService = (function () { + function GaService(logger) { + this.logger = logger; + } + GaService_1 = GaService; + GaService.prototype.initializeGa = function () { + console.log(GaService_1.initializeDelay); + }; + GaService.initializeDelay = 1000; + GaService = GaService_1 = __decorate([ + Injectable(), + __metadata("design:paramtypes", [Logger]) + ], GaService); + return GaService; + var GaService_1; + }()); + `; + + expect(testScrubFile(input)).toBeTruthy(); + expect(tags.oneLine`${transform(input)}`).toEqual(tags.oneLine`${output}`); + }); + it('doesn\t remove constructor parameter metadata for whitelisted classes', () => { const input = tags.stripIndent` import { ElementRef } from '@angular/core';