cmd-line
Version:
Allows you to create command line tools fast and easy.
174 lines (167 loc) • 4.74 kB
JavaScript
'use strict';
exports.__esModule = true;
require('colors');
const configuration = require('./configuration');
const co = require('co');
const inflect = require('inflection');
class Option {
constructor(option) {
// if (option instanceof Array) {
let shortag = option[0];
let [tag, variable, defvalue] = option[1].split(' ');
shortag = shortag === tag ? '' : shortag;
variable = variable || '';
if (shortag === '') {
shortag = tag;
tag = '';
}
this.shortag = shortag;
this.tag = tag;
this.variable = variable;
this.defvalue = defvalue;
this.description = option[2];
}
}
class Command {
constructor(cmd, description) {
this.cmd = cmd.split(/[\\/]/).pop().replace('.js', '');
this.description = description;
this.args = [];
this.options = [new Option(['-h', '--help', 'Show the help for this command'])];
this.action = /* istanbul ignore next */() => {};
this.help = help => {
print(help);
};
}
Help(fn) {
if (!fn) {
return this;
}
this.help = function (...args) {
return co.wrap(fn)(...args);
};
return this;
}
Args(...args) {
this.args = args;
return this;
}
Options(optionArray) {
/* istanbul ignore else */
if (optionArray instanceof Array && optionArray[0] instanceof Array) {
for (const option of optionArray) {
this.options.push(new Option(option));
}
} else if (optionArray instanceof Array) {
this.options.push(new Option(optionArray));
}
return this;
}
Action(fn) {
if (!fn) {
return this;
}
this.action = function (...args) {
return co.wrap(fn)(...args);
};
return this;
}
get Info() {
let longest = 0;
let varlen = 0;
for (const opt of this.options) {
if (opt.shortag.length + opt.tag.length > longest) {
longest = opt.shortag.length + opt.tag.length;
}
if (opt.variable.length > varlen) {
varlen = opt.variable.length;
}
}
longest += 4;
return configuration.template(configuration.name, this.cmd, configuration.argSerializer(this.args), this.options.map(o => configuration.optionSerializer(o, longest, varlen)), this.description);
}
static parse( /* istanbul ignore next */params = []) {
let ARGS = params.slice();
let arg;
let finalargs = [];
for (const idx in this.args) {
const arg = this.args[idx];
if (arg.indexOf('?') === -1) {
finalargs[idx] = null;
} else {
finalargs[idx] = undefined;
}
}
let argindex = 0;
while ((arg = ARGS.shift()) && arg.search(/^\-/) === -1) {
let idx = params.indexOf(arg);
params.splice(idx, 1);
finalargs[argindex] = arg;
argindex++;
}
for (const arg in finalargs) {
if (finalargs[arg] === null) {
throw new Error(`\nParameter ${this.args[arg].red} must be specfied!\n`);
}
}
let opts = params.slice();
let options = {};
for (const option of this.options) {
let camelizedOption = inflect.titleize(option.tag || option.shortag).replace(/^\-+/g, '').replace(/\-/g, ' ').replace(/ /g, '');
camelizedOption = inflect.camelize(camelizedOption, true);
let OPTS = opts.slice();
let arg = OPTS.shift();
options[camelizedOption] = false;
while (arg) {
let index = opts.indexOf(arg);
if (option.tag === arg || option.shortag === arg) {
opts.splice(index, 1);
options[camelizedOption] = true;
if (option.variable) {
options[camelizedOption] = ARGS.splice(index, 1)[0] || option.defvalue;
opts.splice(index, 1);
if (options[camelizedOption] === undefined) {
throw new Error(`The option ${option.tag || /* istanbul ignore next */option.shortag} needs a value`);
}
} else {
options[camelizedOption] = true;
}
} else if (option.shortag.length === 2 && arg.indexOf('-') === 0) {
let st = option.shortag.replace('-', '');
let len = arg.indexOf(st);
if (arg.indexOf('--') === -1 && len > 0) {
options[camelizedOption] = true;
opts[index] = opts[index].replace(st, '');
}
}
arg = OPTS.shift();
}
}
finalargs.push(options);
return finalargs;
}
static execute(args) {
if (this.args.length > 0 && args.length === 0) {
print(this.Info);
return 1;
} else if (args.length === 1 && (args[0] === '-h' || args[0] === '--help')) {
/* istanbul ignore else */
if (this.help) {
return Promise.resolve(this.help(this.Info)).then((result = 0) => {
return result === 0 ? 0 : /* istanbul ignore next */1;
}).catch( /* istanbul ignore next */err => {
print(err.stack);
return 1;
});
}
} else {
return this.action.apply(this, Command.parse.call(this, args)).then((result = 0) => {
return result === 0 ? 0 : 1;
}).catch(err => {
print(err.stack);
return 1;
});
}
}
}
exports.default = Command;