You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
typesetting/pitfall/pdfkit/node_modules/yargs/lib/usage.js

373 lines
11 KiB
JavaScript

// this file handles outputting usage instructions,
// failures, etc. keeps logging in one place.
var decamelize = require('decamelize'),
wordwrap = require('wordwrap'),
wsize = require('window-size');
module.exports = function (yargs) {
var self = {};
// methods for ouputting/building failure message.
var fails = [];
self.failFn = function (f) {
fails.push(f);
};
var failMessage = null;
var showHelpOnFail = true;
self.showHelpOnFail = function (enabled, message) {
if (typeof enabled === 'string') {
message = enabled;
enabled = true;
}
else if (typeof enabled === 'undefined') {
enabled = true;
}
failMessage = message;
showHelpOnFail = enabled;
return self;
};
self.fail = function (msg) {
if (fails.length) {
fails.forEach(function (f) {
f(msg);
});
} else {
if (showHelpOnFail) yargs.showHelp("error");
if (msg) console.error(msg);
if (failMessage) {
if (msg) console.error("");
console.error(failMessage);
}
if (yargs.getExitProcess()){
process.exit(1);
}else{
throw new Error(msg);
}
}
};
// methods for ouputting/building help (usage) message.
var usage;
self.usage = function (msg) {
usage = msg;
};
var examples = [];
self.example = function (cmd, description) {
examples.push([cmd, description || '']);
};
var commands = [];
self.command = function (cmd, description) {
commands.push([cmd, description || '']);
};
self.getCommands = function () {
return commands;
};
var descriptions = {};
self.describe = function (key, desc) {
if (typeof key === 'object') {
Object.keys(key).forEach(function (k) {
self.describe(k, key[k]);
});
}
else {
descriptions[key] = desc;
}
};
self.getDescriptions = function() {
return descriptions;
}
var epilog;
self.epilog = function (msg) {
epilog = msg;
};
var wrap = windowWidth();
self.wrap = function (cols) {
wrap = cols;
};
self.help = function () {
var demanded = yargs.getDemanded(),
options = yargs.getOptions(),
keys = Object.keys(
Object.keys(descriptions)
.concat(Object.keys(demanded))
.concat(Object.keys(options.default))
.reduce(function (acc, key) {
if (key !== '_') acc[key] = true;
return acc;
}, {})
);
var help = keys.length ? [ 'Options:' ] : [];
// your application's commands, i.e., non-option
// arguments populated in '_'.
if (commands.length) {
help.unshift('');
var commandsTable = {};
commands.forEach(function(command) {
commandsTable[command[0]] = {
desc: command[1],
extra: ''
};
});
help = ['Commands:'].concat(formatTable(commandsTable, 5), help);
}
// the usage string.
if (usage) {
var u = usage.replace(/\$0/g, yargs.$0);
if (wrap) u = wordwrap(0, wrap)(u);
help.unshift(u, '');
}
// the options table.
var aliasKeys = (Object.keys(options.alias) || [])
.concat(Object.keys(yargs.parsed.newAliases) || []);
keys = keys.filter(function(key) {
return !yargs.parsed.newAliases[key] && aliasKeys.every(function(alias) {
return -1 == (options.alias[alias] || []).indexOf(key);
});
});
var switches = keys.reduce(function (acc, key) {
acc[key] = [ key ].concat(options.alias[key] || [])
.map(function (sw) {
return (sw.length > 1 ? '--' : '-') + sw
})
.join(', ')
;
return acc;
}, {});
var switchTable = {};
keys.forEach(function (key) {
var kswitch = switches[key];
var desc = descriptions[key] || '';
var type = null;
if (options.boolean[key]) type = '[boolean]';
if (options.count[key]) type = '[count]';
if (options.string[key]) type = '[string]';
if (options.normalize[key]) type = '[string]';
var extra = [
type,
demanded[key]
? '[required]'
: null
,
defaultString(options.default[key], options.defaultDescription[key])
].filter(Boolean).join(' ');
switchTable[kswitch] = {
desc: desc,
extra: extra
};
});
help.push.apply(help, formatTable(switchTable, 3));
if (keys.length) help.push('');
// describe some common use-cases for your application.
if (examples.length) {
examples.forEach(function (example) {
example[0] = example[0].replace(/\$0/g, yargs.$0);
});
var examplesTable = {};
examples.forEach(function(example) {
examplesTable[example[0]] = {
desc: example[1],
extra: ''
};
});
help.push.apply(help, ['Examples:'].concat(formatTable(examplesTable, 5), ''));
}
// the usage string.
if (epilog) {
var e = epilog.replace(/\$0/g, yargs.$0);
if (wrap) e = wordwrap(0, wrap)(e);
help.push(e, '');
}
return help.join('\n');
};
self.showHelp = function (level) {
level = level || 'error';
console[level](self.help());
}
// format the default-value-string displayed in
// the right-hand column.
function defaultString(value, defaultDescription) {
var string = '[default: ';
if (value === undefined) return null;
if (defaultDescription) {
string += defaultDescription;
} else {
switch (typeof value) {
case 'string':
string += JSON.stringify(value);
break;
case 'function':
string += '(' + (value.name.length ? decamelize(value.name, '-') : 'generated-value') + ')'
break;
default:
string += value;
}
}
return string + ']';
}
// word-wrapped two-column layout used by
// examples, options, commands.
function formatTable (table, padding) {
var output = [];
// size of left-hand-column.
var llen = longest(Object.keys(table));
// don't allow the left-column to take up
// more than half of the screen.
if (wrap) {
llen = Math.min(llen, parseInt(wrap / 2));
}
// size of right-column.
var desclen = longest(Object.keys(table).map(function (k) {
return table[k].desc;
}));
Object.keys(table).forEach(function(left) {
var desc = table[left].desc,
extra = table[left].extra,
leftLines = null;
if (wrap) {
desc = wordwrap(llen + padding + 1, wrap)(desc)
.slice(llen + padding + 1);
}
// if we need to wrap the left-hand-column,
// split it on to multiple lines.
if (wrap && left.length > llen) {
leftLines = wordwrap(2, llen)(left.trim()).split('\n');
left = '';
}
var lpadding = new Array(
Math.max(llen - left.length + padding, 0)
).join(' ');
var dpadding = new Array(
Math.max(desclen - desc.length + 1, 0)
).join(' ');
if (!wrap && dpadding.length > 0) {
desc += dpadding;
}
var prelude = ' ' + left + lpadding;
var body = [ desc, extra ].filter(Boolean).join(' ');
if (wrap) {
var dlines = desc.split('\n');
var dlen = dlines.slice(-1)[0].length
+ (dlines.length === 1 ? prelude.length : 0)
if (extra.length > wrap) {
body = desc + '\n' + wordwrap(llen + 4, wrap)(extra)
} else {
body = desc + (dlen + extra.length > wrap - 2
? '\n'
+ new Array(wrap - extra.length + 1).join(' ')
+ extra
: new Array(wrap - extra.length - dlen + 1).join(' ')
+ extra
);
}
}
if (leftLines) { // handle word-wrapping the left-hand-column.
var rightLines = body.split('\n'),
firstLine = prelude + rightLines[0],
lineCount = Math.max(leftLines.length, rightLines.length);
for (var i = 0; i < lineCount; i++) {
var left = leftLines[i],
right = i ? rightLines[i] : firstLine;
output.push(strcpy(left, right, firstLine.length));
}
} else {
output.push(prelude + body);
}
});
return output;
}
// find longest string in array of strings.
function longest (xs) {
return Math.max.apply(
null,
xs.map(function (x) { return x.length })
);
}
// copy one string into another, used when
// formatting usage table.
function strcpy (source, destination, width) {
var str = ''
source = source || '';
destination = destination || new Array(width).join(' ');
for (var i = 0; i < destination.length; i++) {
var char = destination.charAt(i);
if (char === ' ') char = source.charAt(i) || char;
str += char;
}
return str;
}
// guess the width of the console window, max-width 100.
function windowWidth() {
return wsize.width ? Math.min(80, wsize.width) : null;
}
// logic for displaying application version.
var version = null;
self.version = function (ver, opt, msg) {
version = ver;
};
self.showVersion = function() {
if (typeof version === 'function') console.log(version());
else console.log(version);
};
return self;
}