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

Best way to add implicitcommands? #71

Open
jdalrymple opened this issue Jun 6, 2020 · 3 comments
Open

Best way to add implicitcommands? #71

jdalrymple opened this issue Jun 6, 2020 · 3 comments

Comments

@jdalrymple
Copy link

Similar to version or help, Is it possible to add an option that triggers a command on the root?

For example:

cli.js --root-option                    [command: root-option] [boolean]

would run a root-option command just like how --help and -v run their respective commands.

I've tried to do this by using aliases, but having an alias with a '-' prefix doesn't get recognized.

Any suggestions?

@elliot-nelson
Copy link
Member

elliot-nelson commented Jun 14, 2020

Good question... by design, a single execution of sywac only runs one command, so there's not a good way to execute one command from another command.

(This would present a lot of problems -- for example, a subcommand might specify its own different check() handler, or different customization of command-line options, and that configuration would potentially be missing when we went to execute the second command.)

Here's one approach, where you define your top-level commands as separate functions and then call them from your implicit command:

function startServer(argv) {
    console.log('starting server...')
}

function stopServer(argv) {
    console.log('stopping server...')
}

require('sywac')
  .boolean('start', { desc: 'start server' })
  .boolean('stop', { desc: 'stop server' })
  .command('start', startServer)
  .command('stop', stopServer)
  .command('*', argv => {
    if (argv.start) {
      startServer()
    } else if (argv.stop) {
      stopServer()
    } else {
      console.log(sywac.getHelp())
    }
  })
  .parseAndExit()

This has some pretty serious limitations -- if you want your command to have its own set of support option flags, for example, that would not work right. But as long as you can define all supported options at the top-level, then something like this snippet might work.

@nexdrew
Copy link
Member

nexdrew commented Jun 21, 2020

Implicit commands are interesting since they equate a positive boolean option with running a command. Because of this over-simplification, implicit commands don't support most of what normal commands do (e.g. positional arguments, their own custom options, nested subcommands, etc), but you can use an implicit type to define a boolean option that kicks off some asynchronous logic if you want.

Here's an example of what it might look like in sywac 1.3.0 (note that I'm kicking off "command" logic here in a custom boolean type and I'm not using an actual command type):

// issue71.js

// the "implicit" type represents a boolean option with support
// for implicit command parsing built-in
const TypeImplicit = require('sywac/types/implicit')

// extend the implicit type to define a simplified custom command
class RootOption extends TypeImplicit {
  constructor () {
    super({
      flags: '-r, --root-option',
      desc: 'Some description'
    })
  }

  async postParse (context) {
    if (
      this.getValue(context) &&
      !context.helpRequested &&
      !context.helpRequestedImplicitly &&
      !context.versionRequested
    ) {
      // kick off the "command" logic here
      // parsed options are available in context.argv
      console.log('run the root-option command logic here')
    }
  }
}

require('sywac')
  .custom(new RootOption())
  .help('-h, --help')
  .parseAndExit()
$ node issue71.js --help
Usage: issue71 [options]

Options:
  -r, --root-option  Some description                              [commands: root-option] [boolean]
  -h, --help         Show help                                            [commands: help] [boolean]
$ node issue71.js root-option
run the root-option command logic here
$ node issue71.js --root-option
run the root-option command logic here
$ node issue71.js -r
run the root-option command logic here

We could possibly genericize the custom class for better reuse if it accepted a function (similar to a "run handler" for a command) in its configuration, but hopefully this gives you the idea.

Sorry for the long delay in responding to your question. Let me know what you think. Thanks!

@jdalrymple
Copy link
Author

Wow, thank you guys for the details responses! I managed to throw something together similar to what @elliot-nelson mentioned, thought it felt a bit hacky, hence this issue. The method you mentioned @nexdrew seems like a cleaner solution, albeit more verbose. Ill test it out!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants