8 , exec = require('child_process').exec;
14 var version = '2.0.0beta2';
17 * Add session support.
23 * CSS engine to utilize.
29 * Template engine to utilize.
32 var templateEngine = 'jade';
35 * Usage documentation.
39 + '\x1b[1mUsage\x1b[0m: express [options] [PATH]\n'
41 + '\x1b[1mOptions\x1b[0m:\n'
42 + ' -s, --sessions Add session support\n'
43 + ' -t, --template ENGINE Add template ENGINE support (jade|ejs). Defaults to jade\n'
44 + ' -c, --css ENGINE Add stylesheet ENGINE support (less|sass|stylus). Defaults to plain css\n'
45 + ' -v, --version Output framework version\n'
46 + ' -h, --help Output help information\n'
50 * Jade layout template.
58 , ' link(rel=\'stylesheet\', href=\'/stylesheets/style.css\')'
63 * Jade index template.
68 , 'p Welcome to #{title}'
72 * EJS layout template.
79 , ' <title><%= title %></title>'
80 , ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
93 '<h1><%= title %></h1>'
94 , '<p>Welcome to <%= title %></p>'
98 * Default css template.
104 , ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;'
113 * Default less template.
119 , ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;'
128 * Default sass template.
134 , ' :font 14px "Lucida Grande", Helvetica, Arial, sans-serif'
140 * Default stylus template.
146 , ' font 14px "Lucida Grande", Helvetica, Arial, sans-serif'
157 , "// Run $ expresso"
160 , " * Module dependencies."
163 , "var app = require('../app')"
164 , " , assert = require('assert');"
166 , "module.exports = {"
167 , " 'GET /': function(){"
168 , " assert.response(app,"
170 , " { status: 200, headers: { 'Content-Type': 'text/html; charset=utf-8' }},"
172 , " assert.includes(res.body, '<title>Express</title>');"
185 , ' * Module dependencies.'
188 , 'var express = require(\'express\');'
190 , 'var app = module.exports = express.createServer();'
194 , 'app.configure(function(){'
195 , ' app.set(\'views\', __dirname + \'/views\');'
196 , ' app.set(\'view engine\', \':TEMPLATE\');'
197 , ' app.use(express.bodyParser());'
198 , ' app.use(express.methodOverride());{sess}{css}'
199 , ' app.use(app.router);'
200 , ' app.use(express.static(__dirname + \'/public\'));'
203 , 'app.configure(\'development\', function(){'
204 , ' app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); '
207 , 'app.configure(\'production\', function(){'
208 , ' app.use(express.errorHandler()); '
213 , 'app.get(\'/\', function(req, res){'
214 , ' res.render(\'index\', {'
215 , ' title: \'Express\''
219 , '// Only listen on $ node app.js'
221 , 'if (!module.parent) {'
222 , ' app.listen(3000);'
223 , ' console.log("Express server listening on port %d", app.address().port)'
230 var args = process.argv.slice(2)
233 while (args.length) {
234 var arg = args.shift();
252 ? (cssEngine = args.shift())
253 : abort('--css requires an argument');
258 ? (templateEngine = args.shift())
259 : abort('--template requires an argument');
266 // Generate application
268 (function createApplication(path) {
269 emptyDirectory(path, function(empty){
271 createApplicationAt(path);
273 confirm('destination is not empty, continue? ', function(ok){
275 process.stdin.destroy();
276 createApplicationAt(path);
286 * Create application at the given directory `path`.
288 * @param {String} path
291 function createApplicationAt(path) {
292 mkdir(path, function(){
293 mkdir(path + '/pids');
294 mkdir(path + '/logs');
295 mkdir(path + '/public/javascripts');
296 mkdir(path + '/public/images');
297 mkdir(path + '/public/stylesheets', function(){
300 write(path + '/public/stylesheets/style.styl', stylus);
303 write(path + '/public/stylesheets/style.less', less);
306 write(path + '/public/stylesheets/style.sass', sass);
309 write(path + '/public/stylesheets/style.css', css);
312 mkdir(path + '/views', function(){
313 switch (templateEngine) {
315 write(path + '/views/layout.ejs', ejsLayout);
316 write(path + '/views/index.ejs', ejsIndex);
319 write(path + '/views/layout.jade', jadeLayout);
320 write(path + '/views/index.jade', jadeIndex);
324 mkdir(path + '/test', function(){
325 write(path + '/test/app.test.js', appTest);
328 // CSS Engine support
332 app = app.replace('{css}', '\n app.use(express.compiler({ src: __dirname + \'/public\', enable: [\'' + cssEngine + '\'] }));');
335 app = app.replace('{css}', '\n app.use(require(\'stylus\').middleware({ src: __dirname + \'/public\' }));');
338 app = app.replace('{css}', '');
342 app = app.replace('{sess}', sessions
343 ? '\n app.use(express.cookieParser());\n app.use(express.session({ secret: \'your secret here\' }));'
347 app = app.replace(':TEMPLATE', templateEngine);
349 write(path + '/app.js', app);
352 process.on('exit', function(){
354 console.log(' - make sure you have installed %s: \x1b[33m$ npm install %s\x1b[0m'
358 console.log(' - make sure you have installed %s: \x1b[33m$ npm install %s\x1b[0m'
366 * Check if the given directory `path` is empty.
368 * @param {String} path
369 * @param {Function} fn
372 function emptyDirectory(path, fn) {
373 fs.readdir(path, function(err, files){
374 if (err && 'ENOENT' != err.code) throw err;
375 fn(!files || !files.length);
382 * @param {String} path
383 * @param {String} str
386 function write(path, str) {
387 fs.writeFile(path, str);
388 console.log(' \x1b[36mcreate\x1b[0m : ' + path);
392 * Prompt confirmation with the given `msg`.
394 * @param {String} msg
395 * @param {Function} fn
398 function confirm(msg, fn) {
399 prompt(msg, function(val){
400 fn(/^ *y(es)?/i.test(val));
405 * Prompt input with the given `msg` and callback `fn`.
407 * @param {String} msg
408 * @param {Function} fn
411 function prompt(msg, fn) {
413 if (' ' == msg[msg.length - 1]) {
414 process.stdout.write(msg);
420 process.stdin.setEncoding('ascii');
421 process.stdin.once('data', function(data){
429 * @param {String} path
430 * @param {Function} fn
433 function mkdir(path, fn) {
434 exec('mkdir -p ' + path, function(err){
436 console.log(' \x1b[36mcreate\x1b[0m : ' + path);
442 * Exit with the given `str`.
444 * @param {String} str
447 function abort(str) {