From ee488443e71badc6aa19e526e749ac798912fdbc Mon Sep 17 00:00:00 2001 From: Justin Schwartzenberger Date: Tue, 4 Jul 2017 09:54:17 -0700 Subject: [PATCH] feat(@schematics/angular): Add pipe schematic --- packages/schematics/angular/collection.json | 5 + .../__name@dasherize__.pipe.spec.ts | 8 ++ .../__name@dasherize__.pipe.ts | 12 +++ packages/schematics/angular/pipe/index.ts | 91 +++++++++++++++++++ packages/schematics/angular/pipe/schema.json | 47 ++++++++++ 5 files changed, 163 insertions(+) create mode 100644 packages/schematics/angular/pipe/files/__path__/__name@dasherize@if-flat__/__name@dasherize__.pipe.spec.ts create mode 100644 packages/schematics/angular/pipe/files/__path__/__name@dasherize@if-flat__/__name@dasherize__.pipe.ts create mode 100644 packages/schematics/angular/pipe/index.ts create mode 100644 packages/schematics/angular/pipe/schema.json diff --git a/packages/schematics/angular/collection.json b/packages/schematics/angular/collection.json index b880bb98e4..b66ca80d9b 100644 --- a/packages/schematics/angular/collection.json +++ b/packages/schematics/angular/collection.json @@ -30,6 +30,11 @@ "description": "Create an Angular module.", "schema": "./module/schema.json" }, + "pipe": { + "factory": "./pipe", + "description": "Create an Angular pipe.", + "schema": "./pipe/schema.json" + }, "service": { "factory": "./service", "description": "Create an Angular service.", diff --git a/packages/schematics/angular/pipe/files/__path__/__name@dasherize@if-flat__/__name@dasherize__.pipe.spec.ts b/packages/schematics/angular/pipe/files/__path__/__name@dasherize@if-flat__/__name@dasherize__.pipe.spec.ts new file mode 100644 index 0000000000..04bcd1dda3 --- /dev/null +++ b/packages/schematics/angular/pipe/files/__path__/__name@dasherize@if-flat__/__name@dasherize__.pipe.spec.ts @@ -0,0 +1,8 @@ +import { <%= classify(name) %>Pipe } from './<%= dasherize(name) %>.pipe'; + +describe('<%= classify(name) %>Pipe', () => { + it('create an instance', () => { + const pipe = new <%= classify(name) %>Pipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/packages/schematics/angular/pipe/files/__path__/__name@dasherize@if-flat__/__name@dasherize__.pipe.ts b/packages/schematics/angular/pipe/files/__path__/__name@dasherize@if-flat__/__name@dasherize__.pipe.ts new file mode 100644 index 0000000000..dfe487a73d --- /dev/null +++ b/packages/schematics/angular/pipe/files/__path__/__name@dasherize@if-flat__/__name@dasherize__.pipe.ts @@ -0,0 +1,12 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: '<%= camelize(name) %>' +}) +export class <%= classify(name) %>Pipe implements PipeTransform { + + transform(value: any, args?: any): any { + return null; + } + +} diff --git a/packages/schematics/angular/pipe/index.ts b/packages/schematics/angular/pipe/index.ts new file mode 100644 index 0000000000..bfa86c6671 --- /dev/null +++ b/packages/schematics/angular/pipe/index.ts @@ -0,0 +1,91 @@ +/** + * @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 + */ +// TODO: replace `options: any` with an actual type generated from the schema. +// tslint:disable:no-any +import {addDeclarationToModule} from '../utility/ast-utils'; +import {InsertChange} from '../utility/change'; + +import { + Rule, + Tree, + apply, + branchAndMerge, + chain, + filter, + mergeWith, + move, + noop, + template, + url, +} from '@angular-devkit/schematics'; +import * as stringUtils from '../strings'; + +import 'rxjs/add/operator/merge'; +import * as ts from 'typescript'; +import {buildRelativePath, findModule} from '../utility/find-module'; + + +function addDeclarationToNgModule(options: any): Rule { + return (host: Tree) => { + if (options.skipImport) { + return host; + } + + let modulePath; + if (options.module) { + if (!host.exists(options.module)) { + throw new Error(`Module specified (${options.module}) does not exist.`); + } + modulePath = options.module; + } else { + modulePath = findModule(host, options.sourceDir + '/' + options.path); + } + + const sourceText = host.read(modulePath) !.toString('utf-8'); + const source = ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true); + + const pipePath = `/${options.sourceDir}/${options.path}/` + + (options.flat ? '' : stringUtils.dasherize(options.name) + '/') + + stringUtils.dasherize(options.name) + + '.pipe'; + const relativePath = buildRelativePath(modulePath, pipePath); + const changes = addDeclarationToModule(source, modulePath, + stringUtils.classify(`${options.name}Pipe`), + relativePath); + const recorder = host.beginUpdate(modulePath); + for (const change of changes) { + if (change instanceof InsertChange) { + recorder.insertLeft(change.pos, change.toAdd); + } + } + host.commitUpdate(recorder); + + return host; + }; +} + +export default function (options: any): Rule { + + const templateSource = apply(url('./files'), [ + options.spec ? noop() : filter(path => !path.endsWith('.spec.ts')), + template({ + ...stringUtils, + 'if-flat': (s: string) => options.flat ? '' : s, + ...options, + }), + move(options.sourceDir), + ]); + + return chain([ + branchAndMerge(chain([ + filter(path => path.endsWith('.module.ts') && !path.endsWith('-routing.module.ts')), + addDeclarationToNgModule(options), + mergeWith(templateSource), + ])), + ]); +} diff --git a/packages/schematics/angular/pipe/schema.json b/packages/schematics/angular/pipe/schema.json new file mode 100644 index 0000000000..b0950b54cb --- /dev/null +++ b/packages/schematics/angular/pipe/schema.json @@ -0,0 +1,47 @@ +{ + "$schema": "http://json-schema.org/schema", + "id": "SchematicsAngularPipe", + "title": "Angular Pipe Options Schema", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "path": { + "type": "string", + "default": "app" + }, + "sourceDir": { + "type": "string", + "default": "src" + }, + "flat": { + "type": "boolean", + "default": false, + "description": "Flag to indicate if a dir is created." + }, + "spec": { + "type": "boolean", + "default": true, + "description": "Specifies if a spec file is generated." + }, + "skipImport": { + "type": "boolean", + "default": false, + "description": "Allows for skipping the module import." + }, + "module": { + "type": "string", + "default": "", + "description": "Allows specification of the declaring module." + }, + "export": { + "type": "boolean", + "default": false, + "description": "Specifies if declaring module exports the pipe." + } + }, + "required": [ + "name" + ] +}