This repository was archived by the owner on May 1, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 307
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
47dfaf2
commit 333c7d0
Showing
11 changed files
with
470 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { Logger} from './logger/logger'; | ||
import { generateContext } from './util/config'; | ||
import * as Constants from './util/constants'; | ||
import { BuildContext, GeneratorOption, GeneratorRequest } from './util/interfaces'; | ||
|
||
export function generateNonTab(request: GeneratorRequest) { | ||
const context = generateContext(); | ||
return processNonTabRequest(context, request); | ||
} | ||
|
||
function processNonTabRequest(context: BuildContext, request: GeneratorRequest) { | ||
|
||
} | ||
|
||
export function listOptions() { | ||
const list: GeneratorOption[] = []; | ||
list.push({type: Constants.COMPONENT, multiple: false}); | ||
list.push({type: Constants.DIRECTIVE, multiple: false}); | ||
list.push({type: Constants.PAGE, multiple: false}); | ||
list.push({type: Constants.PIPE, multiple: false}); | ||
list.push({type: Constants.PROVIDER, multiple: false}); | ||
list.push({type: Constants.TABS, multiple: true}); | ||
} | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
export const CLASSNAME_VARIABLE = '$CLASSNAME'; | ||
export const FILENAME_VARIABLE = '$FILENAME'; | ||
|
||
export const KNOWN_FILE_EXTENSION = '.tmpl'; | ||
|
||
export const SPEC_FILE_EXTENSION = 'spec.ts'; | ||
export const NG_MODULE_FILE_EXTENSION = 'module.ts'; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,233 @@ | ||
import { basename, join } from 'path'; | ||
import * as fs from 'fs'; | ||
import * as Constants from '../util/constants'; | ||
import * as helpers from '../util/helpers'; | ||
import * as util from './util'; | ||
import * as GeneratorConstants from './constants'; | ||
|
||
describe('util', () => { | ||
describe('hydrateRequest', () => { | ||
it('should take a request and return a hydrated request', () => { | ||
// arrange | ||
const componentsDir = '/Users/dan/project/src/components'; | ||
const context = { | ||
componentsDir: componentsDir | ||
}; | ||
const request = { | ||
type: Constants.COMPONENT, | ||
name: 'settings view', | ||
includeSpec: true, | ||
includeNgModule: true | ||
}; | ||
|
||
const templateDir = '/Users/dan/project/node_modules/ionic-angular/templates'; | ||
spyOn(helpers, helpers.getPropertyValue.name).and.returnValue(templateDir); | ||
|
||
// act | ||
const hydratedRequest = util.hydrateRequest(context, request); | ||
|
||
// assert | ||
expect(hydratedRequest.type).toEqual(Constants.COMPONENT); | ||
expect(hydratedRequest.name).toEqual(request.name); | ||
expect(hydratedRequest.includeNgModule).toBeTruthy(); | ||
expect(hydratedRequest.includeSpec).toBeTruthy(); | ||
expect(hydratedRequest.className).toEqual('SettingsView'); | ||
expect(hydratedRequest.fileName).toEqual('settings-view'); | ||
expect(hydratedRequest.dirToRead).toEqual(join(templateDir, Constants.COMPONENT)); | ||
expect(hydratedRequest.dirToWrite).toEqual(join(componentsDir, hydratedRequest.fileName)); | ||
}); | ||
}); | ||
|
||
describe('readTemplates', () => { | ||
it('should get a map of templates and their content back', () => { | ||
// arrange | ||
const templateDir = '/Users/dan/project/node_modules/ionic-angular/templates/component'; | ||
const knownValues = ['html.tmpl', 'scss.tmpl', 'spec.ts.tmpl', 'ts.tmpl', 'module.tmpl']; | ||
const fileContent = 'SomeContent'; | ||
spyOn(fs, 'readdirSync').and.returnValue(knownValues); | ||
spyOn(helpers, helpers.readFileAsync.name).and.returnValue(Promise.resolve(fileContent)); | ||
|
||
// act | ||
const promise = util.readTemplates(templateDir); | ||
|
||
// assert | ||
return promise.then((map: Map<string, string>) => { | ||
expect(map.get(join(templateDir, knownValues[0]))).toEqual(fileContent); | ||
expect(map.get(join(templateDir, knownValues[1]))).toEqual(fileContent); | ||
expect(map.get(join(templateDir, knownValues[2]))).toEqual(fileContent); | ||
expect(map.get(join(templateDir, knownValues[3]))).toEqual(fileContent); | ||
expect(map.get(join(templateDir, knownValues[4]))).toEqual(fileContent); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('filterOutTemplates', () => { | ||
it('should preserve all templates', () => { | ||
const map = new Map<string, string>(); | ||
const templateDir = '/Users/dan/project/node_modules/ionic-angular/templates/component'; | ||
const fileContent = 'SomeContent'; | ||
const knownValues = ['html.tmpl', 'scss.tmpl', 'spec.ts.tmpl', 'ts.tmpl', 'module.tmpl']; | ||
map.set(join(templateDir, knownValues[0]), fileContent); | ||
map.set(join(templateDir, knownValues[1]), fileContent); | ||
map.set(join(templateDir, knownValues[2]), fileContent); | ||
map.set(join(templateDir, knownValues[3]), fileContent); | ||
map.set(join(templateDir, knownValues[4]), fileContent); | ||
|
||
const newMap = util.filterOutTemplates({includeNgModule: true, includeSpec: true}, map); | ||
expect(newMap.size).toEqual(knownValues.length); | ||
}); | ||
|
||
it('should remove spec', () => { | ||
const map = new Map<string, string>(); | ||
const templateDir = '/Users/dan/project/node_modules/ionic-angular/templates/component'; | ||
const fileContent = 'SomeContent'; | ||
const knownValues = ['html.tmpl', 'scss.tmpl', 'spec.ts.tmpl', 'ts.tmpl', 'module.tmpl']; | ||
map.set(join(templateDir, knownValues[0]), fileContent); | ||
map.set(join(templateDir, knownValues[1]), fileContent); | ||
map.set(join(templateDir, knownValues[2]), fileContent); | ||
map.set(join(templateDir, knownValues[3]), fileContent); | ||
map.set(join(templateDir, knownValues[4]), fileContent); | ||
|
||
const newMap = util.filterOutTemplates({includeNgModule: true, includeSpec: false}, map); | ||
expect(newMap.size).toEqual(4); | ||
expect(newMap.get(join(templateDir, knownValues[0]))).toBeTruthy(); | ||
expect(newMap.get(join(templateDir, knownValues[1]))).toBeTruthy(); | ||
expect(newMap.get(join(templateDir, knownValues[2]))).toBeFalsy(); | ||
expect(newMap.get(join(templateDir, knownValues[3]))).toBeTruthy(); | ||
expect(newMap.get(join(templateDir, knownValues[4]))).toBeTruthy(); | ||
}); | ||
|
||
it('should remove spec and module', () => { | ||
const map = new Map<string, string>(); | ||
const templateDir = '/Users/dan/project/node_modules/ionic-angular/templates/component'; | ||
const fileContent = 'SomeContent'; | ||
const knownValues = ['html.tmpl', 'scss.tmpl', 'spec.ts.tmpl', 'ts.tmpl', 'module.ts.tmpl']; | ||
map.set(join(templateDir, knownValues[0]), fileContent); | ||
map.set(join(templateDir, knownValues[1]), fileContent); | ||
map.set(join(templateDir, knownValues[2]), fileContent); | ||
map.set(join(templateDir, knownValues[3]), fileContent); | ||
map.set(join(templateDir, knownValues[4]), fileContent); | ||
|
||
const newMap = util.filterOutTemplates({includeNgModule: false, includeSpec: false}, map); | ||
expect(newMap.size).toEqual(3); | ||
expect(newMap.get(join(templateDir, knownValues[0]))).toBeTruthy(); | ||
expect(newMap.get(join(templateDir, knownValues[1]))).toBeTruthy(); | ||
expect(newMap.get(join(templateDir, knownValues[2]))).toBeFalsy(); | ||
expect(newMap.get(join(templateDir, knownValues[3]))).toBeTruthy(); | ||
expect(newMap.get(join(templateDir, knownValues[4]))).toBeFalsy(); | ||
}); | ||
}); | ||
|
||
describe('applyTemplates', () => { | ||
it('should replace the template content', () => { | ||
const fileOne = '/Users/dan/fileOne'; | ||
|
||
const fileOneContent = ` | ||
<!-- | ||
Generated template for the $CLASSNAME component. | ||
See https://angular.io/docs/ts/latest/api/core/index/ComponentMetadata-class.html | ||
for more info on Angular 2 Components. | ||
--> | ||
{{text}} | ||
`; | ||
|
||
const fileTwo = '/Users/dan/fileTwo'; | ||
const fileTwoContent = ` | ||
$FILENAME { | ||
} | ||
`; | ||
|
||
const fileThree = '/Users/dan/fileThree'; | ||
const fileThreeContent = ` | ||
describe('$CLASSNAME', () => { | ||
it('should do something', () => { | ||
expect(true).toEqual(true); | ||
}); | ||
}); | ||
`; | ||
|
||
const fileFour = '/Users/dan/fileFour'; | ||
const fileFourContent = ` | ||
import { Component } from '@angular/core'; | ||
/* | ||
Generated class for the $CLASSNAME component. | ||
See https://angular.io/docs/ts/latest/api/core/index/ComponentMetadata-class.html | ||
for more info on Angular 2 Components. | ||
*/ | ||
@Component({ | ||
selector: '$FILENAME', | ||
templateUrl: '$FILENAME.html' | ||
}) | ||
export class $CLASSNAMEComponent { | ||
text: string; | ||
constructor() { | ||
console.log('Hello $CLASSNAME Component'); | ||
this.text = 'Hello World'; | ||
} | ||
} | ||
`; | ||
|
||
const map = new Map<string, string>(); | ||
map.set(fileOne, fileOneContent); | ||
map.set(fileTwo, fileTwoContent); | ||
map.set(fileThree, fileThreeContent); | ||
map.set(fileFour, fileFourContent); | ||
|
||
const className = 'SettingsView'; | ||
const fileName = 'settings-view'; | ||
|
||
const results = util.applyTemplates({ 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); | ||
expect(modifiedContentOne.indexOf(GeneratorConstants.CLASSNAME_VARIABLE)).toEqual(-1); | ||
expect(modifiedContentOne.indexOf(GeneratorConstants.FILENAME_VARIABLE)).toEqual(-1); | ||
expect(modifiedContentTwo.indexOf(GeneratorConstants.CLASSNAME_VARIABLE)).toEqual(-1); | ||
expect(modifiedContentTwo.indexOf(GeneratorConstants.FILENAME_VARIABLE)).toEqual(-1); | ||
expect(modifiedContentThree.indexOf(GeneratorConstants.CLASSNAME_VARIABLE)).toEqual(-1); | ||
expect(modifiedContentThree.indexOf(GeneratorConstants.FILENAME_VARIABLE)).toEqual(-1); | ||
expect(modifiedContentFour.indexOf(GeneratorConstants.CLASSNAME_VARIABLE)).toEqual(-1); | ||
expect(modifiedContentFour.indexOf(GeneratorConstants.FILENAME_VARIABLE)).toEqual(-1); | ||
}); | ||
}); | ||
|
||
describe('writeGeneratedFiles', () => { | ||
it('should return the list of files generated', () => { | ||
const map = new Map<string, string>(); | ||
const templateDir = '/Users/dan/project/node_modules/ionic-angular/templates/component'; | ||
const fileContent = 'SomeContent'; | ||
const knownValues = ['html.tmpl', 'scss.tmpl', 'spec.ts.tmpl', 'ts.tmpl', 'module.tmpl']; | ||
const fileName = 'settings-view'; | ||
const dirToWrite = join('/Users/dan/project/src/components', fileName); | ||
map.set(join(templateDir, knownValues[0]), fileContent); | ||
map.set(join(templateDir, knownValues[1]), fileContent); | ||
map.set(join(templateDir, knownValues[2]), fileContent); | ||
map.set(join(templateDir, knownValues[3]), fileContent); | ||
map.set(join(templateDir, knownValues[4]), fileContent); | ||
|
||
spyOn(helpers, helpers.writeFileAsync.name).and.returnValue(Promise.resolve()); | ||
|
||
const promise = util.writeGeneratedFiles({ dirToWrite: dirToWrite, fileName: fileName }, map); | ||
|
||
return promise.then((filesCreated: string[]) => { | ||
const fileExtensions = knownValues.map(knownValue => basename(knownValue, GeneratorConstants.KNOWN_FILE_EXTENSION)); | ||
expect(filesCreated[0]).toEqual(join(dirToWrite, `${fileName}.${fileExtensions[0]}`)); | ||
expect(filesCreated[1]).toEqual(join(dirToWrite, `${fileName}.${fileExtensions[1]}`)); | ||
expect(filesCreated[2]).toEqual(join(dirToWrite, `${fileName}.${fileExtensions[2]}`)); | ||
expect(filesCreated[3]).toEqual(join(dirToWrite, `${fileName}.${fileExtensions[3]}`)); | ||
expect(filesCreated[4]).toEqual(join(dirToWrite, `${fileName}.${fileExtensions[4]}`)); | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import { basename, 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'; | ||
|
||
export function hydrateRequest(context: BuildContext, request: GeneratorRequest) { | ||
const hydrated = Object.assign({}, request) as HydratedGeneratorRequest; | ||
hydrated.className = pascalCase(request.name); | ||
hydrated.fileName = paramCase(request.name); | ||
|
||
hydrated.dirToRead = join(getPropertyValue(Constants.ENV_VAR_IONIC_ANGULAR_TEMPLATE_DIR), request.type); | ||
|
||
const baseDir = getDirToWriteToByType(context, request.type); | ||
hydrated.dirToWrite = join(baseDir, hydrated.fileName); | ||
|
||
return hydrated; | ||
} | ||
|
||
export function readTemplates(pathToRead: string): Promise<Map<string, string>> { | ||
const fileNames = readdirSync(pathToRead); | ||
const absolutePaths = fileNames.map(fileName => { | ||
return join(pathToRead, fileName); | ||
}); | ||
const filePathToContent = new Map<string, string>(); | ||
const promises = absolutePaths.map(absolutePath => { | ||
const promise = readFileAsync(absolutePath); | ||
promise.then((fileContent: string) => { | ||
filePathToContent.set(absolutePath, fileContent); | ||
}); | ||
}); | ||
return Promise.all(promises).then(() => { | ||
return filePathToContent; | ||
}); | ||
} | ||
|
||
export function filterOutTemplates(request: HydratedGeneratorRequest, templates: Map<string, string>) { | ||
const templatesToUseMap = new Map<string, string>(); | ||
templates.forEach((fileContent: string, filePath: string) => { | ||
const newFileExtension = basename(filePath, GeneratorConstants.KNOWN_FILE_EXTENSION); | ||
const shouldSkip = (!request.includeNgModule && newFileExtension === GeneratorConstants.NG_MODULE_FILE_EXTENSION) || (!request.includeSpec && newFileExtension === GeneratorConstants.SPEC_FILE_EXTENSION); | ||
if (!shouldSkip) { | ||
templatesToUseMap.set(filePath, fileContent); | ||
} | ||
}); | ||
return templatesToUseMap; | ||
} | ||
|
||
export function applyTemplates(request: HydratedGeneratorRequest, templates: Map<string, string>) { | ||
const appliedTemplateMap = new Map<string, string>(); | ||
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); | ||
}); | ||
return appliedTemplateMap; | ||
} | ||
|
||
export function writeGeneratedFiles(request: HydratedGeneratorRequest, processedTemplates: Map<string, string>): Promise<string[]> { | ||
const promises: Promise<any>[] = []; | ||
const createdFileList: string[] = []; | ||
processedTemplates.forEach((fileContent: string, filePath: string) => { | ||
const newFileExtension = basename(filePath, GeneratorConstants.KNOWN_FILE_EXTENSION); | ||
const newFileName = `${request.fileName}.${newFileExtension}`; | ||
const fileToWrite = join(request.dirToWrite, newFileName); | ||
createdFileList.push(fileToWrite); | ||
promises.push(writeFileAsync(fileToWrite, fileContent)); | ||
}); | ||
return Promise.all(promises).then(() => { | ||
return createdFileList; | ||
}); | ||
} | ||
|
||
export function getDirToWriteToByType(context: BuildContext, type: string) { | ||
if (type === Constants.COMPONENT) { | ||
return context.componentsDir; | ||
} else if ( type === Constants.DIRECTIVE) { | ||
return context.directivesDir; | ||
} else if (type === Constants.PAGE) { | ||
return context.pagesDir; | ||
} else if ( type === Constants.PIPE) { | ||
return context.pipesDir; | ||
} else if (type === Constants.PROVIDER) { | ||
return context.providersDir; | ||
} | ||
throw new Error(`Unknown Generator Type: ${type}`); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.