mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-18 03:23:57 +08:00
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:
parent
2435b46560
commit
22fdd7da97
@ -43,8 +43,12 @@ describe('Guard Schematic', () => {
|
|||||||
appTree = await schematicRunner.runSchematic('application', appOptions, appTree);
|
appTree = await schematicRunner.runSchematic('application', appOptions, appTree);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create a guard', async () => {
|
it('should create a (deprecated) class-based guard with --no-functional', async () => {
|
||||||
const tree = await schematicRunner.runSchematic('guard', defaultOptions, appTree);
|
const tree = await schematicRunner.runSchematic(
|
||||||
|
'guard',
|
||||||
|
{ ...defaultOptions, functional: false },
|
||||||
|
appTree,
|
||||||
|
);
|
||||||
|
|
||||||
const files = tree.files;
|
const files = tree.files;
|
||||||
expect(files).toContain('/projects/bar/src/app/foo.guard.spec.ts');
|
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 () => {
|
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 tree = await schematicRunner.runSchematic('guard', options, appTree);
|
||||||
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
|
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
|
||||||
expect(fileString).toContain('CanActivate');
|
expect(fileString).toContain('CanActivate');
|
||||||
@ -89,8 +93,8 @@ describe('Guard Schematic', () => {
|
|||||||
expect(fileString).not.toContain('canMatch');
|
expect(fileString).not.toContain('canMatch');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should respect the functional guard value', async () => {
|
it('should generate a functional guard by default', async () => {
|
||||||
const options = { ...defaultOptions, implements: ['CanActivate'], functional: true };
|
const options = { ...defaultOptions, implements: ['CanActivate'] };
|
||||||
const tree = await schematicRunner.runSchematic('guard', options, appTree);
|
const tree = await schematicRunner.runSchematic('guard', options, appTree);
|
||||||
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
|
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
|
||||||
expect(fileString).toContain('export const fooGuard: CanActivateFn = (route, state) => {');
|
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 () => {
|
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 tree = await schematicRunner.runSchematic('guard', options, appTree);
|
||||||
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.spec.ts');
|
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.spec.ts');
|
||||||
expect(fileString).toContain('const executeGuard: CanActivateFn = (...guardParameters) => ');
|
expect(fileString).toContain('const executeGuard: CanActivateFn = (...guardParameters) => ');
|
||||||
@ -111,7 +115,7 @@ describe('Guard Schematic', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should generate CanDeactivateFn with unknown functional guard', async () => {
|
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 tree = await schematicRunner.runSchematic('guard', options, appTree);
|
||||||
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
|
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
|
||||||
expect(fileString).toContain(
|
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 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 tree = await schematicRunner.runSchematic('guard', options, appTree);
|
||||||
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
|
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 implementationOptions = ['CanMatch'];
|
||||||
const options = { ...defaultOptions, implements: implementationOptions };
|
const options = { ...defaultOptions, implements: implementationOptions, functional: false };
|
||||||
const tree = await schematicRunner.runSchematic('guard', options, appTree);
|
const tree = await schematicRunner.runSchematic('guard', options, appTree);
|
||||||
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
|
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
|
||||||
const expectedImports = `import { CanMatch, Route, UrlSegment, UrlTree } from '@angular/router';`;
|
const expectedImports = `import { CanMatch, Route, UrlSegment, UrlTree } from '@angular/router';`;
|
||||||
@ -144,9 +148,9 @@ describe('Guard Schematic', () => {
|
|||||||
expect(fileString).toContain(expectedImports);
|
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 implementationOptions = ['CanActivate'];
|
||||||
const options = { ...defaultOptions, implements: implementationOptions };
|
const options = { ...defaultOptions, implements: implementationOptions, functional: false };
|
||||||
const tree = await schematicRunner.runSchematic('guard', options, appTree);
|
const tree = await schematicRunner.runSchematic('guard', options, appTree);
|
||||||
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
|
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
|
||||||
const expectedImports = `import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree } from '@angular/router';`;
|
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 () => {
|
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 tree = await schematicRunner.runSchematic('guard', options, appTree);
|
||||||
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
|
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
|
||||||
const expectedImports = `import { CanActivateFn } from '@angular/router';`;
|
const expectedImports = `import { CanActivateFn } from '@angular/router';`;
|
||||||
@ -163,9 +167,9 @@ describe('Guard Schematic', () => {
|
|||||||
expect(fileString).toContain(expectedImports);
|
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 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 tree = await schematicRunner.runSchematic('guard', options, appTree);
|
||||||
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
|
const fileString = tree.readContent('/projects/bar/src/app/foo.guard.ts');
|
||||||
const expectedImports =
|
const expectedImports =
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
"functional": {
|
"functional": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Specifies whether to generate a guard as a function.",
|
"description": "Specifies whether to generate a guard as a function.",
|
||||||
"default": false
|
"default": true
|
||||||
},
|
},
|
||||||
"implements": {
|
"implements": {
|
||||||
"alias": "guardType",
|
"alias": "guardType",
|
||||||
|
@ -41,11 +41,17 @@ describe('resolver Schematic', () => {
|
|||||||
appTree = await schematicRunner.runSchematic('application', appOptions, appTree);
|
appTree = await schematicRunner.runSchematic('application', appOptions, appTree);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create a resolver', async () => {
|
it('should create a (deprecated) class-based resolver with --no-functional', async () => {
|
||||||
const tree = await schematicRunner.runSchematic('resolver', defaultOptions, appTree);
|
const tree = await schematicRunner.runSchematic(
|
||||||
|
'resolver',
|
||||||
|
{ ...defaultOptions, functional: false },
|
||||||
|
appTree,
|
||||||
|
);
|
||||||
const files = tree.files;
|
const files = tree.files;
|
||||||
expect(files).toContain('/projects/bar/src/app/foo.resolver.spec.ts');
|
expect(files).toContain('/projects/bar/src/app/foo.resolver.spec.ts');
|
||||||
expect(files).toContain('/projects/bar/src/app/foo.resolver.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 () => {
|
it('should respect the skipTests flag', async () => {
|
||||||
@ -75,11 +81,7 @@ describe('resolver Schematic', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should create a functional resolver', async () => {
|
it('should create a functional resolver', async () => {
|
||||||
const tree = await schematicRunner.runSchematic(
|
const tree = await schematicRunner.runSchematic('resolver', defaultOptions, appTree);
|
||||||
'resolver',
|
|
||||||
{ ...defaultOptions, functional: true },
|
|
||||||
appTree,
|
|
||||||
);
|
|
||||||
const fileString = tree.readContent('/projects/bar/src/app/foo.resolver.ts');
|
const fileString = tree.readContent('/projects/bar/src/app/foo.resolver.ts');
|
||||||
expect(fileString).toContain(
|
expect(fileString).toContain(
|
||||||
'export const fooResolver: ResolveFn<boolean> = (route, state) => {',
|
'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 () => {
|
it('should create a helper function to run a functional resolver in a test', async () => {
|
||||||
const tree = await schematicRunner.runSchematic(
|
const tree = await schematicRunner.runSchematic('resolver', defaultOptions, appTree);
|
||||||
'resolver',
|
|
||||||
{ ...defaultOptions, functional: true },
|
|
||||||
appTree,
|
|
||||||
);
|
|
||||||
const fileString = tree.readContent('/projects/bar/src/app/foo.resolver.spec.ts');
|
const fileString = tree.readContent('/projects/bar/src/app/foo.resolver.spec.ts');
|
||||||
expect(fileString).toContain(
|
expect(fileString).toContain(
|
||||||
'const executeResolver: ResolveFn<boolean> = (...resolverParameters) => ',
|
'const executeResolver: ResolveFn<boolean> = (...resolverParameters) => ',
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
"functional": {
|
"functional": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Creates the resolver as a `ResolveFn`.",
|
"description": "Creates the resolver as a `ResolveFn`.",
|
||||||
"default": false
|
"default": true
|
||||||
},
|
},
|
||||||
"path": {
|
"path": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -9,7 +9,10 @@ export default async function () {
|
|||||||
await ng('generate', 'guard', 'test-guard');
|
await ng('generate', 'guard', 'test-guard');
|
||||||
await expectFileToExist(guardDir);
|
await expectFileToExist(guardDir);
|
||||||
await expectFileToExist(join(guardDir, 'test-guard.guard.ts'));
|
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 expectFileToExist(join(guardDir, 'test-guard.guard.spec.ts'));
|
||||||
await ng('test', '--watch=false');
|
await ng('test', '--watch=false');
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ export default async function () {
|
|||||||
await ng('generate', 'guard', 'match', '--implements=CanMatch');
|
await ng('generate', 'guard', 'match', '--implements=CanMatch');
|
||||||
await expectFileToExist(guardDir);
|
await expectFileToExist(guardDir);
|
||||||
await expectFileToExist(join(guardDir, 'match.guard.ts'));
|
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 expectFileToExist(join(guardDir, 'match.guard.spec.ts'));
|
||||||
await ng('test', '--watch=false');
|
await ng('test', '--watch=false');
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,14 @@ export default async function () {
|
|||||||
// Does not create a sub directory.
|
// Does not create a sub directory.
|
||||||
const guardDir = join('src', 'app');
|
const guardDir = join('src', 'app');
|
||||||
|
|
||||||
|
// multiple implements are only supported in (deprecated) class-based guards
|
||||||
await ng(
|
await ng(
|
||||||
'generate',
|
'generate',
|
||||||
'guard',
|
'guard',
|
||||||
'multiple',
|
'multiple',
|
||||||
'--implements=CanActivate',
|
'--implements=CanActivate',
|
||||||
'--implements=CanDeactivate',
|
'--implements=CanDeactivate',
|
||||||
|
'--no-functional',
|
||||||
);
|
);
|
||||||
await expectFileToExist(guardDir);
|
await expectFileToExist(guardDir);
|
||||||
await expectFileToExist(join(guardDir, 'multiple.guard.ts'));
|
await expectFileToExist(join(guardDir, 'multiple.guard.ts'));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user