Skip to content

Commit 9de282c

Browse files
FG-33vikerman
authored andcommitted
feat(@schematics/angular): add generator for interceptor
Rework.
1 parent fd6b752 commit 9de282c

File tree

8 files changed

+228
-1
lines changed

8 files changed

+228
-1
lines changed

packages/schematics/angular/application/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ function addAppToWorkspaceFile(options: ApplicationOptions, appDir: string): Rul
169169
}
170170

171171
if (options.skipTests || options.minimal) {
172-
['class', 'component', 'directive', 'guard', 'module', 'pipe', 'service'].forEach((type) => {
172+
['class', 'component', 'directive', 'guard', 'interceptor', 'module', 'pipe', 'service'].forEach((type) => {
173173
if (!(`@schematics/angular:${type}` in schematics)) {
174174
schematics[`@schematics/angular:${type}`] = {};
175175
}

packages/schematics/angular/collection.json

100644100755
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@
6060
"description": "Create a guard.",
6161
"schema": "./guard/schema.json"
6262
},
63+
"interceptor": {
64+
"factory": "./interceptor",
65+
"description": "Create an interceptor.",
66+
"schema": "./interceptor/schema.json"
67+
},
6368
"interface": {
6469
"aliases": [ "i" ],
6570
"factory": "./interface",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { TestBed } from '@angular/core/testing';
2+
3+
import { <%= classify(name) %>Interceptor } from './<%= dasherize(name) %>.interceptor';
4+
5+
describe('<%= classify(name) %>Interceptor', () => {
6+
beforeEach(() => TestBed.configureTestingModule({
7+
providers: [
8+
<%= classify(name) %>Interceptor
9+
]
10+
}));
11+
12+
it('should be created', () => {
13+
const interceptor: <%= classify(name) %>Interceptor = TestBed.inject(<%= classify(name) %>Interceptor);
14+
expect(interceptor).toBeTruthy();
15+
});
16+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Injectable } from '@angular/core';
2+
import {
3+
HttpRequest,
4+
HttpHandler,
5+
HttpEvent,
6+
HttpInterceptor
7+
} from '@angular/common/http';
8+
import { Observable } from 'rxjs';
9+
10+
@Injectable()
11+
export class <%= classify(name) %>Interceptor implements HttpInterceptor {
12+
13+
constructor() {}
14+
15+
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
16+
return next.handle(request);
17+
}
18+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
import { strings } from '@angular-devkit/core';
9+
import {
10+
Rule,
11+
Tree,
12+
apply,
13+
applyTemplates,
14+
chain,
15+
filter,
16+
mergeWith,
17+
move,
18+
noop,
19+
url,
20+
} from '@angular-devkit/schematics';
21+
import { applyLintFix } from '../utility/lint-fix';
22+
import { parseName } from '../utility/parse-name';
23+
import { createDefaultPath } from '../utility/workspace';
24+
import { Schema as InterceptorOptions } from './schema';
25+
26+
export default function (options: InterceptorOptions): Rule {
27+
return async (host: Tree) => {
28+
if (options.path === undefined) {
29+
options.path = await createDefaultPath(host, options.project as string);
30+
}
31+
32+
const parsedPath = parseName(options.path, options.name);
33+
options.name = parsedPath.name;
34+
options.path = parsedPath.path;
35+
36+
const templateSource = apply(url('./files'), [
37+
options.skipTests ? filter(path => !path.endsWith('.spec.ts.template')) : noop(),
38+
applyTemplates({
39+
...strings,
40+
'if-flat': (s: string) => options.flat ? '' : s,
41+
...options,
42+
}),
43+
move(parsedPath.path),
44+
]);
45+
46+
return chain([
47+
mergeWith(templateSource),
48+
options.lintFix ? applyLintFix(options.path) : noop(),
49+
]);
50+
};
51+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
9+
import { Schema as ApplicationOptions } from '../application/schema';
10+
import { Schema as WorkspaceOptions } from '../workspace/schema';
11+
import { Schema as ServiceOptions } from './schema';
12+
13+
describe('Interceptor Schematic', () => {
14+
const schematicRunner = new SchematicTestRunner(
15+
'@schematics/angular',
16+
require.resolve('../collection.json'),
17+
);
18+
const defaultOptions: ServiceOptions = {
19+
name: 'foo',
20+
flat: false,
21+
project: 'bar',
22+
};
23+
24+
const workspaceOptions: WorkspaceOptions = {
25+
name: 'workspace',
26+
newProjectRoot: 'projects',
27+
version: '6.0.0',
28+
};
29+
30+
const appOptions: ApplicationOptions = {
31+
name: 'bar',
32+
inlineStyle: false,
33+
inlineTemplate: false,
34+
routing: false,
35+
skipPackageJson: false,
36+
};
37+
let appTree: UnitTestTree;
38+
beforeEach(async () => {
39+
appTree = schematicRunner.runSchematic('workspace', workspaceOptions);
40+
appTree = await schematicRunner.runSchematicAsync('application', appOptions, appTree).toPromise();
41+
});
42+
43+
it('should create an interceptor', async () => {
44+
const options = { ...defaultOptions };
45+
46+
const tree = await schematicRunner.runSchematicAsync('interceptor', options, appTree)
47+
.toPromise();
48+
const files = tree.files;
49+
expect(files).toContain('/projects/bar/src/app/foo/foo.interceptor.spec.ts');
50+
expect(files).toContain('/projects/bar/src/app/foo/foo.interceptor.ts');
51+
});
52+
53+
it('should respect the skipTests flag', async () => {
54+
const options = { ...defaultOptions, skipTests: true };
55+
56+
const tree = await schematicRunner.runSchematicAsync('interceptor', options, appTree)
57+
.toPromise();
58+
const files = tree.files;
59+
expect(files).toContain('/projects/bar/src/app/foo/foo.interceptor.ts');
60+
expect(files).not.toContain('/projects/bar/src/app/foo/foo.interceptor.spec.ts');
61+
});
62+
63+
it('should respect the sourceRoot value', async () => {
64+
const config = JSON.parse(appTree.readContent('/angular.json'));
65+
config.projects.bar.sourceRoot = 'projects/bar/custom';
66+
appTree.overwrite('/angular.json', JSON.stringify(config, null, 2));
67+
appTree = await schematicRunner.runSchematicAsync('interceptor', defaultOptions, appTree)
68+
.toPromise();
69+
expect(appTree.files).toContain('/projects/bar/custom/app/foo/foo.interceptor.ts');
70+
});
71+
});
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{
2+
"$schema": "http://json-schema.org/schema",
3+
"id": "SchematicsAngularInterceptor",
4+
"title": "Angular Interceptor Options Schema",
5+
"type": "object",
6+
"description": "Creates a new, generic interceptor definition in the given or default project.",
7+
"properties": {
8+
"name": {
9+
"type": "string",
10+
"description": "The name of the interceptor.",
11+
"$default": {
12+
"$source": "argv",
13+
"index": 0
14+
},
15+
"x-prompt": "What name would you like to use for the interceptor?"
16+
},
17+
"path": {
18+
"type": "string",
19+
"format": "path",
20+
"description": "The path at which to create the interceptor, relative to the workspace root.",
21+
"visible": false
22+
},
23+
"project": {
24+
"type": "string",
25+
"description": "The name of the project.",
26+
"$default": {
27+
"$source": "projectName"
28+
}
29+
},
30+
"flat": {
31+
"type": "boolean",
32+
"default": true,
33+
"description": "When true (the default), creates files at the top level of the project."
34+
},
35+
"skipTests": {
36+
"type": "boolean",
37+
"description": "When true, does not create \"spec.ts\" test files for the new interceptor.",
38+
"default": false,
39+
"x-user-analytics": 12
40+
},
41+
"lintFix": {
42+
"type": "boolean",
43+
"default": false,
44+
"description": "When true, applies lint fixes after generating the interceptor.",
45+
"x-user-analytics": 15
46+
}
47+
},
48+
"required": ["name"]
49+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import {join} from 'path';
2+
import {ng} from '../../../utils/process';
3+
import {expectFileToExist} from '../../../utils/fs';
4+
5+
6+
export default function() {
7+
// Does not create a sub directory.
8+
const interceptorDir = join('src', 'app');
9+
10+
return ng('generate', 'interceptor', 'test-interceptor')
11+
.then(() => expectFileToExist(interceptorDir))
12+
.then(() => expectFileToExist(join(interceptorDir, 'test-interceptor.interceptor.ts')))
13+
.then(() => expectFileToExist(join(interceptorDir, 'test-interceptor.interceptor.spec.ts')))
14+
15+
// Try to run the unit tests.
16+
.then(() => ng('test', '--watch=false'));
17+
}

0 commit comments

Comments
 (0)