Repository: oclif/core
Pull request #205 (2021-07-26 19:48:00)

fix: restore short flags for --help and --version
@W-9612538@

peternhale: > I second Mike's comments, [#205 (comment)](https://github.com/oclif/core/pull/205#discussion_r677539916). Per the `sf` styleguide and generally accepted CLI standards if something has `--` at the front it's a long flag, if it has `-` it's a short flag, if it doesn't have either it's a command.
> 
> I also see that the config properties were changed from "override" to "additional" but it seems like everything in the code itself is still using the "override" verbiage. I'd like to see that changed too for consistency and readability.

I have made the adjustments that protect cmds help and version. Fixing refs to override to be more inline with context.

Patch:
diff --git a/src/flags.ts b/src/flags.ts
index b72198b..a0b3872 100644
--- a/src/flags.ts
+++ b/src/flags.ts
@@ -30,7 +30,6 @@ export {boolean, integer, url} from './parser'
 
 export const version = (opts: Partial<BooleanFlag<boolean>> = {}) => {
   return Parser.flags.boolean({
-    // char: 'v',
     description: 'show CLI version',
     ...opts,
     parse: async (_: any, cmd: Command) => {
@@ -42,7 +41,6 @@ export const version = (opts: Partial<BooleanFlag<boolean>> = {}) => {
 
 export const help = (opts: Partial<BooleanFlag<boolean>> = {}) => {
   return Parser.flags.boolean({
-    // char: 'h',
     description: 'show CLI help',
     ...opts,
     parse: async (_: any, cmd: Command) => {
diff --git a/src/help/index.ts b/src/help/index.ts
index 1d041a9..9ba2f32 100644
--- a/src/help/index.ts
+++ b/src/help/index.ts
@@ -11,10 +11,19 @@ import {HelpFormatter} from './formatter'
 export {CommandHelp} from './command'
 export {standardizeIDFromArgv, loadHelpClass} from './util'
 
-function getHelpSubject(args: string[]): string | undefined {
+const helpFlags = ['--help']
+
+export function getHelpFlagAdditions(config: Interfaces.Config): string[] {
+  const additionalHelpFlags = config.pjson.oclif.additionalHelpFlags ?? []
+  return [...new Set([...helpFlags, ...additionalHelpFlags]).values()]
+}
+
+function getHelpSubject(args: string[], config: Interfaces.Config): string | undefined {
+  // for each help flag that starts with '--' create a new flag with same name sans '--'
+  const mergedHelpFlags = getHelpFlagAdditions(config)
   for (const arg of args) {
     if (arg === '--') return
-    if (arg === 'help' || arg === '--help') continue
+    if (mergedHelpFlags.includes(arg) || arg === 'help') continue
     if (arg.startsWith('-')) return
     return arg
   }
@@ -82,7 +91,7 @@ export class Help extends HelpBase {
 
   public async showHelp(argv: string[]) {
     if (this.config.topicSeparator !== ':') argv = standardizeIDFromArgv(argv, this.config)
-    const subject = getHelpSubject(argv)
+    const subject = getHelpSubject(argv, this.config)
     if (!subject) {
       if (this.config.pjson.oclif.default) {
         const rootCmd = this.config.findCommand(this.config.pjson.oclif.default)
diff --git a/src/interfaces/pjson.ts b/src/interfaces/pjson.ts
index 9ce15e7..ca0f534 100644
--- a/src/interfaces/pjson.ts
+++ b/src/interfaces/pjson.ts
@@ -43,6 +43,8 @@ export namespace PJSON {
           hidden?: boolean;
         };
       };
+      additionalHelpFlags?: string[];
+      additionalVersionFlags?: string[];
     };
   }
 
diff --git a/src/main.ts b/src/main.ts
index f75116b..822febd 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -4,7 +4,7 @@ import {format, inspect} from 'util'
 
 import * as Interfaces from './interfaces'
 import {Config} from './config'
-import {loadHelpClass, standardizeIDFromArgv} from './help'
+import {getHelpFlagAdditions, loadHelpClass, standardizeIDFromArgv} from './help'
 
 const log = (message = '', ...args: any[]) => {
   // tslint:disable-next-line strict-type-predicates
@@ -12,17 +12,20 @@ const log = (message = '', ...args: any[]) => {
   process.stdout.write(format(message, ...args) + '\n')
 }
 
-const helpOverride = (argv: string[], config: Interfaces.Config): boolean => {
+export const helpAddition = (argv: string[], config: Interfaces.Config): boolean => {
   if (argv.length === 0 && !config.pjson.oclif.default) return true
+  const mergedHelpFlags = getHelpFlagAdditions(config)
   for (const arg of argv) {
-    if (arg === '--help') return true
+    if (mergedHelpFlags.includes(arg)) return true
     if (arg === '--') return false
   }
   return false
 }
 
-const versionOverride = (argv: string[]): boolean => {
-  if (['--version'].includes(argv[0])) return true
+export const versionAddition = (argv: string[], config?: Interfaces.Config): boolean => {
+  const additionalVersionFlags = config?.pjson.oclif.additionalVersionFlags ?? []
+  const mergedVersionFlags = [...new Set([...['--version'], ...additionalVersionFlags]).values()]
+  if (mergedVersionFlags.includes(argv[0])) return true
   return false
 }
 
@@ -41,17 +44,14 @@ export async function run(argv = process.argv.slice(2), options?: Interfaces.Loa
   await config.runHook('init', {id, argv: argvSlice})
 
   // display version if applicable
-  if (versionOverride(argv)) {
+  if (versionAddition(argv, config)) {
     log(config.userAgent)
     return
   }
 
   // display help version if applicable
-  if (helpOverride(argv, config)) {
-    argv = argv.filter(arg => {
-      if (arg === '--help') return false
-      return true
-    })
+  if (helpAddition(argv, config)) {
+    argv = argv.filter(arg => !getHelpFlagAdditions(config).includes(arg))
     const Help = await loadHelpClass(config)
     const help = new Help(config, config.pjson.helpOptions)
     await help.showHelp(argv)


Test patch:
diff --git a/test/config/fixtures/help/package.json b/test/config/fixtures/help/package.json
new file mode 100644
index 0000000..832fdfa
--- /dev/null
+++ b/test/config/fixtures/help/package.json
@@ -0,0 +1,12 @@
+{
+  "name": "help-plugin",
+  "description": "Module type ESM; Configure help and version flag overrides",
+  "private": true,
+  "type": "module",
+  "files": [],
+  "oclif": {
+    "commands": "./src/commands",
+    "additionalHelpFlags": ["-h", "--mycommandhelp"],
+    "additionalVersionFlags": ["-v", "myversion", "version"]
+  }
+}
diff --git a/test/config/fixtures/help/src/commands/foo/bar/baz.js b/test/config/fixtures/help/src/commands/foo/bar/baz.js
new file mode 100644
index 0000000..778ed84
--- /dev/null
+++ b/test/config/fixtures/help/src/commands/foo/bar/baz.js
@@ -0,0 +1,5 @@
+export class Command {
+  static run() {
+    console.log('it works!')
+  }
+}
diff --git a/test/config/help.config.test.ts b/test/config/help.config.test.ts
new file mode 100644
index 0000000..4692301
--- /dev/null
+++ b/test/config/help.config.test.ts
@@ -0,0 +1,51 @@
+import * as url from 'url'
+import * as path from 'path'
+
+import {Config} from '../../src/config'
+
+import {expect, fancy} from './test'
+import {getHelpFlagAdditions} from '../../src/help'
+import {helpAddition, versionAddition} from '../../src/main'
+
+const root = path.resolve(__dirname, 'fixtures/help')
+// const p = (p: string) => path.join(root, p)
+
+// This tests file URL / import.meta.url simulation.
+const rootAsFileURL = url.pathToFileURL(root).toString()
+
+const withConfig = fancy
+.add('config', () => Config.load(rootAsFileURL))
+
+describe('help and version flag additions', () => {
+  withConfig
+  .it('has help and version additions', ({config}) => {
+    expect(config.pjson.oclif.additionalHelpFlags).to.have.lengthOf(2)
+    expect(config.pjson.oclif.additionalVersionFlags).to.have.lengthOf(3)
+    const mergedHelpFlags = getHelpFlagAdditions(config)
+    expect(mergedHelpFlags).to.deep.equal(['--help', ...config.pjson.oclif.additionalHelpFlags as string[]])
+    expect(helpAddition(['-h'], config)).to.be.true
+    expect(helpAddition(['help'], config)).to.be.false
+    expect(helpAddition(['--mycommandhelp'], config)).to.be.true
+    expect(helpAddition(['foobar'], config)).to.be.false
+    expect(versionAddition(['-v'], config)).to.be.true
+    expect(versionAddition(['version'], config)).to.be.true
+    expect(versionAddition(['myversion'], config)).to.be.true
+    expect(versionAddition(['notmyversion'], config)).to.be.false
+  })
+
+  withConfig
+  .do(({config}) => delete config.pjson.oclif.additionalHelpFlags)
+  .it('has version additions', ({config}) => {
+    expect(config.pjson.oclif.additionalHelpFlags).to.not.be.ok
+    expect(config.pjson.oclif.additionalVersionFlags).to.have.lengthOf(3)
+    const mergedHelpFlags = getHelpFlagAdditions(config)
+    expect(mergedHelpFlags).to.deep.equal(['--help'])
+    expect(helpAddition(['-h'], config)).to.be.false
+    expect(helpAddition(['help'], config)).to.be.false
+    expect(helpAddition(['mycommandhelp'], config)).to.be.false
+    expect(versionAddition(['-v'], config)).to.be.true
+    expect(versionAddition(['version'], config)).to.be.true
+    expect(versionAddition(['myversion'], config)).to.be.true
+    expect(versionAddition(['notmyversion'], config)).to.be.false
+  })
+})