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

Support subcommands #69

Open
sindresorhus opened this issue Sep 29, 2017 · 9 comments
Open

Support subcommands #69

sindresorhus opened this issue Sep 29, 2017 · 9 comments

Comments

@sindresorhus
Copy link
Owner

sindresorhus commented Sep 29, 2017

Not entirely sure the best way to handle this. Suggestions welcome :)

@muuvmuuv
Copy link

Just an idea but I thought about we could do it similar to Listr

#!/usr/bin/env node
"use strict";
const meow = require("meow");
const foo = require(".");

const flags = {
  rainbow: {
    type: "boolean",
    alias: "r"
  }
}

const subCommands = {
  horseman: (flags /* parsed flags from parent */) => {
    return meow(
      `
      Usage
        $ horseman
      .....
    `,
      {
        name: {
          type: "string",
          default: "The Horseman"
        }
      }
    );
  }
}

const cli = meow(
  `
  Usage
    $ foo <input>

  Options
    --rainbow, -r  Include a rainbow

  Examples
    $ foo unicorns --rainbow
    🌈 unicorns 🌈
`,
  {
    flags,
    subCommands
  }
);

foo(cli.input[0], cli.flags);

@gtarsia
Copy link

gtarsia commented Oct 4, 2019

tldr: commands property of type Array<String> that fail if the command is not found, and possibly a level property of type Number that indicates the level of the commands.

I like meow because it's useful yet simple, but most implementations of subcommands are ridiculous, so I favor this change as long as user control and simplicity are prioritized.

I also think that the property should be called commands instead of subcommands, it's shorter and it's still correct. For example, git clone, git add and git push are all git commands.

A more simple way is making meow to expect the commands property to be an Array<String>,
It could even have suggestions in case you misspell a command (like git does).

import fetch from './cli-fetch'
import sort from './cli-sort'

const options = { fetch, sort }
const { command, flags } = meow({
  commands: Object.keys(options),
  ...
})
options[command](flags)
// each cli-<action> module can use meow in turn too
$ foo michael
foo: 'michael' is not a foo command. See foo --help
The most similar commands are
    fetch
    sort

This way meow doesn't concern with calling functions and deciding which params to pass to these.
The Object.keys usage could become a standard for deciding which command to use.

A problem with my solution is that sometimes commands are the second level, for example the connect in docker network connect. So the level option should decide the index of input to pick the command.

// fictional-docker-network.js
meow({
  level: 1,
  commands: ['connect', 'create', 'disconnect', 'inspect', 'ls', 'prune', 'rm']
})

It's simple but I'm not too sold on it. This is open to criticism and I'm willing to push a PR in any case.

Regarding @muuvmuuv's solution, I like that it doesn't support nesting of commands but it still has a couple of challenges that I think disqualifies it:

  1. It doesn't tell you which command should it run.
  2. It takes some control away by calling a function you provide it with.

@MartinMuzatko
Copy link

MartinMuzatko commented Jan 10, 2020

I have written a script to allow subcommands in this structure:
https://gist.github.com/MartinMuzatko/2922add0f84535a44f98a8e8fa729efa

@skoshx
Copy link

skoshx commented Feb 21, 2022

Any work being done on this feature? I like @muuvmuuv 's idea of having meow instances as subcommands, I think it's the most flexible, most simple & makes it easy to separate subcommands into different files for a cleaner and more maintainable codebase.

@sindresorhus Do you have any ideas/criticism to this approach? Was thinking that if no one is working on this that I could do it as soon as I have time.

@sindresorhus
Copy link
Owner Author

Do you have any ideas/criticism to this approach?

Yeah, I'm fine with that approach, but it should be called commands.

@skoshx
Copy link

skoshx commented Feb 21, 2022

I agree that it should be called commands, I'll get on it as soon as possible, unless someone beats me to the punch :D

@aaronccasanova
Copy link

Hello 👋 I've been experimenting with an alternative approach for adding support for subcommands and would love to get folks thoughts and opinions on the API!

Here is my WIP

@detj
Copy link

detj commented Aug 17, 2022

My attempt without changing anything in meow. Uses Dynamic Imports to load the additional command CLIs.

https://github.com/detj/meow-subcommands

I'm sure, there might be issues I'm unaware of. Feel free to offer suggestions.

@tommy-mitchell tommy-mitchell mentioned this issue Mar 28, 2023
9 tasks
@voxpelli
Copy link
Contributor

I solved it like this in the @SocketDev CLI: https://github.com/SocketDev/socket-cli-js/blob/f45cbd408c0575dfe205cf968596f4506f15f44d/lib/utils/meow-with-subcommands.js#L33

Planned to extract it to its own module and might still do even though I'm no longer with Socket

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

Successfully merging a pull request may close this issue.

8 participants