Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

493 lines (410 sloc) 16.387 kb
// Load the basic Geddy toolkit
require('../lib/geddy')
// Dependencies
var fs = require('fs')
, path = require('path')
, utils = require('../lib/utils')
, adapter = require('../lib/template/adapters').Adapter
, templato = new (require('../deps/templato'));
namespace('gen', function () {
var _writeTemplate = function (name, filename, dirname, options) {
options = options || {};
var names = utils.string.inflection(name)
, text = fs.readFileSync(path.join(__dirname, filename + '.ejs'), 'utf8').toString()
, bare = options.bare || false // Default to full controller
, templ
, filePath;
// Render with the right model name
templ = new adapter({data: {ext: '.ejs'}, text: text, templato: templato});
templ.process({names: names, bare: bare, properties: options.properties});
// Write file
filePath = path.join('app', dirname, names.filename[options.inflection] + '.js');
fs.writeFileSync(filePath, templ.markup, 'utf8');
console.log('[Added] ' + filePath);
};
var _formatModelProperties = function(properties) {
var obj = {'default': {name: 'id', type: 'string'}};
if(!properties) return obj;
var itemsArr = properties.split(' ')
, name
, type
, args
, i
, value;
i = -1;
while(++i < itemsArr.length) {
value = itemsArr[i];
name = value.replace(/:.*/g, '');
type = value.replace(/[a-zA-Z]*:?/, '');
args = type.replace(/[a-zA-Z]*:?/, '');
// Take off any args on the type
type = type.replace(/:.*/g, '');
// Defaults and alias's
if(!type) type = 'string';
if(type === 'integer') type = 'int';
if(type === 'bool') type = 'boolean';
if(args === 'def') args = 'default';
if(type === 'default' || type === 'def') {
// If the type is `default` assume they want `string`
// type and want this property to be default
type = 'string';
args = 'default';
}
// Set it as default if given the `default` argument
if(args === 'default') {
obj['default'] = {name: name, type: type};
// Add the original ID property
obj['id'] = obj['id'] || {name: 'id', type: 'string'};
} else {
// If ID property is given and it matches the default
// then rewrite the default with the new ID property
if(name === 'id' && obj['default'].name === 'id') {
obj['default'] = {name: name, type: type};
} else obj[name] = {name: name, type: type};
}
}
return obj;
};
// Creates a new Geddy app scaffold
task('app', [], function(name, engine) {
if(!name) throw new Error('No app name specified.');
if(!engine) engine = 'ejs';
var mkdirs = [
''
, 'config'
, 'app/models'
, 'app/controllers'
, 'lib'
, 'log'
, 'node_modules'
]
, cps = [
['views/' + engine, 'app/views']
, ['public', '']
, ['router.js', 'config']
, ['init.js', 'config']
, ['environment.js', 'config']
, ['development.js', 'config']
, ['production.js', 'config']
, ['main.js', 'app/controllers']
, ['application.js', 'app/controllers']
, ['favicon.ico', 'public']
];
mkdirs.forEach(function(dir) {
jake.mkdirP(path.join(name, dir));
});
cps.forEach(function(cp) {
jake.cpR(path.join(__dirname, 'base', cp[0]), path.join(name, cp[1]));
});
console.log('Created app ' + name + '.');
});
// Creates a resource with a model, controller and a resource route
task('resource', function(name, modelProperties) {
if(!name) throw new Error('No resource name specified.');
var names = utils.string.inflection(name);
jake.Task['gen:model'].invoke(name, modelProperties);
jake.Task['gen:controller'].invoke(name);
jake.Task['gen:route'].invoke(name);
// Create views folder but not actions
jake.mkdirP(path.join('app', 'views', names.filename.plural));
console.log('[Added] ' + names.filename.plural + ' view directory');
});
// Creates a full scaffold with views, a model, controller and a resource route
task('scaffold', function(name, engine, modelProperties) {
if(!modelProperties && engine) {
modelProperties = engine;
engine = '';
}
if(!name) throw new Error('No scaffold name specified.');
if(!engine) engine = 'ejs';
var names = utils.string.inflection(name)
, jsEnvironment = path.normalize('config/environment.js')
, coffeeEnvironment = path.normalize('config/environment.coffee')
, environmentPath
, environmentArr
, text
, splitText
, dbContent = '';
// Check if the environment file exists
utils.fileUtils.searchParentPath(jsEnvironment, function(err) {
if(err) {
var jsErr = err;
// If jsEnvironment wasn't found, try finding coffee variant
utils.fileUtils.searchParentPath(coffeeEnvironment, function(err) {
if(err) {
throw jsErr;
} else {
environmentPath = coffeeEnvironment;
}
});
} else {
environmentPath = jsEnvironment;
}
});
jake.Task['gen:modelScaffold'].invoke(name, modelProperties);
jake.Task['gen:controllerScaffold'].invoke(name, {properties: modelProperties});
jake.Task['gen:route'].invoke(name);
jake.Task['gen:viewsScaffold'].invoke(name, {engine: engine, properties: modelProperties});
// Add the following line to `config/environment.js/.coffee`
if(environmentPath) {
text = fs.readFileSync(environmentPath, 'utf8').toString();
// Create text to add to environment
if(environmentPath.match('.coffee')) {
dbContent = [
' db:'
, ' mongo:'
, ' db: \'' + names.property.plural + '\''
].join('\n');
splitText = 'config = ';
} else if(environmentPath.match('.js')) {
dbContent = [
' db: {'
, ' mongo: {'
, ' db: \'' + names.property.plural + '\''
, ' }'
, ' }'
].join('\n');
splitText = 'var config = {';
}
// Don't add the db config over and over
if(text.indexOf('db:') == -1) {
environmentArr = text.split(splitText);
environmentArr[0] += splitText + '\n' + dbContent + '\n';
text = environmentArr.join('');
fs.writeFileSync(environmentPath, text, 'utf8');
console.log('[Added] Database configuration to ' + environmentPath);
} else console.log('Database configuration already set in ' + environmentPath);
}
});
task('model', [], function(name, properties) {
if(!name) throw new Error('No model name specified.');
_writeTemplate(name, 'resource/model', 'models', {
inflection: 'singular'
, properties: _formatModelProperties(properties)
});
});
task('modelScaffold', [], function(name, properties) {
if(!name) throw new Error('No model name specified.');
_writeTemplate(name, 'scaffold/model', 'models', {
inflection: 'singular'
, properties: _formatModelProperties(properties)
});
});
task('controller', [], function(name) {
if(!name) throw new Error('No controller name specified.');
_writeTemplate(name, 'resource/controller', 'controllers', {inflection: 'plural', bare: false});
});
task('controllerScaffold', [], function(name, options) {
if(!name) throw new Error('No controller name specified.');
options = options || {};
_writeTemplate(name, 'scaffold/controller', 'controllers', {
inflection: 'plural'
, bare: false
, properties: _formatModelProperties(options.properties)
});
});
task('bareController', [], function(name, engine) {
if(!name) throw new Error('No controller name specified.');
if(!engine) engine = 'ejs';
_writeTemplate(name, 'resource/controller', 'controllers', {inflection: 'plural', bare: true});
jake.Task['gen:route'].invoke(name, {bare: true});
jake.Task['gen:views'].invoke(name, {bare: true, engine: engine});
});
task('route', [], function(name, options) {
if(!name) throw new Error('No route name specified.');
options = options || {};
var names = utils.string.inflection(name)
, routeType = options.bare ? 'Bare' : 'Resource'
, jsRouter = path.normalize('config/router.js')
, coffeeRouter = path.normalize('config/router.coffee')
, routerPath
, routerArr
, text
, splitText
, newRoute;
// Check if the router file exists
utils.fileUtils.searchParentPath(jsRouter, function(err) {
if(err) {
var jsErr = err;
// If jsEnvironment wasn't found, try finding coffee variant
utils.fileUtils.searchParentPath(coffeeRouter, function(err) {
if(err) {
throw jsErr;
} else {
routerPath = coffeeRouter;
}
});
} else {
routerPath = jsRouter;
}
});
if(routerPath) {
text = fs.readFileSync(routerPath, 'utf8');
if(routerPath.match('.coffee')) {
if(options.bare) {
newRoute = 'router.match(\'/' + names.filename.plural +
'\').to controller: \'' + names.constructor.plural +
'\', action: \'index\'';
} else {
newRoute = 'router.resource \'' + names.filename.plural + '\'';
}
} else if(routerPath.match('.js')) {
if(options.bare) {
newRoute = 'router.match(\'/' + names.filename.plural +
'\').to({controller: \'' + names.constructor.plural +
'\', action: \'index\'});';
} else {
newRoute = 'router.resource(\'' + names.filename.plural + '\');';
}
}
// Don't add the same route over and over
if(text.indexOf(newRoute) == -1) {
// Add the new resource route just above the export
routerArr = text.split('exports.router');
routerArr[0] += newRoute + '\n';
text = routerArr.join('exports.router');
fs.writeFileSync(routerPath, text, 'utf8');
console.log('[Added] ' + routeType + ' ' + names.filename.plural +
' route added to ' + routerPath);
}
else {
console.log(routeType + ' ' + names.filename.plural + ' route already defined in ' +
routerPath);
}
} else {
console.log('There is no router file to add routes too');
}
});
task('views', [], function(name, options) {
if(!name) throw new Error('No view name specified.');
options = options || {};
// Option defaults
options.engine = options.engine || 'ejs';
var names = utils.string.inflection(name)
, engine = options.engine
, appViewDir = path.join('app', 'views', names.filename.plural)
, templateViewDir = path.join(__dirname, 'views', engine)
, cmds = []
, ext = '.html'
, appLayoutPath
, actions
, addActionView;
// Set extension based on engine option
if(engine === 'ejs') ext += '.ejs';
if(engine === 'jade') ext += '.jade';
if(engine === 'handlebars') ext += '.hbs';
if(engine === 'mustache') ext += '.ms';
// Set application layout path
appLayoutPath = path.join('app', 'views', 'layouts', 'application');
// Copy template view to application path
addActionView = function(action) {
jake.cpR(path.join(templateViewDir, action + ext), appViewDir);
};
jake.mkdirP(appViewDir);
jake.mkdirP('app/views/layouts');
addActionView('index');
// Add views for the other CRUD actions when doing a full-on resource
if(!options.bare) {
['add', 'edit', 'show'].forEach(function (action) {
addActionView(action);
});
}
// Create default layout if one doesn't exist
// Hack: There should be a better way to detect if a application layout exists
if(!utils.compat.existsSync(appLayoutPath + '.html.ejs') && !utils.compat.existsSync(appLayoutPath + '.html.jade') &&
!utils.compat.existsSync(appLayoutPath + '.html.hbs') && !utils.compat.existsSync(appLayoutPath + '.html.ms')) {
// Copy template layout file to apps application layout file
jake.cpR(path.join(templateViewDir, 'layout' + ext), appLayoutPath + ext);
}
console.log('[Added] View templates');
});
task('viewsScaffold', function(name, options) {
if(!name) {
throw new Error('No view name specified.');
}
options = options || {};
// Option defaults
options.engine = options.engine || 'ejs';
var names = utils.string.inflection(name)
, engine = options.engine
, appViewDir = path.join('app', 'views', names.filename.plural)
, templateViewDir = path.join(__dirname, 'scaffold', 'views', engine)
, cmds = []
, ext = '.html'
, appLayoutPath
, actions
, addActionView
, text
, templ;
// Set extension based on engine option
if(engine === 'ejs') ext += '.ejs';
if(engine === 'jade') ext += '.jade';
if(engine === 'handlebars') ext += '.hbs';
if(engine === 'mustache') ext += '.ms';
// Set application layout path
appLayoutPath = path.join('app', 'views', 'layouts', 'application');
// Function to compile the template
addActionView = function(action) {
text = fs.readFileSync(path.join(templateViewDir, action + ext + '.ejs')).toString();
// Compile template text
templ = new adapter({data: {ext: '.ejs'}, text: text, templato: templato});
templ.process({names: names, properties: _formatModelProperties(options.properties)});
// Write file
fs.writeFileSync(path.join(appViewDir, action + ext),
templ.markup.replace(/<@/g, '<%').replace(/@>/g, '%>'), 'utf8');
};
jake.mkdirP(appViewDir);
jake.mkdirP('app/views/layouts');
// Add views for the other CRUD actions when doing a full-on resource
['index', 'add', 'show', 'edit'].forEach(function(action) {
addActionView(action);
});
// Create default layout if one doesn't exist
// Hack: There should be a better way to detect if a application layout exists
if(!utils.compat.existsSync(appLayoutPath + '.html.ejs') && !utils.compat.existsSync(appLayoutPath + '.html.jade') &&
!utils.compat.existsSync(appLayoutPath + '.html.hbs') && !utils.compat.existsSync(appLayoutPath + '.html.ms')) {
// Copy template layout file to apps application layout file
jake.cpR(path.join(templateViewDir, 'layout' + ext), appLayoutPath + ext);
}
console.log('[Added] View templates');
});
// Generate a new application secret in environment.js
task('secret', [], function() {
var jsEnvironment = path.normalize('config/environment.js')
, coffeeEnvironment = path.normalize('config/environment.coffee')
, secret = utils.string.uuid(128)
, environmentPath
, environmentArr
, text
, splitText;
// Check if the environment file exists
utils.fileUtils.searchParentPath(jsEnvironment, function(err) {
if(err) {
var jsErr = err;
// If jsEnvironment wasn't found, try finding coffee variant
utils.fileUtils.searchParentPath(coffeeEnvironment, function(err) {
if(err) {
throw jsErr;
} else {
environmentPath = coffeeEnvironment;
}
});
} else {
environmentPath = jsEnvironment;
}
});
if(environmentPath) {
text = fs.readFileSync(environmentPath, 'utf8').toString();
// Remove any old secret
text = text.replace(/\nconfig.secret.+\n/, '');
splitText = 'module.exports = config';
if(environmentPath.match('.js')) splitText += ';';
environmentArr = text.split(splitText);
environmentArr[0] += "config.secret = '" + secret + "'";
environmentArr[0] += environmentPath.match('.js') ? ';\n\n' : '\n\n';
text = environmentArr.join(splitText);
fs.writeFileSync(environmentPath, text, 'utf8');
console.log('[Added] Application secret to \'' + environmentPath + '\'');
} else console.log('There is no environment config to add the secret too');
});
});
Jump to Line
Something went wrong with that request. Please try again.