Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strange API behaviour for command description #2290

Open
PFight opened this issue Dec 5, 2024 · 3 comments
Open

Strange API behaviour for command description #2290

PFight opened this issue Dec 5, 2024 · 3 comments
Labels
bug Commander is not working as intended pending release Merged into a branch for a future release, but not released yet

Comments

@PFight
Copy link

PFight commented Dec 5, 2024

When adding description to command declaration, command does not work.

Working code:

program.command('analyze')
  .description('Do analyze.')
  .action(() => console.info("Hello explain!");

Execute:

> node index.js analyze
> Hello explain!

Not working code:

program.command('analyze', 'Do analyze.')
  .action(() => console.info("Hello explain!");

Execute:

> node index.js analyze
internal/modules/cjs/loader.js:892
  throw err;
  ^

Error: Cannot find module 'C:\Dev\stuff\npm-dependency-inspector\index-analyze'
?[90m    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:889:15)?[39m
?[90m    at Function.Module._load (internal/modules/cjs/loader.js:745:27)?[39m
?[90m    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:76:12)?[39m
?[90m    at internal/main/run_main_module.js:17:47?[39m {
  code: ?[32m'MODULE_NOT_FOUND'?[39m,
  requireStack: []
}

I spent HOURS to find a way to make commander work for simpliest command. Read all docummentation, tried several versions, and only happy accident helped me - I added description for one command, and do not added to another. So I found, that another command working and this give me a tip.

I think, when description specified, or command options specified, commander begin interpretate it as executable command. If it is true, then action() should throw error - it is usless for executable command. WTF? Why simple adding description change behaviour totally? And where in documentation this behaviour is specified?

@PFight PFight changed the title Strange API behaviour for command Strange API behaviour for command description Dec 5, 2024
@shadowspawn
Copy link
Collaborator

Sorry you hit this problem. This used to be a common source of confusion: #938

The README was updated to mention the behaviour. In particular in the example code in the Commands section: https://github.com/tj/commander.js?tab=readme-ov-file#commands

commander.js/Readme.md

Lines 519 to 541 in 970ecae

For example:
```js
// Command implemented using action handler (description is supplied separately to `.command`)
// Returns new command for configuring.
program
.command('clone <source> [destination]')
.description('clone a repository into a newly created directory')
.action((source, destination) => {
console.log('clone command called');
});
// Command implemented using stand-alone executable file, indicated by adding description as second parameter to `.command`.
// Returns `this` for adding more commands.
program
.command('start <service>', 'start named service')
.command('stop [service]', 'stop named service, or all if no name supplied');
// Command prepared separately.
// Returns `this` for adding more commands.
program
.addCommand(build.makeBuildCommand());
```

And in the section: https://github.com/tj/commander.js?tab=readme-ov-file#stand-alone-executable-subcommands

When .command() is invoked with a description argument, this tells Commander that you're going to use stand-alone executables for subcommands. Commander will search the files in the directory of the entry script for a file with the name combination command-subcommand, like pm-install or pm-search in the example below. The search includes trying common file extensions, like .js.

There is also a message explaining the possible problem if a missing external command is detected at runtime, but you didn't see that. I suspect a different error may be getting thrown on Windows or in recent versions of node. I'll look into that.

- if '${subcommand._name}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead

@shadowspawn
Copy link
Collaborator

Running your example program, I see this on macOS:

% node index.mjs analyze
/Users/john/Documents/Sandpits/commander/my-fork/lib/command.js:1234
        throw new Error(executableMissing);
        ^

Error: 'index-analyze' does not exist
 - if 'analyze' 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/2290'
 ...

@shadowspawn
Copy link
Collaborator

Ah, the way the stand-alone executable commands get launched varies by platform, and the Windows code path does not trigger the extra message. I think we can improve that by checking for the file before spawning the process.

proc = childProcess.spawn(process.execPath, args, { stdio: 'inherit' });

@shadowspawn shadowspawn added bug Commander is not working as intended pending release Merged into a branch for a future release, but not released yet labels Dec 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Commander is not working as intended pending release Merged into a branch for a future release, but not released yet
Projects
None yet
Development

No branches or pull requests

2 participants