Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Refactor help internals #1346

Closed
270 changes: 114 additions & 156 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ class Option {
is(arg) {
return this.short === arg || this.long === arg;
};

/* WIP */
fullDescription() {
return this.description + (
(!this.negate && this.defaultValue !== undefined) ? ' (default: ' + JSON.stringify(this.defaultValue) + ')' : ''
);
};
}

/**
Expand Down Expand Up @@ -1392,64 +1399,82 @@ Read more on https://git.io/JJc0W`);
return this;
};

/**
* Return prepared commands.
*
* @return {Array}
* @api private
*/
/* WIP */
visibleCommands() {
const visibleCommands = this.commands.filter(cmd => !cmd._hidden);
if (this._lazyHasImplicitHelpCommand()) {
const helpCommand = new Command(this._helpCommandnameAndArgs)
.description(this._helpCommandDescription)
.helpOption(false);
visibleCommands.push(helpCommand);
}
return visibleCommands;
}

prepareCommands() {
const commandDetails = this.commands.filter((cmd) => {
return !cmd._hidden;
}).map((cmd) => {
const args = cmd._args.map((arg) => {
return humanReadableArgName(arg);
}).join(' ');

return [
cmd._name +
(cmd._aliases[0] ? '|' + cmd._aliases[0] : '') +
(cmd.options.length ? ' [options]' : '') +
(args ? ' ' + args : ''),
cmd._description
];
});
/* WIP */
visibleOptions() {
const visibleOptions = this.options.slice(); // Hidden not added until PR #1331 lands

if (this._lazyHasImplicitHelpCommand()) {
commandDetails.push([this._helpCommandnameAndArgs, this._helpCommandDescription]);
// Implicit help
const showShortHelpFlag = this._hasHelpOption && this._helpShortFlag && !this._findOption(this._helpShortFlag);
const showLongHelpFlag = this._hasHelpOption && !this._findOption(this._helpLongFlag);
if (showShortHelpFlag || showLongHelpFlag) {
let helpOption;
if (!showShortHelpFlag) {
helpOption = new Option(this._helpLongFlag, this._helpDescription);
} else if (!showLongHelpFlag) {
helpOption = new Option(this._helpShortFlag, this._helpDescription);
} else {
helpOption = new Option(this._helpFlags, this._helpDescription);
}
visibleOptions.push(helpOption);
}
return commandDetails;
};

return visibleOptions;
}

/* WIP */
visibleArguments() {
if (this._argsDescription && this._args.length) {
return this._args.map((argument) => {
return { term: argument.name, description: this._argsDescription[argument.name] || '' };
}, 0);
}
return [];
}

/* WIP: */
helpTerm() {
// Why not just use usage?!
const args = this._args.map(arg => humanReadableArgName(arg)).join(' ');
return this._name +
(this._aliases[0] ? '|' + this._aliases[0] : '') +
(this.options.length ? ' [options]' : '') + // simple check for non-help option
(args ? ' ' + args : '');
}

/**
* Return the largest command length.
*
* @return {number}
* @api private
* @api public
*/

largestCommandLength() {
const commands = this.prepareCommands();
return commands.reduce((max, command) => {
return Math.max(max, command[0].length);
largestCommandHelpTermLength() {
return this.visibleCommands().reduce((max, command) => {
return Math.max(max, command.helpTerm().length);
}, 0);
};

/**
* Return the largest option length.
*
* @return {number}
* @api private
* @api public
*/

largestOptionLength() {
const options = [].slice.call(this.options);
options.push({
flags: this._helpFlags
});

return options.reduce((max, option) => {
return this.visibleOptions().reduce((max, option) => {
return Math.max(max, option.flags.length);
}, 0);
};
Expand All @@ -1458,12 +1483,12 @@ Read more on https://git.io/JJc0W`);
* Return the largest arg length.
*
* @return {number}
* @api private
* @api public
*/

largestArgLength() {
return this._args.reduce((max, arg) => {
return Math.max(max, arg.name.length);
return this.visibleArguments().reduce((max, argument) => {
return Math.max(max, argument.term.length);
}, 0);
};

Expand All @@ -1475,115 +1500,36 @@ Read more on https://git.io/JJc0W`);
*/

padWidth() {
let width = this.largestOptionLength();
if (this._argsDescription && this._args.length) {
if (this.largestArgLength() > width) {
width = this.largestArgLength();
}
}

if (this.commands && this.commands.length) {
if (this.largestCommandLength() > width) {
width = this.largestCommandLength();
}
}

return width;
};

/**
* Return help for options.
*
* @return {string}
* @api private
*/

optionHelp() {
const width = this.padWidth();
const columns = process.stdout.columns || 80;
const descriptionWidth = columns - width - 4;
function padOptionDetails(flags, description) {
return pad(flags, width) + ' ' + optionalWrap(description, descriptionWidth, width + 2);
};

// Explicit options (including version)
const help = this.options.map((option) => {
const fullDesc = option.description +
((!option.negate && option.defaultValue !== undefined) ? ' (default: ' + JSON.stringify(option.defaultValue) + ')' : '');
return padOptionDetails(option.flags, fullDesc);
});

// Implicit help
const showShortHelpFlag = this._hasHelpOption && this._helpShortFlag && !this._findOption(this._helpShortFlag);
const showLongHelpFlag = this._hasHelpOption && !this._findOption(this._helpLongFlag);
if (showShortHelpFlag || showLongHelpFlag) {
let helpFlags = this._helpFlags;
if (!showShortHelpFlag) {
helpFlags = this._helpLongFlag;
} else if (!showLongHelpFlag) {
helpFlags = this._helpShortFlag;
}
help.push(padOptionDetails(helpFlags, this._helpDescription));
}

return help.join('\n');
return Math.max(
this.largestOptionLength(),
this.largestCommandHelpTermLength(),
this.largestArgLength()
);
};

/**
* Return command help documentation.
*
* @return {string}
* @api private
* @api public
*/

commandHelp() {
if (!this.commands.length && !this._lazyHasImplicitHelpCommand()) return '';

const commands = this.prepareCommands();
helpInformation() {
const width = this.padWidth();

const columns = process.stdout.columns || 80;
const descriptionWidth = columns - width - 4;

return [
'Commands:',
commands.map((cmd) => {
const desc = cmd[1] ? ' ' + cmd[1] : '';
return (desc ? pad(cmd[0], width) : cmd[0]) + optionalWrap(desc, descriptionWidth, width + 2);
}).join('\n').replace(/^/gm, ' '),
''
].join('\n');
};

/**
* Return program help documentation.
*
* @return {string}
* @api public
*/

helpInformation() {
let desc = [];
if (this._description) {
desc = [
this._description,
''
];

const argsDescription = this._argsDescription;
if (argsDescription && this._args.length) {
const width = this.padWidth();
const columns = process.stdout.columns || 80;
const descriptionWidth = columns - width - 5;
desc.push('Arguments:');
desc.push('');
this._args.forEach((arg) => {
desc.push(' ' + pad(arg.name, width) + ' ' + wrap(argsDescription[arg.name] || '', descriptionWidth, width + 4));
});
desc.push('');
function formatItem(term, description) {
if (description) {
return pad(term, width) + ' ' + optionalWrap(description, descriptionWidth, width + 2);
}
return term;
};
function formatList(text) {
return text.join('\n').replace(/^/gm, ' ');
}

// Usage
let cmdName = this._name;
if (this._aliases[0]) {
cmdName = cmdName + '|' + this._aliases[0];
Expand All @@ -1592,29 +1538,41 @@ Read more on https://git.io/JJc0W`);
for (let parentCmd = this.parent; parentCmd; parentCmd = parentCmd.parent) {
parentCmdNames = parentCmd.name() + ' ' + parentCmdNames;
}
const usage = [
'Usage: ' + parentCmdNames + cmdName + ' ' + this.usage(),
''
];

let cmds = [];
const commandHelp = this.commandHelp();
if (commandHelp) cmds = [commandHelp];

let options = [];
if (this._hasHelpOption || this.options.length > 0) {
options = [
'Options:',
'' + this.optionHelp().replace(/^/gm, ' '),
''
];
let output = ['Usage: ' + parentCmdNames + cmdName + ' ' + this.usage(), ''];

// Description
if (this._description) {
output = output.concat([this._description, '']);
}

// Arguments
const visibleArguments = this.visibleArguments();
if (visibleArguments.length) {
const argumentsList = visibleArguments.map((argument) => {
return formatItem(argument.term, argument.description);
});
output = output.concat(['Arguments:', formatList(argumentsList), '']);
}

// Optioms
const visibleOptions = this.visibleOptions();
if (visibleOptions.length) {
const optionList = visibleOptions.map((option) => {
return formatItem(option.flags, option.fullDescription());
});
output = output.concat(['Options:', formatList(optionList), '']);
}

// Commands
const visibleCommands = this.visibleCommands();
if (visibleCommands.length) {
const commandList = visibleCommands.map((cmd) => {
return formatItem(cmd.helpTerm(), cmd.description());
});
output = output.concat(['Commands:', formatList(commandList), '']);
}

return usage
.concat(desc)
.concat(options)
.concat(cmds)
.join('\n');
return output.join('\n');
};

/**
Expand Down
19 changes: 0 additions & 19 deletions tests/command.commandHelp.test.js

This file was deleted.

4 changes: 2 additions & 2 deletions tests/helpwrap.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ Options:
-h, --help display help for command

Commands:
alpha Lorem mollit quis dolor ex do eu quis ad
insa a commodo esse.
alpha Lorem mollit quis dolor ex do eu quis ad insa
a commodo esse.
help [command] display help for command
`;

Expand Down