{"id":13493479,"url":"https://github.com/vtex/findhelp","last_synced_at":"2026-03-15T21:04:46.577Z","repository":{"id":57236384,"uuid":"59962678","full_name":"vtex/findhelp","owner":"vtex","description":"A simple and hackable lib to create modular CLI's","archived":false,"fork":false,"pushed_at":"2024-06-28T01:57:58.000Z","size":104,"stargazers_count":9,"open_issues_count":2,"forks_count":2,"subscribers_count":144,"default_branch":"master","last_synced_at":"2025-04-14T09:14:40.860Z","etag":null,"topics":["argv","cli","nodejs","xp-developer"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vtex.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-05-29T20:34:06.000Z","updated_at":"2023-04-27T18:35:53.000Z","dependencies_parsed_at":"2024-10-30T11:42:42.264Z","dependency_job_id":null,"html_url":"https://github.com/vtex/findhelp","commit_stats":{"total_commits":40,"total_committers":6,"mean_commits":6.666666666666667,"dds":0.475,"last_synced_commit":"f3128d11830fd1b334a6166e38168c7e52fc79ca"},"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vtex%2Ffindhelp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vtex%2Ffindhelp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vtex%2Ffindhelp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vtex%2Ffindhelp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vtex","download_url":"https://codeload.github.com/vtex/findhelp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248852183,"owners_count":21171842,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["argv","cli","nodejs","xp-developer"],"created_at":"2024-07-31T19:01:15.667Z","updated_at":"2026-03-15T21:04:46.528Z","avatar_url":"https://github.com/vtex.png","language":"JavaScript","readme":"# findhelp\n\n\u003e A simple and hackable lib to help create modular command line programs.\n\nFor those times when you just need to find some help to structure your CLI. 🔎 ℹ️\n\n## What\n\nGiven a `tree` of commands and an arguments vector, `findhelp` can:\n\n- Create a pretty \"help\" menu.\n- Traverse the tree and find the correct command.\n- *(Optionally)* Run the command `handler` with given `args` and `options`.\n\nFor example, [this tree](./src/fixtures.js) generates this help content:\n\n```\nUsage: findhelp \u003ccommand\u003e [options]\n\nCommands:\n\n  login \u003cstore\u003e [email]    Login with your account\n  logout                   Logout from current account\n  list [query]             List your packages\n  install \u003capp\u003e            Install the given app\n  uninstall \u003capp\u003e          Remove the given app\n  publish \u003capp\u003e            Publish this app\n\n  workspace new \u003cname\u003e       Create a new workspace\n  workspace delete \u003cname\u003e    Delete this workspace\n  workspace promote \u003cname\u003e   Promote this workspace to master\n  workspace list             List available workspaces\n\nOptions:\n\n  --verbose  show all logs\n  -h, --help  show help information\n  -v, --version  show version number\n```\n\nWhat's interesting is that you can assemble that tree any way you want, so your commands might be handled by completely different modules - no problem.\n\nFor a real-life usage example, take a look at [VTEX Toolbelt](https://github.com/vtex/toolbelt/).\n\n## Why\n\nNode has some pretty good, full-feature CLI libs, like [commander](https://github.com/tj/commander.js), [yargs](https://github.com/yargs/yargs) and [neodoc](https://github.com/felixschl/neodoc). Why write another one?  \n\nFirst, those projects are *very* opinionated. This is excellent for small and quick projects - they got the 95% of the cases covered. You won't go wrong with any of them!  \n\nHowever, the structure comes at the price of control. They tend to _own_ the entire lifecycle of your CLI, which might be bad if you want fine-grained control over how your program behaves.  \n\nSecond, I had a free weekend. 🙃\n\n## How\n\nUnlike other CLI solutions available, `findhelp` won't *actually do* anything for you. It finds the command based on arguments, and gets out of your way.\n\n### `find(tree, argv)` and `run(command, root)`\n\nHere's a minimal example of the `find` usage:\n\n```js\n#!/usr/bin/env node\nimport {find, run, MissingRequiredArgsError, CommandNotFoundError} from 'findhelp'\nimport {tree} from './fixtures' // Your tree defining the commands\n\ntry {\n  const found = find(tree, process.argv.slice(2))\n  run(found) // This will run the command called by the user\n} catch (e) {\n  switch (e.constructor) {\n    case MissingRequiredArgsError:\n      console.error('Missing required arguments:', e.message)\n      break\n    case CommandNotFoundError:\n      console.error('Command not found:', process.argv.slice(2))\n      break\n    default:\n      console.error('Something exploded :(')\n      console.error(e, e.stack)\n  }\n}\n```\n\nThat's it. You pass to `find` your command `tree` and your `argv`, and it will return an object like:\n\n```js\n{\n    command: \u003cthe Object with a handler function that matches\u003e,\n    args: ['any', 'required', 'or', 'optional', 'args', argv]\n}\n```\n\nThe last argument is always `argv`, as parsed by `minimist`. It will contain any flag `options` defined by your command.\n\nYou can optionally use `run`, which calls `command.handler` with the provided `args` for you.\n\n### `help(tree, {name})`\n\nYou can use that same `tree` to output a pretty help menu. The second parameter is an object with the name of the command line application. Here's the handler for the root command in that example:\n\n```js\nimport {help} from 'findhelp'\n\nhandler: (options) =\u003e {\n  if (options.h || options.help) {\n    console.log(help(tree, {name: 'findhelp'}))\n  } else if (options.v || options.version) {\n    console.log(pkg.version)\n  } else {\n    console.log('Hi, there! :)')\n  }\n}\n```\n\nNo automatic anything. You're in control. (Use your power wisely).\n\n### The command tree\n\nA command tree is composed of one or many command objects with:\n\n- **`requiredArgs`**: Required arguments to run the command\n- **`optinalArgs`**: Optional arguments\n- **`description`**: Description to be displayed in the `help()` function\n- **`handler`**: Function that will be called with the `run()` function passing the required and optional arguments as parameters\n- **`alias`**: An alias for the command\n- **`options`**: An object of [`options`](#options)\n\nThe `handler` can be either a function or a string that locates the module where the handling function is the default export. The `root` parameter in `run()` will be used to resolve the full path of the module in the case a string is passed. If `handler` is not specified, findhelp will try to locate the module following the folders maching the command tree structure from the specified `root` (see the examples below).\n\n#### Examples\n\n```js\nlogin: {\n  requiredArgs: 'store',\n  optionalArgs: 'email',\n  description: 'Login with your account',\n  handler: (store, email, options) =\u003e { /* do awesome stuff! */ },\nlogout: {\n  description: 'Logout from current account',\n  handler: './logout'\n},\nworkspace: {\n  new: {\n    requiredArgs: 'name',\n    description: 'Create a new workspace',\n    // will look at './workspace/new' (from root) for handling function\n  },\n  delete: {\n    requiredArgs: 'name',\n    description: 'Delete this workspace',\n    options: [\n      {\n        short: 'a',\n        long: 'account',\n        type: 'string',\n      },\n    ],\n    // will look at './workspace/delete' (from root) for handling function\n  },\n}\n```\n\nHere is how './workspace/delete' could look like:\n\n```js\nexport default async (name, {account}) =\u003e {\n  // ...\n}\n```\n\nThese will define the following commands:\n- `yourapp login \u003cstore\u003e [email]`\n- `yourapp crazy \u003cmustbegiven\u003e [thisisfine]`\n\n#### Namespaces\n\nNamespaces enable commands with 2 or more levels. Example:\n\n```js\nworkspace: {\n  new: {\n    requiredArgs: 'name',\n    description: 'Create a new workspace',\n    handler: console.log.bind(console),\n  },\n  delete: {\n    requiredArgs: 'name',\n    description: 'Delete this workspace',\n    options: [\n      {\n        short: 'a',\n        long: 'account',\n        type: 'string',\n      },\n    ],\n    handler: console.log.bind(console),\n  },\n}\n```\n\nThese will define the following commands:\n- `yourapp workspace new \u003cname\u003e`\n- `yourapp workspace delete \u003cname\u003e`\n\n### Options\n\nAn array containing options:\n\n```js\noptions: [\n  {\n    long: 'verbose',\n    description: 'show all logs',\n    type: 'boolean',\n  },\n  {\n    short: 'h',\n    long: 'help',\n    description: 'show help information',\n    type: 'boolean',\n  },\n  {\n    long: 'version',\n    short: 'v',\n    description: 'show version number',\n    type: 'boolean',\n  },\n]\n```\n\nThese will enable the following options:\n- `yourapp --verbose`\n\n- `yourapp --help` or `yourapp -h`\n- `yourapp --version` or `yourapp -v`\n\n## That's it\n\nNow you know everything. Go play! Then, submit a sweet pull request to make this shinier. Thanks. 🤓\n","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvtex%2Ffindhelp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvtex%2Ffindhelp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvtex%2Ffindhelp/lists"}