node-getopt-long
Version:
Sophisticated command line argument parser
303 lines (261 loc) • 7.75 kB
JavaScript
/* global require */
var _ = require('underscore');
function strSplit(str, match, limit) {
var split = str.split(match);
var newSplit = [];
var i = 0;
while (i < limit - 1) {
newSplit.push(split.shift());
i++;
}
newSplit.push(split.join(match));
return newSplit;
}
function padToOrNewLine(str, max) {
if (str.length >= max) {
return str + '\n' + padToOrNewLine('', max);
}
while (str.length < max) {
str = str + ' ';
}
return str;
}
var getoptLongParam = function (details) {
this.test = [];
this.possible = [];
this.short = [];
this.setNames(details[0]);
this.parent = details[1].parent;
this.description = details[1].description;
this.on = details[1].on;
if (details[1].test) {
this.test.push(details[1].test);
}
if (details[1].paramName) {
this.paramName = details[1].paramName;
} else if (details[1].test instanceof Array) {
this.paramName = details[1].test.join('|');
}
};
getoptLongParam.prototype.VERSION = '0.4.0';
getoptLongParam.prototype.name = '';
getoptLongParam.prototype.value = null;
getoptLongParam.prototype.paramName = null;
getoptLongParam.prototype.negatable = false;
getoptLongParam.prototype.increment = false;
getoptLongParam.prototype.parameter = false;
getoptLongParam.prototype.autoNo = false;
getoptLongParam.prototype.arrayTest = function (values, value) {
for (var i = 0; i < values.length; i++) {
if (values[i] === value) {
return value;
}
}
throw '--' + this.name + ' must be one of ' + values.join(', ') + '\n';
};
var testInt = function (value, key, parent, self) {
if ('' + value === '' + parseInt(value, 10)) {
return parseInt(value, 10);
}
else {
throw '--' + self.name + ' must be an integer\n';
}
};
var testFloat = function (value, key, parent, self) {
if ('' + value === '' + parseFloat(value)) {
return parseFloat(value);
}
else {
throw '--' + self.name + ' must be an number\n';
}
};
getoptLongParam.prototype.setNames = function (spec) {
var parts = spec.split(/(?=[!+=])/);
var names = parts[0].split(/[|]/);
this.name = names[0];
this.possible = names;
this.short = [];
if (parts[1] === '!') {
this.negatable = true;
}
else if (parts[1] === '+') {
if (parts[2] === '+') {
this.parameter = true;
this.autoNo = true;
this.paramName = 'int';
this.test.push(testInt);
}
else {
this.increment = true;
}
}
else if (parts[1] && parts[1].substr(0, 1) === '=') {
this.setValueParam(parts);
}
_.each(names, function (name) {
if (name.length === 1) {
this.short.push(name);
}
}.bind(this));
};
getoptLongParam.prototype.setValueParam = function (parts) {
this.parameter = true;
var type = parts[1].substr(1);
if (type && type.substr(0, 1) === 'i') {
this.test.push(testInt);
type = type.substr(1);
this.paramName = 'int';
}
else if (type && (type.substr(0, 1) === 'd' || type.substr(0, 1) === 'f')) {
this.test.push(testFloat);
type = type.substr(1);
this.paramName = 'float';
}
else {
this.paramName = 'string';
type = type.length === 2 ? type.substr(1) : type;
}
if (type) {
if (type === '@') {
this.list = true;
this.value = [];
}
else if (type === '%') {
this.object = true;
this.value = {};
}
}
};
getoptLongParam.prototype.process = function (arg1, arg2) {
var value;
var key;
var possibleMatch = function (name) {
if (this.parameter && arg1.match(/=/)) {
return '--' + name === arg1.split(/=/, 2)[0];
}
return '--' + name === arg1;
}.bind(this);
var shortMatch = function (name) {
return '-' + name === arg1.substr(0, 2);
};
var long = this.possible.reduce(function (prev, cur) {
if (possibleMatch(cur)) {
prev.push(cur);
}
return prev;
}, []).length;
var short = this.short.reduce(function (prev, cur) {
if (shortMatch(cur)) {
prev.push(cur);
}
return prev;
}, []).length;
var auto = this.autoNo ? arg1.match(/^-(\d+)$/) : false;
if (long || short || auto) {
var count = 1;
if (this.increment) {
this.value = this.value ? this.value + 1 : 1;
}
else if (this.parameter) {
var valCount = this.extractValue(key, value, short, auto, arg1, arg2);
value = valCount[0];
if (valCount.length === 2) {
count = valCount[1];
}
if (this.object) {
var keyVal = strSplit(value, '=', 2);
key = keyVal[0];
value = keyVal[1];
}
this.runTests(key, value);
this.setValue(key, value);
}
else {
this.value = true;
}
if (short && !this.parameter && arg1.length > 2) {
// flag that the bundled parameter should be removed
count = -1;
}
if (this.on) {
this.on(value, key, this.parent, this);
}
return count;
}
else if (this.negatable &&
this.possible.reduce(function (prev, cur) {
if ('--no-' + cur === arg1) {
prev.push(cur);
}
return prev;
}, []).length
) {
this.value = false;
if (this.on) {
this.on(value, key, this.parent, this);
}
return 1;
}
return 0;
};
getoptLongParam.prototype.extractValue = function (key, value, short, auto, arg1, arg2) {
if (auto) {
return [auto[1]];
}
else if (arg1.match(/=/)) {
return [strSplit(arg1, '=', 2)[1]];
}
else if (short && arg1.length > 2) {
return [arg1.substr(2)];
}
else if (arg2 !== undefined) {
return [arg2, 2];
}
throw '--' + this.name + ' requires a value\n';
};
getoptLongParam.prototype.setValue = function (key, value) {
if (this.list) {
this.value.push(value);
}
else if (this.object) {
this.value[key] = value;
}
else {
this.value = value;
}
};
getoptLongParam.prototype.runTests = function (key, value) {
// run any value tests
for (var j in this.test) {
if (this.test[j] instanceof Function) {
value = this.test[j](value, key, this.parent, this);
}
else if (this.test[j] instanceof Array) {
value = this.arrayTest(this.test[j], value);
}
}
};
getoptLongParam.prototype.help = function () {
var help = this.short.length ? ' -' + this.short[0] : ' ';
var last = this.possible.length - 1;
while (this.possible[last] && this.possible[last].length === 1) {
last--;
}
if (this.possible[0] === 'har') {
console.log(this);
}
if (this.possible[last]) {
help = help + ' --' + this.possible[last];
}
if (this.parameter) {
help = help + '[=]' + this.paramName;
}
help = padToOrNewLine(help, 16);
if (!this.negatable) {
return help + this.description + '\n';
}
var nagative = padToOrNewLine(' --no-' + this.possible[last], 16) + 'Turn off this option\n';
return help + this.description + '\n' + nagative;
};
var exports;
exports.param = getoptLongParam;