From e31afb7118dffb5141f326a6a5335c2db52705a9 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Thu, 27 Dec 2018 18:49:03 +0000 Subject: [PATCH] fix(ivy): ngcc - identify all ESM5 decorated classes (#27848) In ESM5 decorated classes can be indicated by calls to `__decorate()`. Previously the `ReflectionHost.findDecoratedClasses()` call would identify helper calls of the form: ``` SomeClass = tslib_1.__decorate(...); ``` But it was missing calls of the form: ``` SomeClass = SomeClass_1 = tslib_1.__decorate(...); ``` This form is common in `@NgModule()` decorations, where the class being decorated is referenced inside the decorator or another member. This commit now ensures that a chain of assignments, of any length, is now identified as a class decoration if it results in a call to `__decorate()`. Fixes #27841 PR Close #27848 --- integration/_payload-limits.json | 2 +- integration/ngcc/yarn.lock | 22 +++++++++---------- .../src/ngcc/src/host/esm2015_host.ts | 6 +++-- .../test/host/esm5_host_import_helper_spec.ts | 21 ++++++++++++++++++ 4 files changed, 37 insertions(+), 14 deletions(-) diff --git a/integration/_payload-limits.json b/integration/_payload-limits.json index 9691a8dda6..30c7a708cd 100644 --- a/integration/_payload-limits.json +++ b/integration/_payload-limits.json @@ -12,7 +12,7 @@ "master": { "uncompressed": { "runtime": 1440, - "main": 507677, + "main": 584077, "polyfills": 38390 } } diff --git a/integration/ngcc/yarn.lock b/integration/ngcc/yarn.lock index 7f24bb3051..7321233239 100644 --- a/integration/ngcc/yarn.lock +++ b/integration/ngcc/yarn.lock @@ -3,7 +3,7 @@ "@angular/animations@file:../../dist/packages-dist/animations": - version "7.1.0" + version "7.2.0-rc.0" dependencies: tslib "^1.9.0" @@ -17,12 +17,12 @@ parse5 "^5.0.0" "@angular/common@file:../../dist/packages-dist/common": - version "7.1.0" + version "0.0.0" dependencies: tslib "^1.9.0" "@angular/compiler-cli@file:../../dist/packages-dist/compiler-cli": - version "7.1.0" + version "0.0.0" dependencies: canonical-path "1.0.0" chokidar "^1.4.2" @@ -37,22 +37,22 @@ yargs "9.0.1" "@angular/compiler@file:../../dist/packages-dist/compiler": - version "7.1.0" + version "7.2.0-rc.0" dependencies: tslib "^1.9.0" "@angular/core@file:../../dist/packages-dist/core": - version "7.1.0" + version "0.0.0" dependencies: tslib "^1.9.0" "@angular/forms@file:../../dist/packages-dist/forms": - version "7.1.0" + version "0.0.0" dependencies: tslib "^1.9.0" "@angular/http@file:../../dist/packages-dist/http": - version "7.1.0" + version "7.2.0-rc.0" dependencies: tslib "^1.9.0" @@ -66,17 +66,17 @@ parse5 "^5.0.0" "@angular/platform-browser-dynamic@file:../../dist/packages-dist/platform-browser-dynamic": - version "7.1.0" + version "7.2.0-rc.0" dependencies: tslib "^1.9.0" "@angular/platform-browser@file:../../dist/packages-dist/platform-browser": - version "7.1.0" + version "0.0.0" dependencies: tslib "^1.9.0" "@angular/router@file:../../dist/packages-dist/router": - version "7.1.0" + version "0.0.0" dependencies: tslib "^1.9.0" @@ -3278,7 +3278,7 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= "typescript@file:../../node_modules/typescript": - version "3.1.1" + version "3.2.2" ua-parser-js@0.7.17: version "0.7.17" diff --git a/packages/compiler-cli/src/ngcc/src/host/esm2015_host.ts b/packages/compiler-cli/src/ngcc/src/host/esm2015_host.ts index e4241d62d9..7d9c9b5c45 100644 --- a/packages/compiler-cli/src/ngcc/src/host/esm2015_host.ts +++ b/packages/compiler-cli/src/ngcc/src/host/esm2015_host.ts @@ -661,8 +661,10 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N */ protected getHelperCall(statement: ts.Statement, helperName: string): ts.CallExpression|null { if (ts.isExpressionStatement(statement)) { - const expression = - isAssignmentStatement(statement) ? statement.expression.right : statement.expression; + let expression = statement.expression; + while (isAssignment(expression)) { + expression = expression.right; + } if (ts.isCallExpression(expression) && getCalleeName(expression) === helperName) { return expression; } diff --git a/packages/compiler-cli/src/ngcc/test/host/esm5_host_import_helper_spec.ts b/packages/compiler-cli/src/ngcc/test/host/esm5_host_import_helper_spec.ts index 4fca679d42..55647fbb4f 100644 --- a/packages/compiler-cli/src/ngcc/test/host/esm5_host_import_helper_spec.ts +++ b/packages/compiler-cli/src/ngcc/test/host/esm5_host_import_helper_spec.ts @@ -304,6 +304,27 @@ describe('Esm5ReflectionHost [import helper style]', () => { }); }); + describe('findDecoratedClasses', () => { + it('should return an array of all decorated classes in the given source file', () => { + const program = makeTestProgram(...fileSystem.files); + const host = new Esm5ReflectionHost(false, program.getTypeChecker()); + + const ngModuleFile = program.getSourceFile('/ngmodule.js') !; + const ngModuleClasses = host.findDecoratedClasses(ngModuleFile); + expect(ngModuleClasses.length).toEqual(1); + const ngModuleClass = ngModuleClasses.find(c => c.name === 'HttpClientXsrfModule') !; + expect(ngModuleClass.decorators.map(decorator => decorator.name)).toEqual(['NgModule']); + + const someDirectiveFile = program.getSourceFile('/some_directive.js') !; + const someDirectiveClasses = host.findDecoratedClasses(someDirectiveFile); + expect(someDirectiveClasses.length).toEqual(1); + const someDirectiveClass = someDirectiveClasses.find(c => c.name === 'SomeDirective') !; + expect(someDirectiveClass.decorators.map(decorator => decorator.name)).toEqual([ + 'Directive' + ]); + }); + }); + describe('getDeclarationOfIdentifier', () => { it('should return the declaration of a locally defined identifier', () => { const program = makeTestProgram(fileSystem.files[0]);