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`.
This commit is contained in:
ced 2023-01-20 14:26:50 +01:00 committed by angular-robot[bot]
parent 2435b46560
commit 22fdd7da97
7 changed files with 39 additions and 32 deletions

View File

@ -43,8 +43,12 @@ describe('Guard Schematic', () => {
appTree = await schematicRunner.runSchematic('application', appOptions, appTree);
});
it('should create a guard', async () => {
const tree = await schematicRunner.runSchematic('guard', defaultOptions, appTree);
it('should create a (deprecated) class-based guard with --no-functional', async () => {
const tree = await schematicRunner.runSchematic(
'guard',
{ ...defaultOptions, functional: false },
appTree,
);
const files = tree.files;
expect(files).toContain('/projects/bar/src/app/foo.guard.spec.ts');
@ -78,7 +82,7 @@ describe('Guard Schematic', () => {
});
it('should respect the implements value', async () => {
const options = { ...defaultOptions, implements: ['CanActivate'] };
const options = { ...defaultOptions, implements: ['CanActivate'], functional: false };
const tree = await schematicRunner.runSchematic('guard', options, appTree);
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
expect(fileString).toContain('CanActivate');
@ -89,8 +93,8 @@ describe('Guard Schematic', () => {
expect(fileString).not.toContain('canMatch');
});
it('should respect the functional guard value', async () => {
const options = { ...defaultOptions, implements: ['CanActivate'], functional: true };
it('should generate a functional guard by default', async () => {
const options = { ...defaultOptions, implements: ['CanActivate'] };
const tree = await schematicRunner.runSchematic('guard', options, appTree);
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
expect(fileString).toContain('export const fooGuard: CanActivateFn = (route, state) => {');
@ -101,7 +105,7 @@ describe('Guard Schematic', () => {
});
it('should generate a helper function to execute the guard in a test', async () => {
const options = { ...defaultOptions, implements: ['CanActivate'], functional: true };
const options = { ...defaultOptions, implements: ['CanActivate'] };
const tree = await schematicRunner.runSchematic('guard', options, appTree);
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.spec.ts');
expect(fileString).toContain('const executeGuard: CanActivateFn = (...guardParameters) => ');
@ -111,7 +115,7 @@ describe('Guard Schematic', () => {
});
it('should generate CanDeactivateFn with unknown functional guard', async () => {
const options = { ...defaultOptions, implements: ['CanDeactivate'], functional: true };
const options = { ...defaultOptions, implements: ['CanDeactivate'] };
const tree = await schematicRunner.runSchematic('guard', options, appTree);
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
expect(fileString).toContain(
@ -120,9 +124,9 @@ describe('Guard Schematic', () => {
);
});
it('should respect the implements values', async () => {
it('should respect the implements values in (deprecated) class-based guards', async () => {
const implementationOptions = ['CanActivate', 'CanDeactivate', 'CanActivateChild'];
const options = { ...defaultOptions, implements: implementationOptions };
const options = { ...defaultOptions, implements: implementationOptions, functional: false };
const tree = await schematicRunner.runSchematic('guard', options, appTree);
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
@ -134,9 +138,9 @@ describe('Guard Schematic', () => {
});
});
it('should add correct imports based on CanMatch implementation', async () => {
it('should add correct imports based on CanMatch implementation in (deprecated) class-based guards', async () => {
const implementationOptions = ['CanMatch'];
const options = { ...defaultOptions, implements: implementationOptions };
const options = { ...defaultOptions, implements: implementationOptions, functional: false };
const tree = await schematicRunner.runSchematic('guard', options, appTree);
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
const expectedImports = `import { CanMatch, Route, UrlSegment, UrlTree } from '@angular/router';`;
@ -144,9 +148,9 @@ describe('Guard Schematic', () => {
expect(fileString).toContain(expectedImports);
});
it('should add correct imports based on CanActivate implementation', async () => {
it('should add correct imports based on CanActivate implementation in (deprecated) class-based guards', async () => {
const implementationOptions = ['CanActivate'];
const options = { ...defaultOptions, implements: implementationOptions };
const options = { ...defaultOptions, implements: implementationOptions, functional: false };
const tree = await schematicRunner.runSchematic('guard', options, appTree);
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
const expectedImports = `import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree } from '@angular/router';`;
@ -155,7 +159,7 @@ describe('Guard Schematic', () => {
});
it('should add correct imports based on canActivate functional guard', async () => {
const options = { ...defaultOptions, implements: ['CanActivate'], functional: true };
const options = { ...defaultOptions, implements: ['CanActivate'] };
const tree = await schematicRunner.runSchematic('guard', options, appTree);
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
const expectedImports = `import { CanActivateFn } from '@angular/router';`;
@ -163,9 +167,9 @@ describe('Guard Schematic', () => {
expect(fileString).toContain(expectedImports);
});
it('should add correct imports if multiple implementations was selected', async () => {
it('should add correct imports if multiple implementations was selected in (deprecated) class-based guards', async () => {
const implementationOptions = ['CanActivate', 'CanMatch', 'CanActivateChild'];
const options = { ...defaultOptions, implements: implementationOptions };
const options = { ...defaultOptions, implements: implementationOptions, functional: false };
const tree = await schematicRunner.runSchematic('guard', options, appTree);
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
const expectedImports =

View File

@ -44,7 +44,7 @@
"functional": {
"type": "boolean",
"description": "Specifies whether to generate a guard as a function.",
"default": false
"default": true
},
"implements": {
"alias": "guardType",

View File

@ -41,11 +41,17 @@ describe('resolver Schematic', () => {
appTree = await schematicRunner.runSchematic('application', appOptions, appTree);
});
it('should create a resolver', async () => {
const tree = await schematicRunner.runSchematic('resolver', defaultOptions, appTree);
it('should create a (deprecated) class-based resolver with --no-functional', async () => {
const tree = await schematicRunner.runSchematic(
'resolver',
{ ...defaultOptions, functional: false },
appTree,
);
const files = tree.files;
expect(files).toContain('/projects/bar/src/app/foo.resolver.spec.ts');
expect(files).toContain('/projects/bar/src/app/foo.resolver.ts');
const fileString = tree.readContent('/projects/bar/src/app/foo.resolver.ts');
expect(fileString).toContain('export class FooResolver implements Resolve<boolean>');
});
it('should respect the skipTests flag', async () => {
@ -75,11 +81,7 @@ describe('resolver Schematic', () => {
});
it('should create a functional resolver', async () => {
const tree = await schematicRunner.runSchematic(
'resolver',
{ ...defaultOptions, functional: true },
appTree,
);
const tree = await schematicRunner.runSchematic('resolver', defaultOptions, appTree);
const fileString = tree.readContent('/projects/bar/src/app/foo.resolver.ts');
expect(fileString).toContain(
'export const fooResolver: ResolveFn<boolean> = (route, state) => {',
@ -87,11 +89,7 @@ describe('resolver Schematic', () => {
});
it('should create a helper function to run a functional resolver in a test', async () => {
const tree = await schematicRunner.runSchematic(
'resolver',
{ ...defaultOptions, functional: true },
appTree,
);
const tree = await schematicRunner.runSchematic('resolver', defaultOptions, appTree);
const fileString = tree.readContent('/projects/bar/src/app/foo.resolver.spec.ts');
expect(fileString).toContain(
'const executeResolver: ResolveFn<boolean> = (...resolverParameters) => ',

View File

@ -28,7 +28,7 @@
"functional": {
"type": "boolean",
"description": "Creates the resolver as a `ResolveFn`.",
"default": false
"default": true
},
"path": {
"type": "string",

View File

@ -9,7 +9,10 @@ export default async function () {
await ng('generate', 'guard', 'test-guard');
await expectFileToExist(guardDir);
await expectFileToExist(join(guardDir, 'test-guard.guard.ts'));
await expectFileToMatch(join(guardDir, 'test-guard.guard.ts'), /implements CanActivate/);
await expectFileToMatch(
join(guardDir, 'test-guard.guard.ts'),
/export const testGuardGuard: CanActivateFn/,
);
await expectFileToExist(join(guardDir, 'test-guard.guard.spec.ts'));
await ng('test', '--watch=false');
}

View File

@ -9,7 +9,7 @@ export default async function () {
await ng('generate', 'guard', 'match', '--implements=CanMatch');
await expectFileToExist(guardDir);
await expectFileToExist(join(guardDir, 'match.guard.ts'));
await expectFileToMatch(join(guardDir, 'match.guard.ts'), /implements CanMatch/);
await expectFileToMatch(join(guardDir, 'match.guard.ts'), /export const matchGuard: CanMatch/);
await expectFileToExist(join(guardDir, 'match.guard.spec.ts'));
await ng('test', '--watch=false');
}

View File

@ -6,12 +6,14 @@ export default async function () {
// Does not create a sub directory.
const guardDir = join('src', 'app');
// multiple implements are only supported in (deprecated) class-based guards
await ng(
'generate',
'guard',
'multiple',
'--implements=CanActivate',
'--implements=CanDeactivate',
'--no-functional',
);
await expectFileToExist(guardDir);
await expectFileToExist(join(guardDir, 'multiple.guard.ts'));