{"id":16528027,"url":"https://github.com/rundevelopment/refa","last_synced_at":"2025-09-21T00:51:05.351Z","repository":{"id":47677472,"uuid":"249479294","full_name":"RunDevelopment/refa","owner":"RunDevelopment","description":"A library for finite automata and regular expressions in the context of JS RegExp","archived":false,"fork":false,"pushed_at":"2024-06-16T11:12:37.000Z","size":6106,"stargazers_count":28,"open_issues_count":5,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-30T23:57:38.731Z","etag":null,"topics":["dfa","javascript-regexp","nfa","regex","regexp"],"latest_commit_sha":null,"homepage":"","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/RunDevelopment.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","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":"2020-03-23T16:07:38.000Z","updated_at":"2025-06-12T10:46:43.000Z","dependencies_parsed_at":"2023-02-07T04:33:17.264Z","dependency_job_id":"44b71dd5-c24c-41e0-a2aa-7e3e143484d4","html_url":"https://github.com/RunDevelopment/refa","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/RunDevelopment/refa","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RunDevelopment%2Frefa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RunDevelopment%2Frefa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RunDevelopment%2Frefa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RunDevelopment%2Frefa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RunDevelopment","download_url":"https://codeload.github.com/RunDevelopment/refa/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RunDevelopment%2Frefa/sbom","scorecard":{"id":123093,"data":{"date":"2025-08-11","repo":{"name":"github.com/RunDevelopment/refa","commit":"8d20d94232b1adb043c29810046c060ca1664bf1"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.1,"checks":[{"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":"Code-Review","score":0,"reason":"Found 0/29 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":"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":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","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":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/deploy-docs.yml:1","Warn: no topLevel permission defined: .github/workflows/nodejs.yml:1","Info: no jobLevel write permissions found"],"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":"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":"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":"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":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Pinned-Dependencies","score":5,"reason":"dependency not pinned by hash detected -- score normalized to 5","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/deploy-docs.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/RunDevelopment/refa/deploy-docs.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/deploy-docs.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/RunDevelopment/refa/deploy-docs.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/deploy-docs.yml:36: update your workflow using https://app.stepsecurity.io/secureworkflow/RunDevelopment/refa/deploy-docs.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/deploy-docs.yml:45: update your workflow using https://app.stepsecurity.io/secureworkflow/RunDevelopment/refa/deploy-docs.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/nodejs.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/RunDevelopment/refa/nodejs.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/nodejs.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/RunDevelopment/refa/nodejs.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/nodejs.yml:38: update your workflow using https://app.stepsecurity.io/secureworkflow/RunDevelopment/refa/nodejs.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/nodejs.yml:40: update your workflow using https://app.stepsecurity.io/secureworkflow/RunDevelopment/refa/nodejs.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/nodejs.yml:51: update your workflow using https://app.stepsecurity.io/secureworkflow/RunDevelopment/refa/nodejs.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/nodejs.yml:53: update your workflow using https://app.stepsecurity.io/secureworkflow/RunDevelopment/refa/nodejs.yml/master?enable=pin","Info:   0 out of   7 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   3 third-party GitHubAction dependencies pinned","Info:   4 out of   4 npmCommand dependencies pinned"],"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":"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":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"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"}},{"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":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 12 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"12 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-4q6p-r6v2-jvc5","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-mwcw-c2x4-8c55","Warn: Project is vulnerable to: GHSA-gcx4-mw62-g8wm","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-76p7-773f-r4q5"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-16T02:58:33.809Z","repository_id":47677472,"created_at":"2025-08-16T02:58:33.809Z","updated_at":"2025-08-16T02:58:33.809Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":276179885,"owners_count":25598571,"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","status":"online","status_checked_at":"2025-09-20T02:00:10.207Z","response_time":63,"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":["dfa","javascript-regexp","nfa","regex","regexp"],"created_at":"2024-10-11T17:37:56.796Z","updated_at":"2025-09-21T00:51:05.315Z","avatar_url":"https://github.com/RunDevelopment.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Regular Expressions and Finite Automata (refa)\n\n[![Actions Status](https://github.com/RunDevelopment/refa/workflows/Node.js%20CI/badge.svg)](https://github.com/RunDevelopment/refa/actions)\n[![npm](https://img.shields.io/npm/v/refa)](https://www.npmjs.com/package/refa)\n\nA library for regular expressions (RE) and finite automata (FA) in the context of [Javascript RegExp](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp).\n\n\n## About\n\nrefa is a general library for [DFA](https://en.wikipedia.org/wiki/Deterministic_finite_automaton), [NFA](https://en.wikipedia.org/wiki/Nondeterministic_finite_automaton), and REs of [formal regular languages](https://en.wikipedia.org/wiki/Induction_of_regular_languages). It also includes methods to easily convert from JS RegExp to the internal RE AST and vice versa.\n\n\n## Installation\n\nGet [refa from NPM](https://www.npmjs.com/package/refa):\n\n```\nnpm i --save refa\n```\n\nor\n\n```\nyarn add refa\n```\n\n\n## Features\n\n- Conversions\n\n  * RE AST to NFA and ENFA (_assertions are not implemented yet_)\n  * DFA, NFA, and ENFA can all be converted into each other\n  * DFA, NFA, and ENFA to RE AST\n\n- DFA, NFA, and ENFA operations\n\n  * Construction from other FA, the intersection of two FA, or a finite set of words\n  * Print as [DOT](https://en.wikipedia.org/wiki/DOT_(graph_description_language)) or [Mermaid](https://mermaid.js.org/).\n  * Test whether a word is accepted\n  * Test whether the accepted language is the empty set/a finite set\n  * Accept all prefixes/suffixes of a language\n\n- DFA specific operations\n\n  * Minimization\n  * Complement\n  * Structural equality\n\n- NFA and ENFA specific operations\n\n  * Union and Concatenation with other FA\n  * Quantification\n  * Reverse\n\n- AST transformations\n\n  * Simplify and change the AST of a regex\n  * Remove assertions\n\n- JavaScript RegExp\n\n  * RegExp to RE AST and RE AST to RegExp\n    * All flags are fully supported\n    * Unicode properties\n    * Change flags\n    * Limited support for simple backreferences\n\nSee the [API documentation](https://rundevelopment.github.io/refa/docs/latest/) for a complete list of all currently implemented operations.\n\n### RE AST format\n\nrefa uses its own AST format to represent regular expressions. The RE AST format is language agnostic and relatively simple.\n\nIt supports:\n\n- Concatenation (e.g. `ab`)\n- Alternation (e.g. `a|b`)\n- Quantifiers (greedy and lazy) (e.g. `a{4,6}`, `a{2,}?`, `a?`, `a*`)\n- Assertions (e.g. `(?=a)`, `(?\u003c!a)`)\n- Characters/character sets (represented by interval sets)\n- Unknowns (elements that cannot be represented otherwise. E.g. backreferences)\n\nSome features like atomic groups and capturing groups are not supported (but might be added in the future).\n\nFor information on how to parse JS RegExp and convert RE AST to JS RegExp, see the [`JS` namespace](https://rundevelopment.github.io/refa/docs/latest/modules/JS.html).\n\n### Universal characters\n\nrefa does not use JavaScript strings represent characters or a sequences of characters. Instead it uses integers to represent characters (see the [`Char` type](https://rundevelopment.github.io/refa/docs/latest/modules.html#Char)) and arrays of numbers to represent words/strings (see the [`Word` type](https://rundevelopment.github.io/refa/docs/latest/modules.html#Word)).\n\nThis means that any text encoding can be used.\n\nThe [`Words` namespace](https://rundevelopment.github.io/refa/docs/latest/modules/Words.html) contains functions to convert JavaScript data into refa-compatible words and characters.\n\nFor the sets of characters, the [`CharSet` class](https://rundevelopment.github.io/refa/docs/latest/classes/CharSet.html) is used.\n\n### General limitations\n\nThis library will never be able to support some modern features of regex engines such as [backreferences](https://www.rexegg.com/regex-capture.html) and [recursion](https://www.rexegg.com/regex-recursion.html) because these features, generally, cannot be be represented by a DFA or NFA.\n\n\n## Usage examples\n\nrefa is a relatively low-level library. It only provides the basic building blocks. In the following examples, JS RegExps are used a lot so we will define a few useful helper function beforehand.\n\n```ts\nimport { DFA, FiniteAutomaton, JS, NFA } from \"refa\";\n\nfunction toNFA(regex: RegExp): NFA {\n\tconst { expression, maxCharacter } = JS.Parser.fromLiteral(regex).parse();\n\treturn NFA.fromRegex(expression, { maxCharacter });\n}\nfunction toDFA(regex: RegExp): DFA {\n\treturn DFA.fromFA(toNFA(regex));\n}\nfunction toRegExp(fa: FiniteAutomaton): RegExp {\n\tconst literal = JS.toLiteral(fa.toRegex());\n\treturn new RegExp(literal.source, literal.flags);\n}\n```\n\n- `toNFA` parses the given RegExp and constructs a new NFA from the parsed AST.\n- `toDFA` constructs a new NFA from the RegExp first and then converts that NFA into a new DFA.\n- `toRegex` takes an FA (= NFA or DFA) and converts it into a RegExp.\n\n### Testing whether a word is accepted\n\n```ts\nimport { Words } from \"refa\";\n\nconst regex = /\\w+\\d+/;\nconst nfa = toNFA(regex);\n\nconsole.log(nfa.test(Words.fromStringToUTF16(\"abc\")));\n// =\u003e false\nconsole.log(nfa.test(Words.fromStringToUTF16(\"123\")));\n// =\u003e true\nconsole.log(nfa.test(Words.fromStringToUTF16(\"abc123\")));\n// =\u003e true\nconsole.log(nfa.test(Words.fromStringToUTF16(\"123abc\")));\n// =\u003e false\n```\n\n### Finding the intersection of two JS RegExps\n\n```ts\nconst regex1 = /a+B+c+/i;\nconst regex2 = /Ab*C\\d?/;\n\nconst intersection = NFA.fromIntersection(toNFA(regex1), toNFA(regex2));\n\nconsole.log(toRegExp(intersection));\n// =\u003e /Ab+C/\n```\n\n### Finding the complement of a JS RegExp\n\n```ts\nconst regex = /a+b*/i;\n\nconst dfa = toDFA(regex);\ndfa.complement();\n\nconsole.log(toRegExp(dfa));\n// =\u003e /(?:(?:[^A]|A+(?:[^AB]|B+[^B]))[^]*)?/i\n```\n\n### Converting a JS RegExp to an NFA\n\nIn the above examples, we have been using the `toNFA` helper function to parse and convert RegExps. This function assumes that the given RegExp is a pure regular expression without assertions and backreferences and will throw an error if the assumption is not met.\n\nHowever, the JS parser and `NFA.fromRegex` provide some options to work around and even solve this problem.\n\n#### Backreferences\n\nFirstly, the parser will automatically resolve simple backreferences. Even `toNFA` will do this since it's on by default:\n\n```ts\nconsole.log(toRegExp(toNFA(/(\"|').*?\\1/)));\n// =\u003e /\".*\"|'.*'/i\n```\n\nBut it will throw an error for non-trivial backreferences that cannot be resolved:\n\n```ts\ntoNFA(/(#+).*\\1|foo/);\n// Error: Backreferences are not supported.\n```\n\nThe only way to parse the RegExp despite unresolvable backreferences is to remove the backreferences. This means that the result will be imperfect but it might still be useful.\n\n```ts\nconst regex = /(#+).*\\1|foo/;\nconst { expression } =\n\tJS.Parser.fromLiteral(regex).parse({ backreferences: \"disable\" });\n\nconsole.log(JS.toLiteral(expression));\n// =\u003e { source: 'foo', flags: '' }\n```\n\nNote that the `foo` alternative is kept because it is completely unaffected by the unresolvable backreferences.\n\n#### Assertions\n\nWhile the parser and AST format can handle assertions, the NFA construction cannot.\n\n```ts\nconst regex = /\\b(?!\\d)\\w+\\b|-\u003e/;\nconst { expression, maxCharacter } = JS.Parser.fromLiteral(regex).parse();\n\nconsole.log(JS.toLiteral(expression));\n// =\u003e { source: '\\\\b(?!\\\\d)\\\\w+\\\\b|-\u003e', flags: 'i' }\n\nNFA.fromRegex(expression, { maxCharacter });\n// Error: Assertions are not supported yet.\n```\n\nSimilarly to backreferences, we can let the parser remove them:\n\n```ts\nconst regex = /\\b(?!\\d)\\w+\\b|-\u003e/;\nconst { expression, maxCharacter } =\n\tJS.Parser.fromLiteral(regex).parse({ assertions: \"disable\" });\n\nconsole.log(JS.toLiteral(expression));\n// =\u003e { source: '-\u003e', flags: 'i' }\n\nconst nfa = NFA.fromRegex(expression, { maxCharacter });\nconsole.log(toRegExp(nfa));\n// =\u003e /-\u003e/i\n```\n\n\u003cdetails\u003e\n\nOr we can let the NFA construction method remove them:\n\n```ts\nconst regex = /\\b(?!\\d)\\w+\\b|-\u003e/;\nconst { expression, maxCharacter } = JS.Parser.fromLiteral(regex).parse();\n\nconsole.log(JS.toLiteral(expression));\n// =\u003e { source: '\\\\b(?!\\\\d)\\\\w+\\\\b|-\u003e', flags: 'i' }\n\nconst nfa = NFA.fromRegex(expression, { maxCharacter }, { assertions: \"disable\" });\nconsole.log(toRegExp(nfa));\n// =\u003e /-\u003e/i\n```\n\nPrefer using the parser to remove assertions if possible. The parser is quite clever and will optimize based on that assertions can be removed resulting in faster parse times.\n\n\u003c/details\u003e\n\nHowever, simply removing assertions is not ideal since they are a lot more common than backreferences. To work around this, refa has AST transformers. AST transformers can make changes to a given AST. While each transformer is rather simple, they can also work together to accomplish more complex tasks. Applying and removing assertions is one such task.\n\nThe simplest transformer to remove assertions (among other things) is the `simplify` transformer. It will inline expressions, remove dead branches, apply/remove assertions, optimize quantifiers, and more.\n\n```ts\nimport { JS, NFA, Transformers, transform } from \"refa\";\n\nconst regex = /\\b(?!\\d)\\w+\\b|-\u003e/;\nconst { expression, maxCharacter } = JS.Parser.fromLiteral(regex).parse();\nconsole.log(JS.toLiteral(expression));\n// =\u003e { source: '\\\\b(?!\\\\d)\\\\w+\\\\b|-\u003e', flags: '' }\n\nconst modifiedExpression = transform(Transformers.simplify(), expression);\nconsole.log(JS.toLiteral(modifiedExpression));\n// =\u003e { source: '(?\u003c!\\\\w)[A-Z_]\\\\w*(?!\\\\w)|-\u003e', flags: 'i' }\n\n// Most assertions have been removed but the patterns are still equivalent.\n// The only assertions left assert characters beyond the edge of the pattern.\n// Removing those assertions is easy but slightly changes the pattern.\n\nconst finalExpression = transform(Transformers.patternEdgeAssertions({ remove: true }), modifiedExpression);\nconsole.log(JS.toLiteral(finalExpression));\n// =\u003e { source: '[A-Z_]\\\\w*|-\u003e', flags: 'i' }\n\nconst nfa = NFA.fromRegex(finalExpression, { maxCharacter });\nconsole.log(JS.toLiteral(nfa.toRegex()));\n// =\u003e { source: '-\u003e|[A-Z_]\\\\w*', flags: 'i' }\n```\n\nAST transformers can handle a lot of assertions, but there are limitations. Transformers cannot handle assertions that are too complex or require large-scale changes to the AST. Let's take a look at a few examples:\n\n```ts\nimport { JS, Transformers, transform } from \"refa\";\n\nfunction simplify(regex: RegExp): void {\n  const { expression } = JS.Parser.fromLiteral(regex).parse();\n\n  const simplifiedExpression = transform(Transformers.simplify(), expression);\n\n  const literal = JS.toLiteral(simplifiedExpression);\n  console.log(new RegExp(literal.source, literal.flags));\n}\n\nsimplify(/\\b(?!\\d)\\b\\w+\\b\\s*\\(/);\n// =\u003e /(?\u003c!\\w)[A-Z_]\\w*\\s*\\(/i\nsimplify(/(?:^|@)\\b\\w+\\b/);\n// =\u003e /(?:^|@)\\w+(?!\\w)/\nsimplify(/\"\"\"(?:(?!\"\"\").)*\"\"\"/s);\n// =\u003e /\"\"\"(?:\"{0,2}[^\"])*\"\"\"/\nsimplify(/\"\"\"((?!\"\"\")(?:[^\\\\]|\\\\\"))*\"\"\"/);\n// =\u003e /\"\"\"(?:\"{0,2}(?:[^\"\\\\]|\\\\\"))*\"\"\"/\nsimplify(/\u003ctitle\u003e(?:(?!\u003c\\/title\u003e).)*\u003c\\/title\u003e/s);\n// =\u003e /\u003ctitle\u003e(?:[^\u003c]|\u003c+(?:[^/\u003c]|\\/(?!title\u003e)))*\u003c+\\/title\u003e/\nsimplify(/^```$.*?^```$/ms);\n// =\u003e /^```[\\n\\r\\u2028\\u2029](?:[^]*?[\\n\\r\\u2028\\u2029])??```$/m\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e Note \u003c/summary\u003e\n\n`Transformers.simplify` is *very* aggressive when it comes to assertions. It will try to remove assertions whenever possible even if it means that the overall AST will become more complex (within some limits). This may result in longer/more complex regexes, but it will also allow `NFA` and `ENFA` to support many more regexes.\n\n\u003c/details\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frundevelopment%2Frefa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frundevelopment%2Frefa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frundevelopment%2Frefa/lists"}