Skip to content

Commit

Permalink
Add a way to override help and version help message #963
Browse files Browse the repository at this point in the history
Minor edits from John Gee to typings added during squash.
  • Loading branch information
Ivan authored and shadowspawn committed Jun 26, 2019
1 parent 1c1ffca commit c61d724
Show file tree
Hide file tree
Showing 8 changed files with 248 additions and 17 deletions.
15 changes: 15 additions & 0 deletions Readme.md
Expand Up @@ -224,6 +224,12 @@ You may specify custom flags by passing an additional parameter to the `version`
program.version('0.0.1', '-v, --version');
```
You can also override the help description for the version command.
```js
program.version('0.0.1', '-v, --version', 'output the current version');
```
## Command-specific options
Expand Down Expand Up @@ -433,6 +439,15 @@ function make_red(txt) {
}
```
## .helpOption(flags, description)
Override the default help flags and description.
```js
program
.helpOption('-e, --HELP', 'read more information');
```
## .help(cb)
Output help information and exit immediately.
Expand Down
21 changes: 21 additions & 0 deletions examples/custom-help-description
@@ -0,0 +1,21 @@
#!/usr/bin/env node

/**
* Module dependencies.
*/

var program = require('../');

program
.helpOption('-c, --HELP', 'custom help message')
.option('-s, --sessions', 'add session support')
.option('-t, --template <engine>', 'specify template engine (jade|ejs) [jade]', 'jade');

program
.command('child')
.option('--gender', 'specific gender of child')
.action((cmd) => {
console.log('Childsubcommand...');
});

program.parse(process.argv);
13 changes: 13 additions & 0 deletions examples/custom-version
@@ -0,0 +1,13 @@
#!/usr/bin/env node

/**
* Module dependencies.
*/

var program = require('../');

program
.version('0.0.1', '-v, --VERSION', 'new version message')
.option('-s, --sessions', 'add session support')
.option('-t, --template <engine>', 'specify template engine (jade|ejs) [jade]', 'jade')
.parse(process.argv);
60 changes: 51 additions & 9 deletions index.js
Expand Up @@ -103,6 +103,11 @@ function Command(name) {
this._allowUnknownOption = false;
this._args = [];
this._name = name || '';

this._helpFlags = '-h, --help';
this._helpDescription = 'output usage information';
this._helpShortFlag = '-h';
this._helpLongFlag = '--help';
}

/**
Expand Down Expand Up @@ -182,6 +187,10 @@ Command.prototype.command = function(name, desc, opts) {
if (opts.isDefault) this.defaultExecutable = cmd._name;
}
cmd._noHelp = !!opts.noHelp;
cmd._helpFlags = this._helpFlags;
cmd._helpDescription = this._helpDescription;
cmd._helpShortFlag = this._helpShortFlag;
cmd._helpLongFlag = this._helpLongFlag;
this.commands.push(cmd);
cmd.parseExpectedArgs(args);
cmd.parent = this;
Expand Down Expand Up @@ -466,7 +475,7 @@ Command.prototype.parse = function(argv) {
// github-style sub-commands with no sub-command
if (this.executables && argv.length < 3 && !this.defaultExecutable) {
// this user needs help
argv.push('--help');
argv.push(this._helpLongFlag);
}

// process argv
Expand Down Expand Up @@ -519,7 +528,7 @@ Command.prototype.executeSubCommand = function(argv, args, unknown) {
// <cmd> --help
if (args[0] === 'help') {
args[0] = args[1];
args[1] = '--help';
args[1] = this._helpLongFlag;
}

// executable
Expand Down Expand Up @@ -846,17 +855,21 @@ Command.prototype.variadicArgNotLast = function(name) {
* This method auto-registers the "-V, --version" flag
* which will print the version number when passed.
*
* You can optionally supply the flags and description to override the defaults.
*
* @param {String} str
* @param {String} [flags]
* @param {String} [description]
* @return {Command} for chaining
* @api public
*/

Command.prototype.version = function(str, flags) {
Command.prototype.version = function(str, flags, description) {
if (arguments.length === 0) return this._version;
this._version = str;
flags = flags || '-V, --version';
var versionOption = new Option(flags, 'output the version number');
description = description || 'output the version number';
var versionOption = new Option(flags, description);
this._versionOptionName = versionOption.long.substr(2) || 'version';
this.options.push(versionOption);
this.on('option:' + this._versionOptionName, function() {
Expand Down Expand Up @@ -990,8 +1003,9 @@ Command.prototype.largestCommandLength = function() {
Command.prototype.largestOptionLength = function() {
var options = [].slice.call(this.options);
options.push({
flags: '-h, --help'
flags: this._helpFlags
});

return options.reduce(function(max, option) {
return Math.max(max, option.flags.length);
}, 0);
Expand Down Expand Up @@ -1048,7 +1062,7 @@ Command.prototype.optionHelp = function() {
return this.options.map(function(option) {
return pad(option.flags, width) + ' ' + option.description +
((option.bool && option.defaultValue !== undefined) ? ' (default: ' + JSON.stringify(option.defaultValue) + ')' : '');
}).concat([pad('-h, --help', width) + ' ' + 'output usage information'])
}).concat([pad(this._helpFlags, width) + ' ' + this._helpDescription])
.join('\n');
};

Expand Down Expand Up @@ -1129,7 +1143,10 @@ Command.prototype.helpInformation = function() {
};

/**
* Output help information for this command
* Output help information for this command.
*
* When listener(s) are available for the helpLongFlag
* those callbacks are invoked.
*
* @api public
*/
Expand All @@ -1145,12 +1162,36 @@ Command.prototype.outputHelp = function(cb) {
throw new Error('outputHelp callback must return a string or a Buffer');
}
process.stdout.write(cbOutput);
this.emit('--help');
this.emit(this._helpLongFlag);
};

/**
* You can pass in flags and a description to override the help
* flags and help description for your command.
*
* @param {String} [flags]
* @param {String} [description]
* @return {Command}
* @api public
*/

Command.prototype.helpOption = function(flags, description) {
this._helpFlags = flags || this._helpFlags;
this._helpDescription = description || this._helpDescription;

var splitFlags = this._helpFlags.split(/[ ,|]+/);

if (splitFlags.length > 1) this._helpShortFlag = splitFlags.shift();

this._helpLongFlag = splitFlags.shift();

return this;
};

/**
* Output help information and exit.
*
* @param {Function} [cb]
* @api public
*/

Expand Down Expand Up @@ -1197,8 +1238,9 @@ function pad(str, width) {

function outputHelpIfNecessary(cmd, options) {
options = options || [];

for (var i = 0; i < options.length; i++) {
if (options[i] === '--help' || options[i] === '-h') {
if (options[i] === cmd._helpLongFlag || options[i] === cmd._helpShortFlag) {
cmd.outputHelp();
process.exit(0);
}
Expand Down
46 changes: 46 additions & 0 deletions test/test.command.helpInformation.custom.js
@@ -0,0 +1,46 @@
var program = require('../')
, sinon = require('sinon').sandbox.create()
, should = require('should');

sinon.stub(process, 'exit');
sinon.stub(process.stdout, 'write');

program.helpOption('-c, --HELP', 'custom help output');
program.command('somecommand');
program.command('anothercommand [options]');

var expectedHelpInformation = [
'Usage: [options] [command]',
'',
'Options:',
' -c, --HELP custom help output',
'',
'Commands:',
' somecommand',
' anothercommand [options]',
''
].join('\n');

program.helpInformation().should.equal(expectedHelpInformation);

// Test arguments
var expectedCommandHelpInformation = [
'Usage: test [options] [command]',
'',
'Options:',
' -c, --HELP custom help output',
'',
'Commands:',
' somecommand',
' anothercommand [options]',
''
].join('\n');

program.parse(['node', 'test', '--HELP']);

process.stdout.write.called.should.equal(true);

var output = process.stdout.write.args[0];
output[0].should.equal(expectedCommandHelpInformation);

sinon.restore();
65 changes: 65 additions & 0 deletions test/test.command.helpSubCommand.customFlags.js
@@ -0,0 +1,65 @@
var program = require('../'),
sinon = require('sinon').sandbox.create(),
should = require('should');

sinon.stub(process, 'exit');
sinon.stub(process.stdout, 'write');

// Test that subcommands inherit the help flags
// but can also override help flags
program
.helpOption('-i, --ihelp', 'foo foo');

program
.command('child')
.option('--gender', 'specific gender of child')
.action((cmd) => {
console.log('Childsubcommand...');
});

program
.command('family')
.helpOption('-h, --help')
.action((cmd) => {
console.log('Familysubcommand...');
});

// Test arguments
var expectedCommandHelpInformation = [
'Usage: child [options]',
'',
'Options:',
' --gender specific gender of child',
' -i, --ihelp foo foo',
''
].join('\n');

program.parse(['node', 'test', 'child', '-i']);

process.stdout.write.called.should.equal(true);

var output = process.stdout.write.args[0];
output[0].should.equal(expectedCommandHelpInformation);

// Test other command
sinon.restore();

sinon.stub(process, 'exit');
sinon.stub(process.stdout, 'write');

var expectedFamilyCommandHelpInformation = [
'Usage: family [options]',
'',
'Options:',
' -h, --help foo foo',
''
].join('\n');

program.parse(['node', 'test', 'family', '-h']);

process.stdout.write.called.should.equal(true);

var output2 = process.stdout.write.args[0];
output2[0].should.equal(expectedFamilyCommandHelpInformation);

sinon.restore();
22 changes: 22 additions & 0 deletions test/test.options.version.customHelpDescription.js
@@ -0,0 +1,22 @@
var program = require('../')
, sinon = require('sinon').sandbox.create()
, should = require('should');

program.version('1.0.0', undefined, 'custom version output');
program.command('somecommand');
program.command('anothercommand [options]');

var expectedHelpInformation = [
'Usage: [options] [command]',
'',
'Options:',
' -V, --version custom version output',
' -h, --help output usage information',
'',
'Commands:',
' somecommand',
' anothercommand [options]',
''
].join('\n');

program.helpInformation().should.equal(expectedHelpInformation);
23 changes: 15 additions & 8 deletions typings/index.d.ts
Expand Up @@ -36,16 +36,15 @@ declare namespace local {
constructor(name?: string);

/**
* Set the program version to `str`.
* Set the program version to `str`.
*
* This method auto-registers the "-V, --version" flag
* which will print the version number when passed.
*
* You can optionally supply the flags and description to override the defaults.
*
* @param {string} str
* @param {string} [flags]
* @returns {Command} for chaining
*/
version(str: string, flags?: string): Command;
version(str: string, flags?: string, description?: string): Command;

/**
* Add command `name`.
Expand Down Expand Up @@ -268,13 +267,21 @@ declare namespace local {
/**
* Output help information for this command.
*
* When listener(s) are available for the helpLongFlag
* those callbacks are invoked.
*
* @param {(str: string) => string} [cb]
*/
outputHelp(cb?: (str: string) => string): void;

/** Output help information and exit.
*
* @param {(str: string) => string} [cb]
/**
* You can pass in flags and a description to override the help
* flags and help description for your command.
*/
helpOption(flags?: string, description?: string): Command;

/**
* Output help information and exit.
*/
help(cb?: (str: string) => string): never;
}
Expand Down

0 comments on commit c61d724

Please sign in to comment.