Skip to content

Commit

Permalink
feature() add resolver schematic
Browse files Browse the repository at this point in the history
  • Loading branch information
kamilmysliwiec committed Dec 9, 2018
1 parent bbc984a commit 46657ee
Show file tree
Hide file tree
Showing 19 changed files with 337 additions and 10 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nestjs/schematics",
"version": "5.10.1",
"version": "5.11.0",
"description": "Nest - modern, fast, powerful node.js web framework (@schematics)",
"main": "index.js",
"publishConfig": {
Expand Down
5 changes: 5 additions & 0 deletions src/collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@
"description": "Create a Nest service.",
"schema": "./lib/service/schema.json"
},
"resolver": {
"factory": "./lib/resolver/resolver.factory#main",
"description": "Create a Nest resolver.",
"schema": "./lib/resolver/schema.json"
},
"configuration": {
"factory": "./lib/configuration/configuration.factory#main",
"description": "Create a Nest CLI configuration."
Expand Down
2 changes: 1 addition & 1 deletion src/lib/filter/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
},
"sourceRoot": {
"type": "string",
"description": "Nest decorator source root directory."
"description": "Nest filter source root directory."
},
"flat": {
"default": true,
Expand Down
2 changes: 1 addition & 1 deletion src/lib/gateway/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
},
"sourceRoot": {
"type": "string",
"description": "Nest decorator source root directory."
"description": "Nest gateway source root directory."
},
"flat": {
"default": true,
Expand Down
2 changes: 1 addition & 1 deletion src/lib/guard/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
},
"sourceRoot": {
"type": "string",
"description": "Nest decorator source root directory."
"description": "Nest guard source root directory."
},
"flat": {
"default": true,
Expand Down
2 changes: 1 addition & 1 deletion src/lib/interceptor/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
},
"sourceRoot": {
"type": "string",
"description": "Nest decorator source root directory."
"description": "Nest interceptor source root directory."
},
"flat": {
"default": true,
Expand Down
2 changes: 1 addition & 1 deletion src/lib/interface/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
},
"sourceRoot": {
"type": "string",
"description": "Nest decorator source root directory."
"description": "Nest interface source root directory."
},
"flat": {
"default": true,
Expand Down
2 changes: 1 addition & 1 deletion src/lib/middleware/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
},
"sourceRoot": {
"type": "string",
"description": "Nest decorator source root directory."
"description": "Nest middleware source root directory."
},
"flat": {
"default": true,
Expand Down
2 changes: 1 addition & 1 deletion src/lib/pipe/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
},
"sourceRoot": {
"type": "string",
"description": "Nest decorator source root directory."
"description": "Nest pipe source root directory."
},
"flat": {
"default": true,
Expand Down
2 changes: 1 addition & 1 deletion src/lib/provider/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
},
"sourceRoot": {
"type": "string",
"description": "Nest decorator source root directory."
"description": "Nest provider source root directory."
},
"flat": {
"default": true,
Expand Down
4 changes: 4 additions & 0 deletions src/lib/resolver/files/js/__name__.resolver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { Resolver } from '@nestjs/graphql';

@Resolver('<%= classify(name) %>')
export class <%= classify(name) %>Resolver {}
15 changes: 15 additions & 0 deletions src/lib/resolver/files/js/__name__.resolver.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Test } from '@nestjs/testing';
import { <%= classify(name) %>Resolver } from './<%= name %>.resolver';

describe('<%= classify(name) %>Resolver', () => {
let resolver;
beforeAll(async () => {
const module = await Test.createTestingModule({
providers: [<%= classify(name) %>Resolver],
}).compile();
resolver = module.get(<%= classify(name) %>Resolver);
});
it('should be defined', () => {
expect(resolver).toBeDefined();
});
});
16 changes: 16 additions & 0 deletions src/lib/resolver/files/ts/__name__.resolver.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Test, TestingModule } from '@nestjs/testing';
import { <%= classify(name) %>Resolver } from './<%= name %>.resolver';

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

beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [<%= classify(name) %>Resolver],
}).compile();
resolver = module.get<<%= classify(name) %>Resolver>(<%= classify(name) %>Resolver);
});
it('should be defined', () => {
expect(resolver).toBeDefined();
});
});
4 changes: 4 additions & 0 deletions src/lib/resolver/files/ts/__name__.resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { Resolver } from '@nestjs/graphql';

@Resolver('<%= classify(name) %>')
export class <%= classify(name) %>Resolver {}
117 changes: 117 additions & 0 deletions src/lib/resolver/resolver.factory.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import {
SchematicTestRunner,
UnitTestTree,
} from '@angular-devkit/schematics/testing';
import * as path from 'path';
import { ResolverOptions } from './resolver.schema';

describe('Resolver Factory', () => {
const runner: SchematicTestRunner = new SchematicTestRunner(
'.',
path.join(process.cwd(), 'src/collection.json'),
);
it('should manage name only', () => {
const options: ResolverOptions = {
name: 'foo',
flat: false,
};
const tree: UnitTestTree = runner.runSchematic('resolver', options);
const files: string[] = tree.files;
expect(
files.find(filename => filename === '/foo/foo.resolver.ts'),
).not.toBeUndefined();
expect(tree.readContent('/foo/foo.resolver.ts')).toEqual(
"import { Resolver } from '@nestjs/graphql';\n" +
'\n' +
'@Resolver(\'Foo\')\n' +
'export class FooResolver {}\n',
);
});
it('should manage name as a path', () => {
const options: ResolverOptions = {
name: 'bar/foo',
flat: false,
};
const tree: UnitTestTree = runner.runSchematic('resolver', options);
const files: string[] = tree.files;
expect(
files.find(filename => filename === '/bar/foo/foo.resolver.ts'),
).not.toBeUndefined();
expect(tree.readContent('/bar/foo/foo.resolver.ts')).toEqual(
"import { Resolver } from '@nestjs/graphql';\n" +
'\n' +
'@Resolver(\'Foo\')\n' +
'export class FooResolver {}\n',
);
});
it('should manage name and path', () => {
const options: ResolverOptions = {
name: 'foo',
path: 'baz',
flat: false,
};
const tree: UnitTestTree = runner.runSchematic('resolver', options);
const files: string[] = tree.files;
expect(
files.find(filename => filename === '/baz/foo/foo.resolver.ts'),
).not.toBeUndefined();
expect(tree.readContent('/baz/foo/foo.resolver.ts')).toEqual(
"import { Resolver } from '@nestjs/graphql';\n" +
'\n' +
'@Resolver(\'Foo\')\n' +
'export class FooResolver {}\n',
);
});
it('should manage name to dasherize', () => {
const options: ResolverOptions = {
name: 'fooBar',
flat: false,
};
const tree: UnitTestTree = runner.runSchematic('resolver', options);
const files: string[] = tree.files;
expect(
files.find(filename => filename === '/foo-bar/foo-bar.resolver.ts'),
).not.toBeUndefined();
expect(tree.readContent('/foo-bar/foo-bar.resolver.ts')).toEqual(
"import { Resolver } from '@nestjs/graphql';\n" +
'\n' +
'@Resolver(\'FooBar\')\n' +
'export class FooBarResolver {}\n',
);
});
it('should manage path to dasherize', () => {
const options: ResolverOptions = {
name: 'barBaz/foo',
flat: false,
};
const tree: UnitTestTree = runner.runSchematic('resolver', options);
const files: string[] = tree.files;
expect(
files.find(filename => filename === '/bar-baz/foo/foo.resolver.ts'),
).not.toBeUndefined();
expect(tree.readContent('/bar-baz/foo/foo.resolver.ts')).toEqual(
"import { Resolver } from '@nestjs/graphql';\n" +
'\n' +
'@Resolver(\'Foo\')\n' +
'export class FooResolver {}\n',
);
});
it('should manage javascript file', () => {
const options: ResolverOptions = {
name: 'foo',
language: 'js',
flat: false,
};
const tree: UnitTestTree = runner.runSchematic('resolver', options);
const files: string[] = tree.files;
expect(
files.find(filename => filename === '/foo/foo.resolver.js'),
).not.toBeUndefined();
expect(tree.readContent('/foo/foo.resolver.js')).toEqual(
"import { Resolver } from '@nestjs/graphql';\n" +
'\n' +
'@Resolver(\'Foo\')\n' +
'export class FooResolver {}\n',
);
});
});
92 changes: 92 additions & 0 deletions src/lib/resolver/resolver.factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { join, Path, strings } from '@angular-devkit/core';
import {
apply,
branchAndMerge,
chain,
filter,
mergeWith,
move,
noop,
Rule,
SchematicContext,
SchematicsException,
Source,
template,
Tree,
url,
} from '@angular-devkit/schematics';
import {
DeclarationOptions,
ModuleDeclarator,
} from '../../utils/module.declarator';
import { ModuleFinder } from '../../utils/module.finder';
import { Location, NameParser } from '../../utils/name.parser';
import { mergeSourceRoot } from '../../utils/source-root.helpers';
import { ProviderOptions } from '../provider/provider.schema';
import { ResolverOptions } from './resolver.schema';

export function main(options: ResolverOptions): Rule {
options = transform(options);
return (tree: Tree, context: SchematicContext) => {
return branchAndMerge(
chain([
mergeSourceRoot(options),
addDeclarationToModule(options),
mergeWith(generate(options)),
]),
)(tree, context);
};
}

function transform(options: ResolverOptions): ResolverOptions {
const target: ResolverOptions = Object.assign({}, options);
if (!target.name) {
throw new SchematicsException('Option (name) is required.');
}
target.metadata = 'providers';
target.type = 'resolver';

const location: Location = new NameParser().parse(target);
target.name = strings.dasherize(location.name);
target.path = strings.dasherize(location.path);
target.language = target.language !== undefined ? target.language : 'ts';

target.path = target.flat
? target.path
: join(target.path as Path, target.name);
return target;
}

function generate(options: ResolverOptions): Source {
return (context: SchematicContext) =>
apply(url(join('./files' as Path, options.language)), [
options.spec ? noop() : filter(path => !path.endsWith('.spec.ts')),
template({
...strings,
...options,
}),
move(options.path),
])(context);
}

function addDeclarationToModule(options: ProviderOptions): Rule {
return (tree: Tree) => {
if (options.skipImport !== undefined && options.skipImport) {
return tree;
}
options.module = new ModuleFinder(tree).find({
name: options.name,
path: options.path as Path,
});
if (!options.module) {
return tree;
}
const content = tree.read(options.module).toString();
const declarator: ModuleDeclarator = new ModuleDeclarator();
tree.overwrite(
options.module,
declarator.declare(content, options as DeclarationOptions),
);
return tree;
};
}
36 changes: 36 additions & 0 deletions src/lib/resolver/resolver.schema.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Path } from '@angular-devkit/core';

export interface ResolverOptions {
/**
* The name of the resolver.
*/
name: string;
/**
* The path to create the resolver.
*/
path?: string | Path;
/**
* Application language.
*/
language?: string;
/**
* The source root path
*/
sourceRoot?: string;
/**
* Specifies if a spec file is generated.
*/
spec?: boolean;
/**
* Flag to indicate if a directory is created.
*/
flat?: boolean;
/**
* Metadata name affected by declaration insertion.
*/
metadata?: string;
/**
* Nest element type name
*/
type?: string;
}
Loading

0 comments on commit 46657ee

Please sign in to comment.