Repository: oclif/core
Pull request #1003 (2024-03-05 21:36:03)

feat: print ellipsis on arg if static is false
Print `...` on arg if `static = false`

```
❯ bin/dev.js hello world --help
Say hello world

USAGE
  $ oex hello world [THINGS...]

ARGUMENTS
  THINGS...  things to say

DESCRIPTION
  Say hello world

EXAMPLES
  $ oex hello world
  hello world! (./src/commands/hello/world.ts)
```

Fixes https://github.com/oclif/plugin-help/issues/58
Fixes https://github.com/oclif/oclif/issues/234
Fixes https://github.com/oclif/plugin-help/issues/56


Patch:
diff --git a/src/help/command.ts b/src/help/command.ts
index 8ddbef8..2a09087 100644
--- a/src/help/command.ts
+++ b/src/help/command.ts
@@ -59,7 +59,8 @@ export class CommandHelp extends HelpFormatter {
     if (args.filter((a) => a.description).length === 0) return
 
     return args.map((a) => {
-      const name = a.name.toUpperCase()
+      // Add ellipsis to indicate that the argument takes multiple values if strict is false
+      const name = this.command.strict === false ? `${a.name.toUpperCase()}...` : a.name.toUpperCase()
       let description = a.description || ''
       if (a.default)
         description = `${colorize(this.config?.theme?.flagDefaultValue, `[default: ${a.default}]`)} ${description}`
diff --git a/src/help/docopts.ts b/src/help/docopts.ts
index 5ae005c..1cd80b4 100644
--- a/src/help/docopts.ts
+++ b/src/help/docopts.ts
@@ -61,7 +61,7 @@ export class DocOpts {
 
   private flagMap: {[index: string]: Command.Flag.Any}
 
-  public constructor(private cmd: Command.Cached | Command.Class | Command.Loadable) {
+  public constructor(private cmd: Command.Loadable) {
     // Create a new map with references to the flags that we can manipulate.
     this.flagMap = {}
     this.flagList = Object.entries(cmd.flags || {})
@@ -72,16 +72,18 @@ export class DocOpts {
       })
   }
 
-  public static generate(cmd: Command.Cached | Command.Class | Command.Loadable): string {
+  public static generate(cmd: Command.Loadable): string {
     return new DocOpts(cmd).toString()
   }
 
   public toString(): string {
     const opts = ['<%= command.id %>']
     if (this.cmd.args) {
+      // If strict is false, add ellipsis to indicate that the argument takes multiple values
+      const suffix = this.cmd.strict === false ? '...' : ''
       const a =
         Object.values(ensureArgObject(this.cmd.args)).map((arg) =>
-          arg.required ? arg.name.toUpperCase() : `[${arg.name.toUpperCase()}]`,
+          arg.required ? `${arg.name.toUpperCase()}${suffix}` : `[${arg.name.toUpperCase()}${suffix}]`,
         ) || []
       opts.push(...a)
     }


Test patch:
diff --git a/test/help/format-command.test.ts b/test/help/format-command.test.ts
index ed035e1..5d0cb55 100644
--- a/test/help/format-command.test.ts
+++ b/test/help/format-command.test.ts
@@ -517,6 +517,25 @@ FLAG DESCRIPTIONS
 ARGUMENTS
   ARG1  (option1|option2) Show the options`)
     })
+
+    it('should output arg with ... if static is false', async () => {
+      const cmd = await makeLoadable(
+        makeCommandClass({
+          id: 'apps:create',
+          strict: false,
+          args: {
+            arg1: Args.string({description: 'Show the options'}),
+          },
+        }),
+      )
+
+      const output = help.formatCommand(cmd)
+      expect(output).to.equal(`USAGE
+  $ oclif apps:create [ARG1...]
+
+ARGUMENTS
+  ARG1...  Show the options`)
+    })
   })
 
   describe('usage', () => {
diff --git a/test/help/help-test-utils.ts b/test/help/help-test-utils.ts
index 3461695..8da2d08 100644
--- a/test/help/help-test-utils.ts
+++ b/test/help/help-test-utils.ts
@@ -59,7 +59,7 @@ export async function makeLoadable(command: Command.Class): Promise<Command.Load
   }
 }
 
-export function makeCommandClass(cmdProps: Partial<Command.Class>): Command.Class {
+export function makeCommandClass(cmdProps: Partial<Command.Class & Command.Loadable>): Command.Class {
   return class extends Command {
     async run(): Promise<void> {
       // do nothing