{"id":20339904,"url":"https://github.com/uditkarode/kumi","last_synced_at":"2026-06-08T15:31:30.519Z","repository":{"id":40543753,"uuid":"507631287","full_name":"uditkarode/kumi","owner":"uditkarode","description":"🦡 A parser combinator library for TypeScript.","archived":false,"fork":false,"pushed_at":"2023-01-04T21:46:23.000Z","size":90,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-01-08T17:30:26.782Z","etag":null,"topics":["parser","parser-combinators","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/uditkarode.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":"2022-06-26T16:49:24.000Z","updated_at":"2023-08-19T17:25:48.000Z","dependencies_parsed_at":"2023-02-02T21:01:21.474Z","dependency_job_id":null,"html_url":"https://github.com/uditkarode/kumi","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/uditkarode/kumi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uditkarode%2Fkumi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uditkarode%2Fkumi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uditkarode%2Fkumi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uditkarode%2Fkumi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/uditkarode","download_url":"https://codeload.github.com/uditkarode/kumi/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uditkarode%2Fkumi/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34069489,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-08T02:00:07.615Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["parser","parser-combinators","typescript"],"created_at":"2024-11-14T21:18:57.320Z","updated_at":"2026-06-08T15:31:30.503Z","avatar_url":"https://github.com/uditkarode.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# kumi - a parser combinator library\n\nKumi is a parser combinator library that tries to mimic the way you would normally use Parsec in Haskell.\n\n```haskell\n-- Haskell version\ncells :: Parser [String]\ncells = \n    do first \u003c- cellContent\n       next \u003c- remainingCells\n       return (first : next)\n```\n\n```typescript\n// TypeScript version\nconst cells: Combinator\u003cstring[]\u003e = (ca) =\u003e {\n  const first = cellContent(ca);\n  const next = remainingCells(ca);\n  return [...first, ...next];\n}\n```\n\nHere's a tiny example to parse a declaration like `const abcd = \"some string value\";`:\n```typescript\nconst ConstDecl = Parser.combinator((ca) =\u003e {\n    // stringl is the string literal combinator, what it does is evident\n    stringl(\"const\")(ca);\n    \n    // the spaces combinator parses 1 or more spaces\n    spaces(ca);\n    \n    // the until combinator parses everything till the specified target is reached\n    const identifier = until(\" \");\n    \n    spaces(ca);\n    stringl(\"=\")(ca);\n    spaces(ca);\n    \n    // the within combinator parses everything within the given symbols\n    const value = within('\"', '\"')(ca);\n    \n    stringl(\";\")(ca);\n    \n    // any combinator can return any custom value after it's done parsing\n    // and any combinator that uses this combinator can then proceed with\n    // this return value itself!\n    return {\n      type: \"const-decl\",\n      identifier, // will be \"abcd\"\n      value, // will be \"some string value\"\n    };\n}\n```\n\nLet's break this down!\n\nFirstly, `Parser.combinator` is just a way to not have to manually create a `Combinator\u003cT\u003e` value. Here's the definition:\n```typescript\nstatic combinator = \u003cT\u003e(v: Combinator\u003cT\u003e) =\u003e v; // also doesn't it look much cooler that way? :D\n```\n\nNext, `ca`. This is an argument provided to all combinators and stands for Combinator Args. Here's what it is:\n```typescript\n// note that there's more about the consume function and cursor index below\nexport type CombinatorArgs = {\n  // this is the root consume function\n  // at the root of all combinators is the usage of this function\n  // it's not very different from the string literal combinator (which just uses this function)\n  // however, it's not a combinator. It just matches characters and increases the cursor index\n  // note that the type is approximated to keep things simple\n  consume: (str: string) =\u003e string | ParseError;\n  \n  // creates a ParserError, you can throw this anywhere to denote a custom parsing error if you wish to\n  // any parsing related errors thrown or returned will also be ParseError\n  error: (v: { expected: string; found: string }) =\u003e ParseError;\n  \n  // allows you to get and set the value of the cursor index\n  cursor: {\n    get: () =\u003e number;\n    set: (pos: number) =\u003e void;\n  };\n};\n```\n\nLet's also talk a little bit about the cursor index.\nThe cursor index is just a number which will be used to index the target string whenever you use the `ca.consume` function.\nAt the start, the cursor is at index 0.\nHere's an example of how it would proceed with the target string `\"hello\"` and index 0:\n```typescript\n// ca.consume(\"hells\")\nindex   target-character    consume-character       matches\n0       \"hello\"[0] = h      \"hells\"[0] = h          true\n1       \"hello\"[1] = e      \"hells\"[1] = e          true\n2       \"hello\"[2] = l      \"hells\"[2] = l          true\n3       \"hello\"[3] = l      \"hells\"[3] = l          true\n4       \"hello\"[4] = o      \"hells\"[4] = s          false // ParseError thrown\n\n```\n\nthe second argument to `ca.consume` is the backtracking method to use. Currently, there's 3:  \n\n**Never** (default) - __throws__ a ParseError if any character does not match the one at the target string at cursor index  \n\n**OnFail** - __returns__ a ParseError and does not increase the cursor index in case of a failure at any point  \n\n**IfEncountered** - consumes characters until the required character is reached and returns everything it consumed up until then. In case the character passed to it is never reached, throws a ParseError.  \n\nYou can use the provided combinators to create even bigger combinators that will ultimately parse your target string.\nRemember to pass `ca` to any combinator you want parsing things, or it won't do anything!\n\nThat's about it! You can read the tests for more complete examples.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuditkarode%2Fkumi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fuditkarode%2Fkumi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuditkarode%2Fkumi/lists"}