From e2a45e4c9033390d89c3b3c9948851517dd83e34 Mon Sep 17 00:00:00 2001 From: Dan Bucholtz Date: Mon, 20 Feb 2017 00:40:57 -0600 Subject: [PATCH] feat(generators): generators for page, component, directive, pipe, provider generators for page, component, directive, pipe, provider --- src/generators.ts | 22 ++++++++++++-- src/generators/constants.ts | 1 + src/generators/util.spec.ts | 60 ++++++++++++++++++++++++++++++++++++- src/generators/util.ts | 38 +++++++++++++++++++---- src/index.ts | 2 ++ src/util/helpers.ts | 13 +++++++- src/util/interfaces.ts | 19 ------------ 7 files changed, 126 insertions(+), 29 deletions(-) diff --git a/src/generators.ts b/src/generators.ts index dadc0567..4415a880 100644 --- a/src/generators.ts +++ b/src/generators.ts @@ -1,15 +1,30 @@ import { Logger} from './logger/logger'; import { generateContext } from './util/config'; import * as Constants from './util/constants'; -import { BuildContext, GeneratorOption, GeneratorRequest } from './util/interfaces'; +import { BuildContext } from './util/interfaces'; +import { applyTemplates, filterOutTemplates, GeneratorOption, GeneratorRequest, hydrateRequest, readTemplates, writeGeneratedFiles } from './generators/util'; + +export { GeneratorOption }; +export { GeneratorRequest }; export function generateNonTab(request: GeneratorRequest) { const context = generateContext(); return processNonTabRequest(context, request); } -function processNonTabRequest(context: BuildContext, request: GeneratorRequest) { - +function processNonTabRequest(context: BuildContext, request: GeneratorRequest): Promise { + Logger.debug('[Generators] processNonTabRequest: Hydrating the request with project data ...'); + const hydratedRequest = hydrateRequest(context, request); + Logger.debug('[Generators] processNonTabRequest: Reading templates ...'); + return readTemplates(hydratedRequest.dirToRead).then((map: Map) => { + Logger.debug('[Generators] processNonTabRequest: Filtering out NgModule and Specs if needed ...'); + return filterOutTemplates(hydratedRequest, map); + }).then((filteredMap: Map) => { + Logger.debug('[Generators] processNonTabRequest: Applying tempaltes ...'); + const appliedTemplateMap = applyTemplates(hydratedRequest, filteredMap); + Logger.debug('[Generators] processNonTabRequest: Writing generated files to disk ...'); + return writeGeneratedFiles(hydratedRequest, appliedTemplateMap); + }); } export function listOptions() { @@ -20,6 +35,7 @@ export function listOptions() { list.push({type: Constants.PIPE, multiple: false}); list.push({type: Constants.PROVIDER, multiple: false}); list.push({type: Constants.TABS, multiple: true}); + return list; } diff --git a/src/generators/constants.ts b/src/generators/constants.ts index 2fc854c1..36c369ec 100644 --- a/src/generators/constants.ts +++ b/src/generators/constants.ts @@ -1,5 +1,6 @@ export const CLASSNAME_VARIABLE = '$CLASSNAME'; export const FILENAME_VARIABLE = '$FILENAME'; +export const SUPPLIEDNAME_VARIABLE = '$SUPPLIEDNAME'; export const KNOWN_FILE_EXTENSION = '.tmpl'; diff --git a/src/generators/util.spec.ts b/src/generators/util.spec.ts index 145dcd06..f73815e4 100644 --- a/src/generators/util.spec.ts +++ b/src/generators/util.spec.ts @@ -177,28 +177,86 @@ export class $CLASSNAMEComponent { `; + const fileFive = '/Users/dan/fileFive'; + const fileFiveContent = ` +import { NgModule } from '@angular/core'; +import { $CLASSNAME } from './$FILENAME'; +import { IonicModule } from 'ionic-angular'; + +@NgModule({ + declarations: [ + $CLASSNAME, + ], + imports: [ + IonicModule.forChild($CLASSNAME) + ], + entryComponents: [ + $CLASSNAME + ], + providers: [] +}) +export class $CLASSNAMEModule {} + `; + + const fileSix = '/Users/dan/fileSix'; + const fileSixContent = ` + + + + + $SUPPLIEDNAME + + + + + + + + + `; + const map = new Map(); map.set(fileOne, fileOneContent); map.set(fileTwo, fileTwoContent); map.set(fileThree, fileThreeContent); map.set(fileFour, fileFourContent); + map.set(fileFive, fileFiveContent); + map.set(fileSix, fileSixContent); const className = 'SettingsView'; const fileName = 'settings-view'; + const suppliedName = 'settings view'; - const results = util.applyTemplates({ className: className, fileName: fileName}, map); + const results = util.applyTemplates({ name: suppliedName, className: className, fileName: fileName}, map); const modifiedContentOne = results.get(fileOne); const modifiedContentTwo = results.get(fileTwo); const modifiedContentThree = results.get(fileThree); const modifiedContentFour = results.get(fileFour); + const modifiedContentFive = results.get(fileFive); + const modifiedContentSix = results.get(fileSix); expect(modifiedContentOne.indexOf(GeneratorConstants.CLASSNAME_VARIABLE)).toEqual(-1); expect(modifiedContentOne.indexOf(GeneratorConstants.FILENAME_VARIABLE)).toEqual(-1); + expect(modifiedContentOne.indexOf(GeneratorConstants.SUPPLIEDNAME_VARIABLE)).toEqual(-1); expect(modifiedContentTwo.indexOf(GeneratorConstants.CLASSNAME_VARIABLE)).toEqual(-1); expect(modifiedContentTwo.indexOf(GeneratorConstants.FILENAME_VARIABLE)).toEqual(-1); + expect(modifiedContentTwo.indexOf(GeneratorConstants.SUPPLIEDNAME_VARIABLE)).toEqual(-1); expect(modifiedContentThree.indexOf(GeneratorConstants.CLASSNAME_VARIABLE)).toEqual(-1); expect(modifiedContentThree.indexOf(GeneratorConstants.FILENAME_VARIABLE)).toEqual(-1); + expect(modifiedContentThree.indexOf(GeneratorConstants.SUPPLIEDNAME_VARIABLE)).toEqual(-1); expect(modifiedContentFour.indexOf(GeneratorConstants.CLASSNAME_VARIABLE)).toEqual(-1); expect(modifiedContentFour.indexOf(GeneratorConstants.FILENAME_VARIABLE)).toEqual(-1); + expect(modifiedContentFour.indexOf(GeneratorConstants.SUPPLIEDNAME_VARIABLE)).toEqual(-1); + expect(modifiedContentFive.indexOf(GeneratorConstants.CLASSNAME_VARIABLE)).toEqual(-1); + expect(modifiedContentFive.indexOf(GeneratorConstants.FILENAME_VARIABLE)).toEqual(-1); + expect(modifiedContentFive.indexOf(GeneratorConstants.SUPPLIEDNAME_VARIABLE)).toEqual(-1); + expect(modifiedContentSix.indexOf(GeneratorConstants.CLASSNAME_VARIABLE)).toEqual(-1); + expect(modifiedContentSix.indexOf(GeneratorConstants.FILENAME_VARIABLE)).toEqual(-1); + expect(modifiedContentSix.indexOf(GeneratorConstants.SUPPLIEDNAME_VARIABLE)).toEqual(-1); }); }); diff --git a/src/generators/util.ts b/src/generators/util.ts index 63c427ad..47edb2db 100644 --- a/src/generators/util.ts +++ b/src/generators/util.ts @@ -1,12 +1,12 @@ -import { basename, join } from 'path'; +import { basename, dirname, join } from 'path'; import { readdirSync} from 'fs'; import { paramCase, pascalCase } from 'change-case'; import * as Constants from '../util/constants'; import * as GeneratorConstants from './constants'; -import { getPropertyValue, readFileAsync, replaceAll, writeFileAsync } from '../util/helpers'; -import { BuildContext, GeneratorRequest, HydratedGeneratorRequest } from '../util/interfaces'; +import { getPropertyValue, mkDirpAsync, readFileAsync, replaceAll, writeFileAsync } from '../util/helpers'; +import { BuildContext } from '../util/interfaces'; export function hydrateRequest(context: BuildContext, request: GeneratorRequest) { const hydrated = Object.assign({}, request) as HydratedGeneratorRequest; @@ -32,6 +32,7 @@ export function readTemplates(pathToRead: string): Promise> promise.then((fileContent: string) => { filePathToContent.set(absolutePath, fileContent); }); + return promise; }); return Promise.all(promises).then(() => { return filePathToContent; @@ -55,7 +56,8 @@ export function applyTemplates(request: HydratedGeneratorRequest, templates: Map templates.forEach((fileContent: string, filePath: string) => { const classnameRemovedContent = replaceAll(fileContent, GeneratorConstants.CLASSNAME_VARIABLE, request.className); const fileNameRemovedContent = replaceAll(classnameRemovedContent, GeneratorConstants.FILENAME_VARIABLE, request.fileName); - appliedTemplateMap.set(filePath, fileNameRemovedContent); + const suppliedNameRemovedContent = replaceAll(fileNameRemovedContent, GeneratorConstants.SUPPLIEDNAME_VARIABLE, request.name); + appliedTemplateMap.set(filePath, suppliedNameRemovedContent); }); return appliedTemplateMap; } @@ -68,13 +70,20 @@ export function writeGeneratedFiles(request: HydratedGeneratorRequest, processed const newFileName = `${request.fileName}.${newFileExtension}`; const fileToWrite = join(request.dirToWrite, newFileName); createdFileList.push(fileToWrite); - promises.push(writeFileAsync(fileToWrite, fileContent)); + promises.push(createDirAndWriteFile(fileToWrite, fileContent)); }); return Promise.all(promises).then(() => { return createdFileList; }); } +function createDirAndWriteFile(filePath: string, fileContent: string) { + const directory = dirname(filePath); + return mkDirpAsync(directory).then(() => { + return writeFileAsync(filePath, fileContent); + }); +} + export function getDirToWriteToByType(context: BuildContext, type: string) { if (type === Constants.COMPONENT) { return context.componentsDir; @@ -89,3 +98,22 @@ export function getDirToWriteToByType(context: BuildContext, type: string) { } throw new Error(`Unknown Generator Type: ${type}`); } + +export interface GeneratorOption { + type: string; + multiple: boolean; +}; + +export interface GeneratorRequest { + type?: string; + name?: string; + includeSpec?: boolean; + includeNgModule?: boolean; +}; + +export interface HydratedGeneratorRequest extends GeneratorRequest { + fileName?: string; + className?: string; + dirToRead?: string; + dirToWrite?: string; +}; diff --git a/src/index.ts b/src/index.ts index e88a6101..47cb00cc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,6 +15,8 @@ export * from './util/config'; export * from './util/helpers'; export * from './util/interfaces'; +export * from './generators'; + import { generateContext } from './util/config'; import { getAppScriptsVersion } from './util/helpers'; import { Logger } from './logger/logger'; diff --git a/src/util/helpers.ts b/src/util/helpers.ts index e32b3603..605690f4 100644 --- a/src/util/helpers.ts +++ b/src/util/helpers.ts @@ -1,6 +1,6 @@ import { randomBytes } from 'crypto'; import { basename, dirname, extname, join } from 'path'; -import { createReadStream, createWriteStream, readdir, readFile, readFileSync, readJsonSync, remove, unlink, writeFile } from 'fs-extra'; +import { createReadStream, createWriteStream, ensureDir, readdir, readFile, readFileSync, readJsonSync, remove, unlink, writeFile } from 'fs-extra'; import * as osName from 'os-name'; import * as Constants from './constants'; @@ -184,6 +184,17 @@ export function copyFileAsync(srcPath: string, destPath: string) { }); } +export function mkDirpAsync(directoryPath: string) { + return new Promise((resolve, reject) => { + ensureDir(directoryPath, (err: Error) => { + if (err) { + return reject(err); + } + return resolve(); + }); + }); +} + export function readDirAsync(pathToDir: string) { return new Promise((resolve, reject) => { readdir(pathToDir, (err: Error, fileNames: string[]) => { diff --git a/src/util/interfaces.ts b/src/util/interfaces.ts index 75fafb61..e0a16cf2 100644 --- a/src/util/interfaces.ts +++ b/src/util/interfaces.ts @@ -189,22 +189,3 @@ export interface WebpackModule { export interface WebpackDependency { moduleIdentifier: string; }; - -export interface GeneratorOption { - type: string; - multiple: boolean; -}; - -export interface GeneratorRequest { - type?: string; - name?: string; - includeSpec?: boolean; - includeNgModule?: boolean; -}; - -export interface HydratedGeneratorRequest extends GeneratorRequest { - fileName?: string; - className?: string; - dirToRead?: string; - dirToWrite?: string; -};