From dd1d4efd592e5ed5338e17e80042e10dbf29eb8d Mon Sep 17 00:00:00 2001 From: Billy Lando Date: Mon, 1 Feb 2021 12:47:59 +0100 Subject: [PATCH] fix(@schematics/angular): avoid unuse imports for canLoad guard generation (cherry picked from commit 30815248a8cf972034d336f8cd076d3b7cce8e29) --- .../__name@dasherize__.guard.ts.template | 2 +- packages/schematics/angular/guard/index.ts | 19 +++++- .../schematics/angular/guard/index_spec.ts | 61 ++++++++++++++----- 3 files changed, 62 insertions(+), 20 deletions(-) diff --git a/packages/schematics/angular/guard/files/__name@dasherize__.guard.ts.template b/packages/schematics/angular/guard/files/__name@dasherize__.guard.ts.template index e41530b35898..3dc36a017893 100644 --- a/packages/schematics/angular/guard/files/__name@dasherize__.guard.ts.template +++ b/packages/schematics/angular/guard/files/__name@dasherize__.guard.ts.template @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { <%= implementationImports %>ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router'; +import { <%= implementationImports %> } from '@angular/router'; import { Observable } from 'rxjs'; @Injectable({ diff --git a/packages/schematics/angular/guard/index.ts b/packages/schematics/angular/guard/index.ts index 79fe0e6a8edc..f91495b63489 100644 --- a/packages/schematics/angular/guard/index.ts +++ b/packages/schematics/angular/guard/index.ts @@ -39,12 +39,25 @@ export default function (options: GuardOptions): Rule { const implementations = options.implements .map(implement => implement === 'CanDeactivate' ? 'CanDeactivate' : implement) .join(', '); - let implementationImports = `${options.implements.join(', ')}, `; - // As long as we aren't in IE... ;) + const commonRouterNameImports = ['ActivatedRouteSnapshot', 'RouterStateSnapshot']; + const routerNamedImports: string[] = [...options.implements, 'UrlTree']; + if (options.implements.includes(GuardInterface.CanLoad)) { - implementationImports = `${implementationImports}Route, UrlSegment, `; + routerNamedImports.push( + 'Route', + 'UrlSegment', + ); + + if (options.implements.length > 1) { + routerNamedImports.push(...commonRouterNameImports); + } + } else { + routerNamedImports.push(...commonRouterNameImports); } + routerNamedImports.sort(); + + const implementationImports = routerNamedImports.join(', '); const parsedPath = parseName(options.path, options.name); options.name = parsedPath.name; options.path = parsedPath.path; diff --git a/packages/schematics/angular/guard/index_spec.ts b/packages/schematics/angular/guard/index_spec.ts index d54920f0b929..eba8e654982b 100644 --- a/packages/schematics/angular/guard/index_spec.ts +++ b/packages/schematics/angular/guard/index_spec.ts @@ -38,12 +38,14 @@ describe('Guard Schematic', () => { let appTree: UnitTestTree; beforeEach(async () => { appTree = await schematicRunner.runSchematicAsync('workspace', workspaceOptions).toPromise(); - appTree = await schematicRunner.runSchematicAsync('application', appOptions, appTree) + appTree = await schematicRunner + .runSchematicAsync('application', appOptions, appTree) .toPromise(); }); it('should create a guard', async () => { - const tree = await schematicRunner.runSchematicAsync('guard', defaultOptions, appTree) + const tree = await schematicRunner + .runSchematicAsync('guard', defaultOptions, appTree) .toPromise(); const files = tree.files; expect(files).toContain('/projects/bar/src/app/foo.guard.spec.ts'); @@ -53,8 +55,7 @@ describe('Guard Schematic', () => { it('should respect the skipTests flag', async () => { const options = { ...defaultOptions, skipTests: true }; - const tree = await schematicRunner.runSchematicAsync('guard', options, appTree) - .toPromise(); + const tree = await schematicRunner.runSchematicAsync('guard', options, appTree).toPromise(); const files = tree.files; expect(files).not.toContain('/projects/bar/src/app/foo.guard.spec.ts'); expect(files).toContain('/projects/bar/src/app/foo.guard.ts'); @@ -63,8 +64,7 @@ describe('Guard Schematic', () => { it('should respect the flat flag', async () => { const options = { ...defaultOptions, flat: false }; - const tree = await schematicRunner.runSchematicAsync('guard', options, appTree) - .toPromise(); + const tree = await schematicRunner.runSchematicAsync('guard', options, appTree).toPromise(); const files = tree.files; expect(files).toContain('/projects/bar/src/app/foo/foo.guard.spec.ts'); expect(files).toContain('/projects/bar/src/app/foo/foo.guard.ts'); @@ -74,15 +74,13 @@ describe('Guard Schematic', () => { const config = JSON.parse(appTree.readContent('/angular.json')); config.projects.bar.sourceRoot = 'projects/bar/custom'; appTree.overwrite('/angular.json', JSON.stringify(config, null, 2)); - appTree = await schematicRunner.runSchematicAsync('guard', defaultOptions, appTree) - .toPromise(); + appTree = await schematicRunner.runSchematicAsync('guard', defaultOptions, appTree).toPromise(); expect(appTree.files).toContain('/projects/bar/custom/app/foo.guard.ts'); }); it('should respect the implements value', async () => { - const options = { ...defaultOptions, implements: ['CanActivate']}; - const tree = await schematicRunner.runSchematicAsync('guard', options, appTree) - .toPromise(); + const options = { ...defaultOptions, implements: ['CanActivate'] }; + const tree = await schematicRunner.runSchematicAsync('guard', options, appTree).toPromise(); const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts'); expect(fileString).toContain('CanActivate'); expect(fileString).toContain('canActivate'); @@ -94,9 +92,8 @@ describe('Guard Schematic', () => { it('should respect the implements values', async () => { const implementationOptions = ['CanActivate', 'CanLoad', 'CanActivateChild']; - const options = { ...defaultOptions, implements: implementationOptions}; - const tree = await schematicRunner.runSchematicAsync('guard', options, appTree) - .toPromise(); + const options = { ...defaultOptions, implements: implementationOptions }; + const tree = await schematicRunner.runSchematicAsync('guard', options, appTree).toPromise(); const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts'); // Should contain all implementations @@ -109,8 +106,7 @@ describe('Guard Schematic', () => { it('should use CanActivate if no implements value', async () => { const options = { ...defaultOptions, implements: undefined }; - const tree = await schematicRunner.runSchematicAsync('guard', options, appTree) - .toPromise(); + const tree = await schematicRunner.runSchematicAsync('guard', options, appTree).toPromise(); const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts'); expect(fileString).toContain('CanActivate'); expect(fileString).toContain('canActivate'); @@ -119,4 +115,37 @@ describe('Guard Schematic', () => { expect(fileString).not.toContain('CanLoad'); expect(fileString).not.toContain('canLoad'); }); + + it('should add correct imports based on CanLoad implementation', async () => { + const implementationOptions = ['CanLoad']; + const options = { ...defaultOptions, implements: implementationOptions }; + const tree = await schematicRunner.runSchematicAsync('guard', options, appTree).toPromise(); + const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts'); + const expectedImports = `import { CanLoad, Route, UrlSegment, UrlTree } from '@angular/router';`; + + expect(fileString).toContain(expectedImports); + }); + + it('should add correct imports based on CanActivate implementation', async () => { + const implementationOptions = ['CanActivate']; + const options = { ...defaultOptions, implements: implementationOptions }; + const tree = await schematicRunner.runSchematicAsync('guard', options, appTree).toPromise(); + const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts'); + const expectedImports = `import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree } from '@angular/router';`; + + expect(fileString).toContain(expectedImports); + }); + + it('should add correct imports if multiple implementations was selected', async () => { + const implementationOptions = ['CanActivate', 'CanLoad', 'CanActivateChild']; + const options = { ...defaultOptions, implements: implementationOptions }; + const tree = await schematicRunner.runSchematicAsync('guard', options, appTree).toPromise(); + const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts'); + const expectedImports = + `import ` + + `{ ActivatedRouteSnapshot, CanActivate, CanActivateChild, CanLoad, Route, RouterStateSnapshot, UrlSegment, UrlTree } ` + + `from '@angular/router';`; + + expect(fileString).toContain(expectedImports); + }); });