diff --git a/index.js b/index.js new file mode 100644 index 0000000000..4e52b93f40 --- /dev/null +++ b/index.js @@ -0,0 +1,3 @@ +module.exports = { + generate: require('./tooling/generate') +}; diff --git a/package.json b/package.json index 4ca03dd74f..98da731c23 100644 --- a/package.json +++ b/package.json @@ -6,13 +6,16 @@ "type": "git", "url": "https://github.com/driftyco/ionic2.git" }, + "main": "index.js", "scripts": { "test": "gulp karma", + "test:generators": "jasmine-node ./tooling/spec", "link": "npm install && gulp src && npm link" }, "dependencies": { "angular2": "2.0.0-alpha.44", "es6-shim": "^0.33.6", + "lodash": "^3.10.1", "@reactivex/rxjs": "5.0.0-alpha.4", "reflect-metadata": "0.1.1", "zone.js": "0.5.8" @@ -47,7 +50,6 @@ "karma-chrome-launcher": "^0.1.7", "karma-jasmine": "^0.3.5", "lazypipe": "^0.2.3", - "lodash": "^2.4.1", "lunr": "^0.5.12", "minimist": "^1.1.3", "mkdirp": "^0.5.1", diff --git a/tooling/generate.js b/tooling/generate.js new file mode 100644 index 0000000000..2a2115c4d1 --- /dev/null +++ b/tooling/generate.js @@ -0,0 +1,229 @@ +var _ = require('lodash'), + fs = require('fs'), + // logging = require('../logging'), + path = require('path'), + shell = require('shelljs'), + Generate = module.exports; + +Generate._generators; + +Generate.__defineGetter__('generators', function() { + if (!Generate._generators) { + Generate._generators = Generate.loadGenerators(); + } + + return Generate._generators; +}); + +// options: appDirectory, generatorName, name +Generate.generate = function generate(options) { + // console.log('Generate options', options); + if (!options) { + throw new Error('No options passed to generator'); + } + // var generatorPath = path.join(__dirname, 'generators'); + if (!options.generatorName) { + options.generatorName = 'page'; + } + + var generateOptions = { + appDirectory: options.appDirectory, + fileAndClassName: Generate.fileAndClassName(options.name), + javascriptClassName: Generate.javascriptClassName(options.name), + name: options.name + }; + + Generate.createScaffoldDirectories({appDirectory: options.appDirectory, fileAndClassName: generateOptions.fileAndClassName}); + + return Generate.generators[options.generatorName].run(generateOptions); +}; + +Generate.loadGeneratorTemplates = function loadGeneratorTemplates(generatorPath) { + // var generatorPath = path.join(__dirname, 'generators', generatorName); + 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: template, type: path.extname(template)}); + }); + + return templates; +}; + +Generate.loadGenerator = function loadGenerator(file) { + var generatorPath = path.join(__dirname, 'generators', file); + var generateModule; + try { + generateModule = require(generatorPath); + } catch (ex) { + console.log('Error loading generator module', ex); + } + return generateModule;//page +}; + +Generate.loadGenerators = function loadGenerators() { + var generators = {}; + fs.readdirSync(path.join(__dirname, 'generators')) + .forEach(function (file) { + var generatorName = file.replace('.js', ''); + generators[generatorName] = Generate.loadGenerator(generatorName); + }); + return generators; +}; + +/* + Will take options to render an html, js, or scss template. + options: + they differ based on what is needed in template + For JavaScript file: filename, javascriptClassName + 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; +}; + +/* + Will take options to render the basic page javascript template + the name of the component/page being rendered, ex: 'IonicTest' +*/ +Generate.generateJsTemplate = function generateJsTemplate(name) { + var jsTemplatePath = path.join(__dirname, 'page.tmpl.js'); + var options = { javascriptClassName: Generate.javascriptClassName(name), filename: Generate.fileAndClassName(name), templatePath: jsTemplatePath}; + return Generate.renderTemplateFromFile(options); +}; + +/* + Will take options to render the basic page html template + the name of the component/page being rendered, ex: 'IonicTest' +*/ +Generate.generateHtmlTemplate = function generateHtmlTemplate(name) { + var htmlTemplatePath = path.join(__dirname, 'page.tmpl.html'); + return Generate.renderTemplateFromFile({ name: Generate.fileAndClassName(name), capitalizedName: Generate.capitalizeName(name) ,templatePath: htmlTemplatePath}); +}; + +Generate.generateScssTemplate = function generateScssTemplate(name) { + var scssTemplatePath = path.join(__dirname, 'page.tmpl.scss'); + return Generate.renderTemplateFromFile({ name: Generate.fileAndClassName(name), templatePath: scssTemplatePath}); +}; + +// 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, name); + + // Generate page with tabs: + var tabsFileAndClassName = Generate.fileAndClassName(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, 'www', 'app', tabsFileAndClassName), + jsPath = path.join(pagePath, [tabsFileAndClassName, '.js'].join('')), + htmlPath = path.join(pagePath, [tabsFileAndClassName, '.html'].join('')); + // scssPath = path.join(pagePath, [tabsFileAndClassName, '.scss'].join('')); + + tabs.forEach(function(tab) { + Generate.createScaffoldDirectories(appDirectory, tab); + var tabJs = Generate.generateJsTemplate(appDirectory, tab); + var tabHtml = Generate.generateHtmlTemplate(appDirectory, tab); + + }) +}; + +Generate.generateTabHtmlTemplate = function generateTabHtmlTemplate(appDirectory, name) { + throw new Error('not implemented'); +}; + +Generate.generateTabsHtmlTemplate = function generateTabsHtmlTemplate(appDirectory, name, tabs) { + // throw new Error('not implemented'); + var fileAndClassName = Generate.fileAndClassName(name); + var javascriptClassName = Generate.javascriptClassName(name); + // Generate.createScaffoldDirectories(appDirectory, fileAndClassName); + + var tabsData = []; + tabs.forEach(function(tab) { + var tabObj = { name: tab, javascriptClassName: Generate.javascriptClassName(tab)}; + tabsData.push(tabObj); + }); + + var tabsHtmlTemplatePath = path.join(__dirname, 'tabs.tmpl.html'); + return Generate.renderTemplateFromFile({tabs: tabsData, templatePath: tabsHtmlTemplatePath }); + + // + // <% _.forEach(tabs, function(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.javascriptClassName %>} from '../<%= tab.filename %>/<%= tab.filename %>'; + // <% }); %> + // @Page({ + // templateUrl: 'app/<%= filename %>/<%= filename %>.html', + // providers: [DataService] + // }) + // class <%= javascriptClassName %> { + // constructor(nav: NavController) { + // // set the root pages for each tab + // <% _.forEach(tabs, function(tab) { %> + // this.{<%= tab.javascriptClassName %>} = <%= tab.javascriptClassName %>; + // <% }); %> + // } + // } + var fileAndClassName = Generate.fileAndClassName(name); + var javascriptClassName = Generate.javascriptClassName(name); + + var tabsData = []; + tabs.forEach(function(tab) { + var tabObj = { name: tab, filename: Generate.fileAndClassName(tab), javascriptClassName: Generate.javascriptClassName(tab)}; + tabsData.push(tabObj); + }); + + var tabsHtmlTemplatePath = path.join(__dirname, 'tabs.tmpl.js'); + return Generate.renderTemplateFromFile({tabs: tabsData, templatePath: tabsHtmlTemplatePath, filename: fileAndClassName, javascriptClassName: javascriptClassName }); +}; + +Generate.generateTabScssTemplate = function generateTabScssTemplate(appDirectory, name) { + throw new Error('not implemented'); +}; + +Generate.generateTabsScssTemplate = function generateTabsScssTemplate(appDirectory, name) { + throw new Error('not implemented'); +}; +// end of tabs + +Generate.createScaffoldDirectories = function createScaffoldDirectories(options) { + // console.log('Create', options.appDirectory, options.fileAndClassName); + var componentPath = path.join(options.appDirectory, 'www', 'app', options.fileAndClassName); + shell.mkdir('-p', componentPath); +}; + +Generate.fileAndClassName = function fileAndClassName(name) { + return name.replace(/([a-z])([A-Z])/g, '$1-$2').replace('_', '-').toLowerCase(); +}; + +Generate.capitalizeName = function capitalizeName(name) { + return name.charAt(0).toUpperCase() + name.slice(1); +}; + +Generate.javascriptClassName = function javascriptClassName(name) { + return _.capitalize(_.camelCase(name)); +}; diff --git a/tooling/generators/page-sidemenu/index.js b/tooling/generators/page-sidemenu/index.js new file mode 100644 index 0000000000..3487cbcb9d --- /dev/null +++ b/tooling/generators/page-sidemenu/index.js @@ -0,0 +1,5 @@ +var SideMenu = module.exports; + +SideMenu.run = function run(options) { + +}; diff --git a/tooling/generators/page-tabs/index.js b/tooling/generators/page-tabs/index.js new file mode 100644 index 0000000000..3cfee84735 --- /dev/null +++ b/tooling/generators/page-tabs/index.js @@ -0,0 +1,6 @@ +var Generator = module.exports, + Generate = require('../../generate'); + +Generator.run = function run(options) { + console.log('got options!', options); +}; diff --git a/tooling/generators/page-tabs/tabs.tmpl.html b/tooling/generators/page-tabs/tabs.tmpl.html new file mode 100644 index 0000000000..8e8314deb0 --- /dev/null +++ b/tooling/generators/page-tabs/tabs.tmpl.html @@ -0,0 +1,6 @@ + +<% _.forEach(tabs, function(tab) { %> + + +<% }); %> + diff --git a/tooling/generators/page-tabs/tabs.tmpl.js b/tooling/generators/page-tabs/tabs.tmpl.js new file mode 100644 index 0000000000..a18aee60b3 --- /dev/null +++ b/tooling/generators/page-tabs/tabs.tmpl.js @@ -0,0 +1,18 @@ +import {NavController, Page} from 'ionic/ionic'; + +<% _.forEach(tabs, function(tab) { %> +import {<%= tab.javascriptClassName %>} from '../<%= tab.filename %>/<%= tab.filename %>'; +<% }); %> + +@Page({ + templateUrl: 'app/<%= filename %>/<%= filename %>.html' +}) +export class <%= javascriptClassName %> { + constructor(nav: NavController) { + // set the root pages for each tab + <% _.forEach(tabs, function(tab) { %> + this.<%= tab.javascriptClassName %> = <%= tab.javascriptClassName %>; + <% }); %> + } + +} diff --git a/tooling/generators/page/index.js b/tooling/generators/page/index.js new file mode 100644 index 0000000000..92159ab58a --- /dev/null +++ b/tooling/generators/page/index.js @@ -0,0 +1,61 @@ +/* + ionic g page about + what should happen: + create directories if not existing: /www, /www/app, /www/app/about + create files (about.html, about.scss, about.js) in /www/app/about +*/ +var fs = require('fs'), + Generator = module.exports, + Generate = require('../../generate'), + path = require('path'), + Q = require('q'); +/* + Run: generate a page template from the name and save + it in the desired app directory + @options + name: Page name + appDirectory: App directory of where to save file +*/ +Generator.run = function run(options) { + options.rootDirectory = options.rootDirectory || path.join('www', 'app'); + var savePath = path.join(options.appDirectory, options.rootDirectory, options.fileAndClassName); + + var templates = Generate.loadGeneratorTemplates(__dirname); + + templates.forEach(function(template) { + var templatePath = path.join(__dirname, template.file); + options.templatePath = templatePath; + var renderedTemplate = Generate.renderTemplateFromFile(options); + var saveFilePath = path.join(savePath, [options.fileAndClassName, template.type].join('')); + // console.log('renderedTemplate', renderedTemplate, 'saving to', saveFilePath); + console.log('\n√ Create'.blue, path.relative(options.appDirectory, saveFilePath)); + fs.writeFileSync(saveFilePath, renderedTemplate); + }); + + return Q(); +}; + +// var fileAndClassName = Generate.fileAndClassName(name); +// var javascriptClassName = Generate.javascriptClassName(name); +// Generate.createScaffoldDirectories(appDirectory, fileAndClassName); + +// var jsTemplate = Generate.generateJsTemplate(name); +// var htmlTemplate = Generate.generateHtmlTemplate(name); +// var scssTemplate = Generate.generateScssTemplate(name); + +// var pagePath = path.join(appDirectory, 'www', 'app', fileAndClassName), +// jsPath = path.join(pagePath, [fileAndClassName, '.js'].join('')), +// htmlPath = path.join(pagePath, [fileAndClassName, '.html'].join('')), +// scssPath = path.join(pagePath, [fileAndClassName, '.scss'].join('')); + +// logging.logger.info('√ Create'.blue, path.relative(appDirectory, jsPath)); +// fs.writeFileSync(jsPath, jsTemplate, 'utf8'); +// logging.logger.info('√ Create'.blue, path.relative(appDirectory, htmlPath)); +// fs.writeFileSync(htmlPath, htmlTemplate, 'utf8'); +// logging.logger.info('√ Create'.blue, path.relative(appDirectory, scssPath)); +// fs.writeFileSync(scssPath, scssTemplate, 'utf8'); + +// //TODO: Modify the main sass file (via config) to somehow update it +// //to include this sass file. +// //In the meantime, put a console message to alert them +// logging.logger.info('* Tip: if youd like to use the generated sass file, use \'@import "' + path.relative(appDirectory, scssPath) + '"\' in your main sass file'); diff --git a/tooling/generators/page/page.tmpl.html b/tooling/generators/page/page.tmpl.html new file mode 100644 index 0000000000..37a133b0b4 --- /dev/null +++ b/tooling/generators/page/page.tmpl.html @@ -0,0 +1,6 @@ + + <%= javascriptClassName %> + + + + diff --git a/tooling/generators/page/page.tmpl.js b/tooling/generators/page/page.tmpl.js new file mode 100644 index 0000000000..b89436f62f --- /dev/null +++ b/tooling/generators/page/page.tmpl.js @@ -0,0 +1,9 @@ +import {Page, NavController} from 'ionic/ionic'; +@Page({ + templateUrl: 'app/<%= fileAndClassName %>/<%= fileAndClassName %>.html', +}) +export class <%= javascriptClassName %> { + constructor(nav: NavController) { + this.nav = nav; + } +} diff --git a/tooling/generators/page/page.tmpl.scss b/tooling/generators/page/page.tmpl.scss new file mode 100644 index 0000000000..978da27ba4 --- /dev/null +++ b/tooling/generators/page/page.tmpl.scss @@ -0,0 +1,3 @@ +.<%= fileAndClassName %> { + +}