Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

493 lines (410 sloc) 16.362 kb
// Load the basic Geddy toolkit
require('../lib/geddy')
// Dependencies
var fs = require('fs')
, path = require('path')
, utils = require('utilities')
, 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.getInflections(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.getInflections(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.getInflections(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.file.searchParentPath(jsEnvironment, function(err) {
if(err) {
var jsErr = err;
// If jsEnvironment wasn't found, try finding coffee variant
utils.file.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.getInflections(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.file.searchParentPath(jsRouter, function(err) {
if(err) {
var jsErr = err;
// If jsEnvironment wasn't found, try finding coffee variant
utils.file.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.getInflections(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.file.existsSync(appLayoutPath + '.html.ejs') && !utils.file.existsSync(appLayoutPath + '.html.jade') &&
!utils.file.existsSync(appLayoutPath + '.html.hbs') && !utils.file.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.getInflections(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.file.existsSync(appLayoutPath + '.html.ejs') && !utils.file.existsSync(appLayoutPath + '.html.jade') &&
!utils.file.existsSync(appLayoutPath + '.html.hbs') && !utils.file.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.file.searchParentPath(jsEnvironment, function(err) {
if(err) {
var jsErr = err;
// If jsEnvironment wasn't found, try finding coffee variant
utils.file.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.