From b4ee4e50c8c1a21256e0f28a2605e88cc75d2619 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 15 Jan 2019 06:06:36 -0500 Subject: [PATCH] feat(@schematics/angular): Added multiselect guard implements option Adds support for the guard schematic to use multiselect for which interfaces the guard should implement. Fixes #13400 --- .../guard/files/__name@dasherize__.guard.ts | 16 ++++++++--- packages/schematics/angular/guard/index.ts | 16 +++++++++++ .../schematics/angular/guard/index_spec.ts | 27 ++++++++++++++++++- packages/schematics/angular/guard/schema.json | 18 +++++++++++++ 4 files changed, 73 insertions(+), 4 deletions(-) diff --git a/packages/schematics/angular/guard/files/__name@dasherize__.guard.ts b/packages/schematics/angular/guard/files/__name@dasherize__.guard.ts index 1aa0068e9aef..02babf15472d 100644 --- a/packages/schematics/angular/guard/files/__name@dasherize__.guard.ts +++ b/packages/schematics/angular/guard/files/__name@dasherize__.guard.ts @@ -1,14 +1,24 @@ import { Injectable } from '@angular/core'; -import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router'; +import { <%= implementationImports %>ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) -export class <%= classify(name) %>Guard implements CanActivate { - canActivate( +export class <%= classify(name) %>Guard implements <%= implementations %> { + <% if (implements.includes('CanActivate')) { %>canActivate( next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | Promise | boolean | UrlTree { return true; } + <% } %><% if (implements.includes('CanActivateChild')) { %>canActivateChild( + next: ActivatedRouteSnapshot, + state: RouterStateSnapshot): Observable | Promise | boolean | UrlTree { + return true; + } + <% } %><% if (implements.includes('CanLoad')) { %>canLoad( + route: Route, + segments: UrlSegment[]): Observable | Promise | boolean { + return true; + }<% } %> } diff --git a/packages/schematics/angular/guard/index.ts b/packages/schematics/angular/guard/index.ts index 660caee84c35..efd617b94287 100644 --- a/packages/schematics/angular/guard/index.ts +++ b/packages/schematics/angular/guard/index.ts @@ -36,6 +36,20 @@ export default function (options: GuardOptions): Rule { if (options.path === undefined) { options.path = buildDefaultPath(project); } + if (options.implements === undefined) { + options.implements = []; + } + + let implementations = ''; + let implementationImports = ''; + if (options.implements.length > 0) { + implementations = options.implements.join(', '); + implementationImports = `${implementations}, `; + // As long as we aren't in IE... ;) + if (options.implements.includes('CanLoad')) { + implementationImports = `${implementationImports}Route, UrlSegment, `; + } + } const parsedPath = parseName(options.path, options.name); options.name = parsedPath.name; @@ -47,6 +61,8 @@ export default function (options: GuardOptions): Rule { const templateSource = apply(url('./files'), [ options.skipTests ? filter(path => !path.endsWith('.spec.ts')) : noop(), template({ + implementations, + implementationImports, ...strings, ...options, }), diff --git a/packages/schematics/angular/guard/index_spec.ts b/packages/schematics/angular/guard/index_spec.ts index 7c0077fd089b..0c8c413ab970 100644 --- a/packages/schematics/angular/guard/index_spec.ts +++ b/packages/schematics/angular/guard/index_spec.ts @@ -10,7 +10,6 @@ import { Schema as ApplicationOptions } from '../application/schema'; import { Schema as WorkspaceOptions } from '../workspace/schema'; import { Schema as GuardOptions } from './schema'; - describe('Guard Schematic', () => { const schematicRunner = new SchematicTestRunner( '@schematics/angular', @@ -64,4 +63,30 @@ describe('Guard Schematic', () => { appTree = schematicRunner.runSchematic('guard', defaultOptions, appTree); expect(appTree.files).toContain('/projects/bar/custom/app/foo.guard.ts'); }); + + it('should respect the implements value', () => { + const options = { ...defaultOptions, implements: ['CanActivate']}; + const tree = schematicRunner.runSchematic('guard', options, appTree); + const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts'); + expect(fileString).toContain('CanActivate'); + expect(fileString).toContain('canActivate'); + expect(fileString).not.toContain('CanActivateChild'); + expect(fileString).not.toContain('canActivateChild'); + expect(fileString).not.toContain('CanLoad'); + expect(fileString).not.toContain('canLoad'); + }); + + it('should respect the implements values', () => { + const implementationOptions = ['CanActivate', 'CanLoad', 'CanActivateChild']; + const options = { ...defaultOptions, implements: implementationOptions}; + const tree = schematicRunner.runSchematic('guard', options, appTree); + const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts'); + + // Should contain all implementations + implementationOptions.forEach((implementation: string) => { + expect(fileString).toContain(implementation); + const functionName = `${implementation.charAt(0).toLowerCase()}${implementation.slice(1)}`; + expect(fileString).toContain(functionName); + }); + }); }); diff --git a/packages/schematics/angular/guard/schema.json b/packages/schematics/angular/guard/schema.json index a71b831a974f..2ad3a42e9e66 100644 --- a/packages/schematics/angular/guard/schema.json +++ b/packages/schematics/angular/guard/schema.json @@ -47,6 +47,24 @@ "type": "boolean", "default": false, "description": "When true, applies lint fixes after generating the guard." + }, + "implements": { + "type": "array", + "description": "Specifies which interfaces to implement.", + "uniqueItems": true, + "items": { + "type": "string" + }, + "x-prompt": { + "message": "Which interfaces would you like to implement?", + "type": "list", + "multiselect": true, + "items": [ + "CanActivate", + "CanActivateChild", + "CanLoad" + ] + } } }, "required": [