Comparing version 0.0.2 to 0.0.3
@@ -9,4 +9,6 @@ | ||
help: require('./lib/help'), | ||
history: require('./lib/history') | ||
history: require('./lib/history'), | ||
router: require('./lib/router'), | ||
error: require('./lib/error') | ||
}; | ||
@@ -14,3 +14,3 @@ | ||
var suggestions = [], | ||
routes = shell.router.routes; | ||
routes = shell.routes; | ||
for(var i=0; i<routes.length; i++){ | ||
@@ -17,0 +17,0 @@ var command = routes[i].command; |
@@ -9,12 +9,12 @@ | ||
// Register function | ||
shell.help = function(){ | ||
shell.styles.cyan('Available commands:').ln(); | ||
var routes = shell.router.routes; | ||
shell.help = function(req, res, next){ | ||
res.cyan('Available commands:').ln(); | ||
var routes = shell.routes; | ||
for(var i=0; i<routes.length; i++){ | ||
var route = routes[i]; | ||
if(route.description){ | ||
shell.styles.cyan(shell.pad(route.command, 20)).white(route.description).ln(); | ||
res.cyan(shell.pad(route.command, 20)).white(route.description).ln(); | ||
} | ||
} | ||
shell.prompt(); | ||
res.prompt(); | ||
} | ||
@@ -21,0 +21,0 @@ // Register commands |
@@ -1,2 +0,1 @@ | ||
var styles = require('./styles'); | ||
@@ -51,3 +50,3 @@ var querystring = { | ||
function match(comand, routes, i) { | ||
function match(req, routes, i) { | ||
var captures, | ||
@@ -60,3 +59,3 @@ i = i || 0; | ||
keys = route.keys; | ||
if (captures = regexp.exec(comand)) { | ||
if (captures = regexp.exec(req.command)) { | ||
fn._params = {}; | ||
@@ -82,3 +81,3 @@ var index = 0; | ||
module.exports = function(options){ | ||
module.exports = function router(options){ | ||
// Validation | ||
@@ -88,5 +87,14 @@ if(!options.shell){ | ||
} | ||
// Store | ||
var routes = []; | ||
function register(route){ | ||
var shell = options.shell; | ||
// Expose routes | ||
var routes = shell.routes = []; | ||
shell.cmd = function cmd(command, description, fn){ | ||
if(typeof description === 'function'){ | ||
fn = description, description = null; | ||
} | ||
var route = { | ||
command: command, | ||
description: description, | ||
fn: fn | ||
}; | ||
var keys = []; | ||
@@ -100,28 +108,27 @@ route.regexp = route.command instanceof RegExp | ||
}; | ||
function route(command, next){ | ||
var route, | ||
self = this; | ||
(function pass(i){ | ||
if (route = match(command, routes, i)) { | ||
var params = route._params; | ||
try { | ||
var res = styles({stdout: options.shell.options.stdout}); | ||
route.call(self, | ||
{command: command, params: params}, | ||
res, | ||
next); | ||
} catch (err) { | ||
next(err); | ||
} | ||
} else { | ||
next(new Error('Invalid command "'+command+'"')); | ||
} | ||
})(); | ||
return function router(req, res, next){ | ||
var route, | ||
self = this; | ||
(function pass(i){ | ||
if (route = match(req, routes, i)) { | ||
req.params = route._params; | ||
try { | ||
route.call(self, req, res, function(err){ | ||
if (err === true) { | ||
next(); | ||
} else if (err) { | ||
next(err); | ||
} else { | ||
pass(route._index+1); | ||
} | ||
}); | ||
} catch (err) { | ||
next(err); | ||
} | ||
} else { | ||
next(); | ||
} | ||
})(); | ||
}; | ||
return { | ||
routes: routes, | ||
register: register, | ||
route: route | ||
}; | ||
}; | ||
@@ -5,4 +5,5 @@ | ||
EventEmitter = require('events').EventEmitter, | ||
router = require('./router'), | ||
styles = require('./styles'); | ||
styles = require('./styles'), | ||
Request = require('./Request'), | ||
Response = require('./Response'); | ||
@@ -30,2 +31,3 @@ // Fix readline interface | ||
this.options.stdout = this.options.stdout || process.stdout; | ||
this.stack = []; | ||
this.styles = styles({stdout: this.options.stdout}); | ||
@@ -47,7 +49,6 @@ this.interface = readline.createInterface( | ||
this.isShell = process.argv.length === 2; | ||
// Prepare routing | ||
this.router = router({shell: this}); | ||
this.cmd('quit', 'Exit this shell', this.quit); | ||
// Start | ||
process.nextTick(function(){ | ||
// Carefull, router need to be here | ||
this.cmd('quit', 'Exit this shell', this.quit); | ||
if(this.isShell){ | ||
@@ -76,4 +77,9 @@ this.prompt(); | ||
// Configure callback for the given `env` | ||
Shell.prototype.use = function(plugin){ | ||
// don't do much yet | ||
Shell.prototype.use = function(handle){ | ||
// Add the route, handle pair to the stack | ||
if(handle){ | ||
this.stack.push({ route: null, handle: handle }); | ||
} | ||
// Allow chaining | ||
return this; | ||
@@ -85,23 +91,29 @@ } | ||
// Register new commands | ||
Shell.prototype.cmd = function(command, description, fn){ | ||
if(typeof description === 'function'){ | ||
fn = description, description = null; | ||
} | ||
this.router.register({ | ||
command: command, | ||
description: description, | ||
fn: fn | ||
}); | ||
}; | ||
// Run a command | ||
Shell.prototype.run = function(command){ | ||
command = command.trim(); | ||
this.router.route(command, function(err){ | ||
if(err){ | ||
return this.styles.red(err.message), this.prompt(); | ||
var self = this, | ||
req = new Request(), | ||
res = new Response({shell: this, stdout: this.options.stdout}), | ||
index = 0; | ||
req.command = command; | ||
function next(err){ | ||
var layer = self.stack[index++]; | ||
if(!layer){ | ||
return res.red('Command failed to execute'); | ||
} | ||
this.prompt(); | ||
}.bind(this)); | ||
var arity = layer.handle.length; | ||
if (err) { | ||
if (arity === 4) { | ||
layer.handle(err, req, res, next); | ||
} else { | ||
next(err); | ||
} | ||
} else if (arity < 4) { | ||
layer.handle(req, res, next); | ||
} else { | ||
next(); | ||
} | ||
} | ||
next(); | ||
}; | ||
@@ -108,0 +120,0 @@ |
{ "name": "shell" | ||
, "version": "0.0.2" | ||
, "version": "0.0.3" | ||
, "description": "Full features and pretty console applications" | ||
@@ -4,0 +4,0 @@ , "author": "David Worms <david@adaltas.com>" |
@@ -14,3 +14,5 @@ # Shell - Full features and pretty console applications | ||
app.use( shell.completer({shell: app}) ); | ||
app.use( shell.router({shell: app}) ); | ||
app.use( shell.help({shell: app, introduction: true}) ); | ||
app.use( shell.error({shell: app}) ); | ||
}); | ||
@@ -25,3 +27,3 @@ | ||
app.server = spawn('redis-server', [__dirname+'/redis.conf']); | ||
next(); | ||
res.prompt(); | ||
}); | ||
@@ -36,3 +38,3 @@ | ||
res.cyan(keys.join('\n')||'no keys'); | ||
next(); | ||
res.prompt(); | ||
}); | ||
@@ -61,3 +63,3 @@ }); | ||
## Routes | ||
## Routes plugin | ||
@@ -64,0 +66,0 @@ A route is made of a command pattern, an optional description and one or more route specific middleware. |
@@ -36,3 +36,3 @@ #!/usr/bin/env node | ||
} | ||
next(); | ||
res.prompt(); | ||
}); | ||
@@ -53,3 +53,3 @@ }); | ||
setTimeout(function(){ | ||
next(); | ||
res.prompt(); | ||
},500); | ||
@@ -60,3 +60,3 @@ }); | ||
if(!redis){ | ||
return res.red('Redis not started'), next(); | ||
return res.red('Redis not started'), res.prompt(); | ||
} | ||
@@ -67,3 +67,3 @@ redis.on('exit', function(code){ | ||
} | ||
next(); | ||
res.prompt(); | ||
}); | ||
@@ -75,3 +75,3 @@ redis.kill(); | ||
if(!redis){ | ||
return res.red('Redis not started'), next(); | ||
return res.red('Redis not started'), res.prompt(); | ||
} | ||
@@ -87,3 +87,3 @@ server = spawn('node', [__dirname+'/lib/server']); | ||
}) | ||
next(); | ||
res.prompt(); | ||
}); | ||
@@ -93,3 +93,3 @@ | ||
if(!server){ | ||
return res.red('Server not started'), next(); | ||
return res.red('Server not started'), res.prompt(); | ||
} | ||
@@ -100,5 +100,5 @@ server.on('exit', function(code){ | ||
} | ||
next(); | ||
res.prompt(); | ||
}); | ||
server.kill(); | ||
}); |
@@ -10,3 +10,5 @@ #!/usr/bin/env node | ||
app.use( shell.completer({shell: app}) ); | ||
app.use( shell.router({shell: app}) ); | ||
app.use( shell.help({shell: app, introduction: true}) ); | ||
app.use( shell.error({shell: app}) ); | ||
}); | ||
@@ -21,3 +23,3 @@ | ||
app.server = spawn('redis-server', [__dirname+'/redis.conf']); | ||
next(); | ||
res.prompt(); | ||
}); | ||
@@ -32,4 +34,4 @@ | ||
res.cyan(keys.join('\n')||'no keys'); | ||
next(); | ||
res.prompt(); | ||
}); | ||
}); |
22692
21
665
90
4