From 5564ce6ea1a96bda981d88cb86932b4874d30bef Mon Sep 17 00:00:00 2001 From: Filipe Silva Date: Tue, 24 Sep 2019 15:50:18 +0100 Subject: [PATCH] =?UTF-8?q?feat(@angular-devkit/build-optimizer):=20scrub?= =?UTF-8?q?=20=C9=B5setClassMetadata=20and=20=C9=B5=C9=B5setNgModuleScope?= =?UTF-8?q?=20calls?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/transforms/scrub-file.ts | 23 ++++++++++- .../src/transforms/scrub-file_spec.ts | 38 +++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) 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 3eb8fa0f64..748abcd9c0 100644 --- a/packages/angular_devkit/build_optimizer/src/transforms/scrub-file.ts +++ b/packages/angular_devkit/build_optimizer/src/transforms/scrub-file.ts @@ -17,6 +17,8 @@ export function testScrubFile(content: string) { '__decorate', 'propDecorators', 'ctorParameters', + 'ɵsetClassMetadata', + 'ɵɵsetNgModuleScope', ]; return markers.some((marker) => content.indexOf(marker) !== -1); @@ -51,7 +53,8 @@ function scrubFileTransformer(checker: ts.TypeChecker, isAngularCoreFile: boolea } const exprStmt = node as ts.ExpressionStatement; // Do checks that don't need the typechecker first and bail early. - if (isCtorParamsAssignmentExpression(exprStmt)) { + if (isIvyPrivateCallExpression(exprStmt) + || isCtorParamsAssignmentExpression(exprStmt)) { nodes.push(node); } else if (isDecoratorAssignmentExpression(exprStmt)) { nodes.push(...pickDecorationNodesToRemove(exprStmt, ngMetadata, checker)); @@ -310,6 +313,24 @@ function isAssignmentExpressionTo(exprStmt: ts.ExpressionStatement, name: string return true; } +function isIvyPrivateCallExpression(exprStmt: ts.ExpressionStatement) { + const callExpr = exprStmt.expression; + if (!ts.isCallExpression(callExpr)) { + return false; + } + const propAccExpr = callExpr.expression; + if (!ts.isPropertyAccessExpression(propAccExpr)) { + return false; + } + + if (propAccExpr.name.text != 'ɵsetClassMetadata' + && propAccExpr.name.text != 'ɵɵsetNgModuleScope') { + return false; + } + + return true; +} + // Remove Angular decorators from`Clazz.decorators = [...];`, or expression itself if all are // removed. function pickDecorationNodesToRemove( 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 b2cd87e700..84feac63a7 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 @@ -612,4 +612,42 @@ describe('scrub-file', () => { expect(tags.oneLine`${transform(input)}`).toEqual(tags.oneLine`${output}`); }); }); + + describe('Ivy', () => { + it('removes ɵsetClassMetadata call', () => { + const output = tags.stripIndent` + import { Component } from '@angular/core'; + ${clazz} + `; + const input = tags.stripIndent` + ${output} + /*@__PURE__*/ i0.ɵsetClassMetadata(Clazz, [{ + type: Component, + args: [{ + selector: 'app-lazy', + template: 'very lazy', + styles: [] + }] + }], null, null); + `; + + expect(testScrubFile(input)).toBeTruthy(); + expect(tags.oneLine`${transform(input)}`).toEqual(tags.oneLine`${output}`); + }); + + it('removes ɵɵsetNgModuleScope call', () => { + const output = tags.stripIndent` + import { CommonModule } from '@angular/common'; + import * as i0 from "@angular/core"; + ${clazz} + `; + const input = tags.stripIndent` + ${output} + /*@__PURE__*/ i0.ɵɵsetNgModuleScope(Clazz, { declarations: [], imports: [CommonModule] }); + `; + + expect(testScrubFile(input)).toBeTruthy(); + expect(tags.oneLine`${transform(input)}`).toEqual(tags.oneLine`${output}`); + }); + }); });