Skip to content

Commit 22fdd7d

Browse files
cexbrayatangular-robot[bot]
authored andcommitted
feat(@schematics/angular): generate functional resolvers and guards by default
As Angular v15.2 deprecates class-based resolvers and guards, this commit switches the `functional` flag default value to `true`. BREAKING CHANGE: `ng g resolver` and `ng g guard` now generate a functional resolver or guard by default. It is still possible to generate a (deprecated) class-based resolver or guard by using `ng g resolver --no-functional` or `ng g guard --no-functional`.
1 parent 2435b46 commit 22fdd7d

File tree

7 files changed

+39
-32
lines changed

7 files changed

+39
-32
lines changed

packages/schematics/angular/guard/index_spec.ts

+20-16
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,12 @@ describe('Guard Schematic', () => {
4343
appTree = await schematicRunner.runSchematic('application', appOptions, appTree);
4444
});
4545

46-
it('should create a guard', async () => {
47-
const tree = await schematicRunner.runSchematic('guard', defaultOptions, appTree);
46+
it('should create a (deprecated) class-based guard with --no-functional', async () => {
47+
const tree = await schematicRunner.runSchematic(
48+
'guard',
49+
{ ...defaultOptions, functional: false },
50+
appTree,
51+
);
4852

4953
const files = tree.files;
5054
expect(files).toContain('/projects/bar/src/app/foo.guard.spec.ts');
@@ -78,7 +82,7 @@ describe('Guard Schematic', () => {
7882
});
7983

8084
it('should respect the implements value', async () => {
81-
const options = { ...defaultOptions, implements: ['CanActivate'] };
85+
const options = { ...defaultOptions, implements: ['CanActivate'], functional: false };
8286
const tree = await schematicRunner.runSchematic('guard', options, appTree);
8387
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
8488
expect(fileString).toContain('CanActivate');
@@ -89,8 +93,8 @@ describe('Guard Schematic', () => {
8993
expect(fileString).not.toContain('canMatch');
9094
});
9195

92-
it('should respect the functional guard value', async () => {
93-
const options = { ...defaultOptions, implements: ['CanActivate'], functional: true };
96+
it('should generate a functional guard by default', async () => {
97+
const options = { ...defaultOptions, implements: ['CanActivate'] };
9498
const tree = await schematicRunner.runSchematic('guard', options, appTree);
9599
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
96100
expect(fileString).toContain('export const fooGuard: CanActivateFn = (route, state) => {');
@@ -101,7 +105,7 @@ describe('Guard Schematic', () => {
101105
});
102106

103107
it('should generate a helper function to execute the guard in a test', async () => {
104-
const options = { ...defaultOptions, implements: ['CanActivate'], functional: true };
108+
const options = { ...defaultOptions, implements: ['CanActivate'] };
105109
const tree = await schematicRunner.runSchematic('guard', options, appTree);
106110
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.spec.ts');
107111
expect(fileString).toContain('const executeGuard: CanActivateFn = (...guardParameters) => ');
@@ -111,7 +115,7 @@ describe('Guard Schematic', () => {
111115
});
112116

113117
it('should generate CanDeactivateFn with unknown functional guard', async () => {
114-
const options = { ...defaultOptions, implements: ['CanDeactivate'], functional: true };
118+
const options = { ...defaultOptions, implements: ['CanDeactivate'] };
115119
const tree = await schematicRunner.runSchematic('guard', options, appTree);
116120
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
117121
expect(fileString).toContain(
@@ -120,9 +124,9 @@ describe('Guard Schematic', () => {
120124
);
121125
});
122126

123-
it('should respect the implements values', async () => {
127+
it('should respect the implements values in (deprecated) class-based guards', async () => {
124128
const implementationOptions = ['CanActivate', 'CanDeactivate', 'CanActivateChild'];
125-
const options = { ...defaultOptions, implements: implementationOptions };
129+
const options = { ...defaultOptions, implements: implementationOptions, functional: false };
126130
const tree = await schematicRunner.runSchematic('guard', options, appTree);
127131
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
128132

@@ -134,19 +138,19 @@ describe('Guard Schematic', () => {
134138
});
135139
});
136140

137-
it('should add correct imports based on CanMatch implementation', async () => {
141+
it('should add correct imports based on CanMatch implementation in (deprecated) class-based guards', async () => {
138142
const implementationOptions = ['CanMatch'];
139-
const options = { ...defaultOptions, implements: implementationOptions };
143+
const options = { ...defaultOptions, implements: implementationOptions, functional: false };
140144
const tree = await schematicRunner.runSchematic('guard', options, appTree);
141145
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
142146
const expectedImports = `import { CanMatch, Route, UrlSegment, UrlTree } from '@angular/router';`;
143147

144148
expect(fileString).toContain(expectedImports);
145149
});
146150

147-
it('should add correct imports based on CanActivate implementation', async () => {
151+
it('should add correct imports based on CanActivate implementation in (deprecated) class-based guards', async () => {
148152
const implementationOptions = ['CanActivate'];
149-
const options = { ...defaultOptions, implements: implementationOptions };
153+
const options = { ...defaultOptions, implements: implementationOptions, functional: false };
150154
const tree = await schematicRunner.runSchematic('guard', options, appTree);
151155
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
152156
const expectedImports = `import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree } from '@angular/router';`;
@@ -155,17 +159,17 @@ describe('Guard Schematic', () => {
155159
});
156160

157161
it('should add correct imports based on canActivate functional guard', async () => {
158-
const options = { ...defaultOptions, implements: ['CanActivate'], functional: true };
162+
const options = { ...defaultOptions, implements: ['CanActivate'] };
159163
const tree = await schematicRunner.runSchematic('guard', options, appTree);
160164
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
161165
const expectedImports = `import { CanActivateFn } from '@angular/router';`;
162166

163167
expect(fileString).toContain(expectedImports);
164168
});
165169

166-
it('should add correct imports if multiple implementations was selected', async () => {
170+
it('should add correct imports if multiple implementations was selected in (deprecated) class-based guards', async () => {
167171
const implementationOptions = ['CanActivate', 'CanMatch', 'CanActivateChild'];
168-
const options = { ...defaultOptions, implements: implementationOptions };
172+
const options = { ...defaultOptions, implements: implementationOptions, functional: false };
169173
const tree = await schematicRunner.runSchematic('guard', options, appTree);
170174
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
171175
const expectedImports =

packages/schematics/angular/guard/schema.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"functional": {
4545
"type": "boolean",
4646
"description": "Specifies whether to generate a guard as a function.",
47-
"default": false
47+
"default": true
4848
},
4949
"implements": {
5050
"alias": "guardType",

packages/schematics/angular/resolver/index_spec.ts

+10-12
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,17 @@ describe('resolver Schematic', () => {
4141
appTree = await schematicRunner.runSchematic('application', appOptions, appTree);
4242
});
4343

44-
it('should create a resolver', async () => {
45-
const tree = await schematicRunner.runSchematic('resolver', defaultOptions, appTree);
44+
it('should create a (deprecated) class-based resolver with --no-functional', async () => {
45+
const tree = await schematicRunner.runSchematic(
46+
'resolver',
47+
{ ...defaultOptions, functional: false },
48+
appTree,
49+
);
4650
const files = tree.files;
4751
expect(files).toContain('/projects/bar/src/app/foo.resolver.spec.ts');
4852
expect(files).toContain('/projects/bar/src/app/foo.resolver.ts');
53+
const fileString = tree.readContent('/projects/bar/src/app/foo.resolver.ts');
54+
expect(fileString).toContain('export class FooResolver implements Resolve<boolean>');
4955
});
5056

5157
it('should respect the skipTests flag', async () => {
@@ -75,23 +81,15 @@ describe('resolver Schematic', () => {
7581
});
7682

7783
it('should create a functional resolver', async () => {
78-
const tree = await schematicRunner.runSchematic(
79-
'resolver',
80-
{ ...defaultOptions, functional: true },
81-
appTree,
82-
);
84+
const tree = await schematicRunner.runSchematic('resolver', defaultOptions, appTree);
8385
const fileString = tree.readContent('/projects/bar/src/app/foo.resolver.ts');
8486
expect(fileString).toContain(
8587
'export const fooResolver: ResolveFn<boolean> = (route, state) => {',
8688
);
8789
});
8890

8991
it('should create a helper function to run a functional resolver in a test', async () => {
90-
const tree = await schematicRunner.runSchematic(
91-
'resolver',
92-
{ ...defaultOptions, functional: true },
93-
appTree,
94-
);
92+
const tree = await schematicRunner.runSchematic('resolver', defaultOptions, appTree);
9593
const fileString = tree.readContent('/projects/bar/src/app/foo.resolver.spec.ts');
9694
expect(fileString).toContain(
9795
'const executeResolver: ResolveFn<boolean> = (...resolverParameters) => ',

packages/schematics/angular/resolver/schema.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"functional": {
2929
"type": "boolean",
3030
"description": "Creates the resolver as a `ResolveFn`.",
31-
"default": false
31+
"default": true
3232
},
3333
"path": {
3434
"type": "string",

tests/legacy-cli/e2e/tests/generate/guard/guard-basic.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ export default async function () {
99
await ng('generate', 'guard', 'test-guard');
1010
await expectFileToExist(guardDir);
1111
await expectFileToExist(join(guardDir, 'test-guard.guard.ts'));
12-
await expectFileToMatch(join(guardDir, 'test-guard.guard.ts'), /implements CanActivate/);
12+
await expectFileToMatch(
13+
join(guardDir, 'test-guard.guard.ts'),
14+
/export const testGuardGuard: CanActivateFn/,
15+
);
1316
await expectFileToExist(join(guardDir, 'test-guard.guard.spec.ts'));
1417
await ng('test', '--watch=false');
1518
}

tests/legacy-cli/e2e/tests/generate/guard/guard-implements.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export default async function () {
99
await ng('generate', 'guard', 'match', '--implements=CanMatch');
1010
await expectFileToExist(guardDir);
1111
await expectFileToExist(join(guardDir, 'match.guard.ts'));
12-
await expectFileToMatch(join(guardDir, 'match.guard.ts'), /implements CanMatch/);
12+
await expectFileToMatch(join(guardDir, 'match.guard.ts'), /export const matchGuard: CanMatch/);
1313
await expectFileToExist(join(guardDir, 'match.guard.spec.ts'));
1414
await ng('test', '--watch=false');
1515
}

tests/legacy-cli/e2e/tests/generate/guard/guard-multiple-implements.ts

+2
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@ export default async function () {
66
// Does not create a sub directory.
77
const guardDir = join('src', 'app');
88

9+
// multiple implements are only supported in (deprecated) class-based guards
910
await ng(
1011
'generate',
1112
'guard',
1213
'multiple',
1314
'--implements=CanActivate',
1415
'--implements=CanDeactivate',
16+
'--no-functional',
1517
);
1618
await expectFileToExist(guardDir);
1719
await expectFileToExist(join(guardDir, 'multiple.guard.ts'));

0 commit comments

Comments
 (0)