{"id":17623429,"url":"https://github.com/stater/read-cli","last_synced_at":"2026-04-30T01:40:15.341Z","repository":{"id":57150104,"uuid":"81201872","full_name":"stater/read-cli","owner":"stater","description":"A small NodeJS Module to help parsing the CLI command and options.","archived":false,"fork":false,"pushed_at":"2017-04-10T03:29:12.000Z","size":18,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-24T23:35:01.307Z","etag":null,"topics":["cli","cli-parser","command","javascript","node-js","node-module","nodejs","parser"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stater.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-02-07T11:41:18.000Z","updated_at":"2023-02-15T21:58:39.000Z","dependencies_parsed_at":"2022-09-03T17:51:19.078Z","dependency_job_id":null,"html_url":"https://github.com/stater/read-cli","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/stater/read-cli","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stater%2Fread-cli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stater%2Fread-cli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stater%2Fread-cli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stater%2Fread-cli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stater","download_url":"https://codeload.github.com/stater/read-cli/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stater%2Fread-cli/sbom","scorecard":{"id":846743,"data":{"date":"2025-08-11","repo":{"name":"github.com/stater/read-cli","commit":"9d922a90cba6ab80f121059d66e81c6441ad5566"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.6,"checks":[{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":0,"reason":"Found 0/11 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-23T21:39:52.200Z","repository_id":57150104,"created_at":"2025-08-23T21:39:52.200Z","updated_at":"2025-08-23T21:39:52.200Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32451481,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-29T22:27:22.272Z","status":"ssl_error","status_checked_at":"2026-04-29T22:10:49.234Z","response_time":110,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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","cli-parser","command","javascript","node-js","node-module","nodejs","parser"],"created_at":"2024-10-22T21:09:12.780Z","updated_at":"2026-04-30T01:40:15.300Z","avatar_url":"https://github.com/stater.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ReadCLI\n\nA small NodeJS module to help parsing the CLI command and options.\n\n**Example**\n\n```bash\n./main build script --verbose --production --port 3309 host=localhost\n```\n\nParsing the CLI command above will resulting:\n\n```json\n{\n  \"env\": \"production\",\n  \"arg\" :{\n    \"command\": \"build\",\n    \"build\": \"script\",\n    \"verbose\": true,\n    \"production\": \"true\"\n  }\n}\n```\n\n***\n\n## Instalation\n\nSimply add the `@stater/read-cli` as dependencies and load it from your script.\n\n```bash\nnpm install --save @stater/read-cli\n```\n\n**Example**\n\n`#1`\n\n```bash\nnode main.js build script\n```\n\n`#2`\n\n```bash\nnode main.js build script --host prod.localhost --port 8080 --verbose --production\n```\n\n`#3`\n\n```bash\nNODE_ENV=staging node main.js publish --host stag.localhost --port 9090 --verbose\n```\n\n`main.js`\n\n```js\nimport { parse } from '@stater/read-cli';\n\nconst {env, arg: {command, build, host, port, verbose}} = parse({\n  configs: {\n    build: null,\n    '--host': 'localhost',\n    '--port': 3000\n  }\n});\n\n// RESULT #1:\n// env =\u003e 'development'\n// command =\u003e 'build'\n// build =\u003e 'script'\n// host =\u003e 'localhost;\n// port =\u003e 8080\n// verbose =\u003e undefined\n\n// RESULT #2:\n// env =\u003e 'production'\n// command =\u003e 'build'\n// build =\u003e 'script'\n// host =\u003e 'prod.localhost;\n// port =\u003e 8080\n// verbose =\u003e true\n\n// RESULT #3:\n// env =\u003e 'staging'\n// command =\u003e 'publish'\n// build =\u003e null\n// host =\u003e 'stag.localhost;\n// port =\u003e 9090\n// verbose =\u003e true\n```\n\n***\n\n## Usage\n\n### parse(*optional* `config{}`);\n\nUse it to parse the CLI command and options. Add **`config{}`** to configure the parser.\n\n```js\nimport {parse} from '@stater/read-cli';\n\nconst {env, arg} = parse();\n```\n\nFor the `env` it using `development`, `staging`, and `production` pattern. E.g: adding `--production` to the CLI will set the `env` to `production`. If none of the pattern given on the CLI command or `NODE_ENV` then `development` will be used.\n\nThe parser will use the first `process.argv` (without node and file) as the command, and parse the configs and options based on the parser config (if given).\n\n**Configs**\n\n*   **`options[]`** - Array to register CLI options (only key and be true if given). Useful for protecting the options usage.\n*   **`configs{}`** - Object to register the CLI configs (has key and value), also giving default value if not defined on the CLI configs.\n*   **`remdash!?`** - Boolean does the parser should remove the `--` or `-` from the begining of keys. By default it'll be always removed, so use `remdash: false` to keep them.\n*   **`protect??`** - Prevent from using unknown command, configs, and options. Use `true` to add the error object to the `arg`, or use `throw` to throw the error directly.\n*   **`nocommand??`** - Ignore to mark fisrt argument as command.\n\n**Example**\n\n```bash\nnode main.js build script --host localhost --port 8080 --verbose --production\n```\n\n```js\nimport {parse} from '@stater/read-cli';\n\nconst {env, arg} = parse({\n  configs: {\n    '--host': '127.0.0.1',\n    '--port': 3000\n  }\n});\n\n// RESULT:\n// env =\u003e production\n// arg =\u003e { command: 'build', build: 'script', host: 'localhost', port: 8080, verose: true }\n```\n\nFrom the sample above, if we don't map the configs (using `configs: {}`) anything will be parsed as options, so the value is `true`, even the `localhost` and `8080` will be parsed as option. E.g: `{ host: true, port: true, localhost: true, 8080: true }`.\n\n\n\n```bash\nnode main.js build script --verbose --production --foo\n```\n\n```js\nimport {parse} from '@stater/read-cli';\n\nconst {env, arg} = parse({\n  options: ['--verbose', '--production', '--staging'],\n  configs: {\n    build: null\n  },\n  protect: true\n});\n\n// RESULT:\n// arg =\u003e { error: Error }\n```\n\nFrom the sample above, the parser will mark it as error since the configs is protected and the CLI giving unknown option `--foo` that not registered on the parser configs. The parser will add `error` to the `arg` object so you can use that to log the error.\n\n```bash\nnode main.js build script --foo --bar --verbose --production\n```\n\n```js\nimport {parse} from '@stater/read-cli';\n\nconst {env, arg} = parse({\n  options: ['--verbose', '--production', '--staging'],\n  configs: {\n    build: null\n  },\n  protect: 'throw'\n});\n```\n\n```\nError: Unknown agrument(s): build script ![--foo]=true ![--bar] --verbose --production.\n    at parse ...\n```\n\nFrom the sample above, the parser will throw the error directly since the option `--foo` is not registered and the `protect` setting is `throw`.\n\n### byEnv(*required*  `object{}`);\n\nMerge the object depend on the `env`. This helper requires `parse()` has been called.\n\n**Example**\n\n```bash\nnode main.js build --production\n```\n\n```bash\nNODE_EVN=production node main.js build\n```\n\n```js\nimport {parse, byEnv} from '@stater/read-cli';\n\n// Initialize the parser.\nparse();\n\nlet settings = byEnv({\n  default: {\n    host: 'localhost',\n    port: 8080\n  },\n  staging: {\n    host: 'staging.localhost'\n  },\n  production: {\n    host: 'production.localhost'\n  }\n});\n\n// RESULT:\n// { host: 'production.localhost', port: 8080 }\n```\n\nFrom the sample above, we change the default settings (`auto`) that depend on the `env`. Since we give `--production` or using `NODE_ENV=production` on the CLI (parser set `env` as `production`), then the `host` changed to `production.localhost`.\n\n### byOpt(*required* `object{}`);\n\nMerge the object depend on the CLI ENV or options. Thisl helper requires `parse()` has been called.\n\n**Example**\n\n```bash\nnode main.js build --typescript\n```\n\n```bash\nNODE_SRC_TYPE=typescript node main.js build\n```\n\n```js\nimport {parse, byOpt} from '@stater/read-cli';\n\n// Initialize the parser.\nparse();\n\nlet inputs = byOpt(['typescript', 'NODE_SRC_TYPE'], {\n  default: { file: 'index.js' },\n  typescript: { file: 'index.ts' }\n});\n\n// RESULT:\n// { main: 'index.ts' }\n```\n\nFrom the sample above, the `inputs.main` is overriden by `typescript` option since it was given on the CLI option or ENV variable.\n\n***\n\n## More Example\n\n```bash\nNODE_EVN=production node main.js build script --port 8080 --verbose --typescript\n```\n\n```js\nimport { parse, byEnv, byOpt } from '@stater/read-cli';\n\nconst handlers = {\n  build: {\n    script(settings) {\n      const { host, port, main: { file } } = settings;\n\n      console.log(settings);\n\n      // host =\u003e 'prod.localhost'\n      console.log(host);\n      // port =\u003e 8080\n      console.log(port);\n      // file =\u003e 'main.ts'\n      console.log(file);\n    }\n  }\n}\n\nlet configs = {\n  build: null,\n  '--host': 'localhost',\n  '--port': 3000\n}\n\nlet { arg: { command, build, host, port, verbose } } = parse({ configs });\n\nif (verbose) {\n  console.log(`Starting to ${command} the ${build}...`);\n}\n\nif (handlers[command] \u0026\u0026 handlers[command][build]) {\n  handlers[command][build](byEnv({\n    default: {\n      host,\n      port,\n      main: byOpt(['typescript', 'NODE_SRC_TYPE'], {\n        default: { file: 'main.js' },\n        typescript: { file: 'main.ts' }\n      })\n    },\n    production: {\n      host: 'prod.localhost'\n    }\n  }));\n}\n```\n\n***\n\n## Changelog\n\n#### **`v1.1.4`** - Apr 10, 2017\n\n*   Included the unknown options list. { env, arg, uop }\n\n#### **`v1.1.3`** - Apr 4, 2017\n\n*   Moving to @stater/read-cli\n\n#### **`v1.1.1`** - Apr 3, 2017\n\n*   Small patch.\n\n#### **`v1.1.0`** - Apr 3, 2017\n\n*   Adding `nocommand` config.\n*   Change `Unknow parameters:` to `Unknown argument(s):`.\n\n#### **`v1.0.0`** - Feb 7, 2017\n\n*   Initial release.\n\n***\n\n## The MIT License **`(MIT)`**\n\nCopyright © 2017 Nanang Mahdaen El Agung\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstater%2Fread-cli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstater%2Fread-cli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstater%2Fread-cli/lists"}