{"id":19273939,"url":"https://github.com/rintoj/clifer","last_synced_at":"2025-04-21T22:33:19.722Z","repository":{"id":62358843,"uuid":"559833786","full_name":"rintoj/clifer","owner":"rintoj","description":"Light weight utility to build command line interfaces for NodeJS","archived":false,"fork":false,"pushed_at":"2025-03-11T07:20:55.000Z","size":898,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-01T16:24:13.160Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","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/rintoj.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}},"created_at":"2022-10-31T07:33:29.000Z","updated_at":"2025-03-11T07:20:17.000Z","dependencies_parsed_at":"2023-01-28T23:46:18.443Z","dependency_job_id":null,"html_url":"https://github.com/rintoj/clifer","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rintoj%2Fclifer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rintoj%2Fclifer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rintoj%2Fclifer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rintoj%2Fclifer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rintoj","download_url":"https://codeload.github.com/rintoj/clifer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250145216,"owners_count":21382373,"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":[],"created_at":"2024-11-09T20:44:31.592Z","updated_at":"2025-04-21T22:33:14.712Z","avatar_url":"https://github.com/rintoj.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Clifer\n\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\nA lightweight library for building beautiful command-line interfaces for NodeJS applications.\n\n## Install\n\n### Yarn\n\n```sh\nyarn add clifer\n```\n\n### NPM\n\n```sh\nnpm install clifer\n```\n\n## Usage\n\nCreate `src/cli.ts` with the following content:\n\n```ts\nimport { cli, input, runCli } from 'clifer'\n\nenum Type {\n  api = 'api',\n  subscriber = 'subscriber',\n}\n\ninterface Props {\n  service: string\n  instances?: number\n  type?: Type\n  dryRun?: boolean\n}\n\nfunction run(props: Props) {\n  // Handle the action here\n  console.log({ props })\n}\n\nconst program = cli\u003cProps\u003e('create-model')\n  // Add an option '--version' to the version of the CLI\n  .version('1.0')\n\n  // Add a positional input of type string and prompt if not provided\n  .argument(input('name').description('Name of the model').string().required().prompt())\n\n  // Add --service=\u003cstring\u003e\n  .option(input('service').description('Name of the service').string().required())\n\n  // Add --instances=\u003cnumber\u003e\n  .option(input('instances').description('Number of instances').number().default(2))\n\n  // Add --type=[api|subscriber]\n  .option(\n    input('type').description('Type of the model').string().options([Type.api, Type.subscriber]),\n  )\n\n  // Add --dry-run flag\n  .option(input('dryRun').description('Perform a dry run'))\n\n  // Load values from an external source or at runtime (e.g., from a file)\n  .load(async (props: Partial\u003cT\u003e) =\u003e readJSONAsync('./env.json'))\n\n  // Handle the command\n  .handle(run)\n\nrunCli(program).catch(e =\u003e console.error(e))\n```\n\n## Configure Project\n\nTo make an npm package executable, follow these steps:\n\n1. **Add a `bin` field to `package.json`:** This field specifies the executable files and the\n   command names.\n2. **Create the executable file:** The file should start with a shebang (`#!`) that specifies the\n   path to the Node.js executable.\n3. **Ensure the file has execute permissions:** Make the file executable by setting the correct\n   permissions.\n\nHere's a step-by-step guide:\n\n### Step 1: Add `bin` Field to `package.json`\n\nIn your `package.json`, add a `bin` field that maps command names to executable files. For example:\n\n```json\n{\n  \"name\": \"your-package-name\",\n  \"version\": \"1.0.0\",\n  \"bin\": {\n    \"your-command\": \"bin/cli\"\n  },\n  ...\n}\n```\n\n### Step 2: Create the Executable File\n\nCreate the executable JavaScript file (`bin/cli`) and start it with a shebang:\n\n```javascript\n#!/usr/bin/env node\n\nconst { spawn } = require('child_process')\nconst { resolve } = require('path')\nconst cli = resolve(__dirname, '..', 'dist', 'cli.js')\nconst args = process.argv.slice(2).join(' ')\nconst cmd = `${cli} ${args}`\nconst child = spawn('node', cmd.split(' '), {\n  detached: false,\n  stdio: 'inherit',\n  cwd: process.cwd(),\n})\nchild.on('exit', function (code, signal) {\n  process.exit(code)\n})\n```\n\n### Step 3: Ensure the File has Execute Permissions\n\nMake the file executable by setting the correct permissions. Run the following command in your\nterminal:\n\n```sh\nchmod +x bin/cli\n```\n\n### Step 4: Install the Package Globally (Optional)\n\nIf you want to test the command globally, you can install your package globally:\n\n```sh\nnpm install -g .\n```\n\n### Step 5: Run Your Command\n\nAfter following the above steps, you should be able to run your command from the terminal:\n\n```sh\nyour-command\n```\n\n### Testing the Package Locally\n\nInstead of installing globally, you can also link the package locally for testing:\n\n```sh\nnpm link\n```\n\nNow you can run the `your-command` command:\n\n```sh\nyour-command\n```\n\nBy following these steps, you can make your npm package executable and create your own command-line\ntools.\n\n## Auto-Generated Help\n\n![TypeScript](./docs/type-script.jpg)\n\n## Commands\n\n```ts\nimport { cli, command, input, runCli } from 'clifer'\n\nenum Type {\n  ts = 'ts',\n  js = 'js',\n}\n\ninterface Props {\n  dryRun?: boolean\n}\n\ninterface CreateCommandProps {\n  name: string\n  type?: Type\n}\n\ninterface IndexCommandProps {\n  name: string\n  publish?: boolean\n}\n\nconst createModel = command\u003cCreateCommandProps\u003e('model')\n  .description('Create a model')\n  .argument(input('name').description('Name of the model').string().required())\n  .option(input('type').description('Type of the model').string().options([Type.ts, Type.js]))\n  .handle((props: CreateCommandProps) =\u003e {\n    // Handle action\n  })\n\nconst createRepository = command\u003cCreateCommandProps\u003e('repository')\n  .description('Create a repository')\n  .argument(input('name').description('Name of the repository').string().required())\n  .option(input('type').description('Type of the repository').string().options([Type.ts, Type.js]))\n  .handle((props: CreateCommandProps) =\u003e {\n    // Handle action\n  })\n\nconst createSchema = command\u003cCreateCommandProps\u003e('schema')\n  .description('Create a schema file')\n  .argument(input('name').description('Name of the schema').string().required())\n  .option(input('type').description('Type of the schema').string().options([Type.ts, Type.js]))\n  .handle((props: CreateCommandProps) =\u003e {\n    // Handle action\n  })\n\nconst createCommand = command('create')\n  .description('Create backend modules')\n  .command(createModel)\n  .command(createRepository)\n  .command(createSchema)\n\nconst indexCommand = command\u003cIndexCommandProps\u003e('index')\n  .description('Create database index')\n  .argument(input('name').description('Name of the file to create').string().required())\n  .option(input('publish').description('Publish the index'))\n  .handle((props: IndexCommandProps) =\u003e {\n    // Handle action\n  })\n\nconst program = cli\u003cProps\u003e('builder')\n  .version('1.0')\n  .command(createCommand)\n  .command(indexCommand)\n  .option(input('dryRun').description('Execute a sample run'))\n\nrunCli(program).catch((e: any) =\u003e console.error(e))\n```\n\n![Create](./docs/create.jpg)\n\n## Use Prompt\n\n```ts\nimport { input, prompt } from 'clifer'\n\n// Yes/No confirmation\nconst { overwrite } = await prompt(\n  input('overwrite').description('Overwrite existing files?').prompt('Should overwrite?'),\n)\nconsole.log({ overwrite })\n\n// String prompt\nconst { projectName } = await prompt(\n  input('projectName')\n    .description('Name of the project')\n    .string()\n    .prompt('What is the name of the project?'),\n)\nconsole.log({ projectName })\n\n// String prompt with auto-complete\nconst { environment } = await prompt(\n  input('environment')\n    .description('Environment')\n    .string()\n    .prompt('Enter environment')\n    .choices(['local', 'dev', 'prod']),\n)\nconsole.log({ environment })\n\n// Number prompt\nconst { port } = await prompt(\n  input('port').description('Server port').number().prompt('Enter port'),\n)\nconsole.log({ port })\n\n// Number prompt with choices\nconst { diskSize } = await prompt(\n  input('diskSize')\n    .description('Disk size to use the cloud')\n    .number()\n    .choices([10, 20, 50, 100])\n    .prompt('Disk sizes (in GB)'),\n)\nconsole.log({ diskSize })\n\n// Multiple inputs together\nconst output = await prompt(\n  input('firstName').description('First name').string().prompt(),\n  input('lastName').description('Last name').string().prompt(),\n  input('gender').description('Gender').string().choices(['Male', 'Female']).prompt(),\n)\nconsole.log(output)\n```\n\n![Prompt](./docs/prompt.jpg)\n\n## Error Handling\n\nUse the `CliExpectedError` class to throw errors for validation issues and configuration errors,\nensuring that Clifer displays a clear error message without a stack trace.\n\n```ts\nimport { CliExpectedError } from 'clifer'\n\nthrow new CliExpectedError('Missing a required argument \"--arg\"')\n```\n\nHere are additional sections that are commonly found in open-source project documentation:\n\n## Contributing\n\nContributions are welcome! If you'd like to contribute to Clifer, please follow these steps:\n\n1. Fork the repository.\n2. Create a new branch (`git checkout -b feature/YourFeature`).\n3. Commit your changes (`git commit -m 'Add some feature'`).\n4. Push to the branch (`git push origin feature/YourFeature`).\n5. Open a pull request.\n\nPlease ensure your code adheres to our coding standards and includes tests where applicable.\n\n## License\n\nThis project is licensed under the MIT License. See the [LICENSE](./LICENSE) file for details.\n\n## Code of Conduct\n\nTo ensure a welcoming environment, please follow our [Code of Conduct](./CODE_OF_CONDUCT.md).\n\n## Changelog\n\nSee the [Changelog](https://github.com/rintoj/clifer/releases) for a detailed history of changes to\nthe project.\n\nIf you encounter any issues or have any questions, feel free to open an issue on GitHub.\n\n## FAQ\n\n**Q: How do I install Clifer?** A: You can install Clifer using Yarn or NPM. See the\n[Install](#install) section for details.\n\n**Q: How do I create a command-line tool with Clifer?** A: Refer to the [Usage](#usage) section for\na step-by-step guide on creating a command-line tool.\n\n**Q: How can I contribute to Clifer?** A: See the [Contributing](#contributing) section for\ninstructions on how to contribute to the project.\n\nFeel free to modify or expand these sections to better fit your project's needs.\n\n## Automatic Release\n\nHere is an example of the release type based on commit messages:\n\n| Commit Message      | Release Type          |\n| ------------------- | --------------------- |\n| fix: [comment]      | Patch Release         |\n| feat: [comment]     | Minor Feature Release |\n| perf: [comment]     | Major Feature Release |\n| doc: [comment]      | No Release            |\n| refactor: [comment] | No Release            |\n| chore: [comment]    | No Release            |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frintoj%2Fclifer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frintoj%2Fclifer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frintoj%2Fclifer/lists"}