Comparing version 19.4.0 to 19.5.0
@@ -13,3 +13,3 @@ const chalk = require('chalk') | ||
for (let parts of stack.map((line) => line.match(/^(.*?)(\(.*\))?$/))) { | ||
for (const parts of stack.map((line) => line.match(/^(.*?)(\(.*\))?$/))) { | ||
console.error(chalk.gray(parts[1]) + (parts[2] != null ? parts[2] : '')) | ||
@@ -16,0 +16,0 @@ } |
86
help.js
@@ -15,23 +15,7 @@ const chalk = require('chalk') | ||
if (parameters.length || options.length) { | ||
let usage = [name] | ||
const usages = getUsages(name, {options, parameters, commands}) | ||
if (options.length) { | ||
usage = usage.concat(options.map(function (definition) { | ||
const valPart = definition.type != null | ||
? ' <' + definition.type.name + '>' | ||
: '' | ||
return wrapUsage(addDashes(definition.key) + valPart, definition) | ||
})) | ||
} | ||
if (parameters.length) { | ||
usage = usage.concat(parameters.map(function (definition) { | ||
return wrapUsage('<' + definition.key + '>', definition) | ||
})) | ||
} | ||
console.error('') | ||
if (commands.length) { | ||
if (usages.length > 1) { | ||
console.error(chalk.green('Usage:')) | ||
@@ -41,10 +25,12 @@ | ||
console.error(usage.join(' ')) | ||
console.error(name + ' <command> [--help]') | ||
for (const usage of usages) { | ||
console.error(usage) | ||
} | ||
} else { | ||
console.error(chalk.green('Usage:') + ' ' + usage.join(' ')) | ||
console.error(chalk.green('Usage:') + ' ' + usages[0]) | ||
} | ||
} | ||
parameters = getNested('parameters', {parameters, commands}) | ||
if (parameters.length) { | ||
@@ -61,3 +47,3 @@ console.error('') | ||
for (let definition of parameters) { | ||
for (const definition of parameters) { | ||
const description = [spaces(longestParameter - definition.key.length) + definition.key] | ||
@@ -81,2 +67,4 @@ | ||
options = getNested('options', {options, commands}) | ||
if (options.length) { | ||
@@ -90,7 +78,7 @@ console.error('') | ||
const longestOption = longest(options.map(function (definition) { | ||
return getSignature(definition) | ||
return getOptionWithDashesAndAliases(definition) | ||
})) | ||
for (let definition of options) { | ||
const signature = getSignature(definition) | ||
for (const definition of options) { | ||
const signature = getOptionWithDashesAndAliases(definition) | ||
const description = [spaces(longestOption - signature.length) + signature] | ||
@@ -114,20 +102,46 @@ | ||
if (commands.length) { | ||
const longestCommand = longest(commands.map((command) => command.name)) | ||
console.error('') | ||
} | ||
console.error('') | ||
function getUsages (name, {options, parameters, commands}) { | ||
let usage = [name] | ||
console.error(chalk.green('Commands:')) | ||
if (options && options.length) { | ||
usage = usage.concat(options.map(function (definition) { | ||
const valPart = definition.type != null | ||
? ' <' + definition.type.name + '>' | ||
: '' | ||
console.error('') | ||
return getWithBracketsParensAndEllipsis(addDashes(definition.key) + valPart, definition) | ||
})) | ||
} | ||
for (let command of commands) { | ||
console.error(command.name + (command.description ? ' ' + spaces(longestCommand - command.name.length) + chalk.gray(command.description != null ? command.description : '') : '')) | ||
if (parameters && parameters.length) { | ||
usage = usage.concat(parameters.map(function (definition) { | ||
return getWithBracketsParensAndEllipsis('<' + definition.key + '>', definition) | ||
})) | ||
} | ||
let usages = [usage.join(' ')] | ||
if (commands) { | ||
for (const command of commands) { | ||
usages = usages.concat(getUsages(name + ' ' + command.name, command.action)) | ||
} | ||
} | ||
console.error('') | ||
return usages | ||
} | ||
function wrapUsage (usage, {required, multiple}) { | ||
function getNested (id, obj) { | ||
if (obj.commands) { | ||
for (const command of obj.commands) { | ||
obj[id] = obj[id].concat(getNested(id, command.action).filter((a) => obj[id].find((b) => b.key !== a.key))) | ||
} | ||
} | ||
return obj[id] | ||
} | ||
function getWithBracketsParensAndEllipsis (usage, {required, multiple}) { | ||
const opt = usage.startsWith('-') | ||
@@ -138,3 +152,3 @@ | ||
function getSignature (definition) { | ||
function getOptionWithDashesAndAliases (definition) { | ||
let signature = addDashes(definition.key) | ||
@@ -141,0 +155,0 @@ |
65
main.js
const parse = require('./parse') | ||
const error = require('./error') | ||
const help = require('./help') | ||
const assert = require('assert') | ||
module.exports = function sergeant (name, description, define) { | ||
module.exports = function sergeant (name, description, define, parent = {}) { | ||
if (define == null) { | ||
@@ -12,16 +13,5 @@ define = description | ||
const options = [] | ||
const parameters = [] | ||
const commands = [] | ||
option('help', { | ||
aliases: ['h'], | ||
description: 'get help' | ||
}) | ||
const action = define({option, parameter, command}) | ||
return function (argv) { | ||
function cli (argv) { | ||
const filtered = argv.filter((arg) => arg !== '-' && !arg.startsWith('-')) | ||
const command = commands.find((command) => command.name === filtered[0]) | ||
const command = cli.commands.find((command) => command.name === filtered[0]) | ||
@@ -35,3 +25,3 @@ if (filtered[0] != null && command != null) { | ||
} else { | ||
const args = parse(argv, {options, parameters}) | ||
const args = parse(argv, {options: cli.options, parameters: cli.parameters}) | ||
@@ -41,3 +31,3 @@ try { | ||
if (args.help === true || action == null) { | ||
help(name, description, {options, parameters, commands}) | ||
help(name, description, {options: cli.options, parameters: cli.parameters, commands: cli.commands}) | ||
} else if (action != null) { | ||
@@ -57,2 +47,23 @@ const result = action(args) | ||
cli.name = name | ||
cli.options = [] | ||
cli.parameters = [] | ||
cli.commands = [] | ||
const option = getAppender('options') | ||
const parameter = getAppender('parameters') | ||
option('help', { | ||
aliases: ['h'], | ||
description: 'get help' | ||
}) | ||
const action = define({option, parameter, command}) | ||
return cli | ||
function command (subname, description, define) { | ||
@@ -65,5 +76,5 @@ if (define == null) { | ||
commands.push({ | ||
cli.commands.push({ | ||
name: subname, | ||
action: sergeant(name + ' ' + subname, description, define), | ||
action: sergeant(name + ' ' + subname, description, define, cli), | ||
description | ||
@@ -73,9 +84,17 @@ }) | ||
function option (key, definition) { | ||
options.push(Object.assign(definition, {key})) | ||
} | ||
function getAppender (id) { | ||
return function (key, definition) { | ||
const current = Object.assign(definition, {key}) | ||
function parameter (key, definition) { | ||
parameters.push(Object.assign(definition, {key})) | ||
if (parent[id] != null) { | ||
const prev = parent[id].find((option) => option.key === key) | ||
if (prev != null) { | ||
assert.deepStrictEqual(current, prev, 'the defintion of ' + key + ' can not be changed') | ||
} | ||
} | ||
cli[id].push(current) | ||
} | ||
} | ||
} |
{ | ||
"name": "sergeant", | ||
"version": "19.4.0", | ||
"version": "19.5.0", | ||
"description": "", | ||
@@ -22,3 +22,3 @@ "main": "main.js", | ||
"standard": "^11.0.1", | ||
"tape": "^4.9.0" | ||
"tape": "^4.9.1" | ||
}, | ||
@@ -25,0 +25,0 @@ "dependencies": { |
12
parse.js
@@ -16,3 +16,3 @@ const chalk = require('chalk') | ||
if (definition.aliases) { | ||
for (let alias of definition.aliases) { | ||
for (const alias of definition.aliases) { | ||
options.push(Object.assign({}, definition, {key: alias, alias: true})) | ||
@@ -63,6 +63,6 @@ } | ||
for (let i = 0; i < argv.length; i++) { | ||
for (let definition of options) { | ||
for (const definition of options) { | ||
const search = addDashes(definition.key) | ||
const property = definition.property | ||
let vals = [] | ||
const vals = [] | ||
@@ -105,3 +105,3 @@ if (argv[i] === search) { | ||
for (let definition of options.filter((option) => options.alias !== true)) { | ||
for (const definition of options.filter((option) => options.alias !== true)) { | ||
const property = definition.property | ||
@@ -136,3 +136,3 @@ | ||
for (let arg of argv) { | ||
for (const arg of argv) { | ||
if (arg.startsWith('-') && !arg.startsWith('---')) { | ||
@@ -153,3 +153,3 @@ throw new Error('unknown option ' + arg.split('=')[0]) | ||
for (let definition of parameters) { | ||
for (const definition of parameters) { | ||
const property = definition.property | ||
@@ -156,0 +156,0 @@ remainingKeys -= 1 |
60
test.js
@@ -423,12 +423,44 @@ const test = require('tape') | ||
key: 'p0', | ||
description: 'the description', | ||
required: true | ||
}], | ||
options: [], | ||
options: [{ | ||
key: 'aaa', | ||
aliases: ['a'], | ||
description: 'a Boolean' | ||
}], | ||
commands: [ | ||
{ | ||
name: 'sub-command-b' | ||
}, | ||
{ | ||
name: 'sub-command', | ||
description: 'a sub command' | ||
name: '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' | ||
}] | ||
} | ||
} | ||
] | ||
} | ||
} | ||
@@ -474,13 +506,17 @@ ] | ||
'', | ||
'test-command <p0>', | ||
'test-command <command> [--help]', | ||
'test-command [--aaa] <p0>', | ||
'test-command sub [--bbb] <p1>', | ||
'test-command sub sub-sub [--ccc] <p2>', | ||
'', | ||
chalk.green('Parameters:'), | ||
'', | ||
'p0', | ||
'p0 ' + chalk.gray('the description'), | ||
'p1 ' + chalk.gray('the description'), | ||
'p2 ' + chalk.gray('the description'), | ||
'', | ||
chalk.green('Commands:'), | ||
chalk.green('Options:'), | ||
'', | ||
'sub-command-b', | ||
'sub-command ' + chalk.gray('a sub command'), | ||
'-a, --aaa ' + chalk.gray('a Boolean'), | ||
'-b, --bbb ' + chalk.gray('a Boolean'), | ||
'-c, --ccc ' + chalk.gray('a Boolean'), | ||
'', | ||
@@ -487,0 +523,0 @@ '', |
32557
1029