Skip to content

Commit 8863bc0

Browse files
okeefem2Keen Yee Liau
authored andcommitted
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
1 parent a38db5d commit 8863bc0

File tree

4 files changed

+73
-4
lines changed

4 files changed

+73
-4
lines changed
Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
11
import { Injectable } from '@angular/core';
2-
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router';
2+
import { <%= implementationImports %>ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router';
33
import { Observable } from 'rxjs';
44

55
@Injectable({
66
providedIn: 'root'
77
})
8-
export class <%= classify(name) %>Guard implements CanActivate {
9-
canActivate(
8+
export class <%= classify(name) %>Guard implements <%= implementations %> {
9+
<% if (implements.includes('CanActivate')) { %>canActivate(
1010
next: ActivatedRouteSnapshot,
1111
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
1212
return true;
1313
}
14+
<% } %><% if (implements.includes('CanActivateChild')) { %>canActivateChild(
15+
next: ActivatedRouteSnapshot,
16+
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
17+
return true;
18+
}
19+
<% } %><% if (implements.includes('CanLoad')) { %>canLoad(
20+
route: Route,
21+
segments: UrlSegment[]): Observable<boolean> | Promise<boolean> | boolean {
22+
return true;
23+
}<% } %>
1424
}

packages/schematics/angular/guard/index.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,20 @@ export default function (options: GuardOptions): Rule {
3636
if (options.path === undefined) {
3737
options.path = buildDefaultPath(project);
3838
}
39+
if (options.implements === undefined) {
40+
options.implements = [];
41+
}
42+
43+
let implementations = '';
44+
let implementationImports = '';
45+
if (options.implements.length > 0) {
46+
implementations = options.implements.join(', ');
47+
implementationImports = `${implementations}, `;
48+
// As long as we aren't in IE... ;)
49+
if (options.implements.includes('CanLoad')) {
50+
implementationImports = `${implementationImports}Route, UrlSegment, `;
51+
}
52+
}
3953

4054
const parsedPath = parseName(options.path, options.name);
4155
options.name = parsedPath.name;
@@ -47,6 +61,8 @@ export default function (options: GuardOptions): Rule {
4761
const templateSource = apply(url('./files'), [
4862
options.skipTests ? filter(path => !path.endsWith('.spec.ts')) : noop(),
4963
template({
64+
implementations,
65+
implementationImports,
5066
...strings,
5167
...options,
5268
}),

packages/schematics/angular/guard/index_spec.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import { Schema as ApplicationOptions } from '../application/schema';
1010
import { Schema as WorkspaceOptions } from '../workspace/schema';
1111
import { Schema as GuardOptions } from './schema';
1212

13-
1413
describe('Guard Schematic', () => {
1514
const schematicRunner = new SchematicTestRunner(
1615
'@schematics/angular',
@@ -64,4 +63,30 @@ describe('Guard Schematic', () => {
6463
appTree = schematicRunner.runSchematic('guard', defaultOptions, appTree);
6564
expect(appTree.files).toContain('/projects/bar/custom/app/foo.guard.ts');
6665
});
66+
67+
it('should respect the implements value', () => {
68+
const options = { ...defaultOptions, implements: ['CanActivate']};
69+
const tree = schematicRunner.runSchematic('guard', options, appTree);
70+
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
71+
expect(fileString).toContain('CanActivate');
72+
expect(fileString).toContain('canActivate');
73+
expect(fileString).not.toContain('CanActivateChild');
74+
expect(fileString).not.toContain('canActivateChild');
75+
expect(fileString).not.toContain('CanLoad');
76+
expect(fileString).not.toContain('canLoad');
77+
});
78+
79+
it('should respect the implements values', () => {
80+
const implementationOptions = ['CanActivate', 'CanLoad', 'CanActivateChild'];
81+
const options = { ...defaultOptions, implements: implementationOptions};
82+
const tree = schematicRunner.runSchematic('guard', options, appTree);
83+
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
84+
85+
// Should contain all implementations
86+
implementationOptions.forEach((implementation: string) => {
87+
expect(fileString).toContain(implementation);
88+
const functionName = `${implementation.charAt(0).toLowerCase()}${implementation.slice(1)}`;
89+
expect(fileString).toContain(functionName);
90+
});
91+
});
6792
});

packages/schematics/angular/guard/schema.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,24 @@
4747
"type": "boolean",
4848
"default": false,
4949
"description": "When true, applies lint fixes after generating the guard."
50+
},
51+
"implements": {
52+
"type": "array",
53+
"description": "Specifies which interfaces to implement.",
54+
"uniqueItems": true,
55+
"items": {
56+
"type": "string"
57+
},
58+
"x-prompt": {
59+
"message": "Which interfaces would you like to implement?",
60+
"type": "list",
61+
"multiselect": true,
62+
"items": [
63+
"CanActivate",
64+
"CanActivateChild",
65+
"CanLoad"
66+
]
67+
}
5068
}
5169
},
5270
"required": [

0 commit comments

Comments
 (0)