{"id":20961495,"url":"https://github.com/didavid61202/type-level-regexp","last_synced_at":"2025-04-06T16:14:54.695Z","repository":{"id":134598907,"uuid":"605220457","full_name":"didavid61202/type-level-regexp","owner":"didavid61202","description":"🔤🔍 Type-level RegExp, parse and match string in TypeScript type system.","archived":false,"fork":false,"pushed_at":"2023-06-15T09:25:36.000Z","size":461,"stargazers_count":113,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-30T15:11:45.559Z","etag":null,"topics":["javascript","parser","regex","regexp","types","typescript"],"latest_commit_sha":null,"homepage":"https://tsplay.dev/mbvEEm","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/didavid61202.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-02-22T17:47:10.000Z","updated_at":"2025-01-14T22:26:42.000Z","dependencies_parsed_at":"2025-02-20T10:21:06.079Z","dependency_job_id":null,"html_url":"https://github.com/didavid61202/type-level-regexp","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/didavid61202%2Ftype-level-regexp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/didavid61202%2Ftype-level-regexp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/didavid61202%2Ftype-level-regexp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/didavid61202%2Ftype-level-regexp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/didavid61202","download_url":"https://codeload.github.com/didavid61202/type-level-regexp/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247509237,"owners_count":20950232,"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":["javascript","parser","regex","regexp","types","typescript"],"created_at":"2024-11-19T02:13:58.991Z","updated_at":"2025-04-06T16:14:54.669Z","avatar_url":"https://github.com/didavid61202.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🔤🔍 Type-Level RegExp (WIP)\n[![npm version][npm-version-src]][npm-version-href]\n\n\u003e TypeScript type-level RegExp parser and matcher implemented using template literals.\n\n![Demo](https://user-images.githubusercontent.com/29917252/224330392-daeee9a5-d448-4f00-baf2-29365bdfa4b5.png)\n\n\n[![Open in Codeflow](https://developer.stackblitz.com/img/open_in_codeflow.svg)](https://stackblitz.com/~/github.com/didavid61202/type-level-regexp)\n\n👉 [Try on TypeScript Playground](https://www.typescriptlang.org/play?target=99\u0026jsx=0#code/PQKhCgAIUqYMQPYCdIFsUFNKYB4EM0AHAG0wGdJ8A7AEypJMnIFciiUAXTegJUwDmAUVxFIRfJ27JqlGvRbl8AzABo44svnLYdmAFyQAFlKLl9wYAICWnIywBGAOgDGiNMFrXa+AG7eANgBGACYABhDgTgBPIkwAWjJfTBJ45EE8Ig04YHBwS0gAIW1rF0hFZQNIa2IuKjpynUgAAxd0yUx+YVEACgByAB4ukTEJKUwZAD4+gEpm6upNfBdsRAAzSGjEFlRqFDR8JmAhwRHxSWlqSeBIYdFIRAcAK0wXTidwGo5kTkgAb0gbUwHTuYgAvpA1sh3JAAEQxOKJTDJVLpFSiWEAblgBQAhPjIAAFLRNADu+FskMwpOYr0QdEoaxQkAAKgBlJbRATQlgNTiIKmcFxGSB9BEJJIpNIZUR9SHQtCQahERXySDpKEUEV2bDihZrCaYagrSD43F5UAQaCQNmcZDWagCJwHIVGHozHAEYhkHLgNyyX5os4AXkB7W4oJ6sKZiB6AH4BgIgpMHPgANoCNIAXRm8f0PVTAC8ZgAfByIRAzOPx4MARxYuBmsNUkDTsOssJzmPyN0gfcgAD043l-eRfi7hfxWCRfqH4RROIY1gB5R74XjlxAARQbsOdkmFPSDohm3YK-cHw-AE6MU5YM7TYSzZ97F4vQ7yN7vD6Cz57b7fD8vwoe9ODTEI-3PAC+yAg9bxAh8AGZINfaDYNdb93gdWg8BfaD+3QycEPeMhHTsPD8Mva84MwpxuW2MwKPwj98jADRbXtR0nHSUhlkwd1PUIUhMF9Udfh8bgOIdARIFDPpYRZIxsB8aJICCABOdSgniMJ1PiIIAFZqjkG1eRU2E+m4zBeJWHooEgKCqL7IEQVOXp7L7WF4wGYMAB1fIAdVzBMiA1axcEmPN-NJEt-PIGYQDjYKBmiYFkEmfzaD+AAWMEZnibyMGoOwMt8rKQjygqExU0ryry7zWDWNZwsiuN9Gi2LfPikAZn8gLYXsmZ1D7OyLxvYb+1CzBmtwCa+wKD8L1S-BkDmhybkW-sirsNaVLWxqZrW9YDR0Tg1oW4cLwdIgWDOjzIHothyHui7BtkyZ7uaABJRY0wAEj+a7brBLMWxvSAAZvCFJAWHDcEMAHjooTBOAhaxKC+tll0gAAOAIwiCJxARoBhyAFJlkBdKhzAhv4ppmsEAceswnBUsFgEh+k7HZpmeRZ5bkEZv4DvCiEehU2TabZ+p6AFyWAYFvLmnAU8LTY612RwZBoVQawNgdXxDm8W43LEchomK-BZuMRBklQflaWUlGKSYCYdfQCglBUD5oFyMSFkNkhvFBSWXIjU2oxjAsVthVXHKooA)\nor see examples in `Playground` and `test` folders.\n\n 🚧 Work In Progress, PRs and issues are welcome 🚧 \n\n## Quick Setup\n\n1. Add `type-level-regexp` dependency to your project\n\n```bash\n# Using pnpm\npnpm i -D type-level-regexp\n\n# Using npm\nnpm i -D type-level-regexp\n```\n\n2. Import `createRegExp` function, pass in a RegExp string pattern to it creates a `TypedRegExp`, passing this `TypedRegExp` to `String.match()`, `String.matchAll()` or `String.replace()` functions to get fully typed match result.\n\n## Basic Usage\nmatch result will be fully typed if match against a literal stirng, or shows emumerated results if match against a dynamic string.\n```ts\nimport { createRegExp, spreadRegExpIterator } from 'type-level-regexp'\n\n/** string.match() */\nconst regExp = createRegExp('foO(?\u003cg1\u003eb[a-g]r)(?:BAz|(?\u003cg2\u003equx))', ['i'])\nconst matchResult = 'prefix foobarbaz suffix'.match(regExp) // matching literal string\nmatchResult[0] // 'foobarbaz'\nmatchResult[1] // 'bar'\nmatchResult[3] // show type error `type '3' can't be used to index type 'RegExpMatchResult\u003c...\u003e`\nmatchResult.length // 3\nmatchResult.index // 7\nmatchResult.groups // { g1: \"bar\"; g2: undefined; }\n\n/** string.replace() */\nconst regExp2 = createRegExp('(\\\\d{4})[-.](?\u003cmonth\u003e\\\\w{3,4})[-.](\\\\d{1,2})')\nconst replaceResult = '1991-Sept-15'.replace(regExp2, '$\u003cmonth\u003e $3, $1')\nreplaceResult // 'Sept 15, 1991'\n\n/** string.matchAll() */\nconst regExp3 = createRegExp('c[a-z]{2}', ['g'])\nconst matchALlIterator = 'cat car caw cay caw cay'.matchAll(regExp3)\nconst spreadedResult = spreadRegExpIterator(matchALlIterator)\nspreadedResult[2][0] // 'caw'\nspreadedResult[3].index // 12\n\nconst InvalidRegExp = createRegExp('foo(bar')\n// TypeScript error: Argument of type 'string' is not assignable to parameter of type 'RegExpSyntaxError\u003c\"Invalid regular expression, missing closing \\`)\\`\"\u003e'\n```\n\nFor TypeScript library authors, you can also import individual generic types to parse and match RegExp string at type-level and combine with your library's type-level features.\n\n```ts\nimport { ParseRegExp, MatchRegExp } from 'type-level-regexp'\n\ntype MatchResult = MatchRegExp\u003c'fooBAR42', ParseRegExp\u003c'Fo[a-z](Bar)\\\\d{2}'\u003e, 'i'\u003e\n\ntype Matched = MatchResult[0] // 'fooBAR42'\ntype First = MatchResult[1] // 'BAR'\n\ntype RegExpAST = ParseRegExp\u003c'foo(?\u003cg1\u003ebar)'\u003e\n// [{\n//     type: \"string\";\n//     value: \"foo\";\n// }, {\n//     type: \"namedCapture\";\n//     name: \"g1\";\n//     value: [{\n//         type: \"string\";\n//         value: \"bar\";\n//     }];\n// }]\n\n```\n\n\n## Origin \u0026 Notice\nThe main purpose of this project is to test and demonstrate the possibility and limitations of writing a RegExp parser/matcher in TypeScript's type-level. Note that this may not be practically useful, but rather an interesting showcase.\n\nThe idea for this project originated while I was working on improving the type hints of string.match and replace in [magic-regexp](https://github.com/danielroe/magic-regexp) (created by the most inspiring, resourceful, and kind [Daniel Roe](https://github.com/danielroe) from [Nuxt](https://nuxt.com), definitely check it out if you are working with RegExp and TypeScript!).\n\nAs the complexity grows, I start working on this separated repo to increase development speed and try out different iterations. It will be incorporate and use in [magic-regexp](https://github.com/danielroe/magic-regexp), and [Gabriel Vergnaud](https://github.com/gvergnaud)'s awesome [hotscript](https://github.com/gvergnaud/hotscript) very soon.\n\n❤️ Testing, feedbacks and PRs are welcome!\n \n## Features\n\n- Export `createRegExp` function to create a`TypedRegExp` that replace your original `/regex_pattern/` regex object, which can be pass to  `String.match()`, `String.matchAll()` and `String.replace()` functions and gets fully typed result.\n- Shows `RegExpSyntaxError` if the provided RegExp pattern is invalid.\n- Enhance types of RegExp related `String` functions (`.match`, `matchAll`, `.replace`...) for literal or dynamic typed string.\n- Result of `String` functions matched exactly as runtime result.\n- Support all common RegExp tokens (incl. Lookarounds, Backreferences...etc), quantifiers (incl. greedy/lazy) and (`g`,`i`) flags.\n- Export helper functions `spreadRegExpMatchArray` and `spreadRegExpIterator` to get tuple type of match results and iterators.\n- Provide generic type `ParseRegExp` to parse and RegExp string to AST.\n- Provide generic type `MatchRegExp` to match giving string with a parsed RegExp.\n- Provide generic type `ResolvePermutation` to permutation all possible matching string of given RegExp if possible (due to TypeScript type-level limitation)\n- More details please [try on TypeScript Playground](https://www.typescriptlang.org/play?target=99\u0026jsx=0#code/PQKhCgAIUqYMQPYCdIFsUFNKYB4EM0AHAG0wGdJ8A7AEypJMnIFciiUAXTegJUwDmAUVxFIRfJ27JqlGvRbl8AzABo44svnLYdmAFyQAFlKLl9wYAICWnIywBGAOgDGiNMFrXa+AG7eANgBGACYABhDgTgBPIkwAWjJfTBJ45EE8Ig04YHBwS0gAIW1rF0hFZQNIa2IuKjpynUgAAxd0yUx+YVEACgByAB4ukTEJKUwZAD4+gEpm6upNfBdsRAAzSGjEFlRqFDR8JmAhwRHxSWlqSeBIYdFIRAcAK0wXTidwGo5kTkgAb0gbUwHTuYgAvpA1sh3JAAEQxOKJTDJVLpFSiWEAblgBQAhPjIAAFLRNADu+FskMwpOYr0QdEoaxQkAAKgBlJbRATQlgNTiIKmcFxGSB9BEJJIpNIZUR9SHQtCQahERXySDpKEUEV2bDihZrCaYagrSD43F5UAQaCQNmcZDWagCJwHIVGHozHAEYhkHLgNyyX5os4AXkB7W4oJ6sKZiB6AH4BgIgpMHPgANoCNIAXRm8f0PVTAC8ZgAfByIRAzOPx4MARxYuBmsNUkDTsOssJzmPyN0gfcgAD043l-eRfi7hfxWCRfqH4RROIY1gB5R74XjlxAARQbsOdkmFPSDohm3YK-cHw-AE6MU5YM7TYSzZ97F4vQ7yN7vD6Cz57b7fD8vwoe9ODTEI-3PAC+yAg9bxAh8AGZINfaDYNdb93gdWg8BfaD+3QycEPeMhHTsPD8Mva84MwpxuW2MwKPwj98jADRbXtR0nHSUhlkwd1PUIUhMF9Udfh8bgOIdARIFDPpYRZIxsB8aJICCABOdSgniMJ1PiIIAFZqjkG1eRU2E+m4zBeJWHooEgKCqL7IEQVOXp7L7WF4wGYMAB1fIAdVzBMiA1axcEmPN-NJEt-PIGYQDjYKBmiYFkEmfzaD+AAWMEZnibyMGoOwMt8rKQjygqExU0ryry7zWDWNZwsiuN9Gi2LfPikAZn8gLYXsmZ1D7OyLxvYb+1CzBmtwCa+wKD8L1S-BkDmhybkW-sirsNaVLWxqZrW9YDR0Tg1oW4cLwdIgWDOjzIHothyHui7BtkyZ7uaABJRY0wAEj+a7brBLMWxvSAAZvCFJAWHDcEMAHjooTBOAhaxKC+tll0gAAOAIwiCJxARoBhyAFJlkBdKhzAhv4ppmsEAceswnBUsFgEh+k7HZpmeRZ5bkEZv4DvCiEehU2TabZ+p6AFyWAYFvLmnAU8LTY612RwZBoVQawNgdXxDm8W43LEchomK-BZuMRBklQflaWUlGKSYCYdfQCglBUD5oFyMSFkNkhvFBSWXIjU2oxjAsVthVXHKooA), or see tests files in [Tests](./test) and [Stackblitz](https://stackblitz.com/~/github.com/didavid61202/type-level-regexp). (examples in index.test-d.ts)\n\n\n#### Example - type-safe args in replacing function of `string.replace()`\n![replaceRegexp](https://user-images.githubusercontent.com/29917252/224333879-50d51207-f63c-4ac6-b561-34ace9ebb7d4.JPG)\n\n#### Example - spreaded `string.matchAll()` with union of RegExp pattern remain as tuple\n![type-level-matchAll-with-union](https://user-images.githubusercontent.com/29917252/224666590-0bfdc22b-ac5d-4b8e-94e3-545fd57a8233.png)\n\n\n### RegExp Tokens \u0026 Flags\n\n| Tokens | Description | Support |\n| --- | --- | --- |\n|  `.` | Matches any single character. | ✅ |\n|  `*`, `*?` | Matches zero or more occurrences (Greedy/Lazy). | ✅ |\n|  `+`, `*?` | Matches one or more occurrences (Greedy/Lazy). | ✅ |\n|  `?`, `??` | Matches zero or one occurrence (Greedy/Lazy). | ✅ |\n|  `^` | Matches the start of a line. | ✅ |\n|  `$` | Matches the end of a line. | ✅ |\n|  `\\s`, `\\S` | Matches any whitespace, non-whitespace character. | ✅ |\n|  `\\d`, `\\D` | Matches any digit, non-digit character. | ✅ |\n|  `\\w`, `\\W` | Matches any word, non-word character. | ✅ |\n|  `\\b`, `\\B` | Matches a word-boundary, non-word-boundary. | ✅ |\n|  `[abc]` | Matches any character in the set. | ✅ |\n|  `[^abc]` | Matches any character not in the set. | ✅ |\n|  `()` | Creates a capturing group. | ✅ |\n|  `(?:)` | Creates a non-capturing group. | ✅ |\n|  `(?\u003cname\u003e)` | Creates a named-capturing group. | ✅ |\n|  `\\|` | Matches either the expression before or after the vertical bar. | ✅ |\n|  `{n}` | Matches exactly `n` occurrences. | ✅ |\n|  `{n,}` | Matches at least `n` occurrences. | ✅ |\n|  `{n,m}` | Matches between `n` and `m` occurrences. | ✅ |\n|  `(?=)`, `(?!)` | Positive/Negative lookahead. | ✅ |\n|  `(?\u003c=)`, `(?\u003c!)` | Positive/Negative lookbehind. | ✅ |\n\n| Flags | Description | Support |\n| --- | --- | --- |\n|  `g` | Global matching (matches all occurrences). | ✅ |\n|  `i` | Case-insensitive matching. | ✅ |\n\n## 💻 Development\n\n- Clone this repository\n- Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable` (use `npm i -g corepack` for Node.js \u003c 16.10)\n- Install dependencies using `pnpm install`\n- Run interactive tests using `pnpm dev`\n\n## License\n\nMade with 🔥 and ❤️\n\nPublished under [MIT License](./LICENCE).\n\n\u003c!-- Badges --\u003e\n[npm-version-src]: https://img.shields.io/npm/v/type-level-regexp?style=flat-square\n[npm-version-href]: https://npmjs.com/package/type-level-regexp","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdidavid61202%2Ftype-level-regexp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdidavid61202%2Ftype-level-regexp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdidavid61202%2Ftype-level-regexp/lists"}