8 , exec = require('child_process').exec;
14 var version = '2.4.3';
17 * Add session support.
23 * CSS engine to utilize.
29 * Template engine to utilize.
32 var templateEngine = 'jade';
35 * Usage documentation.
40 + ' Usage: express [options] [path]\n'
43 + ' -s, --sessions add session support\n'
44 + ' -t, --template <engine> add template <engine> support (jade|ejs). default=jade\n'
45 + ' -c, --css <engine> add stylesheet <engine> support (less|sass|stylus). default=plain css\n'
46 + ' -v, --version output framework version\n'
47 + ' -h, --help output help information\n'
51 * Jade layout template.
59 , ' link(rel=\'stylesheet\', href=\'/stylesheets/style.css\')'
64 * Jade index template.
69 , 'p Welcome to #{title}'
73 * EJS layout template.
80 , ' <title><%= title %></title>'
81 , ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
94 '<h1><%= title %></h1>'
95 , '<p>Welcome to <%= title %></p>'
99 * Default css template.
105 , ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;'
114 * Default less template.
120 , ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;'
129 * Default sass template.
135 , ' :font 14px "Lucida Grande", Helvetica, Arial, sans-serif'
141 * Default stylus template.
147 , ' font 14px "Lucida Grande", Helvetica, Arial, sans-serif'
159 , ' * Module dependencies.'
162 , 'var express = require(\'express\');'
164 , 'var app = module.exports = express.createServer();'
168 , 'app.configure(function(){'
169 , ' app.set(\'views\', __dirname + \'/views\');'
170 , ' app.set(\'view engine\', \':TEMPLATE\');'
171 , ' app.use(express.bodyParser());'
172 , ' app.use(express.methodOverride());{sess}{css}'
173 , ' app.use(app.router);'
174 , ' app.use(express.static(__dirname + \'/public\'));'
177 , 'app.configure(\'development\', function(){'
178 , ' app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); '
181 , 'app.configure(\'production\', function(){'
182 , ' app.use(express.errorHandler()); '
187 , 'app.get(\'/\', function(req, res){'
188 , ' res.render(\'index\', {'
189 , ' title: \'Express\''
193 , 'app.listen(3000);'
194 , 'console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);'
200 var args = process.argv.slice(2)
203 while (args.length) {
204 var arg = args.shift();
222 ? (cssEngine = args.shift())
223 : abort('--css requires an argument');
228 ? (templateEngine = args.shift())
229 : abort('--template requires an argument');
236 // Generate application
238 (function createApplication(path) {
239 emptyDirectory(path, function(empty){
241 createApplicationAt(path);
243 confirm('destination is not empty, continue? ', function(ok){
245 process.stdin.destroy();
246 createApplicationAt(path);
256 * Create application at the given directory `path`.
258 * @param {String} path
261 function createApplicationAt(path) {
262 mkdir(path, function(){
263 mkdir(path + '/public/javascripts');
264 mkdir(path + '/public/images');
265 mkdir(path + '/public/stylesheets', function(){
268 write(path + '/public/stylesheets/style.styl', stylus);
271 write(path + '/public/stylesheets/style.less', less);
274 write(path + '/public/stylesheets/style.sass', sass);
277 write(path + '/public/stylesheets/style.css', css);
280 mkdir(path + '/views', function(){
281 switch (templateEngine) {
283 write(path + '/views/layout.ejs', ejsLayout);
284 write(path + '/views/index.ejs', ejsIndex);
287 write(path + '/views/layout.jade', jadeLayout);
288 write(path + '/views/index.jade', jadeIndex);
293 // CSS Engine support
297 app = app.replace('{css}', '\n app.use(express.compiler({ src: __dirname + \'/public\', enable: [\'' + cssEngine + '\'] }));');
300 app = app.replace('{css}', '\n app.use(require(\'stylus\').middleware({ src: __dirname + \'/public\' }));');
303 app = app.replace('{css}', '');
307 app = app.replace('{sess}', sessions
308 ? '\n app.use(express.cookieParser());\n app.use(express.session({ secret: \'your secret here\' }));'
312 app = app.replace(':TEMPLATE', templateEngine);
316 json += ' "name": "application-name"\n';
317 json += ' , "version": "0.0.1"\n';
318 json += ' , "private": true\n';
319 json += ' , "dependencies": {\n';
320 json += ' "express": "' + version + '"\n';
321 if (cssEngine) json += ' , "' + cssEngine + '": ">= 0.0.1"\n';
322 if (templateEngine) json += ' , "' + templateEngine + '": ">= 0.0.1"\n';
327 write(path + '/package.json', json);
328 write(path + '/app.js', app);
333 * Check if the given directory `path` is empty.
335 * @param {String} path
336 * @param {Function} fn
339 function emptyDirectory(path, fn) {
340 fs.readdir(path, function(err, files){
341 if (err && 'ENOENT' != err.code) throw err;
342 fn(!files || !files.length);
349 * @param {String} path
350 * @param {String} str
353 function write(path, str) {
354 fs.writeFile(path, str);
355 console.log(' \x1b[36mcreate\x1b[0m : ' + path);
359 * Prompt confirmation with the given `msg`.
361 * @param {String} msg
362 * @param {Function} fn
365 function confirm(msg, fn) {
366 prompt(msg, function(val){
367 fn(/^ *y(es)?/i.test(val));
372 * Prompt input with the given `msg` and callback `fn`.
374 * @param {String} msg
375 * @param {Function} fn
378 function prompt(msg, fn) {
380 if (' ' == msg[msg.length - 1]) {
381 process.stdout.write(msg);
387 process.stdin.setEncoding('ascii');
388 process.stdin.once('data', function(data){
396 * @param {String} path
397 * @param {Function} fn
400 function mkdir(path, fn) {
401 exec('mkdir -p ' + path, function(err){
403 console.log(' \x1b[36mcreate\x1b[0m : ' + path);
409 * Exit with the given `str`.
411 * @param {String} str
414 function abort(str) {