{"id":16836830,"url":"https://github.com/maartennnn/cli-builder","last_synced_at":"2025-04-11T05:12:44.497Z","repository":{"id":36985640,"uuid":"338625700","full_name":"maarteNNNN/cli-builder","owner":"maarteNNNN","description":"A cli builder tool to create fast and easy executable CLIs","archived":false,"fork":false,"pushed_at":"2023-02-10T01:58:41.000Z","size":554,"stargazers_count":5,"open_issues_count":6,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-11T05:12:38.378Z","etag":null,"topics":["cli","javascript","nodejs","repl"],"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/maarteNNNN.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2021-02-13T17:11:25.000Z","updated_at":"2024-06-28T09:05:16.000Z","dependencies_parsed_at":"2024-06-21T05:54:33.150Z","dependency_job_id":null,"html_url":"https://github.com/maarteNNNN/cli-builder","commit_stats":null,"previous_names":[],"tags_count":44,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maarteNNNN%2Fcli-builder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maarteNNNN%2Fcli-builder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maarteNNNN%2Fcli-builder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maarteNNNN%2Fcli-builder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maarteNNNN","download_url":"https://codeload.github.com/maarteNNNN/cli-builder/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248345267,"owners_count":21088244,"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":["cli","javascript","nodejs","repl"],"created_at":"2024-10-13T12:15:03.925Z","updated_at":"2025-04-11T05:12:44.479Z","avatar_url":"https://github.com/maarteNNNN.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CLI-Builder\n\n[API Docs](API.md)\n\n## Trying out an example\n\nThis example can be found in `bin/example-cli.js`\n\n```sh\ngit clone https://github.com/maarteNNNN/cli-builder.git\nnpm install\nnpm link\ncli-builder help\nnpm unlink # to delete the cli-builder bin\n```\n\n## Installing\n\n```\nnpm install cli-builder\n```\n\nBe sure to take a look at `bin/example-cli.js`\n\nInstantiate a new CLI with `new REPLClient({ ...options })` `REPL` stands for `Read Eval Print Loop`\n\ndefining an `commands` Object as shown below in [below](#commands-example)\n\n```js\ncli.run(commands);\n```\n\n## Commands example\n\n```js\n// DO NOT ADD HELP TO THE ROOT OBJECT. THIS IS DYNAMICALLY MOUNTED\nconst commands = {\n  test: {\n    execute: () =\u003e console.log('this is the test run'),\n    help: 'help of test',\n    testing: {\n      execute: ({ argument, options }) =\u003e\n        console.log('ARGUMENT: ', argument, '\\nOPTIONS: ', options),\n      help: 'testing help',\n      input: '\u003carg-to-pass-to-execute-function\u003e', // argument and options are passed as an object passed to execute function\n      // cmd test testing IAMPASSEDTOFUNCTION -f\n      options: [{ option: 'f', help: 'Follow the logs' }],\n    },\n    testing2: {\n      execute: () =\u003e console.log('executing testing2'),\n      help: 'testing2 help',\n    },\n  },\n  test2: {\n    execute: () =\u003e console.log('this is the test2 run'),\n    help: 'help of test2',\n  },\n  deep: {\n    nesting: {\n      works: {\n        as: {\n          // Without help\n          command: () =\u003e\n            console.log('to run this type `deep nesting works as command`'),\n          // Or with help\n          // command: {\n          //   // this get executed as `deep nesting works as command`\n          //   execute: () =\u003e console.log('to run this type `deep nesting works as command`'),\n          //   // this get executed as `deep nesting works as command help`\n          //   help: 'help of command'\n          // }\n        },\n      },\n    },\n  },\n  runSomeFunction: async () =\u003e {\n    // DO SOME INSANE LOGIC HERE\n  },\n  // A more comprehensive example below titled: Defining help with only one execute function\n  exampleWithOneExecute: {\n    knownCommand: {\n      help: 'Help for this known command',\n    },\n    // Show the user there are other commands available\n    'any-yet-unknown-property': {\n      help: 'Help for ANY UNKOWN PROPERTY',\n    },\n    async execute({ argument, options }) {\n      console.log(this); // Mounts the REPLClient dynamically\n      console.log(param); // Passes the last given argument/param dynamically\n      console.log(options); // Passes the last given options/flags dynamically\n    },\n  },\n};\n```\n\n---\n\n\u003cspan style=\"color:orange\"\u003e**WARNING**\u003c/span\u003e\n\nHelp is dynamically mounted to the `commands` object. It generates a function which will mount all child `help` properties.\n\n---\n\n---\n\n**NOTE**\n\nRunning is going through the object and should be written as arguments the following way: `deep nesting works as command` for the [example above](#commands-example) (It executes the function or the `execute` child function in case help wants to be added).\n`deep nesting works as command --help` (executes `--help or -h` child function in case it's available)\n\n---\n\n---\n\n\u003cspan style=\"color:orange\"\u003e**WARNING**\u003c/span\u003e\n\nfunctions are added as camelCase but are transformed to kebab-case:\n`run-some-function` will call result in `runSomeFunction`.\n\n---\n\n---\n\n\u003cspan style=\"color:red\"\u003e**ADVANCED EXAMPLE**\u003c/span\u003e\n\n`actions` can be used to integrate imported files. You can check out the example of a full-fledged cli implementation in [ldpos-commander](https://github.com/Leasehold/ldpos-commander/) or [SocketCluster](https://github.com/SocketCluster/socketcluster).\n\nThe CLI (`REPLCient`) object is passed to the actions functions by [`Function.prototype.bind`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)\n\nThe `bindActionArgs` are passed via [`Function.prototype.bind`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) as well. Except if an argument is passed in the commands object function Eg.\n\n---\n\n```js\nsomeFunctionCmd: {\n  // CLI as this will be available but bindActionArgs won't be as argument replaces them\n  execute: (argument) =\u003e cli.actions.someFunction(argument),\n}\n```\n\n---\n\n## A more apprehensive example\n\n```js\nconst actions = {\n  getUserData = async (id, someFunction, aString, aNumber) =\u003e {\n    try {\n      const data = await axios.get(`user/${id}`)\n\n      console.log(this.argv) // logs all passed arguments with - and --\n\n      // this references to the cli object as it's bound\n      this.successLog(data)\n\n      someFunction()\n\n      console.log(aString, aNumber)\n    } catch (e) {\n      throw new Error(e)\n    }\n  }\n}\n\n// Binding below array to `options.bindActionArgs` in `new REPLClient({ ...options })`\nconst options = {\n  bindActionArgs = [123, () =\u003e console.log('function executed'), 'a string', 23123]\n}\n\nconst cli = new REPLClient(options)\n\nconst commands = {\n  // No arguments are passed here, they are mounted dynamically\n  anActionTest: async () =\u003e await cli.actions.getUserData()\n}\n\ncli.run(commands)\n```\n\nusing `cli-builder an-action-test` will execute the `getUserData` function with the `bindActionArgs` parameters bound to it.\n\n## Defining `help` with only one `execute` function\n\nWhen you want to dynamically output to the console Eg. get a JSON Object from an API with undefined structure but you want to be able to log any of those properties to the console it can be done via:\n\n```js\nconst commands = {\n  entrypoint: {\n    any: {\n      help: 'Help for any',\n    },\n    extra: {\n      help: 'Help for extra',\n    },\n    helping: {\n      help: 'Help for helping',\n    },\n    commands: {\n      help: 'Help for commands',\n    },\n    'any-unknown-property': {\n      help: 'Help for ANY UNKOWN PROPERTY',\n    },\n    async execute(param) {\n      param = cli.kebabCaseToCamel(param);\n\n      // We don't want the paging info in this case\n      const {\n        data: { data },\n      } = axios.get('https://reqres.in/api/users?page=2');\n\n      // If null it could be accessible, if undefined we know for sure it isn't\n      if (!data[param] === undefined)\n        throw new Error('Custom property not found.');\n\n      // The `REPLCient` is object is dynamically mounted\n      this.successLog(data[param], `${param}:`);\n    },\n  },\n};\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaartennnn%2Fcli-builder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaartennnn%2Fcli-builder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaartennnn%2Fcli-builder/lists"}