diff --git a/lib/help.js b/lib/help.js index 64e358a0b..1214864f2 100644 --- a/lib/help.js +++ b/lib/help.js @@ -15,6 +15,7 @@ class Help { this.sortSubcommands = false; this.sortOptions = false; this.showGlobalOptions = false; + this.optionGroups = {}; } /** @@ -330,6 +331,41 @@ class Help { return argument.description; } + /** + * + * @param {Command} cmd + * @param {Help} helper + * @returns { object } + */ + visibleOptionGroups(cmd, helper) { + const result = { 'Options:': [] }; + + // Invert the optionGroups object to a map of optionName to groupName. + const groupLookup = new Map(); + Object.keys(this.optionGroups).concat().forEach((title) => { + result[title] = []; + this.optionGroups[title].forEach(optionName => { + // (only supporting option appearing in one group for now, last one wins) + groupLookup.set(optionName, title); + }); + }); + + // Build list of options in each group title (in order as returned by visibleOptions). + helper.visibleOptions(cmd).forEach((option) => { + const title = groupLookup.get(option.attributeName()) ?? 'Options:'; + result[title].push(option); + }); + + // Remove empty groups. + Object.keys(result).forEach((title) => { + if (result[title].length === 0) { + delete result[title]; + } + }); + + return result; + } + /** * Generate the built-in help text. * @@ -372,12 +408,13 @@ class Help { } // Options - const optionList = helper.visibleOptions(cmd).map((option) => { - return formatItem(helper.optionTerm(option), helper.optionDescription(option)); + const visibleOptionGroups = helper.visibleOptionGroups(cmd, helper); + Object.keys(visibleOptionGroups).forEach((groupTitle) => { + const optionList = visibleOptionGroups[groupTitle].map((opt) => { + return formatItem(helper.optionTerm(opt), helper.optionDescription(opt)); + }); + output = output.concat([groupTitle, formatList(optionList), '']); }); - if (optionList.length > 0) { - output = output.concat(['Options:', formatList(optionList), '']); - } if (this.showGlobalOptions) { const globalOptionList = helper.visibleGlobalOptions(cmd).map((option) => {