Skip to content

Commit

Permalink
Merge pull request #819 from oclif/mdonnalley/hide-aliases-option
Browse files Browse the repository at this point in the history
feat: add hideAliases help option
  • Loading branch information
WillieRuemmele committed Oct 13, 2023
2 parents 5c38ac6 + 1ac65fe commit e5f9d6e
Show file tree
Hide file tree
Showing 13 changed files with 113 additions and 15 deletions.
4 changes: 4 additions & 0 deletions src/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ export abstract class Command {
/** Hide the command from help */
public static hidden: boolean

/** An array of aliases for this command that are hidden from help. */
public static hiddenAliases: string[] = []

/** A command ID, used mostly in error or verbose reporting. */
public static id: string

Expand Down Expand Up @@ -414,6 +417,7 @@ export namespace Command {
flags: {[name: string]: Flag.Cached}
hasDynamicHelp?: boolean
hidden: boolean
hiddenAliases: string[]
id: string
isESM?: boolean
permutations?: string[]
Expand Down
16 changes: 12 additions & 4 deletions src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -784,17 +784,15 @@ export class Config implements IConfig {
this.commandPermutations.add(permutation, command.id)
}

// set command aliases
for (const alias of command.aliases ?? []) {
const handleAlias = (alias: string, hidden = false) => {
if (this._commands.has(alias)) {
const prioritizedCommand = this.determinePriority([this._commands.get(alias)!, command])
this._commands.set(alias, {...prioritizedCommand, id: alias})
} else {
this._commands.set(alias, {...command, id: alias})
this._commands.set(alias, {...command, hidden, id: alias})
}

// set every permutation of the aliases

// v3 moved command alias permutations to the manifest, but some plugins may not have
// the new manifest yet. For those, we need to calculate the permutations here.
const aliasPermutations =
Expand All @@ -806,6 +804,16 @@ export class Config implements IConfig {
this.commandPermutations.add(permutation, command.id)
}
}

// set command aliases
for (const alias of command.aliases ?? []) {
handleAlias(alias)
}

// set hidden command aliases
for (const alias of command.hiddenAliases ?? []) {
handleAlias(alias, true)
}
}

marker?.addDetails({commandCount: plugin.commands.length})
Expand Down
5 changes: 3 additions & 2 deletions src/flags.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable valid-jsdoc */
import {URL} from 'node:url'

import {CLIError} from './errors'
Expand Down Expand Up @@ -140,7 +139,9 @@ export const help = (opts: Partial<BooleanFlag<boolean>> = {}): BooleanFlag<void
...opts,
async parse(_, cmd) {
const Help = await loadHelpClass(cmd.config)
await new Help(cmd.config, cmd.config.pjson.helpOptions).showHelp(cmd.id ? [cmd.id, ...cmd.argv] : cmd.argv)
await new Help(cmd.config, cmd.config.pjson.oclif.helpOptions ?? cmd.config.pjson.helpOptions).showHelp(
cmd.id ? [cmd.id, ...cmd.argv] : cmd.argv,
)
cmd.exit(0)
},
})
Expand Down
11 changes: 6 additions & 5 deletions src/help/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,13 @@ export class Help extends HelpBase {

protected formatCommands(commands: Array<Command.Loadable>): string {
if (commands.length === 0) return ''

const body = this.renderList(
commands.map((c) => {
if (this.config.topicSeparator !== ':') c.id = c.id.replaceAll(':', this.config.topicSeparator)
return [c.id, this.summary(c)]
}),
commands
.filter((c) => (this.opts.hideAliasesFromRoot ? !c.aliases?.includes(c.id) : true))
.map((c) => {
if (this.config.topicSeparator !== ':') c.id = c.id.replaceAll(':', this.config.topicSeparator)
return [c.id, this.summary(c)]
}),
{
indentation: 2,
spacer: '\n',
Expand Down
4 changes: 4 additions & 0 deletions src/interfaces/help.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ export interface HelpOptions {
* Use docopts as the usage. Defaults to true.
*/
docopts?: boolean
/**
* If true, hide command aliases from the root help output. Defaults to false.
*/
hideAliasesFromRoot?: boolean
/**
* By default, the command summary is show at the top of the help and as the first line in
* the command description. Repeating the summary in the command description improves readability
Expand Down
2 changes: 1 addition & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export async function run(argv?: string[], options?: Interfaces.LoadOptions): Pr
// display help version if applicable
if (helpAddition(argv, config)) {
const Help = await loadHelpClass(config)
const help = new Help(config, config.pjson.helpOptions)
const help = new Help(config, config.pjson.oclif.helpOptions ?? config.pjson.helpOptions)
await help.showHelp(argv)
await collectPerf()
return
Expand Down
6 changes: 4 additions & 2 deletions src/util/cache-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,15 +95,17 @@ export async function cacheCommand(
const args = await cacheArgs(ensureArgObject(cmd.args), respectNoCacheDefault)

const stdProperties = {
aliases: cmd.aliases || [],
aliases: cmd.aliases ?? [],
args,
deprecateAliases: cmd.deprecateAliases,
deprecationOptions: cmd.deprecationOptions,
description: cmd.description,
examples: cmd.examples || (cmd as any).example,
// Support both `examples` and `example` for backwards compatibility.
examples: cmd.examples ?? (cmd as unknown as {example: string}).example,
flags,
hasDynamicHelp: Object.values(flags).some((f) => f.hasDynamicHelp),
hidden: cmd.hidden,
hiddenAliases: cmd.hiddenAliases ?? [],
id: cmd.id,
pluginAlias: plugin && plugin.alias,
pluginName: plugin && plugin.name,
Expand Down
2 changes: 2 additions & 0 deletions test/config/config.flexible.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ describe('Config with flexible taxonomy', () => {
flagA: Flags.boolean({char: 'a'}),
},
hidden: false,
hiddenAliases: [],
id: commandIds[0],
async load(): Promise<Command.Class> {
return MyCommandClass
Expand All @@ -74,6 +75,7 @@ describe('Config with flexible taxonomy', () => {
flagB: Flags.boolean({}),
},
hidden: false,
hiddenAliases: [],
id: commandIds[1],
async load(): Promise<Command.Class> {
return MyCommandClass
Expand Down
2 changes: 2 additions & 0 deletions test/config/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ describe('Config', () => {
args: {},
flags: {},
hidden: false,
hiddenAliases: [],
id: commandIds[0],
async load(): Promise<Command.Class> {
return MyCommandClass
Expand All @@ -264,6 +265,7 @@ describe('Config', () => {
args: {},
flags: {},
hidden: false,
hiddenAliases: [],
id: commandIds[1],
async load(): Promise<Command.Class> {
return MyCommandClass
Expand Down
9 changes: 9 additions & 0 deletions test/help/fixtures/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,12 @@ export class LongDescription extends Command {
'run'
}
}

export class CommandWithAliases extends Command {
static aliases = ['bar', 'baz', 'qux']
static description = 'This is a command with aliases'
static id = 'foo'
async run(): Promise<void> {
'run'
}
}
64 changes: 64 additions & 0 deletions test/help/show-help.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
AppsDestroy,
AppsIndex,
AppsTopic,
CommandWithAliases,
DbCreate,
DbTopic,
DeprecateAliases,
Expand Down Expand Up @@ -135,6 +136,69 @@ USAGE
COMMANDS
apps List all apps (app index command)`)
})

test
.loadConfig()
.stdout()
.do(async (ctx) => {
const {config} = ctx

monkeyPatchCommands(config, [
{
name: 'plugin-1',
commands: [CommandWithAliases],
topics: [],
},
])

const help = new TestHelp(config as any, {hideAliasesFromRoot: true})
await help.showHelp([])
})
.it('shows root help without aliases if hideAliasesFromRoot=true', ({stdout, config}) => {
expect(stdout.trim()).to.equal(`base library for oclif CLIs
VERSION
${config.userAgent}
USAGE
$ oclif [COMMAND]
COMMANDS
foo This is a command with aliases`)
})

test
.loadConfig()
.stdout()
.do(async (ctx) => {
const {config} = ctx

monkeyPatchCommands(config, [
{
name: 'plugin-1',
commands: [CommandWithAliases],
topics: [],
},
])

const help = new TestHelp(config as any)
await help.showHelp([])
})
.it('shows root help with aliases commands by default', ({stdout, config}) => {
expect(stdout.trim()).to.equal(`base library for oclif CLIs
VERSION
${config.userAgent}
USAGE
$ oclif [COMMAND]
COMMANDS
bar This is a command with aliases
baz This is a command with aliases
foo This is a command with aliases
qux This is a command with aliases`)
})
})

describe('showHelp for a topic', () => {
Expand Down
1 change: 0 additions & 1 deletion test/integration/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ export class Executor {
}
}

// eslint-disable-next-line valid-jsdoc
/**
* Setup for integration tests.
*
Expand Down
2 changes: 2 additions & 0 deletions test/util/cache-command.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ describe('cacheCommand', () => {
state: undefined,
description: 'test command',
aliases: ['alias1', 'alias2'],
hiddenAliases: [],
title: 'cmd title',
usage: ['$ usage'],
examples: undefined,
Expand Down Expand Up @@ -193,6 +194,7 @@ describe('cacheCommand', () => {
hidden: undefined,
state: 'beta',
aliases: ['base'],
hiddenAliases: [],
examples: undefined,
deprecationOptions: undefined,
deprecateAliases: undefined,
Expand Down

0 comments on commit e5f9d6e

Please sign in to comment.