From 645b1bfce9a7e925d56d099692244ae9efae57f5 Mon Sep 17 00:00:00 2001 From: cravler Date: Fri, 8 Jan 2016 11:54:33 +0200 Subject: [PATCH 1/3] colors, l10n, args details --- index.js | 108 ++++++++++++++++++++++++++++++++++++++++++--------- package.json | 1 + 2 files changed, 90 insertions(+), 19 deletions(-) diff --git a/index.js b/index.js index 715c4df98..990feb032 100644 --- a/index.js +++ b/index.js @@ -9,6 +9,7 @@ var path = require('path'); var dirname = path.dirname; var basename = path.basename; var fs = require('fs'); +var colors = require('colors/safe'); /** * Expose the root command. @@ -194,7 +195,7 @@ Command.prototype.arguments = function (desc) { */ Command.prototype.addImplicitHelpCommand = function() { - this.command('help [cmd]', 'display help for [cmd]'); + this.command('help [cmd]', l10n('display help for [cmd]')); }; /** @@ -541,9 +542,9 @@ Command.prototype.executeSubCommand = function(argv, args, unknown) { proc.on('close', process.exit.bind(process)); proc.on('error', function(err) { if (err.code == "ENOENT") { - console.error('\n %s(1) does not exist, try --help\n', bin); + console.error(colors.red(l10n('\n %s(1) does not exist, try --help\n')), bin); } else if (err.code == "EACCES") { - console.error('\n %s(1) not executable. try chmod or run with root\n', bin); + console.error(colors.red(l10n('\n %s(1) not executable. try chmod or run with root\n')), bin); } process.exit(1); }); @@ -750,7 +751,7 @@ Command.prototype.opts = function() { Command.prototype.missingArgument = function(name) { console.error(); - console.error(" error: missing required argument `%s'", name); + console.error(colors.red(l10n(" error: missing required argument `%s'")), name); console.error(); process.exit(1); }; @@ -766,9 +767,9 @@ Command.prototype.missingArgument = function(name) { Command.prototype.optionMissingArgument = function(option, flag) { console.error(); if (flag) { - console.error(" error: option `%s' argument missing, got `%s'", option.flags, flag); + console.error(colors.red(l10n(" error: option `%s' argument missing, got `%s'")), option.flags, flag); } else { - console.error(" error: option `%s' argument missing", option.flags); + console.error(colors.red(l10n(" error: option `%s' argument missing")), option.flags); } console.error(); process.exit(1); @@ -784,7 +785,7 @@ Command.prototype.optionMissingArgument = function(option, flag) { Command.prototype.unknownOption = function(flag) { if (this._allowUnknownOption) return; console.error(); - console.error(" error: unknown option `%s'", flag); + console.error(colors.red(l10n(" error: unknown option `%s'")), flag); console.error(); process.exit(1); }; @@ -798,7 +799,7 @@ Command.prototype.unknownOption = function(flag) { Command.prototype.variadicArgNotLast = function(name) { console.error(); - console.error(" error: variadic arguments must be last `%s'", name); + console.error(colors.red(l10n(" error: variadic arguments must be last `%s'")), name); console.error(); process.exit(1); }; @@ -819,7 +820,7 @@ Command.prototype.version = function(str, flags) { if (0 == arguments.length) return this._version; this._version = str; flags = flags || '-V, --version'; - this.option(flags, 'output the version number'); + this.option(flags, l10n('output the version number')); this.on('version', function() { process.stdout.write(str + '\n'); process.exit(0); @@ -831,13 +832,15 @@ Command.prototype.version = function(str, flags) { * Set the description to `str`. * * @param {String} str + * @param {Object} argsDescription * @return {String|Command} * @api public */ -Command.prototype.description = function(str) { +Command.prototype.description = function(str, argsDescription) { if (0 === arguments.length) return this._description; this._description = str; + this._argsDescription = argsDescription; return this; }; @@ -903,6 +906,36 @@ Command.prototype.largestOptionLength = function() { }, 0); }; +/** + * Return the largest arg length. + * + * @return {Number} + * @api private + */ + +Command.prototype.largestArgLength = function() { + return this._args.reduce(function(max, arg) { + return Math.max(max, arg.name.length); + }, 0); +}; + +/** + * Return the pad width. + * + * @return {Number} + * @api private + */ + +Command.prototype.padWidth = function() { + var width = this.largestOptionLength(); + if (this._argsDescription && this._args.length) { + if (this.largestArgLength() > width) { + width = this.largestArgLength(); + } + } + return width; +}; + /** * Return help for options. * @@ -911,10 +944,10 @@ Command.prototype.largestOptionLength = function() { */ Command.prototype.optionHelp = function() { - var width = this.largestOptionLength(); + var width = this.padWidth(); // Prepend the help information - return [pad('-h, --help', width) + ' ' + 'output usage information'] + return [pad('-h, --help', width) + ' ' + l10n('output usage information')] .concat(this.options.map(function(option) { return pad(option.flags, width) + ' ' + option.description; })) @@ -952,8 +985,7 @@ Command.prototype.commandHelp = function() { }, 0); return [ - '' - , ' Commands:' + ' ' + colors.yellow(l10n('Commands:')) , '' , commands.map(function(cmd) { var desc = cmd[1] ? ' ' + cmd[1] : ''; @@ -974,9 +1006,20 @@ Command.prototype.helpInformation = function() { var desc = []; if (this._description) { desc = [ - ' ' + this._description + ' ' + colors.cyan(this._description) , '' ]; + + var argsDescription = this._argsDescription; + if (argsDescription && this._args.length) { + var width = this.padWidth(); + desc.push(' ' + colors.yellow(l10n('Arguments:'))); + desc.push(''); + this._args.forEach(function(arg) { + desc.push(' ' + pad(arg.name, width) + ' ' + argsDescription[arg.name]); + }); + desc.push(''); + } } var cmdName = this._name; @@ -985,7 +1028,7 @@ Command.prototype.helpInformation = function() { } var usage = [ '' - ,' Usage: ' + cmdName + ' ' + this.usage() + , ' ' + colors.yellow(l10n('Usage:')) + ' ' + cmdName + ' ' + this.usage() , '' ]; @@ -994,7 +1037,7 @@ Command.prototype.helpInformation = function() { if (commandHelp) cmds = [commandHelp]; var options = [ - ' Options:' + ' ' + colors.yellow(l10n('Options:')) , '' , '' + this.optionHelp().replace(/^/gm, ' ') , '' @@ -1035,6 +1078,34 @@ Command.prototype.help = function(cb) { process.exit(); }; +/** + * Add yours translations + * @param {Object} translations + * + * Examples: + * + * program.l10n({ + * '...': '...', + * ... + * }); + */ + +Command.prototype.l10n = function(translations) { + for (var key in translations) { + l10n[key] = translations[key]; + }; +}; + +/** + * Localization + * @param str + * @returns {*} + */ + +function l10n(str) { + return l10n[str] || str; +} + /** * Camel-case the given `flag` * @@ -1060,7 +1131,7 @@ function camelcase(flag) { function pad(str, width) { var len = Math.max(0, width - str.length); - return str + Array(len + 1).join(' '); + return colors.green(str) + Array(len + 1).join(' '); } /** @@ -1107,4 +1178,3 @@ function exists(file) { return false; } } - diff --git a/package.json b/package.json index 77311492d..dd21281d2 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "index.js" ], "dependencies": { + "colors": "^1.1.2", "graceful-readlink": ">= 1.0.0" } } From 121b2d972552c200d91f1b5fe1f7afa27ffda612 Mon Sep 17 00:00:00 2001 From: cravler Date: Fri, 8 Jan 2016 12:43:24 +0200 Subject: [PATCH 2/3] colors as mocksmock colors --- index.js | 29 ++++++++++++++++++++++++++++- package.json | 1 - 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 990feb032..b9da48594 100644 --- a/index.js +++ b/index.js @@ -9,7 +9,6 @@ var path = require('path'); var dirname = path.dirname; var basename = path.basename; var fs = require('fs'); -var colors = require('colors/safe'); /** * Expose the root command. @@ -1078,6 +1077,34 @@ Command.prototype.help = function(cb) { process.exit(); }; +/** + * Add colors + * @param {Object} + */ + +Command.prototype.colors = function(obj) { + for (var key in obj) { + if (typeof obj[key] == 'function') { + colors[key] = obj[key]; + } + }; +}; + +/** + * Colors + * + * @param {String} str + * @returns {String} + */ + +function colors(str) { + return str; +} +colors.red = colors; +colors.green = colors; +colors.yellow = colors; +colors.cyan = colors; + /** * Add yours translations * @param {Object} translations diff --git a/package.json b/package.json index dd21281d2..77311492d 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "index.js" ], "dependencies": { - "colors": "^1.1.2", "graceful-readlink": ">= 1.0.0" } } From 04148338ad4822e36c4fe87fffc916c1b9b255c7 Mon Sep 17 00:00:00 2001 From: Sergei Vizel Date: Sat, 9 Jan 2016 00:02:42 +0200 Subject: [PATCH 3/3] test fix --- test/test.command.help.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.command.help.js b/test/test.command.help.js index 68973cde6..7b759ac25 100644 --- a/test/test.command.help.js +++ b/test/test.command.help.js @@ -7,4 +7,4 @@ program.command('mycommand [options]'); program.parse(['node', 'test']); -program.commandHelp().should.equal('\n Commands:\n\n mycommand [options]\n'); +program.commandHelp().should.equal(' Commands:\n\n mycommand [options]\n');