Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(@schematics/angular): add generation for resolvers #19048

Merged
merged 1 commit into from Oct 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/schematics/angular/collection.json
Expand Up @@ -60,6 +60,12 @@
"description": "Create a guard.",
"schema": "./guard/schema.json"
},
"resolver": {
"aliases": [ "r" ],
"factory": "./resolver",
"description": "Create a resolver.",
"schema": "./resolver/schema.json"
},
"interceptor": {
"factory": "./interceptor",
"description": "Create an interceptor.",
Expand Down
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';

import { <%= classify(name) %>Resolver } from './<%= dasherize(name) %>.resolver';

describe('<%= classify(name) %>Resolver', () => {
let resolver: <%= classify(name) %>Resolver;

beforeEach(() => {
TestBed.configureTestingModule({});
resolver = TestBed.inject(<%= classify(name) %>Resolver);
});

it('should be created', () => {
expect(resolver).toBeTruthy();
});
});
@@ -0,0 +1,16 @@
import { Injectable } from '@angular/core';
import {
Router, Resolve,
RouterStateSnapshot,
ActivatedRouteSnapshot
} from '@angular/router';
import { Observable, of } from 'rxjs';

@Injectable({
providedIn: 'root'
})
export class <%= classify(name) %>Resolver implements Resolve<boolean> {
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
return of(true);
}
}
49 changes: 49 additions & 0 deletions packages/schematics/angular/resolver/index.ts
@@ -0,0 +1,49 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import { strings } from '@angular-devkit/core';
import {
Rule,
Tree,
apply,
applyTemplates,
chain,
filter,
mergeWith,
move,
noop,
url,
} from '@angular-devkit/schematics';
import { parseName } from '../utility/parse-name';
import { createDefaultPath } from '../utility/workspace';
import { Schema } from './schema';


export default function (options: Schema): Rule {
return async (host: Tree) => {
if (options.path === undefined) {
options.path = await createDefaultPath(host, options.project as string);
}

const parsedPath = parseName(options.path, options.name);
options.name = parsedPath.name;
options.path = parsedPath.path;

const templateSource = apply(url('./files'), [
options.skipTests ? filter(path => !path.endsWith('.spec.ts.template')) : noop(),
applyTemplates({
...strings,
...options,
}),
move(parsedPath.path + (options.flat ? '' : '/' + strings.dasherize(options.name))),
]);

return chain([
mergeWith(templateSource),
]);
};
}
80 changes: 80 additions & 0 deletions packages/schematics/angular/resolver/index_spec.ts
@@ -0,0 +1,80 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
import { Schema as ApplicationOptions } from '../application/schema';
import { Schema as WorkspaceOptions } from '../workspace/schema';
import { Schema } from './schema';

describe('resolver Schematic', () => {
const schematicRunner = new SchematicTestRunner(
'@schematics/angular',
require.resolve('../collection.json'),
);
const defaultOptions: Schema = {
name: 'foo',
flat: true,
project: 'bar',
};
const workspaceOptions: WorkspaceOptions = {
name: 'workspace',
newProjectRoot: 'projects',
version: '6.0.0',
};

const appOptions: ApplicationOptions = {
name: 'bar',
inlineStyle: false,
inlineTemplate: false,
routing: false,
skipTests: false,
skipPackageJson: false,
};
let appTree: UnitTestTree;
beforeEach(async () => {
appTree = await schematicRunner.runSchematicAsync('workspace', workspaceOptions).toPromise();
appTree = await schematicRunner.runSchematicAsync('application', appOptions, appTree)
.toPromise();
});

it('should create a resolver', async () => {
const tree = await schematicRunner.runSchematicAsync('resolver', defaultOptions, appTree)
.toPromise();
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');
});

it('should respect the skipTests flag', async () => {
const options = { ...defaultOptions, skipTests: true };

const tree = await schematicRunner.runSchematicAsync('resolver', options, appTree)
.toPromise();
const files = tree.files;
expect(files).not.toContain('/projects/bar/src/app/foo.resolver.spec.ts');
expect(files).toContain('/projects/bar/src/app/foo.resolver.ts');
});

it('should respect the flat flag', async () => {
const options = { ...defaultOptions, flat: false };

const tree = await schematicRunner.runSchematicAsync('resolver', options, appTree)
.toPromise();
const files = tree.files;
expect(files).toContain('/projects/bar/src/app/foo/foo.resolver.spec.ts');
expect(files).toContain('/projects/bar/src/app/foo/foo.resolver.ts');
});

it('should respect the sourceRoot value', async () => {
const config = JSON.parse(appTree.readContent('/angular.json'));
config.projects.bar.sourceRoot = 'projects/bar/custom';
appTree.overwrite('/angular.json', JSON.stringify(config, null, 2));
appTree = await schematicRunner.runSchematicAsync('resolver', defaultOptions, appTree)
.toPromise();
expect(appTree.files).toContain('/projects/bar/custom/app/foo.resolver.ts');
});
});
45 changes: 45 additions & 0 deletions packages/schematics/angular/resolver/schema.json
@@ -0,0 +1,45 @@
{
"$schema": "http://json-schema.org/schema",
"id": "SchematicsAngularResolver",
"title": "Angular resolver Options Schema",
"type": "object",
"description": "Generates a new, generic resolver definition in the given or default project.",
"properties": {
"name": {
"type": "string",
"description": "The name of the new resolver.",
"$default": {
"$source": "argv",
"index": 0
},
"x-prompt": "What name would you like to use for the resolver?"
},
"skipTests": {
"type": "boolean",
"description": "When true, does not create \"spec.ts\" test files for the new resolver.",
"default": false,
"x-user-analytics": 12
},
"flat": {
"type": "boolean",
"description": "When true (the default), creates the new files at the top level of the current project.",
"default": true
},
"path": {
"type": "string",
"format": "path",
"description": "The path at which to create the interface that defines the resolver, relative to the current workspace.",
"visible": false
},
"project": {
"type": "string",
"description": "The name of the project.",
"$default": {
"$source": "projectName"
}
}
},
"required": [
"name"
]
}