tj / commander.js

node.js command-line interfaces made easy
MIT License
26.67k stars 1.69k forks source link

Usage with Bun #2195

Closed hmidmrii closed 5 months ago

hmidmrii commented 5 months ago

I'm trying to build a CLI in TS with Bun, but the issue that the behavior is different from bun ./src/cli.ts command and node ./dist/cli.js command,

I'm getting this error from commander when using bun: image

for some reasons, commander is trying to merge the name with the command and then try to evaluate it, for instance if I provide pizza to the new Command('pizza'), the error became image

it only works when I try to do something like bun run ./src/cli.ts {name}-release while changing the name to the name passed to new Command(name)

hmidmrii commented 5 months ago

My code:

const prog = new Command(pkg.name);

prog.description(pkg.description).version(pkg.version);

prog
  .command('release', 'Run the fluid release tool to create a release')
  .option(releaseOptions.immediate.flags, releaseOptions.immediate.desc, releaseOptions.immediate.default)
  .option(releaseOptions.base.flags, releaseOptions.base.desc, releaseOptions.base.default)
  .option(releaseOptions.head.flags, releaseOptions.head.desc, releaseOptions.head.default)
  .option(releaseOptions.count.flags, releaseOptions.count.desc, Number, releaseOptions.count.default)
  .action(async (opts: ReleaseCommandOptions) => release(await getReleaseOptions(opts)));

prog.parse();
shadowspawn commented 5 months ago

Move the command description into a separate method like:

prog
   .command('release')
   .description('Run the fluid release tool to create a release')

(For historical reasons, the signature with command name and description together as parameters triggers a different model where the command is implemented as an external command named like ${programName}-${commandName}.)

hmidmrii commented 5 months ago

Move the command description into a separate method like:

prog
   .command('release')
   .description('Run the fluid release tool to create a release')

(For historical reasons, the signature with command name and description together as parameters triggers a different model where the command is implemented as an external command named like ${programName}-${commandName}.)

It worked!

but I think it would be helpful to be documented

shadowspawn commented 5 months ago

but I think it would be helpful to be documented

This is covered in the README, but is still subtle.

I noticed when running with node that you get extra clues when the (accidental) external command is not found. The error handling is a little different in Bun and this helpful extra text did not get displayed. I'll have a look at whether this can be displayed when using Bun too.

% node cli.js release 
/Users/john/Documents/Sandpits/commander/my-fork/lib/command.js:1225
        throw new Error(executableMissing);
        ^

Error: 'super-release' does not exist
 - if 'release' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
 - if the default executable name is not suitable, use the executableFile option to supply a custom name or path
 - searched for local subcommand relative to directory '/Users/john/Documents/Sandpits/commander/issues/2195'
    at ChildProcess.<anonymous> (/Users/john/Documents/Sandpits/commander/my-fork/lib/command.js:1225:15)
    at ChildProcess.emit (node:events:519:28)
    at ChildProcess._handle.onexit (node:internal/child_process:292:12)
    at onErrorNT (node:internal/child_process:484:16)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21)

Node.js v20.13.0
shadowspawn commented 5 months ago

I think bun might be throwing an exception from the spawn call while node is sending an error event. Looks hard enough to improve that I'll wait and see if other Bun users hit same problem.

https://github.com/tj/commander.js/blob/83c3f4e391754d2f80b179acc4bccc2d4d0c863d/lib/command.js#L1088