Comparing version 16.0.1 to 16.1.0
90
help.js
const chalk = require('chalk') | ||
const { console, process } = require('./src/globals') | ||
const { isNumber, addDashes, longest, spaces, quoteString } = require('./src/helpers') | ||
const { addDashes, longest, spaces, quoteString } = require('./src/helpers') | ||
module.exports = function (name, description, definitions, commands = {}) { | ||
definitions = Object.assign({}, definitions) | ||
module.exports = function (name, description, {options, parameters, commands}) { | ||
process.exitCode = 1 | ||
@@ -16,39 +14,18 @@ | ||
Object.keys(definitions).forEach(function (key) { | ||
const definition = definitions[key] | ||
if (isNumber(key)) { | ||
definition.signature = definition.key | ||
} else { | ||
definition.signature = addDashes(definition.key) | ||
if (definition.aliases != null && definition.aliases.length) { | ||
definition.signature += ',' + definition.aliases.map((k) => addDashes(k)).join(',') | ||
} | ||
} | ||
}) | ||
const parameterKeys = Object.keys(definitions).filter((key) => isNumber(key)) | ||
const optionKeys = Object.keys(definitions).filter((key) => isNumber(key) === false) | ||
if (parameterKeys.length || optionKeys.length) { | ||
if (parameters.length || options.length) { | ||
let usage = [name] | ||
if (optionKeys.length) { | ||
usage = usage.concat(optionKeys.map((key) => { | ||
const definition = definitions[key] | ||
if (options.length) { | ||
usage = usage.concat(options.map((definition) => { | ||
const valPart = definition.type !== Boolean | ||
? '=' + '<' + (definition.type ? definition.type.name : key) + '>' | ||
? '=<' + (definition.type ? definition.type.name : 'String') + '>' | ||
: '' | ||
return wrapUsage(definition.signature + valPart, definition) | ||
return wrapUsage(getSignature(definition) + valPart, definition) | ||
})) | ||
} | ||
if (parameterKeys.length) { | ||
usage = usage.concat(parameterKeys.map((key) => { | ||
const definition = definitions[key] | ||
return wrapUsage('<' + definition.signature + '>', definition) | ||
if (parameters.length) { | ||
usage = usage.concat(parameters.map((definition) => { | ||
return wrapUsage('<' + definition.key + '>', definition) | ||
})) | ||
@@ -59,3 +36,3 @@ } | ||
if (Object.keys(commands).length) { | ||
if (commands.length) { | ||
console.error(chalk.green('Usage:')) | ||
@@ -73,3 +50,3 @@ | ||
if (parameterKeys.length) { | ||
if (parameters.length) { | ||
console.error('') | ||
@@ -81,9 +58,8 @@ | ||
const longestParameter = longest(parameterKeys.map((key) => { | ||
return definitions[key].signature | ||
const longestParameter = longest(parameters.map((definition) => { | ||
return definition.key | ||
})) | ||
parameterKeys.forEach((key) => { | ||
const definition = definitions[key] | ||
const description = [spaces(longestParameter - definition.signature.length) + definition.signature] | ||
parameters.forEach((definition) => { | ||
const description = [spaces(longestParameter - definition.key.length) + definition.key] | ||
@@ -102,3 +78,3 @@ if (definition.description) { | ||
if (optionKeys.length) { | ||
if (options.length) { | ||
console.error('') | ||
@@ -110,9 +86,9 @@ | ||
const longestOption = longest(optionKeys.map((key) => { | ||
return definitions[key].signature | ||
const longestOption = longest(options.map((definition) => { | ||
return getSignature(definition) | ||
})) + 1 | ||
optionKeys.forEach((key) => { | ||
const definition = definitions[key] | ||
const description = [spaces(longestOption - definition.signature.length) + definition.signature] | ||
options.forEach((definition) => { | ||
const signature = getSignature(definition) | ||
const description = [spaces(longestOption - signature.length) + signature] | ||
@@ -131,7 +107,5 @@ if (definition.description) { | ||
const commandKeys = Object.keys(commands) | ||
if (commands.length) { | ||
const longestCommand = longest(commands.map((command) => command.name)) | ||
if (commandKeys.length) { | ||
const longestCommand = longest(commandKeys) | ||
console.error('') | ||
@@ -143,6 +117,4 @@ | ||
commandKeys.forEach((key) => { | ||
const command = commands[key] | ||
console.error(key + (command.description ? ' ' + spaces(longestCommand - key.length) + chalk.gray(command.description != null ? command.description : '') : '')) | ||
commands.forEach((command) => { | ||
console.error(command.name + (command.description ? ' ' + spaces(longestCommand - command.name.length) + chalk.gray(command.description != null ? command.description : '') : '')) | ||
}) | ||
@@ -157,1 +129,11 @@ } | ||
} | ||
function getSignature (definition) { | ||
let signature = addDashes(definition.key) | ||
if (definition.aliases != null && definition.aliases.length) { | ||
signature += ',' + definition.aliases.map((k) => addDashes(k)).join(',') | ||
} | ||
return signature | ||
} |
24
main.js
@@ -12,4 +12,5 @@ const parse = require('./parse') | ||
const definitions = {} | ||
const commands = {} | ||
const options = [] | ||
const parameters = [] | ||
const commands = [] | ||
@@ -22,3 +23,2 @@ option('help', { | ||
let i = 0 | ||
const action = define({option, parameter, command}) | ||
@@ -28,4 +28,5 @@ | ||
const filtered = argv.filter((arg) => arg !== '-' && !arg.startsWith('-')) | ||
const command = commands.find((command) => command.name === filtered[0]) | ||
if (filtered[0] != null && commands[filtered[0]] != null) { | ||
if (filtered[0] != null && command != null) { | ||
const index0 = argv.indexOf(filtered[0]) | ||
@@ -35,5 +36,5 @@ | ||
commands[filtered[0]].action(argv) | ||
command.action(argv) | ||
} else { | ||
const args = parse(argv, definitions) | ||
const args = parse(argv, {options, parameters}) | ||
@@ -43,3 +44,3 @@ try { | ||
if (args.help === true || action == null) { | ||
help(name, description, definitions, commands) | ||
help(name, description, {options, parameters, commands}) | ||
} else if (action != null) { | ||
@@ -66,14 +67,15 @@ const result = action(args) | ||
commands[subname] = { | ||
commands.push({ | ||
name: subname, | ||
action: sergeant(name + ' ' + subname, description, define), | ||
description | ||
} | ||
}) | ||
} | ||
function option (key, definition) { | ||
definitions[key] = getDefinition(key, definition) | ||
options.push(getDefinition(key, definition)) | ||
} | ||
function parameter (key, definition) { | ||
definitions[i++] = getDefinition(key, definition) | ||
parameters.push(getDefinition(key, definition)) | ||
} | ||
@@ -80,0 +82,0 @@ |
{ | ||
"name": "sergeant", | ||
"version": "16.0.1", | ||
"version": "16.1.0", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "main": "main.js", |
41
parse.js
const chalk = require('chalk') | ||
const { console, process } = require('./src/globals') | ||
const { isNumber, addDashes, getDefault } = require('./src/helpers') | ||
const { addDashes, getDefault, getProperty } = require('./src/helpers') | ||
module.exports = function (argv, definitions) { | ||
module.exports = function (argv, {options, parameters}) { | ||
try { | ||
definitions = Object.assign({}, definitions) | ||
argv = argv.slice(0) | ||
const args = {} | ||
Object.keys(definitions).forEach((key) => { | ||
const definition = definitions[key] | ||
options = options.reduce((options, definition) => { | ||
definition = Object.assign({}, definition, {property: getProperty(definition)}) | ||
const split = definition.key.split('-') | ||
options.push(definition) | ||
definition.property = split[0] + split.slice(1).map((part) => part.substr(0, 1).toUpperCase() + part.substr(1)).join('') | ||
if (definition.aliases) { | ||
definition.aliases.forEach((alias) => { | ||
definitions[alias] = Object.assign({}, definition, {alias: true}) | ||
options.push(Object.assign({}, definition, {key: alias, alias: true})) | ||
}) | ||
} | ||
}) | ||
return options | ||
}, []) | ||
let afterDashDash = [] | ||
@@ -54,8 +52,6 @@ const indexOfDashDash = argv.indexOf('--') | ||
const toBeDeleted = [] | ||
const optionKeys = Object.keys(definitions).filter((key) => isNumber(key) === false) | ||
for (let i = 0; i < argv.length; i++) { | ||
optionKeys.forEach((key) => { | ||
const search = addDashes(key) | ||
const definition = definitions[key] | ||
options.forEach((definition) => { | ||
const search = addDashes(definition.key) | ||
const property = definition.property | ||
@@ -102,4 +98,3 @@ let vals = [] | ||
optionKeys.filter((key) => definitions[key].alias !== true).forEach((key) => { | ||
const definition = definitions[key] | ||
options.filter((option) => options.alias !== true).forEach((definition) => { | ||
const property = definition.property | ||
@@ -134,13 +129,11 @@ | ||
const parameterKeys = Object.keys(definitions).filter((key) => isNumber(key)) | ||
const hasMultiple = parameterKeys.filter((key) => definitions[key].multiple).length > 0 | ||
const hasMultiple = parameters.filter((definition) => definition.multiple).length > 0 | ||
if (!hasMultiple && remainder.length > parameterKeys.length) { | ||
if (!hasMultiple && remainder.length > parameters.length) { | ||
throw new Error('too many arguments') | ||
} | ||
parameterKeys.forEach((key) => { | ||
const definition = definitions[key] | ||
const property = definition.property | ||
const remainingKeys = parameterKeys.length - 1 - key | ||
parameters.forEach((definition, key) => { | ||
const property = definition.key | ||
const remainingKeys = parameters.length - 1 - key | ||
@@ -147,0 +140,0 @@ if (!remainder.length) { |
@@ -1,2 +0,2 @@ | ||
module.exports = { addDashes, quoteString, longest, spaces, isNumber, getDefault } | ||
module.exports = { addDashes, quoteString, longest, spaces, getDefault, getProperty } | ||
@@ -27,6 +27,2 @@ function addDashes (key) { | ||
function isNumber (key) { | ||
return Number.isInteger(Number(key)) | ||
} | ||
function getDefault (definition) { | ||
@@ -45,1 +41,8 @@ let result = definition.default | ||
} | ||
function getProperty (definition) { | ||
const split = definition.key.split('-') | ||
const property = split[0] + split.slice(1).map((part) => part.substr(0, 1).toUpperCase() + part.substr(1)).join('') | ||
return property | ||
} |
263
test.js
@@ -17,5 +17,6 @@ const test = require('tape') | ||
t.deepEquals({'test': '-a'}, parse(['--', '-a'], { | ||
'0': { | ||
options: [], | ||
parameters: [{ | ||
key: 'test' | ||
} | ||
}] | ||
})) | ||
@@ -25,6 +26,7 @@ | ||
t.deepEquals({'test': 123}, parse(['--', '123'], { | ||
'0': { | ||
options: [], | ||
parameters: [{ | ||
type: Number, | ||
key: 'test' | ||
} | ||
}] | ||
})) | ||
@@ -34,17 +36,19 @@ | ||
t.deepEquals({}, parse([], { | ||
'0': { | ||
options: [], | ||
parameters: [{ | ||
key: 'test' | ||
} | ||
}] | ||
})) | ||
// test empty | ||
t.deepEquals({}, parse([''], {})) | ||
t.deepEquals({}, parse([''], {options: [], parameters: []})) | ||
// test short | ||
t.deepEquals({aaA: true}, parse(['-a'], { | ||
'aa-a': { | ||
parameters: [], | ||
options: [{ | ||
key: 'aa-a', | ||
type: Boolean, | ||
aliases: ['a'] | ||
} | ||
}] | ||
})) | ||
@@ -54,6 +58,7 @@ | ||
t.deepEquals({aaA: 'bcd'}, parse(['-a=bcd'], { | ||
'aa-a': { | ||
parameters: [], | ||
options: [{ | ||
key: 'aa-a', | ||
aliases: ['a'] | ||
} | ||
}] | ||
})) | ||
@@ -63,10 +68,11 @@ | ||
t.deepEquals({aaA: 'bcd', b: true}, parse(['-ba=bcd'], { | ||
'aa-a': { | ||
parameters: [], | ||
options: [{ | ||
key: 'aa-a', | ||
aliases: ['a'] | ||
}, | ||
b: { | ||
{ | ||
key: 'b', | ||
type: Boolean | ||
} | ||
}] | ||
})) | ||
@@ -76,3 +82,4 @@ | ||
t.deepEquals({aaA: true, b: true}, parse(['-ba'], { | ||
'aa-a': { | ||
parameters: [], | ||
options: [{ | ||
key: 'aa-a', | ||
@@ -82,6 +89,6 @@ type: Boolean, | ||
}, | ||
b: { | ||
{ | ||
key: 'b', | ||
type: Boolean | ||
} | ||
}] | ||
})) | ||
@@ -91,7 +98,8 @@ | ||
t.deepEquals({aaA: ['bcd', '---', '-']}, parse(['-a', 'bcd', '-a', '---', '-a', '-'], { | ||
'aa-a': { | ||
parameters: [], | ||
options: [{ | ||
key: 'aa-a', | ||
multiple: true, | ||
aliases: ['a'] | ||
} | ||
}] | ||
})) | ||
@@ -101,3 +109,4 @@ | ||
t.deepEquals({aaA: ['', ' ']}, parse(['-a'], { | ||
'aa-a': { | ||
parameters: [], | ||
options: [{ | ||
key: 'aa-a', | ||
@@ -108,3 +117,3 @@ aliases: ['a'], | ||
default: ['', ' '] | ||
} | ||
}] | ||
})) | ||
@@ -114,3 +123,4 @@ | ||
t.deepEquals({aaA: ''}, parse(['-a'], { | ||
'aa-a': { | ||
parameters: [], | ||
options: [{ | ||
key: 'aa-a', | ||
@@ -121,3 +131,3 @@ aliases: ['a'], | ||
default: '' | ||
} | ||
}] | ||
})) | ||
@@ -127,7 +137,8 @@ | ||
t.deepEquals({aaA: ''}, parse(['--aa-a='], { | ||
'aa-a': { | ||
parameters: [], | ||
options: [{ | ||
key: 'aa-a', | ||
aliases: ['a'], | ||
default: 'abc' | ||
} | ||
}] | ||
})) | ||
@@ -137,9 +148,10 @@ | ||
t.deepEquals({'0': 'testing', '1': 'yes'}, parse(['testing'], { | ||
'0': { | ||
options: [], | ||
parameters: [{ | ||
key: '0' | ||
}, | ||
'1': { | ||
{ | ||
key: '1', | ||
default: 'yes' | ||
} | ||
}] | ||
})) | ||
@@ -150,3 +162,4 @@ | ||
parse(['1', '2', '3', '4', '5', '6', '7', '8', '9'], { | ||
'0': { | ||
options: [], | ||
parameters: [{ | ||
type: Number, | ||
@@ -156,10 +169,10 @@ key: 'test0', | ||
}, | ||
'1': { | ||
{ | ||
type: Number, | ||
key: 'test1' | ||
}, | ||
'2': { | ||
{ | ||
type: Number, | ||
key: 'test2' | ||
} | ||
}] | ||
})) | ||
@@ -170,14 +183,15 @@ | ||
parse(['1', '2', '3', '4', '5', '6', '7', '8', '9'], { | ||
'0': { | ||
options: [], | ||
parameters: [{ | ||
type: Number, | ||
key: 'test0' | ||
}, | ||
'1': { | ||
{ | ||
key: 'test1', | ||
multiple: true | ||
}, | ||
'2': { | ||
{ | ||
type: Number, | ||
key: 'test2' | ||
} | ||
}] | ||
})) | ||
@@ -188,15 +202,16 @@ | ||
parse(['1', '2', '3', '4', '5', '6', '7', '8', '9'], { | ||
'0': { | ||
options: [], | ||
parameters: [{ | ||
type: Number, | ||
key: 'test0' | ||
}, | ||
'1': { | ||
{ | ||
type: Number, | ||
key: 'test1' | ||
}, | ||
'2': { | ||
{ | ||
type: Number, | ||
key: 'test2', | ||
multiple: true | ||
} | ||
}] | ||
})) | ||
@@ -229,6 +244,7 @@ }) | ||
parse(['-a=abc'], { | ||
a: { | ||
parameters: [], | ||
options: [{ | ||
key: 'a', | ||
type: Boolean | ||
} | ||
}] | ||
}) | ||
@@ -238,20 +254,22 @@ | ||
parse(['--aaa=abc'], { | ||
aaa: { | ||
parameters: [], | ||
options: [{ | ||
key: 'aaa', | ||
type: Boolean | ||
} | ||
}] | ||
}) | ||
// test unknown | ||
parse(['-a'], {}) | ||
parse(['-a'], {options: [], parameters: []}) | ||
// test unknown | ||
parse(['--aaa'], {}) | ||
parse(['--aaa'], {options: [], parameters: []}) | ||
// test required | ||
parse([''], { | ||
a: { | ||
parameters: [], | ||
options: [{ | ||
key: 'a', | ||
required: true | ||
} | ||
}] | ||
}) | ||
@@ -261,6 +279,7 @@ | ||
parse([''], { | ||
aaa: { | ||
parameters: [], | ||
options: [{ | ||
key: 'aaa', | ||
required: true | ||
} | ||
}] | ||
}) | ||
@@ -270,6 +289,7 @@ | ||
parse(['--aaa=123', '--aaa=456'], { | ||
aaa: { | ||
parameters: [], | ||
options: [{ | ||
type: Number, | ||
key: 'aaa' | ||
} | ||
}] | ||
}) | ||
@@ -279,10 +299,11 @@ | ||
parse([], { | ||
'0': { | ||
options: [], | ||
parameters: [{ | ||
key: 'test', | ||
required: true | ||
} | ||
}] | ||
}) | ||
// test too many arguments | ||
parse(['--', '-a'], {}) | ||
parse(['--', '-a'], {options: [], parameters: []}) | ||
@@ -327,42 +348,51 @@ t.equals(globals.process.exitCode, 1) | ||
help('test-command', '', { | ||
'0': { | ||
key: 'p0', | ||
description: 'the description', | ||
required: true | ||
}, | ||
'1': { | ||
key: 'p1', | ||
multiple: true, | ||
default: ['a', 'b'] | ||
}, | ||
'aaa': { | ||
key: 'aaa', | ||
aliases: ['aa', 'a'], | ||
type: Boolean, | ||
multiple: true, | ||
description: 'a Boolean' | ||
}, | ||
'b': { | ||
key: 'b', | ||
type: Number, | ||
description: 'a Number', | ||
default: 100 | ||
} | ||
parameters: [ | ||
{ | ||
key: 'p0', | ||
description: 'the description', | ||
required: true | ||
}, | ||
{ | ||
key: 'p1', | ||
multiple: true, | ||
default: ['a', 'b'] | ||
} | ||
], | ||
options: [ | ||
{ | ||
key: 'aaa', | ||
aliases: ['aa', 'a'], | ||
type: Boolean, | ||
multiple: true, | ||
description: 'a Boolean' | ||
}, | ||
{ | ||
key: 'b', | ||
type: Number, | ||
description: 'a Number', | ||
default: 100 | ||
} | ||
], | ||
commands: [] | ||
}) | ||
help('test-command', 'a test command', { | ||
'0': { | ||
parameters: [{ | ||
key: 'p0', | ||
required: true | ||
} | ||
}, { | ||
'sub-command-b': { | ||
}, | ||
'sub-command': { | ||
description: 'a sub command' | ||
} | ||
}], | ||
options: [], | ||
commands: [ | ||
{ | ||
name: 'sub-command-b' | ||
}, | ||
{ | ||
name: 'sub-command', | ||
description: 'a sub command' | ||
} | ||
] | ||
}) | ||
help('test-command', 'a test command', { | ||
'aaa': { | ||
options: [{ | ||
key: 'aaa', | ||
@@ -373,6 +403,8 @@ aliases: ['aa', 'a'], | ||
description: 'a Boolean' | ||
} | ||
}], | ||
parameters: [], | ||
commands: [] | ||
}) | ||
help('test-command', 'a test command', {}) | ||
help('test-command', 'a test command', {options: [], parameters: [], commands: []}) | ||
@@ -488,16 +520,18 @@ t.plan(2) | ||
t.deepEquals({ | ||
'0': { | ||
options: [ | ||
{ | ||
key: 'help', | ||
aliases: [ 'h' ], | ||
description: 'get help', | ||
type: Boolean | ||
}, | ||
{ | ||
key: 'bbb', | ||
testing: true | ||
} | ||
], | ||
parameters: [{ | ||
key: 'aaa', | ||
testing: true | ||
}, | ||
bbb: { | ||
key: 'bbb', | ||
testing: true | ||
}, | ||
help: { | ||
key: 'help', | ||
aliases: [ 'h' ], | ||
description: 'get help', | ||
type: Boolean | ||
} | ||
}] | ||
}, definitions) | ||
@@ -548,16 +582,19 @@ | ||
t.deepEquals({ | ||
'0': { | ||
options: [ | ||
{ | ||
key: 'help', | ||
aliases: [ 'h' ], | ||
description: 'get help', | ||
type: Boolean | ||
}, | ||
{ | ||
key: 'bbb', | ||
testing: true | ||
} | ||
], | ||
parameters: [{ | ||
key: 'aaa', | ||
testing: true | ||
}, | ||
bbb: { | ||
key: 'bbb', | ||
testing: true | ||
}, | ||
help: { | ||
key: 'help', | ||
aliases: [ 'h' ], | ||
description: 'get help', | ||
type: Boolean | ||
} | ||
}], | ||
commands: [] | ||
}, definitions) | ||
@@ -564,0 +601,0 @@ } |
30033
954