Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions lib/help.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ module.exports = function() {

const optionHandle = groups.options ? '[options] ' : '';
const cmdHandle = groups.commands ? '[command]' : '';
const value = typeof this.config.value === 'string'
? ' ' + this.config.value
: '';
const value =
typeof this.config.value === 'string' ? ' ' + this.config.value : '';

parts.push([
'',
`Usage: ${this.printMainColor(name)} ${this.printSubColor(optionHandle + cmdHandle + value)}`,
`Usage: ${this.printMainColor(name)} ${this.printSubColor(
optionHandle + cmdHandle + value
)}`,
''
]);

Expand Down Expand Up @@ -68,6 +69,8 @@ module.exports = function() {

console.log(output);

// eslint-disable-next-line unicorn/no-process-exit
process.exit();
if (this.config.exit && this.config.exit.help) {
// eslint-disable-next-line unicorn/no-process-exit
process.exit();
}
};
6 changes: 3 additions & 3 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ const publicMethods = {
parse: require('./parse'),
example: require('./example'),
examples: require('./examples'),
showHelp: require('./help')
showHelp: require('./help'),
showVersion: require('./version')
};

function Args() {
Expand All @@ -22,6 +23,7 @@ function Args() {

// Configuration defaults
this.config = {
exit: { help: true, version: true },
help: true,
version: true,
usageFilter: null,
Expand All @@ -33,8 +35,6 @@ function Args() {

this.printMainColor = chalk;
this.printSubColor = chalk;

this.parent = module.parent;
}

// Assign internal helpers
Expand Down
21 changes: 6 additions & 15 deletions lib/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,21 @@ module.exports = function(argv, options) {
this.printSubColor = this.printSubColor[this.config.subColor];
}

if (this.config.help) {
// Register default options and commands
this.option('help', 'Output usage information');
this.command('help', 'Display help', this.showHelp);
}

// Parse arguments using mri
this.raw = parser(argv.slice(1), this.config.mri || this.config.minimist);
this.binary = path.basename(this.raw._[0]);

// If default version is allowed, check for it
if (this.config.version) {
this.checkVersion(this.parent);
this.checkVersion();
}

const subCommand = this.raw._[1];
const helpTriggered = this.raw.h || this.raw.help;
// If default help is allowed, check for it
if (this.config.help) {
this.checkHelp();
}

const subCommand = this.raw._[1];
const args = {};
const defined = this.isDefined(subCommand, 'commands');
const optionList = this.getOptions(defined);
Expand All @@ -67,12 +64,6 @@ module.exports = function(argv, options) {
return {};
}

// Show usage information if "help" or "h" option was used
// And respect the option related to it
if (this.config.help && helpTriggered) {
this.showHelp();
}

// Hand back list of options
return optionList;
};
74 changes: 47 additions & 27 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,16 @@ module.exports = {

generateDetails(kind) {
// Get all properties of kind from global scope
const items = typeof kind === 'string' ? this.details[kind] : kind;
const items = [];

// Clone passed objects so changing them here doesn't affect real data.
const passed = [].concat(
typeof kind === 'string' ? this.details[kind] : kind
);
for (let i = 0, l = passed.length; i < l; i++) {
items.push(Object.assign({}, passed[i]));
}

const parts = [];
const isCmd = kind === 'commands';

Expand Down Expand Up @@ -269,6 +278,11 @@ module.exports = {
details.init = false;
}

// If version is disabled, remove initializer
if (details.usage === 'version' && !this.config.version) {
details.init = false;
}

// If command has initializer, call it
if (details.init) {
const sub = [].concat(this.sub);
Expand All @@ -283,17 +297,22 @@ module.exports = {
: details.usage;
let full = this.binary + '-' + subCommand;

const args = process.argv;
let i = 0;
// Remove node and original command.
const args = process.argv.slice(2);

while (i < 3) {
args.shift();
i++;
// Remove the first occurance of subCommand from the args.
for (let i = 0, l = args.length; i < l; i++) {
if (args[i] === subCommand) {
args.splice(i, 1);
break;
}
}

if (process.platform === 'win32') {
const binaryExt = path.extname(this.binary);
const mainModule = process.env.APPVEYOR ? '_fixture' : process.mainModule.filename;
const mainModule = process.env.APPVEYOR
? '_fixture'
: process.mainModule.filename;

full = `${mainModule}-${subCommand}`;

Expand Down Expand Up @@ -337,29 +356,25 @@ module.exports = {
});
},

checkVersion(parent) {
// Load parent module
try {
const pkginfo = require('pkginfo');
pkginfo(parent);
} catch (err) {
// Do nothing, but version could not be aquired
}
checkHelp() {
// Register default option and command.
this.option('help', 'Output usage information');
this.command('help', 'Display help', this.showHelp);

// And get its version property
const version = parent.exports.version || '-/-';

if (version) {
// If it exists, register it as a default option
this.option('version', 'Output the version number');
// Immediately output if option was provided.
if (this.optionWasProvided('help')) {
this.showHelp();
}
},

// And immediately output it if used in command line
if (this.raw.v || this.raw.version) {
console.log(version);
checkVersion() {
// Register default option and command.
this.option('version', 'Output the version number');
this.command('version', 'Display version', this.showVersion);

// eslint-disable-next-line unicorn/no-process-exit
process.exit();
}
// Immediately output if option was provided.
if (this.optionWasProvided('version')) {
this.showVersion();
}
},

Expand All @@ -383,5 +398,10 @@ module.exports = {

// If nothing matches, item is not defined
return false;
},

optionWasProvided(name) {
const option = this.isDefined(name, 'options');
return option && (this.raw[option.usage[0]] || this.raw[option.usage[1]]);
}
};
34 changes: 34 additions & 0 deletions lib/version.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
'use strict';

const fs = require('fs');
const path = require('path');

/**
* Retrieves the main module package.json information.
*
* @param {string} directory
* The directory to start looking in.
*
* @return {Object|null}
* An object containing the package.json contents or NULL if it could not be found.
*/
function findPackage(directory) {
const file = path.resolve(directory, 'package.json');
if (fs.existsSync(file) && fs.statSync(file).isFile()) {
return require(file);
}
const parent = path.resolve(directory, '..');
return parent === directory ? null : findPackage(parent);
}

module.exports = function() {
const pkg = findPackage(path.dirname(process.mainModule.filename));
const version = (pkg && pkg.version) || '-/-';

console.log(version);

if (this.config.exit && this.config.exit.version) {
// eslint-disable-next-line unicorn/no-process-exit
process.exit();
}
};
45 changes: 39 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@
"camelcase": "4.1.0",
"chalk": "2.1.0",
"mri": "1.1.0",
"pkginfo": "0.4.1",
"string-similarity": "1.2.0"
}
}
9 changes: 7 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,14 +165,19 @@ pizza eat ./directory

### .showHelp()

Outputs the usage information based on the options and comments you've registered so far.
Outputs the usage information based on the options and comments you've registered so far and exits, if configured to do so.

### .showVersion()

Outputs the version and exits, if configured to do so.

## Configuration

By default, the module already registers some default options (e.g. "version" and "help"), as well as a command named "help". These things have been implemented to make creating CLIs easier for beginners. However, they can also be disabled by taking advantage of the following properties:
By default, the module already registers some default options and commands (e.g. "version" and "help"). These things have been implemented to make creating CLIs easier for beginners. However, they can also be disabled by taking advantage of the following properties:

| Property | Description | Default&nbsp;value | Type |
| -------- | ----------- | ------------------ | ---- |
| exit | Automatically exits when help or version is rendered | `{ help: true, version: true }` | Object |
| help | Automatically render the usage information when running `help`, `-h` or `--help` | true | Boolean |
| name | The name of your program to display in help | Name of script file | String |
| version | Outputs the version tag of your package.json | true | Boolean |
Expand Down
Loading