{"id":21730258,"url":"https://github.com/matt-mcmahon/fluentty","last_synced_at":"2026-05-03T12:35:35.826Z","repository":{"id":140002524,"uuid":"310619744","full_name":"matt-mcmahon/fluentty","owner":"matt-mcmahon","description":"A fluent prompt builder for your Deno command-line programs.","archived":false,"fork":false,"pushed_at":"2020-11-18T18:10:25.000Z","size":546,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-31T00:07:03.326Z","etag":null,"topics":["cli","deno","fluent","terminal","tty"],"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/matt-mcmahon.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,"zenodo":null}},"created_at":"2020-11-06T14:29:56.000Z","updated_at":"2023-02-26T03:13:13.000Z","dependencies_parsed_at":"2023-05-01T03:48:16.247Z","dependency_job_id":null,"html_url":"https://github.com/matt-mcmahon/fluentty","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/matt-mcmahon/fluentty","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matt-mcmahon%2Ffluentty","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matt-mcmahon%2Ffluentty/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matt-mcmahon%2Ffluentty/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matt-mcmahon%2Ffluentty/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/matt-mcmahon","download_url":"https://codeload.github.com/matt-mcmahon/fluentty/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matt-mcmahon%2Ffluentty/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32569714,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-03T06:36:36.687Z","status":"ssl_error","status_checked_at":"2026-05-03T06:36:09.306Z","response_time":103,"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","deno","fluent","terminal","tty"],"created_at":"2024-11-26T04:14:15.199Z","updated_at":"2026-05-03T12:35:35.812Z","avatar_url":"https://github.com/matt-mcmahon.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 𝓕𝓵𝓾𝓮𝓷 🆃 🆃 🆈\n\n*Fluentty* is a [fluent] command-line interface builder that runs on [Deno].\nHere's an example:\n\n```javascript\nimport { blue, green, red }\n  from \"https://deno.land/std@0.76.0/fmt/colors.ts\";\nimport { askYesNo, IO, ifYes, question }\n  from \"https://raw.githubusercontent.com/matt-mcmahon/fluentty/v0.3.0/module.ts\";\n\nconst name = await question(\"Choose your Knight:\")\n  .accept(\n    \"Arthur, King of the Britains\",\n    \"Sir Lancelot the Brave\",\n    \"Sir Robin the Not-Quite-So-Brave-as-Sir-Lancelot\",\n    \"Sir Bedevere the Wise\",\n    \"Sir Galahad the Pure\",\n    \"Sir Bors\",\n    \"Sir not Appearing in this Film\",\n  )\n  .ignoreCase()\n  .matchAnywhere()\n  .retry()\n  .IO();\n\nconst approach = await askYesNo(`${name}, do you approach the bridge of death?`)\n  .IO()\n  .then(ifYes(answerTheQuestions));\n\nasync function answerTheQuestions() {\n  const questions = [\n    question(\"What is your name?\")\n      .validate((input) =\u003e {\n        const re = new RegExp(input, \"i\");\n        return re.test(name) ? name : false;\n      }),\n    question(\"What is your quest?\")\n      .retry()\n      .validate((input) =\u003e /grail/i.test(input) ? input : false)\n      .format((input) =\u003e input.replace(/[\\!\\.\\?]?$/, \"!\")),\n    question(\"What is your favorite color?\")\n      .suggest(\"red\", \"green\").ignoreCase().matchFull()\n      .accept(\"blue\").ignoreCase().matchFull()\n      .format((color) =\u003e\n        color === \"red\"\n          ? red(color)\n          : color === \"green\"\n          ? green(color)\n          : color === \"blue\"\n          ? blue(color)\n          : color\n      ),\n    question(\"African or European?\")\n      .accept(\"African\", \"European\").matchCase().matchInitial()\n      .sanitize((input) =\u003e\n        input.substr(0, 1).toLocaleUpperCase() +\n        input.substr(1).toLocaleLowerCase()\n      )\n      .retry(),\n  ];\n\n  const answers = await IO(...questions);\n}\n```\n\nWhich produces the following program:\n\n```text\nbash : matt@matt-desktop:~/@mwm/fluentty\n     : [working ≡]\n     \u003e deno run --unstable source/question.process.ts ↵\n\nChoose your Knight: sir ↵\nChoose your Knight: sir b ↵\nChoose your Knight: lance ↵\nChoose your Knight: sir l ↵\nSir Lancelot the Brave, do you approach the bridge of death?: (yes/no) y ↵\nWhat is your name: lance ↵\nWhat is your quest: I seek a shrubbery! ↵\nWhat is your quest: I seek the Holy Grail? ↵\nWhat is your favorite color: (red/green) blue ↵\nAfrican or European: eu ↵\n```\n\nAnd, finally, our user's answers.\n\n```js\n[\n  \"Sir Lancelot the Brave\",\n  \"I seek the Holy Grail!\",\n  \"\\u001b[34mblue\\u001b[39m\",\n  \"European\"\n]\n```\n\nIn this example we're using the `question` and `IO` exports from *Fluentty* to\nask the user a series of questions. Specifically:\n\n1. \"Choose your Knight\" allows you to choose which knight will approach the\n   bridge. Input is loosely matched, so you can type any part of the name. As\n   long as your input matches exactly one suggestion, it will be accepted. We\n   want to use our answer to this question to validate later questions, so we\n   ask it in a separate async expression.\n\n2. \"Approach the bridge of death\" asks a simple Yes/No question. By default, it\n   matches input to the beginning of each option, ignores case, and will\n   automatically retry if the user gives invalid input. If the user answers \"no\"\n   the script will return.\n\n3. \"What is your name?\" checks your answer from #1 above. It validates as long\n   the user's input can be found anywhere in the Knight's name.\n\n4. \"What is your quest?\" has a custom validator that will only accept an answer\n   if it includes the word \"grail\". Unlike the man form scene 24, our Knight can\n   try again if he gets this wrong. Finally, we use a custom formatter to make\n   the answer an exclamation, replacing other punctuation if necessary. (We\n   don't any uncertainty in our ranks!)\n\n5. \"What is your favorite color?\", will accept \"red\", \"green\", and \"blue\", but\n   will only suggest \"red\" and \"green\". Fluentty will **not** automatically\n   retry on invalid input. Valid input will be formatted so it\n   shows in that color when output on the terminal. Users who enter an invalid\n   answer will presumably be cast into the *Gorge of Eternal Peril*.\n\n   ![\n     Sir Robin, the Not-Quite-So-Brave-as-Sir-Lancelot, is flung into the\n     *Gorge of Eternal Peril* after forgetting his favorite color.\n    ][gif]\n\n6. Our bonus question, \"African or European?\", is a case-sensitive question.\n   Our entry, \"eu\", should fail a case-sensitive match, but we're sanitizing our\n   input before matching it. The sanitize function capitalizes \"Eu\", which\n   matches the first two characters of \"European\", and makes our input valid.\n\n[fluent]: https://dev.to/shoupn/what-is-a-fluent-api-2m4f\n[deno]: https://deno.land/\n[gif]: https://i.makeagif.com/media/2-07-2016/-FG4XC.gif\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatt-mcmahon%2Ffluentty","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmatt-mcmahon%2Ffluentty","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatt-mcmahon%2Ffluentty/lists"}