refactor(generators): make them more oo

This commit is contained in:
Tim Lancina
2016-01-07 14:09:06 -06:00
parent 0d695546e5
commit a11b880ca3
6 changed files with 125 additions and 220 deletions

View File

@ -581,3 +581,13 @@ function buildDemoBundle(opts, done) {
}); });
} }
gulp.task('tooling', function(){
gulp.src('*tooling/**/*')
.pipe(gulp.dest('dist'));
watch('tooling/**/*', function(){
gulp.src('*tooling/**/*')
.pipe(gulp.dest('dist'));
})
})

View File

@ -1,11 +1,8 @@
var _ = require('lodash'), var fs = require('fs'),
fs = require('fs'),
inquirer = require('inquirer'),
path = require('path'), path = require('path'),
shell = require('shelljs'), inquirer = require('inquirer');
Generate = module.exports;
Generate._generators; Generate = module.exports;
Generate.__defineGetter__('generators', function() { Generate.__defineGetter__('generators', function() {
if (!Generate._generators) { if (!Generate._generators) {
@ -15,208 +12,50 @@ Generate.__defineGetter__('generators', function() {
return Generate._generators; return Generate._generators;
}); });
Generate.log = function log() {
console.log('DEBUG'.red, arguments);
};
// options: appDirectory, generator, name
Generate.generate = function generate(options) { Generate.generate = function generate(options) {
Generate.inquirer = inquirer;
// Generate.log('Generate options', options);
if (!options) { if (!options) {
throw new Error('No options passed to generator'); throw new Error('No options passed to generator');
} }
//add optional logger for CLI or other tools
if (options.log) {
Generate.log = options.log;
}
if (options.generator && !Generate.generators[options.generator]) {
throw new Error('There is no generator available with that name: ' + options.generator + '.');
}
if (!options.generator) { if (!options.generator) {
options.generator = 'page'; throw new Error('No generator passed to generate');
} }
var generateOptions = { var GeneratorType = Generate.loadGenerator(options.generator);
appDirectory: options.appDirectory, return new GeneratorType(options).run();
cssClassName: Generate.cssClassName(options.name),
fileName: Generate.fileName(options.name),
jsClassName: Generate.jsClassName(options.name),
name: options.name,
template: options.generator
};
try {
//Try to run the generator if it supplies a run method.
var generator = Generate.generators[options.generator];
if (generator && generator.run) {
return Generate.generators[options.generator].run(generateOptions);
} else {
return Generate.defaultTemplates(generateOptions);
}
} catch (ex) {
console.log('Error with generation:', ex);
console.log(ex.stack);
}
}; };
Generate.defaultTemplates = function defaultTemplates(options) {
var template = options.template ? options.template : 'page';
options.rootDirectory = options.rootDirectory || path.join('app'); Generate.loadGenerator = function loadGenerator(generator) {
var savePath = path.join(options.appDirectory, options.rootDirectory, options.fileName);
var templates = Generate.loadGeneratorTemplates(path.join(__dirname, 'generators', options.template));
templates.forEach(function(template) {
var templatePath = template.file;
options.templatePath = templatePath;
var renderedTemplate = Generate.renderTemplateFromFile(options);
var saveFilePath = path.join(savePath, [options.fileName, template.type].join(''));
// console.log('renderedTemplate', renderedTemplate, 'saving to', saveFilePath);
console.log('√ Create'.blue, path.relative(options.appDirectory, saveFilePath));
fs.writeFileSync(saveFilePath, renderedTemplate);
});
}
Generate.loadGeneratorTemplates = function loadGeneratorTemplates(generatorPath) {
var templates = [];
fs.readdirSync(generatorPath)
.forEach(function(template) {
var type;
// Go through all the files in the folder, grab the templates, read in the file contents
// return as template type, contents
if (template.indexOf('.tmpl') == -1) {
return;
}
templates.push({file: path.join(generatorPath, template), type: path.extname(template)});
});
return templates;
};
Generate.loadGenerator = function loadGenerator(file) {
var generatorPath = path.join(__dirname, 'generators', file);
var generateModule; var generateModule;
try { try {
generateModule = require(generatorPath); generateModule = require(path.join(__dirname, 'generators', generator));
} catch (ex) { } catch (err) {
Generate.log('Error loading generator module', ex); if (err.code === 'MODULE_NOT_FOUND') {
Generate.log(ex.stack); throw new Error('There is no generator available with the name ' + generator + '.');
} else {
throw err;
}
} }
return generateModule; return generateModule;
}; };
/*
Return array of filenames in the generators directory
*/
Generate.loadGenerators = function loadGenerators() { Generate.loadGenerators = function loadGenerators() {
var generators = {}; var generators = {};
fs.readdirSync(path.join(__dirname, 'generators')) try {
.forEach(function (file) { generators = fs.readdirSync(path.join(__dirname, 'generators'));
if (file.indexOf('.') !== -1) { } catch(err) {
return; throw new Error('There was an error loading the generators list', err);
} }
var generatorName = file.replace('.js', '');
var generator = Generate.loadGenerator(generatorName);
generators[generatorName] = generator;
});
return generators; return generators;
}; };
/* Generate.printAvailableGenerators = function printAvailableGenerators() {
Will take options to render an html, js, or scss template. console.log('Available generators:'.blue);
options: Generate.generators.forEach(function(generator){
they differ based on what is needed in template console.log(' *'.blue, generator);
For JavaScript file: filename, jsClassName
For HTML file: name, nameUppercased
templatePath: the path of the template to render (html/js/scss), ex: '/path/to/page.tmpl.html'
*/
Generate.renderTemplateFromFile = function renderTemplateFromFile(options) {
var templateContents = fs.readFileSync(options.templatePath, 'utf8');
var templateCompiler = _.template(templateContents);
var result = templateCompiler(options);
return result;
};
// Tabs - name = name of the page with the tabs,
// tabs = array of the tabs to create.
// Generate.tabPages = function tabPages(appDirectory, name, tabs) {
// Generate.createScaffoldDirectories(appDirectory, 'tabs', name);
//
// // Generate page with tabs:
// var tabsfileName = Generate.fileName(name);
//
// var tabsHtml = Generate.generateTabsHtmlTemplate(appDirectory, name, tabs);
// var tabsJs = Generate.generateTabsJsTemplate(appDirectory, name, tabs);
// // var tabsScss = Generate.generateTabsScssTemplate(appDirectory, name, tabs);
// var pagePath = path.join(appDirectory, 'app', tabsfileName),
// jsPath = path.join(pagePath, [tabsfileName, '.js'].join('')),
// htmlPath = path.join(pagePath, [tabsfileName, '.html'].join(''));
// // scssPath = path.join(pagePath, [tabsfileName, '.scss'].join(''));
//
// tabs.forEach(function(tab) {
// Generate.createScaffoldDirectories(appDirectory, 'tabs', tab);
// var tabJs = Generate.generateJsTemplate(appDirectory, tab);
// var tabHtml = Generate.generateHtmlTemplate(appDirectory, tab);
//
// })
// };
Generate.generateTabJsTemplate = function generateTabJsTemplate(appDirectory, name) {
throw new Error('not implemented');
};
Generate.generateTabsJsTemplate = function generateTabsJsTemplate(appDirectory, name, tabs) {
// import {NavController, Page} from 'ionic/ionic';
// <% _.forEach(tabs, function(tab) { %>
// import {<%= tab.jsClassName %>} from '../<%= tab.filename %>/<%= tab.filename %>';
// <% }); %>
// @Page({
// templateUrl: 'app/<%= filename %>/<%= filename %>.html',
// providers: [DataService]
// })
// class <%= jsClassName %> {
// constructor(nav: NavController) {
// // set the root pages for each tab
// <% _.forEach(tabs, function(tab) { %>
// this.{<%= tab.jsClassName %>} = <%= tab.jsClassName %>;
// <% }); %>
// }
// }
var fileName = Generate.fileName(name);
var jsClassName = Generate.jsClassName(name);
var tabsData = [];
tabs.forEach(function(tab) {
var tabObj = { name: tab, filename: Generate.fileName(tab), jsClassName: Generate.jsClassName(tab)};
tabsData.push(tabObj);
}); });
var tabsHtmlTemplatePath = path.join(__dirname, 'tabs.tmpl.js');
return Generate.renderTemplateFromFile({tabs: tabsData, templatePath: tabsHtmlTemplatePath, filename: fileName, jsClassName: jsClassName });
};
Generate.createScaffoldDirectories = function createScaffoldDirectories(options) {
console.log('createScaffoldDirectories', options);
// Generate.log('Create', options.appDirectory, options.fileName);
var componentPath = path.join(options.appDirectory, 'app', options.componentDirectory, options.fileName);
shell.mkdir('-p', componentPath);
};
Generate.fileName = function fileName(name) {
return name.replace(/([a-z])([A-Z])/g, '$1-$2').replace('_', '-').toLowerCase();
};
Generate.cssClassName = function cssClassName(name) {
return Generate.fileName(name);
} }
Generate.capitalizeName = function capitalizeName(name) {
return name.charAt(0).toUpperCase() + name.slice(1);
};
Generate.jsClassName = function jsClassName(name) {
return _.capitalize(_.camelCase(name));
};

67
tooling/generator.js Normal file
View File

@ -0,0 +1,67 @@
var _ = require('lodash'),
fs = require('fs'),
path = require('path'),
shell = require('shelljs');
module.exports = Generator;
function Generator(options) {
this.name = options.name;
this.type = options.generator;
this.appDirectory = options.appDirectory;
}
Generator.prototype.run = function(){
this.makeDirectories();
this.renderTemplates();
}
Generator.prototype.makeDirectories = function(){
if (!this.directory) {
throw new Error('Generators must define their directory in their constructor');
}
shell.mkdir('-p', path.join(this.appDirectory, this.directory, this.name));
}
Generator.prototype.renderTemplates = function renderTemplates() {
var templates = this.loadTemplates();
templates.forEach(function(template) {
var renderedTemplate = this.renderTemplate(template);
var renderedTemplateDest = path.join(this.appDirectory, this.directory, this.name, this.name + template.extension);
console.log('√ Create'.blue, path.relative(this.appDirectory, renderedTemplateDest));
fs.writeFileSync(renderedTemplateDest, renderedTemplate);
}, this);
}
Generator.prototype.loadTemplates = function() {
var generatorPath = path.join(__dirname, 'generators', this.type);
var templates = [];
fs.readdirSync(generatorPath)
.forEach(function(template) {
var type;
// Go through all the files in the folder, grab the templates, read in the file contents
// return as template type, contents
if (template.indexOf('.tmpl') == -1) {
return;
}
templates.push({path: path.join(generatorPath, template), extension: path.extname(template)});
}, this);
return templates;
};
Generator.prototype.renderTemplate = function(template) {
var templateVars = {
fileName: _.kebabCase(this.name),
directory: this.directory,
cssClassName: _.kebabCase(this.name),
jsClassName: _.capitalize(_.camelCase(this.name))
}
var templateContents = fs.readFileSync(template.path, 'utf8');
var templateCompiler = _.template(templateContents);
var result = templateCompiler(templateVars);
return result;
};

View File

@ -1,3 +1,9 @@
<div *ng-if="value"> <!--
<%= jsClassName %> Generated template for <%= jsClassName %>.
See https://angular.io/docs/ts/latest/api/core/ComponentMetadata-class.html
for more info on Components.
-->
<div>
{{text}}
</div> </div>

View File

@ -1,14 +1,13 @@
import {Component, NgIf} from 'angular2/angular2'; import {Component} from 'angular2/core';
import {NavController} from 'ionic/ionic'; import {IONIC_DIRECTIVES} from 'ionic/ionic';
@Component({ @Component({
directives: [NgIf],
properties: ['value'], //Change to be whatever properties you want, ex: <<%= fileName %> value="5">
selector: '<%= fileName %>', selector: '<%= fileName %>',
templateUrl: 'app/<%= fileName %>/<%= fileName %>.html' templateUrl: '<%= directory %>/<%= fileName %>/<%= fileName %>.html',
directives: [IONIC_DIRECTIVES] // makes all Ionic directives available to your component
}) })
export class <%= jsClassName %> { export class <%= jsClassName %> {
constructor(nav: NavController) { constructor() {
this.nav = nav; this.text = 'Hello World, I\'m <%= jsClassName %>';
} }
} }

View File

@ -1,28 +1,12 @@
var fs = require('fs'),
Generator = module.exports,
Generate = require('../../generate'),
path = require('path'),
Q = require('q');
/*
@options
name: Page name
appDirectory: App directory of where to save file
*/
Generator.run = function run(options) {
Generate.createScaffoldDirectories({appDirectory: options.appDirectory, componentDirectory: 'components', fileName: options.fileName});
options.rootDirectory = options.rootDirectory || path.join('app', 'components'); var path = require('path'),
Generator = require('../../generator');
var savePath = path.join(options.appDirectory, options.rootDirectory, options.fileName); module.exports = ComponentGenerator;
var templates = Generate.loadGeneratorTemplates(__dirname); function ComponentGenerator(options) {
Generator.call(this, options);
this.directory = path.join('app', 'components');
}
templates.forEach(function(template) { ComponentGenerator.prototype = Object.create(Generator.prototype);
options.templatePath = template.file;
var renderedTemplate = Generate.renderTemplateFromFile(options);
var saveFilePath = path.join(savePath, [options.fileName, template.type].join(''));
// console.log('renderedTemplate', renderedTemplate, 'saving to', saveFilePath);
console.log('√ Create'.blue, path.relative(options.appDirectory, saveFilePath));
fs.writeFileSync(saveFilePath, renderedTemplate);
});
};