Comparing version 20.1.0 to 20.2.0
113
help.js
@@ -5,3 +5,3 @@ const chalk = require('chalk') | ||
module.exports = function (name, description, {options, parameters, commands}) { | ||
module.exports = function (title, description, {options, parameters, commands}) { | ||
process.exitCode = 1 | ||
@@ -15,22 +15,15 @@ | ||
if (parameters.length || options.length) { | ||
const usages = getUsages(name, {options, parameters, commands}) | ||
console.error('') | ||
console.error('') | ||
console.error(chalk.green('Usage:') + ' ' + getUsage(title, {options, parameters})) | ||
if (usages.length > 1) { | ||
console.error(chalk.green('Usage:')) | ||
const longestArg = longest([ | ||
...parameters.map(function (definition) { | ||
return '<' + definition.key + '>' | ||
}), | ||
...options.map(function (definition) { | ||
return getOptionSignature(definition) | ||
}) | ||
]) | ||
console.error('') | ||
for (const usage of usages) { | ||
console.error(usage) | ||
} | ||
} else { | ||
console.error(chalk.green('Usage:') + ' ' + usages[0]) | ||
} | ||
} | ||
parameters = getNested('parameters', {parameters, commands}) | ||
if (parameters.length) { | ||
@@ -43,11 +36,7 @@ console.error('') | ||
const longestParameter = longest(parameters.map(function (definition) { | ||
return definition.key | ||
})) | ||
for (const definition of parameters) { | ||
const description = ['<' + definition.key + '>' + spaces(longestParameter - definition.key.length) + ' '] | ||
let line = '<' + definition.key + '>' + spaces(longestArg - definition.key.length - 2) + ' ' | ||
if (definition.description) { | ||
description.push(definition.description) | ||
line += chalk.gray(definition.description) + ' ' | ||
} | ||
@@ -59,12 +48,10 @@ | ||
if (_default != null) { | ||
description.push((definition.description ? ' ' : '') + chalk.gray('[default: ' + JSON.stringify(_default) + ']')) | ||
line += chalk.gray('[default: ' + JSON.stringify(_default) + ']') | ||
} | ||
} | ||
console.error(description.join('')) | ||
console.error(line.trim()) | ||
} | ||
} | ||
options = getNested('options', {options, commands}) | ||
if (options.length) { | ||
@@ -77,12 +64,8 @@ console.error('') | ||
const longestOption = longest(options.map(function (definition) { | ||
return getOptionWithDashesAndAliases(definition) | ||
})) | ||
for (const definition of options) { | ||
const signature = getOptionWithDashesAndAliases(definition) | ||
const description = [signature + spaces(longestOption - signature.length) + ' '] | ||
const signature = getOptionSignature(definition) | ||
let line = signature + spaces(longestArg - signature.length) + ' ' | ||
if (definition.description) { | ||
description.push(definition.description) | ||
line += chalk.gray(definition.description) + ' ' | ||
} | ||
@@ -94,15 +77,23 @@ | ||
if (_default != null) { | ||
description.push((definition.description ? ' ' : '') + chalk.gray('[default: ' + JSON.stringify(_default) + ']')) | ||
line += chalk.gray('[default: ' + JSON.stringify(_default) + ']') | ||
} | ||
} | ||
console.error(description.join('')) | ||
console.error(line.trim()) | ||
} | ||
} | ||
if (commands.length) { | ||
console.error('') | ||
console.error(chalk.green('Commands:')) | ||
commandList(title, commands) | ||
} | ||
console.error('') | ||
} | ||
function getUsages (name, {options, parameters, commands}) { | ||
let usage = [name] | ||
function getUsage (title, {options, parameters}) { | ||
let usage = [title] | ||
@@ -115,3 +106,3 @@ if (options && options.length) { | ||
return getWithBracketsParensAndEllipsis(addDashes(definition.key) + valPart, definition) | ||
return wrapUsage(addDashes(definition.key) + valPart, definition) | ||
})) | ||
@@ -122,28 +113,10 @@ } | ||
usage = usage.concat(parameters.map(function (definition) { | ||
return getWithBracketsParensAndEllipsis('<' + definition.key + '>', definition) | ||
return wrapUsage('<' + definition.key + '>', definition) | ||
})) | ||
} | ||
let usages = [usage.join(' ')] | ||
if (commands) { | ||
for (const command of commands) { | ||
usages = usages.concat(getUsages(name + ' ' + command.name, command.action)) | ||
} | ||
} | ||
return usages | ||
return usage.join(' ') | ||
} | ||
function getNested (id, obj) { | ||
if (obj.commands) { | ||
for (const command of obj.commands) { | ||
obj[id] = obj[id].concat(getNested(id, command.action)) | ||
} | ||
} | ||
return obj[id].filter((a, i) => obj[id].findIndex((b) => a.key === b.key) === i) | ||
} | ||
function getWithBracketsParensAndEllipsis (usage, {required, multiple}) { | ||
function wrapUsage (usage, {required, multiple}) { | ||
const opt = usage.startsWith('-') | ||
@@ -154,3 +127,3 @@ | ||
function getOptionWithDashesAndAliases (definition) { | ||
function getOptionSignature (definition) { | ||
let val = definition.type != null | ||
@@ -167,1 +140,17 @@ ? ' <' + definition.type.name + '>' | ||
} | ||
function commandList (title, commands) { | ||
for (const command of commands) { | ||
console.error('') | ||
console.error(getUsage(title + ' ' + command.title, command)) | ||
if (command.description) { | ||
console.error('') | ||
console.error(' ' + chalk.gray(command.description)) | ||
} | ||
commandList(title + ' ' + command.title, command.commands) | ||
} | ||
} |
48
main.js
const parse = require('./parse') | ||
const error = require('./error') | ||
const help = require('./help') | ||
const assert = require('assert') | ||
// const assert = require('assert') | ||
module.exports = function sergeant (name, description, define, parent = {}) { | ||
module.exports = function sergeant (path, description, define) { | ||
const title = path.split(' ').reverse()[0] | ||
if (define == null) { | ||
@@ -15,3 +17,3 @@ define = description | ||
const filtered = argv.filter((arg) => arg !== '-' && !arg.startsWith('-')) | ||
const command = cli.commands.find((command) => command.name === filtered[0]) | ||
const command = cli.commands.find((command) => command.title === filtered[0]) | ||
@@ -23,3 +25,3 @@ if (filtered[0] != null && command != null) { | ||
command.action(argv) | ||
command(argv) | ||
} else { | ||
@@ -31,3 +33,3 @@ const args = parse(argv, {options: cli.options, parameters: cli.parameters}) | ||
if (args.help === true || action == null) { | ||
help(name, description, {options: cli.options, parameters: cli.parameters, commands: cli.commands}) | ||
help(path, description, {options: cli.options, parameters: cli.parameters, commands: cli.commands}) | ||
} else if (action != null) { | ||
@@ -47,4 +49,6 @@ const result = action(args) | ||
cli.name = name | ||
cli.title = title | ||
cli.description = description | ||
cli.options = [] | ||
@@ -56,6 +60,4 @@ | ||
const option = getAppender('options') | ||
const action = define({option, parameter, command}) | ||
const parameter = getAppender('parameters') | ||
option('help', { | ||
@@ -66,7 +68,5 @@ aliases: ['h'], | ||
const action = define({option, parameter, command}) | ||
return cli | ||
function command (subname, description, define) { | ||
function command (subtitle, description, define) { | ||
if (define == null) { | ||
@@ -78,24 +78,16 @@ define = description | ||
cli.commands.push({ | ||
name: subname, | ||
action: sergeant(name + ' ' + subname, description, define, cli), | ||
description | ||
}) | ||
cli.commands.push(sergeant(path.split(' ').concat([ subtitle ]).join(' '), description, define)) | ||
} | ||
function getAppender (id) { | ||
return function (key, definition) { | ||
const current = Object.assign(definition, {key}) | ||
function option (key, definition) { | ||
const current = Object.assign(definition, {key}) | ||
if (parent[id] != null) { | ||
const prev = parent[id].find((option) => option.key === key) | ||
cli.options.push(current) | ||
} | ||
if (prev != null) { | ||
assert.deepStrictEqual(current, prev, 'the defintion of ' + key + ' can not be changed') | ||
} | ||
} | ||
function parameter (key, definition) { | ||
const current = Object.assign(definition, {key}) | ||
cli[id].push(current) | ||
} | ||
cli.parameters.push(current) | ||
} | ||
} |
{ | ||
"name": "sergeant", | ||
"version": "20.1.0", | ||
"version": "20.2.0", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "main": "main.js", |
@@ -29,5 +29,3 @@ # sergeant | ||
return function (args) { | ||
args.name = 'world' | ||
say(args) | ||
say('world', args.loud) | ||
} | ||
@@ -39,11 +37,11 @@ }) | ||
say(args) | ||
say(args.name, args.loud) | ||
} | ||
})(process.argv.slice(2)) | ||
function say (args) { | ||
let message = `hello ${args.name}!` | ||
function say (name, loud = false) { | ||
let message = `hello ${name}!` | ||
if (args.loud) { | ||
message = message.toUpperCase() | ||
if (loud) { | ||
message = message.toUpperCase() + '!' | ||
} | ||
@@ -50,0 +48,0 @@ |
111
test.js
@@ -434,34 +434,31 @@ const test = require('tape') | ||
{ | ||
name: 'sub', | ||
title: 'sub', | ||
description: 'a sub command', | ||
action: { | ||
parameters: [{ | ||
key: 'p1', | ||
description: 'the description', | ||
required: true | ||
}], | ||
options: [{ | ||
key: 'bbb', | ||
aliases: ['b'], | ||
description: 'a Boolean' | ||
}], | ||
commands: [ | ||
{ | ||
name: 'sub-sub', | ||
description: 'a sub sub command', | ||
action: { | ||
parameters: [{ | ||
key: 'p2', | ||
description: 'the description', | ||
required: true | ||
}], | ||
options: [{ | ||
key: 'ccc', | ||
aliases: ['c'], | ||
description: 'a Boolean' | ||
}] | ||
} | ||
} | ||
] | ||
} | ||
parameters: [{ | ||
key: 'p1', | ||
description: 'the description', | ||
required: true | ||
}], | ||
options: [{ | ||
key: 'bbb', | ||
aliases: ['b'], | ||
description: 'a Boolean' | ||
}], | ||
commands: [ | ||
{ | ||
title: 'sub-sub', | ||
description: 'a sub sub command', | ||
commands: [], | ||
parameters: [{ | ||
key: 'p2', | ||
description: 'the description', | ||
required: true | ||
}], | ||
options: [{ | ||
key: 'ccc', | ||
aliases: ['c'], | ||
description: 'a Boolean' | ||
}] | ||
} | ||
] | ||
} | ||
@@ -494,9 +491,9 @@ ] | ||
'', | ||
'<p0> the description', | ||
'<p1> ' + chalk.gray('[default: ["a","b"]]'), | ||
'<p0> ' + chalk.gray('the description'), | ||
'<p1> ' + chalk.gray('[default: ["a","b"]]'), | ||
'', | ||
chalk.green('Options:'), | ||
'', | ||
'-a, --aaa a Boolean', | ||
'-b <val>, --bbb <val> a Number ' + chalk.gray('[default: 100]'), | ||
'-a, --aaa ' + chalk.gray('a Boolean'), | ||
'-b <val>, --bbb <val> ' + chalk.gray('a Number') + ' ' + chalk.gray('[default: 100]'), | ||
'', | ||
@@ -506,21 +503,23 @@ '', | ||
'', | ||
chalk.green('Usage:'), | ||
chalk.green('Usage:') + ' test-command [--aaa] <p0>', | ||
'', | ||
'test-command [--aaa] <p0>', | ||
'test-command sub [--bbb] <p1>', | ||
'test-command sub sub-sub [--ccc] <p2>', | ||
'', | ||
chalk.green('Parameters:'), | ||
'', | ||
'<p0> the description', | ||
'<p1> the description', | ||
'<p2> the description', | ||
'<p0> ' + chalk.gray('the description'), | ||
'', | ||
chalk.green('Options:'), | ||
'', | ||
'-a, --aaa a Boolean', | ||
'-b, --bbb a Boolean', | ||
'-c, --ccc a Boolean', | ||
'-a, --aaa ' + chalk.gray('a Boolean'), | ||
'', | ||
chalk.green('Commands:'), | ||
'', | ||
'test-command sub [--bbb] <p1>', | ||
'', | ||
' ' + chalk.gray('a sub command'), | ||
'', | ||
'test-command sub sub-sub [--ccc] <p2>', | ||
'', | ||
' ' + chalk.gray('a sub sub command'), | ||
'', | ||
'', | ||
'a test command', | ||
@@ -532,6 +531,8 @@ '', | ||
'', | ||
'-a, --aaa a Boolean', | ||
'-a, --aaa ' + chalk.gray('a Boolean'), | ||
'', | ||
'', | ||
'a test command', | ||
'', | ||
chalk.green('Usage:') + ' test-command', | ||
'' | ||
@@ -610,9 +611,9 @@ ], messages) | ||
{ | ||
key: 'bbb', | ||
testing: true | ||
}, | ||
{ | ||
key: 'help', | ||
aliases: [ 'h' ], | ||
description: 'get help' | ||
}, | ||
{ | ||
key: 'bbb', | ||
testing: true | ||
} | ||
@@ -673,9 +674,9 @@ ], | ||
{ | ||
key: 'bbb', | ||
testing: true | ||
}, | ||
{ | ||
key: 'help', | ||
aliases: [ 'h' ], | ||
description: 'get help' | ||
}, | ||
{ | ||
key: 'bbb', | ||
testing: true | ||
} | ||
@@ -682,0 +683,0 @@ ], |
31994
1017
101