{"id":18879742,"url":"https://github.com/loilo/rx","last_synced_at":"2025-04-14T19:23:34.337Z","repository":{"id":75329212,"uuid":"217047420","full_name":"loilo/rx","owner":"loilo","description":"A template tag for creating regular expressions","archived":false,"fork":false,"pushed_at":"2025-01-22T06:24:38.000Z","size":373,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-28T07:51:10.438Z","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/loilo.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}},"created_at":"2019-10-23T12:05:57.000Z","updated_at":"2025-01-22T06:24:36.000Z","dependencies_parsed_at":"2024-11-08T11:00:07.039Z","dependency_job_id":"786a9060-8f99-4fbe-a89c-d736b80657e7","html_url":"https://github.com/loilo/rx","commit_stats":{"total_commits":19,"total_committers":2,"mean_commits":9.5,"dds":"0.052631578947368474","last_synced_commit":"008539ba229866cd1cf59af942d47589c6b5e822"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loilo%2Frx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loilo%2Frx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loilo%2Frx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loilo%2Frx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/loilo","download_url":"https://codeload.github.com/loilo/rx/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248943517,"owners_count":21186978,"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-08T06:39:06.635Z","updated_at":"2025-04-14T19:23:34.313Z","avatar_url":"https://github.com/loilo.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# rx\n\n\u003e A regular expression template tag written in TypeScript\n\n[![Tests](https://badgen.net/github/checks/loilo/rx/master)](https://github.com/loilo/rx/actions)\n[![Version on npm](https://badgen.net/npm/v/@loilo/rx)](https://www.npmjs.com/package/@loilo/rx)\n\n**IMPORTANT:** This package is ESM-only. [Read more.](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c)\n\n## Motivation\n\nRegular expressions are a tool needed fairly often in the web world — mostly due to JavaScript's lackluster ability to do string matching/searching/replacing.\n\nHowever, writing regular expressions gets messy very quickly as soon as any third party input is involved. User-provided strings have to be escaped and the convenient regex literals give way to that unwieldy [`RegExp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) constructor.\n\nAfter struggling with this for years, it crossed my mind ([and the mind of many others](#credit)) that this might be solved pretty comfortably with a tagged template literal:\n\n```ts\nimport rx from '@loilo/rx'\n\nconst disallowedWindowsFilenameChars = rx`[${'\u003c\u003e:\"/\\\\|?*'}]`\n\nif (disallowedWindowsFilenameChars.test(someFilename)) {\n  console.error('Invalid characters in filename')\n} else {\n  console.log(\"You're probably fine\")\n}\n```\n\nThis package exposes a nice `rx` template tag. It's\n\n- **tiny** — less than 450 bytes minified \u0026 gzipped, no dependencies\n- **typed** — written in TypeScript, so our IDE can provide type hints 🎉\n- **fun** — to the extent that regular expressions can be fun\n\n## Installation\n\nInstall from npm:\n\n```bash\nnpm install --save @loilo/rx\n```\n\nOr use in the browser via [unpkg](https://unpkg.com) (using the global `rx` variable):\n\n```html\n\u003cscript src=\"https://unpkg.com/@loilo/rx\"\u003e\u003c/script\u003e\n```\n\n## Usage\n\n\u003e _Disclaimer:_ Please keep in mind that all code examples in this readme are exclusively for demonstrational purposes. Most of them can be solved more efficiently and elegantly without any use of regular expressions.\n\n### Flags\n\nWe can add flags to our regular expressions like this:\n\n```js\nfunction matchCaseInsensitive(string) {\n  return rx.i`${string}`\n}\n\nconst pattern = matchCaseInsensitive('foo') // pattern = /foo/i\npattern.test('foo') // true\npattern.test('fOO') // true\n```\n\n\u003e **Note:** This way of adding flags will only work in modern environments (Node.js version 6 and up, evergreen browsers). If we need to support Internet Explorer etc., we may use `rx('i')` instead of `rx.i`.\n\u003e\n\u003e This is because an unpolyfillable technique called [Proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) is used for the default way of adding flags.\n\n### Raw Strings\n\nFrom time to time, we may want to include control characters in some kind of conditional when `rx` inadvertently escapes them:\n\n```js\nfunction naiveNumberMatcher(allowFloat) {\n  return rx`^-?[0-9]+${allowFloat ? '(\\\\.[0-9]+)?' : ''}$`\n}\n\nconst pattern = naiveNumberMatcher(true)\n// pattern = /^-?[0-9]+\\(\\\\\\.\\[0\\-9\\]\\+\\)\\?$/\n// Snap! This won't match floating point numbers.\n```\n\nLuckily, there's an easy solution: just return the control characters as a regular expression:\n\n```js\nfunction naiveNumberMatcher(allowFloat) {\n  return rx`^-?[0-9]+${allowFloat ? /(\\.[0-9]+)?/ : ''}$`\n}\n\nconst intPattern = naiveNumberMatcher(false) // intPattern = /^-?[0-9]+$/\nintPattern.test('abc') // false\nintPattern.test('0') // true\nintPattern.test('-1') // true\nintPattern.test('1.5') // false\n\nconst floatPattern = naiveNumberMatcher(true) // floatPattern = /^-?[0-9]+(\\.[0-9]+)?$/\nfloatPattern.test('abc') // false\nfloatPattern.test('0') // true\nfloatPattern.test('-1') // true\nfloatPattern.test('1.5') // true\n```\n\nAlternatively, we could have wrapped the control characters in an `rx.raw()` call which will exclude them from being escaped:\n\n```js\nfunction naiveNumberMatcher(allowFloat) {\n  return rx`^-?[0-9]+${allowFloat ? rx.raw('(\\\\.[0-9]+)?') : ''}$`\n\n  // rx.raw also works as a template tag — note that we don't even have to double-escape the \".\" wildcard:\n  return rx`^-?[0-9]+${allowFloat ? rx.raw`(\\.[0-9]+)?')` : ''}$`\n}\n```\n\nThis can be necessary when the wrapped control characters are quantifiers which cannot form a regular expression of their own, e.g. `/?/`.\n\n### Arrays\n\nIf an array is passed as a placeholder, its entries will be escaped and joined by a vertical bar — this way, we can easily express enumerations:\n\n```js\nfunction oneOf(...strings) {\n  return rx.i`^${strings}$`\n}\n\nconst pattern = oneOf('a', 'b') // pattern = /^a|b$/i\npattern.test('a') // true\npattern.test('B') // true\npattern.test('d') // false\n```\n\nNote that arrays may also contain regular expressions or `rx.raw` strings which stay unescaped as [described above](#raw-strings):\n\n```js\nfunction oneOfTheseOrInteger(...strings) {\n  return rx.i`^(${[...strings, /[0-9]+/]})$`\n}\n\nconst pattern = oneOfTheseOrInteger('a', 'b') // pattern = /^(a|b|[0-9]+)$/i\npattern.test('A') // true\npattern.test('d') // false\npattern.test('42') // true\n```\n\nArrays can even be nested and are flattened automatically:\n\n```js\nconst naivePluralize = value =\u003e value + 's'\n\nfunction oneOrMultipleOf(...strings) {\n  return rx`^${strings.map(string =\u003e [string, naivePluralize(string)])}$`\n}\n\noneOrMultipleOf('cat', 'dog') // /^cat|cats|dog|dogs$/i\n```\n\n## Credit\n\nIn the world of programming, you're basically never the first person to come up with a clever trick. I [googled](https://www.google.com/search?q=regex+template+tag) my idea and it turned out that Lea Verou published [the very same thing](http://lea.verou.me/2018/06/easy-dynamic-regular-expressions-with-tagged-template-literals-and-proxies/) in 2018, and Dr. Axel Rauschmeyer [created a similar utility](https://2ality.com/2017/07/re-template-tag.html) in 2017.\n\nKey differences to those implementations are that I added type hints (therefore this package is written in TypeScript) and the aforementioned capability to merge in arrays and raw strings.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Floilo%2Frx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Floilo%2Frx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Floilo%2Frx/lists"}