四好公路
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

155 lines
3.3 KiB

3 years ago
'use strict';
const EQQ = /\s|=/;
const FLAG = /^-{1,2}/;
const PREFIX = /^--no-/i;
function isBool(any) {
return typeof any === 'boolean';
}
function toArr(any) {
return Array.isArray(any) ? any : any == null ? [] : [any];
}
function toString(any) {
return any == null || any === true ? '' : String(any);
}
function toBool(any) {
return any === 'false' ? false : Boolean(any);
}
function toNum(any) {
return (!isBool(any) && Number(any)) || any;
}
function getAlibi(names, arr) {
if (arr.length === 0) return arr;
let k, i = 0, len = arr.length, vals = [];
for (; i < len; i++) {
k = arr[i];
vals.push(k);
if (names[k] !== void 0) {
vals = vals.concat(names[k]);
}
}
return vals;
}
function typecast(key, val, strings, booleans) {
if (strings.indexOf(key) !== -1) return toString(val);
if (booleans.indexOf(key) !== -1) return toBool(val);
return toNum(val);
}
module.exports = function(args, opts) {
args = args || [];
opts = opts || {};
opts.string = toArr(opts.string);
opts.boolean = toArr(opts.boolean);
const aliases = {};
let k, i, j, x, y, len, type;
if (opts.alias !== void 0) {
for (k in opts.alias) {
aliases[k] = toArr(opts.alias[k]);
len = aliases[k].length; // save length
for (i = 0; i < len; i++) {
x = aliases[k][i]; // alias's key name
aliases[x] = [k]; // set initial array
for (j = 0; j < len; j++) {
if (x !== aliases[k][j]) {
aliases[x].push(aliases[k][j]);
}
}
}
}
}
if (opts.default !== void 0) {
for (k in opts.default) {
type = typeof opts.default[k];
opts[type] = (opts[type] || []).concat(k);
}
}
// apply to all aliases
opts.string = getAlibi(aliases, opts.string);
opts.boolean = getAlibi(aliases, opts.boolean);
let idx = 0;
const out = { _: [] };
while (args[idx] !== void 0) {
let incr = 1;
const val = args[idx];
if (val === '--') {
out._ = out._.concat(args.slice(idx + 1));
break;
} else if (!FLAG.test(val)) {
out._.push(val);
} else if (PREFIX.test(val)) {
out[val.replace(PREFIX, '')] = false;
} else {
let tmp;
const segs = val.split(EQQ);
const isGroup = segs[0].charCodeAt(1) !== 45; // '-'
const flag = segs[0].substr(isGroup ? 1 : 2);
len = flag.length;
const key = isGroup ? flag[len - 1] : flag;
if (opts.unknown !== void 0 && aliases[key] === void 0) {
return opts.unknown(segs[0]);
}
if (segs.length > 1) {
tmp = segs[1];
} else {
tmp = args[idx + 1] || true;
FLAG.test(tmp) ? (tmp = true) : (incr = 2);
}
if (isGroup && len > 1) {
for (i = len - 1; i--; ) {
k = flag[i]; // all but last key
out[k] = typecast(k, true, opts.string, opts.boolean);
}
}
const value = typecast(key, tmp, opts.string, opts.boolean);
out[key] = out[key] !== void 0 ? toArr(out[key]).concat(value) : value;
// handle discarded args when dealing with booleans
if (isBool(value) && !isBool(tmp) && tmp !== 'true' && tmp !== 'false') {
out._.push(tmp);
}
}
idx += incr;
}
if (opts.default !== void 0) {
for (k in opts.default) {
if (out[k] === void 0) {
out[k] = opts.default[k];
}
}
}
for (k in out) {
if (aliases[k] === void 0) continue;
y = out[k];
len = aliases[k].length;
for (i = 0; i < len; i++) {
out[aliases[k][i]] = y; // assign value
}
}
return out;
};