From da8987b6fdf78495c7f2f36d5822b1bb49bdbf34 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Mon, 4 Mar 2019 19:58:47 +0100 Subject: [PATCH] fix(schematics): incorrectly throws if NgModule uses namespaced decorator (#15298) Currently if the developer defines the primary app `NgModule` using a namespaced import (e.g. "@ngCore.NgModule`), the Material schematics will incorrectly not detect that module as the logic that resolves the decorator name of a class declaration is flawed. This is because it incorrectly traverses a `PropertyAccessExpression`, while the accessed property name is exposed at the root level `PropertyAccessExpression`. This commit fixes this and also adds additional unit tests for the `hasNgModuleImport` utility function. (We have integration tests for this; but we don't test that special case) --- .../utils/ast/ng-module-imports.spec.ts | 38 +++++++++++++++++++ .../schematics/utils/ast/ng-module-imports.ts | 2 +- 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/cdk/schematics/utils/ast/ng-module-imports.spec.ts diff --git a/src/cdk/schematics/utils/ast/ng-module-imports.spec.ts b/src/cdk/schematics/utils/ast/ng-module-imports.spec.ts new file mode 100644 index 00000000000..a9f80fe6028 --- /dev/null +++ b/src/cdk/schematics/utils/ast/ng-module-imports.spec.ts @@ -0,0 +1,38 @@ +import {HostTree} from '@angular-devkit/schematics'; +import {UnitTestTree} from '@angular-devkit/schematics/testing'; +import {hasNgModuleImport} from './ng-module-imports'; + +describe('NgModule import utils', () => { + + let host: UnitTestTree; + + beforeEach(() => { + host = new UnitTestTree(new HostTree()); + }); + + describe('hasNgModuleImport', () => { + it('should properly detect imports', () => { + host.create('/test.ts', ` + @NgModule({ + imports: [TestModule], + }) + export class MyModule {} + `); + + expect(hasNgModuleImport(host, '/test.ts', 'TestModule')).toBe(true); + expect(hasNgModuleImport(host, '/test.ts', 'NotExistent')).toBe(false); + }); + + it(`should detect imports for NgModule's using a namespaced identifier`, () => { + host.create('/test.ts', ` + @myImport.NgModule({ + imports: [TestModule], + }) + export class MyModule {} + `); + + expect(hasNgModuleImport(host, '/test.ts', 'TestModule')).toBe(true); + expect(hasNgModuleImport(host, '/test.ts', 'NotExistent')).toBe(false); + }); + }); +}); diff --git a/src/cdk/schematics/utils/ast/ng-module-imports.ts b/src/cdk/schematics/utils/ast/ng-module-imports.ts index 41ee271d70c..f7586006392 100644 --- a/src/cdk/schematics/utils/ast/ng-module-imports.ts +++ b/src/cdk/schematics/utils/ast/ng-module-imports.ts @@ -49,7 +49,7 @@ function resolveIdentifierOfExpression(expression: ts.Expression): ts.Identifier if (ts.isIdentifier(expression)) { return expression; } else if (ts.isPropertyAccessExpression(expression)) { - return resolveIdentifierOfExpression(expression.expression); + return expression.name; } return null; }