Comparing version 6.3.0 to 6.4.0
@@ -21,7 +21,10 @@ 'use strict' | ||
this.command('help', { description: 'provides help for the application' }, function (options, done) { | ||
let cols = [] | ||
let longest = 0 | ||
let usage | ||
var cols = [] | ||
var longest = 0 | ||
var usage | ||
output.log(chalk.magenta('Description:') + ' ' + self.settings.description) | ||
if (self.settings.description) { | ||
output.log(chalk.magenta('Description:') + ' ' + self.settings.description) | ||
} | ||
if (Object.keys(self.commands).length) { | ||
@@ -56,2 +59,4 @@ output.log(chalk.magenta('Commands:')) | ||
settings.parameters = settings.parameters || {} | ||
settings.options = assign({}, options, settings.options || {}) | ||
@@ -63,6 +68,5 @@ } | ||
let context0 = this.context.length > 1 ? this.context[0] : false | ||
let options = last(this.context) | ||
let abbrevs = abbrev(Object.keys(this.commands)) | ||
var err | ||
var context0 = this.context.length > 1 ? this.context[0] : false | ||
var options = last(this.context) | ||
var abbrevs = abbrev(Object.keys(this.commands)) | ||
@@ -73,7 +77,32 @@ if (context0 && abbrevs[context0] && options.help) { | ||
let longest = 0 | ||
let usage | ||
usage = getParams(command.action).slice(0, -2).map(function (v) { return '<' + v + '>' }).join(' ') | ||
let params = getParams(command.action).slice(0, -2) | ||
let usage = params.map(function (v) { return '<' + v + '>' }).join(' ') | ||
output.log(chalk.magenta('Description:') + ' ' + command.settings.description) | ||
output.log(chalk.magenta('Usage:') + ' [options] ' + command.name + ' ' + usage) | ||
output.log(chalk.magenta('Usage:') + ' [options] ' + abbrevs[context0] + ' ' + usage) | ||
if (Object.keys(command.settings.parameters).length) { | ||
output.log(chalk.magenta('Parameters:')) | ||
} | ||
params.forEach(function (p) { | ||
if (command.settings.parameters[p]) { | ||
if (p.length > longest) { | ||
longest = p.length | ||
} | ||
cols.push([p, command.settings.parameters[p]]) | ||
} | ||
}) | ||
longest += 2 | ||
cols.forEach(function (v) { | ||
output.log(' ' + chalk.cyan(v[0]) + repeat(' ', longest - v[0].length) + v[1]) | ||
}) | ||
longest = 0 | ||
cols = [] | ||
if (Object.keys(command.settings.options).length) { | ||
@@ -132,3 +161,3 @@ output.log(chalk.magenta('Options:')) | ||
} else { | ||
err = new Error('run help to get a list of commands') | ||
let err = new Error('run help to get a list of commands') | ||
@@ -135,0 +164,0 @@ output.error(chalk.red(err)) |
@@ -29,6 +29,3 @@ 'use strict' | ||
this.commands[name] = { | ||
name: name, | ||
settings: assign({ | ||
description: '', | ||
options: {}, | ||
aliases: {} | ||
@@ -43,24 +40,17 @@ }, settings), | ||
let context0 = this.context.length > 1 ? this.context[0] : false | ||
let options = last(this.context) | ||
let abbrevs = abbrev(Object.keys(this.commands)) | ||
let command | ||
let params | ||
let missing | ||
let action | ||
let err | ||
var context0 = this.context.length > 1 ? this.context[0] : false | ||
if (context0) { | ||
if (!abbrevs[context0]) { | ||
err = new Error(context0 + ' not found') | ||
let options = last(this.context) | ||
let abbrevs = abbrev(Object.keys(this.commands)) | ||
output.error(chalk.red(err)) | ||
try { | ||
if (!abbrevs[context0]) { | ||
throw new Error(context0 + ' not found') | ||
} | ||
callback(err) | ||
} else { | ||
command = this.commands[abbrevs[context0]] | ||
this.context.shift() | ||
action = command.action | ||
params = getParams(action) | ||
let command = this.commands[abbrevs[context0]] | ||
let action = command.action | ||
let params = getParams(action) | ||
@@ -80,36 +70,28 @@ for (let s in command.settings.aliases) { | ||
if (this.context.length < params.length - 1) { | ||
missing = params.slice(this.context.length - 1, -2) | ||
let missing = params.slice(this.context.length - 1, -2) | ||
err = new Error('missing argument' + (missing.length > 1 ? 's' : '') + ' (' + missing.join(', ') + ') for ' + command.name) | ||
throw new Error('missing argument' + (missing.length > 1 ? 's' : '') + ' (' + missing.join(', ') + ') for ' + abbrevs[context0]) | ||
} else if (this.context.length > params.length - 1) { | ||
throw new Error('too many arguments for ' + abbrevs[context0]) | ||
} | ||
output.error(chalk.red(err)) | ||
action = ap(this.context, action) | ||
} | ||
callback(err) | ||
} else if (this.context.length > params.length - 1) { | ||
err = new Error('too many arguments for ' + command.name) | ||
asyncDone(action, function (err) { | ||
if (err) { | ||
output.error(chalk.red(err)) | ||
callback(err) | ||
} else { | ||
callback() | ||
} | ||
}) | ||
} catch (err) { | ||
output.error(chalk.red(err)) | ||
action = ap(this.context, action) | ||
} | ||
if (!err) { | ||
asyncDone(action, function (err) { | ||
if (err) { | ||
output.error(chalk.red(err)) | ||
callback(err) | ||
} else { | ||
callback() | ||
} | ||
}) | ||
} | ||
callback(err) | ||
} | ||
} else { | ||
callback() | ||
} | ||
} | ||
} |
@@ -6,8 +6,8 @@ 'use strict' | ||
module.exports = function (argv) { | ||
let context = [] | ||
let options = {} | ||
var context = [] | ||
var options = {} | ||
argv.forEach(function (arg) { | ||
let parts | ||
let val | ||
var parts | ||
var val | ||
@@ -14,0 +14,0 @@ if (arg.startsWith('--')) { |
{ | ||
"name": "sergeant", | ||
"version": "6.3.0", | ||
"version": "6.4.0", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "main": "code/main.js", |
# sergeant | ||
A very minimal CLI solution that passes commands to async-done, provides --help for individual commands and the application as a whole. A work in progress. | ||
A CLI solution inspired by [Commander.js](https://github.com/tj/commander.js) and [gulp](https://github.com/gulpjs/gulp). | ||
Essentially I was using gulp for all sorts of things, and got sick of having to either separate anything that had parameters out of the gulpfile, or just convert those parameters into options. Also I was not happy with any of the existing option parsers. And I wanted built in help with colors. | ||
## an example | ||
```javascript | ||
var sergeant = require('sergeant') | ||
var app = sergeant({ | ||
description: 'an example application' | ||
}) | ||
app.command('command1', { | ||
// the settings object is optional | ||
// description, parameters, and options are used for --help | ||
description: 'an example command', | ||
parameters: { | ||
parameter1: 'an example parameter' | ||
}, | ||
options: { | ||
'--option1': 'an example option' | ||
}, | ||
// aliases are converted to options | ||
aliases: { | ||
o: { option1: true } | ||
'not-option1': { option1: false } | ||
} | ||
}, function (parameter1, options, done) { | ||
// validate parameters and options by throwing exceptions | ||
assert.ok(typeof parameter1 === 'string') | ||
// actions can have any number of parameters | ||
// they can use the done callback, or use any of the other strategies of completion supported by async-done | ||
done() | ||
}) | ||
app.command('command2', | ||
// parallel and series return a function that takes options and done. Options are passed along to all nested functions when run. Every function may use the done callback or anything supported by async-done | ||
sergeant.parallel( | ||
function (options, done) { | ||
}, | ||
sergeant.series( | ||
function (options) { | ||
}, | ||
function (options) { | ||
} | ||
) | ||
)) | ||
``` |
@@ -69,4 +69,20 @@ require('../mock/output.js') | ||
it('provides help for each command (description, usage, options, aliases)', function (done) { | ||
it('provides help for the whole app', function (done) { | ||
var output = require('../mock/output.js')() | ||
var app = new Application({}, ['help', {}]) | ||
app.run(function (err) { | ||
assert.ifError(err) | ||
assert.deepEqual(output.logs(), [ | ||
chalk.magenta('Commands:'), | ||
' ' + chalk.cyan('[options] help ') + ' provides help for the application' | ||
]) | ||
done() | ||
}) | ||
}) | ||
it('provides help for each command (description, usage, parameters, options, aliases)', function (done) { | ||
var output = require('../mock/output.js')() | ||
var app = new Application({description: 'a test app'}, ['test', { help: true } ]) | ||
@@ -76,2 +92,5 @@ | ||
description: 'test command', | ||
parameters: { | ||
'arg': 'an argument' | ||
}, | ||
options: { | ||
@@ -97,2 +116,4 @@ '--option': 'an option', | ||
chalk.magenta('Usage:') + ' [options] test <arg>', | ||
chalk.magenta('Parameters:'), | ||
' ' + chalk.cyan('arg') + ' an argument', | ||
chalk.magenta('Options:'), | ||
@@ -99,0 +120,0 @@ ' ' + chalk.cyan('--help') + ' provide help for this command', |
@@ -165,3 +165,3 @@ require('../mock/output.js') | ||
it('gathers errors from commands', function (done) { | ||
it('gathers errors from commands (thrown)', function (done) { | ||
var output = require('../mock/output.js')() | ||
@@ -174,2 +174,22 @@ var app = new Application({description: 'a test app'}, ['test', 'testing', {}]) | ||
}, function (arg, options, d) { | ||
throw new Error('nothing bad happened') | ||
}) | ||
app.run(function (err) { | ||
assert.deepEqual(output.errors(), [ chalk.red('Error: nothing bad happened') ]) | ||
assert.equal(err.message, 'nothing bad happened') | ||
done() | ||
}) | ||
}) | ||
it('gathers errors from commands (callback)', function (done) { | ||
var output = require('../mock/output.js')() | ||
var app = new Application({description: 'a test app'}, ['test', 'testing', {}]) | ||
app.command('test', { | ||
description: 'test command', | ||
options: {'--option': 'an option'} | ||
}, function (arg, options, d) { | ||
d(new Error('nothing bad happened')) | ||
@@ -176,0 +196,0 @@ }) |
28756
789
57