8 , exec = require('child_process').exec;
14 var version = '2.3.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'
158 , "// Run $ expresso"
161 , " * Module dependencies."
164 , "var app = require('../app')"
165 , " , assert = require('assert');"
167 , "module.exports = {"
168 , " 'GET /': function(){"
169 , " assert.response(app,"
171 , " { status: 200, headers: { 'Content-Type': 'text/html; charset=utf-8' }},"
173 , " assert.includes(res.body, '<title>Express</title>');"
186 , ' * Module dependencies.'
189 , 'var express = require(\'express\');'
191 , 'var app = module.exports = express.createServer();'
195 , 'app.configure(function(){'
196 , ' app.set(\'views\', __dirname + \'/views\');'
197 , ' app.set(\'view engine\', \':TEMPLATE\');'
198 , ' app.use(express.bodyParser());'
199 , ' app.use(express.methodOverride());{sess}{css}'
200 , ' app.use(app.router);'
201 , ' app.use(express.static(__dirname + \'/public\'));'
204 , 'app.configure(\'development\', function(){'
205 , ' app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); '
208 , 'app.configure(\'production\', function(){'
209 , ' app.use(express.errorHandler()); '
214 , 'app.get(\'/\', function(req, res){'
215 , ' res.render(\'index\', {'
216 , ' title: \'Express\''
220 , '// Only listen on $ node app.js'
222 , 'if (!module.parent) {'
223 , ' app.listen(3000);'
224 , ' console.log("Express server listening on port %d", app.address().port);'
231 var args = process.argv.slice(2)
234 while (args.length) {
235 var arg = args.shift();
253 ? (cssEngine = args.shift())
254 : abort('--css requires an argument');
259 ? (templateEngine = args.shift())
260 : abort('--template requires an argument');
267 // Generate application
269 (function createApplication(path) {
270 emptyDirectory(path, function(empty){
272 createApplicationAt(path);
274 confirm('destination is not empty, continue? ', function(ok){
276 process.stdin.destroy();
277 createApplicationAt(path);
287 * Create application at the given directory `path`.
289 * @param {String} path
292 function createApplicationAt(path) {
293 mkdir(path, function(){
294 mkdir(path + '/pids');
295 mkdir(path + '/logs');
296 mkdir(path + '/public/javascripts');
297 mkdir(path + '/public/images');
298 mkdir(path + '/public/stylesheets', function(){
301 write(path + '/public/stylesheets/style.styl', stylus);
304 write(path + '/public/stylesheets/style.less', less);
307 write(path + '/public/stylesheets/style.sass', sass);
310 write(path + '/public/stylesheets/style.css', css);
313 mkdir(path + '/views', function(){
314 switch (templateEngine) {
316 write(path + '/views/layout.ejs', ejsLayout);
317 write(path + '/views/index.ejs', ejsIndex);
320 write(path + '/views/layout.jade', jadeLayout);
321 write(path + '/views/index.jade', jadeIndex);
325 mkdir(path + '/test', function(){
326 write(path + '/test/app.test.js', appTest);
329 // CSS Engine support
333 app = app.replace('{css}', '\n app.use(express.compiler({ src: __dirname + \'/public\', enable: [\'' + cssEngine + '\'] }));');
336 app = app.replace('{css}', '\n app.use(require(\'stylus\').middleware({ src: __dirname + \'/public\' }));');
339 app = app.replace('{css}', '');
343 app = app.replace('{sess}', sessions
344 ? '\n app.use(express.cookieParser());\n app.use(express.session({ secret: \'your secret here\' }));'
348 app = app.replace(':TEMPLATE', templateEngine);
350 write(path + '/app.js', app);
353 process.on('exit', function(){
355 console.log(' - make sure you have installed %s: \x1b[33m$ npm install %s\x1b[0m'
359 console.log(' - make sure you have installed %s: \x1b[33m$ npm install %s\x1b[0m'
367 * Check if the given directory `path` is empty.
369 * @param {String} path
370 * @param {Function} fn
373 function emptyDirectory(path, fn) {
374 fs.readdir(path, function(err, files){
375 if (err && 'ENOENT' != err.code) throw err;
376 fn(!files || !files.length);
383 * @param {String} path
384 * @param {String} str
387 function write(path, str) {
388 fs.writeFile(path, str);
389 console.log(' \x1b[36mcreate\x1b[0m : ' + path);
393 * Prompt confirmation with the given `msg`.
395 * @param {String} msg
396 * @param {Function} fn
399 function confirm(msg, fn) {
400 prompt(msg, function(val){
401 fn(/^ *y(es)?/i.test(val));
406 * Prompt input with the given `msg` and callback `fn`.
408 * @param {String} msg
409 * @param {Function} fn
412 function prompt(msg, fn) {
414 if (' ' == msg[msg.length - 1]) {
415 process.stdout.write(msg);
421 process.stdin.setEncoding('ascii');
422 process.stdin.once('data', function(data){
430 * @param {String} path
431 * @param {Function} fn
434 function mkdir(path, fn) {
435 exec('mkdir -p ' + path, function(err){
437 console.log(' \x1b[36mcreate\x1b[0m : ' + path);
443 * Exit with the given `str`.
445 * @param {String} str
448 function abort(str) {