{"_id":"@codincod/codemirror-lang-regex","_rev":"6-bdc95463259e16b96ae90621cf0ccebf","name":"@codincod/codemirror-lang-regex","dist-tags":{"latest":"0.4.0"},"versions":{"0.1.0":{"name":"@codincod/codemirror-lang-regex","version":"0.1.0","keywords":["editor","code","regex","regexp","pcre","raku","lua","vim","codemirror"],"author":{"name":"CodinCod","email":"hello@codincod.com"},"license":"MIT","_id":"@codincod/codemirror-lang-regex@0.1.0","maintainers":[{"name":"juicemitapfelndrin","email":"juicemitapfelndrin@gmail.com"}],"dist":{"shasum":"243fc4c64e2d18a10b0899665d545e75d1dd4130","tarball":"https://registry.npmjs.org/@codincod/codemirror-lang-regex/-/codemirror-lang-regex-0.1.0.tgz","fileCount":35,"integrity":"sha512-wNUO4qWYd5wzk/nscrQ0KXe/YtKygpAYcja4Yh0vxhZ/sFMc3I3g++/J3L3nChla6M+WpALN5jnPEO8o1PpTRQ==","signatures":[{"sig":"MEUCIQCUT0PY6F8Mh6Q5XXDzJ9dmEgisg0UNCikTcpJiiz33kAIgZ67+iYdr3D2UUCoM2+Z6tBbM/Sxi74WUS5az0mV/eck=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":458276},"main":"dist/index.cjs","type":"module","types":"dist/index.d.ts","module":"dist/index.js","exports":{"import":"./dist/index.js","require":"./dist/index.cjs"},"gitHead":"05c5fd559a97f92cf078348a73f90c436f4e1dab","scripts":{"test":"npm run build && node --test \"test/*.test.ts\"","build":"rm -rf dist && lezer-generator src/regex.grammar -o src/parser.js && lezer-generator src/raku.grammar -o src/raku-parser.js && lezer-generator src/lua.grammar -o src/lua-parser.js && lezer-generator src/vim.grammar -o src/vim-parser.js && cm-buildhelper src/regex.ts","corpus":"npm run build && node test/corpus.ts","prepare":"npm run build","build-debug":"lezer-generator src/regex.grammar --names -o src/parser.js && lezer-generator src/raku.grammar --names -o src/raku-parser.js && lezer-generator src/lua.grammar --names -o src/lua-parser.js && lezer-generator src/vim.grammar --names -o src/vim-parser.js && cm-buildhelper src/regex.ts"},"_npmUser":{"name":"juicemitapfelndrin","email":"juicemitapfelndrin@gmail.com"},"repository":{"url":"git+https://codeberg.org/reeven/codemirror-lang-regex.git","type":"git"},"_npmVersion":"11.6.2","description":"Regular expression support for the CodeMirror code editor, in fifteen engines' dialects","directories":{},"sideEffects":false,"_nodeVersion":"25.0.0","dependencies":{"@lezer/lr":"^1.0.0","@lezer/common":"^1.0.0","@lezer/highlight":"^1.0.0","@codemirror/language":"^6.0.0","@codemirror/autocomplete":"^6.0.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.6.0","@lezer/generator":"^1.7.0","@codemirror/state":"^6.7.1","@codemirror/buildhelper":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/codemirror-lang-regex_0.1.0_1785111129759_0.6831163610095237","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@codincod/codemirror-lang-regex","version":"0.2.0","keywords":["editor","code","regex","regexp","pcre","raku","lua","vim","codemirror"],"author":{"name":"CodinCod","email":"hello@codincod.com"},"license":"MIT","_id":"@codincod/codemirror-lang-regex@0.2.0","maintainers":[{"name":"juicemitapfelndrin","email":"juicemitapfelndrin@gmail.com"}],"dist":{"shasum":"de9c957b6420d18d7a1410d22415997e284c8c19","tarball":"https://registry.npmjs.org/@codincod/codemirror-lang-regex/-/codemirror-lang-regex-0.2.0.tgz","fileCount":35,"integrity":"sha512-6iz1pQ9u8ZC6q6z/SvlKRkOstAI7+U9Qeico7XYW9EJh1ciqwsp70ZDcwalTCsKsKJfp6a3PeMU05+wcDpqhaA==","signatures":[{"sig":"MEQCIGjgP38J8gT7Q7FgJMrKUdnUKMu0bBBeAEqxeeaHfiQcAiA0B98k3NNGR9ZSHbVEGHqUduBlJFEipXOfEcC0AXXaqw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":477453},"main":"dist/index.cjs","type":"module","types":"dist/index.d.ts","module":"dist/index.js","exports":{"import":"./dist/index.js","require":"./dist/index.cjs"},"gitHead":"7420b32fb09a1b62df9e7795203325722a244125","scripts":{"test":"npm run build && node --test \"test/*.test.ts\"","build":"rm -rf dist && lezer-generator src/regex.grammar -o src/parser.js && lezer-generator src/raku.grammar -o src/raku-parser.js && lezer-generator src/lua.grammar -o src/lua-parser.js && lezer-generator src/vim.grammar -o src/vim-parser.js && cm-buildhelper src/regex.ts","corpus":"npm run build && node test/corpus.ts","prepare":"npm run build","build-debug":"lezer-generator src/regex.grammar --names -o src/parser.js && lezer-generator src/raku.grammar --names -o src/raku-parser.js && lezer-generator src/lua.grammar --names -o src/lua-parser.js && lezer-generator src/vim.grammar --names -o src/vim-parser.js && cm-buildhelper src/regex.ts"},"_npmUser":{"name":"juicemitapfelndrin","email":"juicemitapfelndrin@gmail.com"},"repository":{"url":"git+https://codeberg.org/reeven/codemirror-lang-regex.git","type":"git"},"_npmVersion":"11.6.2","description":"Regular expression support for the CodeMirror code editor, in fifteen engines' dialects","directories":{},"sideEffects":false,"_nodeVersion":"25.0.0","dependencies":{"@lezer/lr":"^1.0.0","@lezer/common":"^1.0.0","@lezer/highlight":"^1.0.0","@codemirror/language":"^6.0.0","@codemirror/autocomplete":"^6.0.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.6.0","@lezer/generator":"^1.7.0","@codemirror/state":"^6.7.1","@codemirror/buildhelper":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/codemirror-lang-regex_0.2.0_1785112907017_0.8258959936872299","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@codincod/codemirror-lang-regex","version":"0.3.0","keywords":["editor","code","regex","regexp","pcre","icu","tcl","xsd","postgres","raku","lua","vim","codemirror"],"author":{"name":"CodinCod","email":"hello@codincod.com"},"license":"MIT","_id":"@codincod/codemirror-lang-regex@0.3.0","maintainers":[{"name":"juicemitapfelndrin","email":"juicemitapfelndrin@gmail.com"}],"dist":{"shasum":"10330a0c9e6409e562010e5ddd36fb4339207e88","tarball":"https://registry.npmjs.org/@codincod/codemirror-lang-regex/-/codemirror-lang-regex-0.3.0.tgz","fileCount":35,"integrity":"sha512-2buftIzbOQBz4LP2zhvzxtH+XKQlUhn8SzSUTC6+bJskWo1BDJ+WkqTwhXZm39B1XSyDJvAV1i0wB54Y9zAYdw==","signatures":[{"sig":"MEUCIQCMKV4lxBBMOtCT2CzAzhMyfbfwVROAVOV4Ovnf8nuOaAIgXknjvMpZD2GojjtHAndYJyazgEghf2PK7Lq4k1U6lxI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":512593},"main":"dist/index.cjs","type":"module","types":"dist/index.d.ts","module":"dist/index.js","exports":{"import":"./dist/index.js","require":"./dist/index.cjs"},"gitHead":"922b7089b25753a7b6c09b3c2f1e8cc8b4f5d511","scripts":{"test":"npm run build && node --test \"test/*.test.ts\"","build":"rm -rf dist && lezer-generator src/regex.grammar -o src/parser.js && lezer-generator src/raku.grammar -o src/raku-parser.js && lezer-generator src/lua.grammar -o src/lua-parser.js && lezer-generator src/vim.grammar -o src/vim-parser.js && cm-buildhelper src/regex.ts","corpus":"npm run build && node test/corpus.ts","prepare":"npm run build","build-debug":"lezer-generator src/regex.grammar --names -o src/parser.js && lezer-generator src/raku.grammar --names -o src/raku-parser.js && lezer-generator src/lua.grammar --names -o src/lua-parser.js && lezer-generator src/vim.grammar --names -o src/vim-parser.js && cm-buildhelper src/regex.ts"},"_npmUser":{"name":"juicemitapfelndrin","email":"juicemitapfelndrin@gmail.com"},"repository":{"url":"git+https://codeberg.org/reeven/codemirror-lang-regex.git","type":"git"},"_npmVersion":"11.6.2","description":"Regular expression support for the CodeMirror code editor, in nineteen engines' dialects","directories":{},"sideEffects":false,"_nodeVersion":"25.0.0","dependencies":{"@lezer/lr":"^1.0.0","@lezer/common":"^1.0.0","@lezer/highlight":"^1.0.0","@codemirror/language":"^6.0.0","@codemirror/autocomplete":"^6.0.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.6.0","@lezer/generator":"^1.7.0","@codemirror/state":"^6.7.1","@codemirror/buildhelper":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/codemirror-lang-regex_0.3.0_1785157004594_0.5457312227526203","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@codincod/codemirror-lang-regex","version":"0.3.1","keywords":["editor","code","regex","regexp","pcre","icu","tcl","xsd","postgres","raku","lua","vim","codemirror"],"author":{"name":"CodinCod","email":"hello@codincod.com"},"license":"MIT","_id":"@codincod/codemirror-lang-regex@0.3.1","maintainers":[{"name":"juicemitapfelndrin","email":"juicemitapfelndrin@gmail.com"}],"homepage":"https://codincod.com/","dist":{"shasum":"f62b1ee4cf0de68dddfda5452d29de40d5e8ef97","tarball":"https://registry.npmjs.org/@codincod/codemirror-lang-regex/-/codemirror-lang-regex-0.3.1.tgz","fileCount":35,"integrity":"sha512-MAIoTHZ++mEISAH0BjDCrrUdajkc58ya7R8aNSamwIp18JSt6daiyp5KGhX1ZpCu8vPKIPjhzl9L85GGaIA5fA==","signatures":[{"sig":"MEQCIDTT5KVu9Dw59+yYKyRbt+kHCRPhNRsQJAf8Mo0DqIimAiAxZd0o/Hef1BEEy1dQonfM9qdjGaoLwrzwSFJWf3U8UA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":512812},"main":"dist/index.cjs","type":"module","types":"dist/index.d.ts","module":"dist/index.js","exports":{"import":"./dist/index.js","require":"./dist/index.cjs"},"gitHead":"7bf90eba25390b7dfd17d9c4b523af330edc6dfe","scripts":{"test":"npm run build && node --test \"test/*.test.ts\"","build":"rm -rf dist && lezer-generator src/regex.grammar -o src/parser.js && lezer-generator src/raku.grammar -o src/raku-parser.js && lezer-generator src/lua.grammar -o src/lua-parser.js && lezer-generator src/vim.grammar -o src/vim-parser.js && cm-buildhelper src/regex.ts","corpus":"npm run build && node test/corpus.ts","prepare":"npm run build","build-debug":"lezer-generator src/regex.grammar --names -o src/parser.js && lezer-generator src/raku.grammar --names -o src/raku-parser.js && lezer-generator src/lua.grammar --names -o src/lua-parser.js && lezer-generator src/vim.grammar --names -o src/vim-parser.js && cm-buildhelper src/regex.ts"},"_npmUser":{"name":"juicemitapfelndrin","email":"juicemitapfelndrin@gmail.com"},"repository":{"url":"git+https://codeberg.org/reeven/codemirror-lang-regex.git","type":"git"},"_npmVersion":"11.6.2","description":"Regular expression support for the CodeMirror code editor, in nineteen engines' dialects","directories":{},"sideEffects":false,"_nodeVersion":"25.0.0","dependencies":{"@lezer/lr":"^1.0.0","@lezer/common":"^1.0.0","@lezer/highlight":"^1.0.0","@codemirror/language":"^6.0.0","@codemirror/autocomplete":"^6.0.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.6.0","@lezer/generator":"^1.7.0","@codemirror/state":"^6.7.1","@codemirror/buildhelper":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/codemirror-lang-regex_0.3.1_1785286916105_0.3883613486472137","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"@codincod/codemirror-lang-regex","version":"0.3.2","keywords":["editor","code","regex","regexp","pcre","icu","tcl","xsd","postgres","raku","lua","vim","codemirror"],"author":{"name":"CodinCod","email":"hello@codincod.com"},"license":"MIT","_id":"@codincod/codemirror-lang-regex@0.3.2","maintainers":[{"name":"juicemitapfelndrin","email":"juicemitapfelndrin@gmail.com"}],"homepage":"https://codincod.com/","dist":{"shasum":"4072b8738753a76781c4e05f2dd88b939a3d0284","tarball":"https://registry.npmjs.org/@codincod/codemirror-lang-regex/-/codemirror-lang-regex-0.3.2.tgz","fileCount":35,"integrity":"sha512-BhtE8e1NcDOIaimEndbxxTSeH0cprkyiPopyrvDM511p97IFmImu8gQ1PBlQ7LGe8oAMgs8kC6UDGwWSW63vnA==","signatures":[{"sig":"MEQCIHr/D7JjXHGWj7+g6SL6lv1VekodwhSVq3gmylB4BbeIAiAt2aXAcuTgDNDelQ3e5hBPkHXIFFBWHHDWGsXLtXpAqQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":512804},"main":"dist/index.cjs","type":"module","types":"dist/index.d.ts","module":"dist/index.js","exports":{"import":"./dist/index.js","require":"./dist/index.cjs"},"gitHead":"7bf90eba25390b7dfd17d9c4b523af330edc6dfe","scripts":{"test":"npm run build && node --test \"test/*.test.ts\"","build":"rm -rf dist && lezer-generator src/regex.grammar -o src/parser.js && lezer-generator src/raku.grammar -o src/raku-parser.js && lezer-generator src/lua.grammar -o src/lua-parser.js && lezer-generator src/vim.grammar -o src/vim-parser.js && cm-buildhelper src/regex.ts","corpus":"npm run build && node test/corpus.ts","prepare":"npm run build","build-debug":"lezer-generator src/regex.grammar --names -o src/parser.js && lezer-generator src/raku.grammar --names -o src/raku-parser.js && lezer-generator src/lua.grammar --names -o src/lua-parser.js && lezer-generator src/vim.grammar --names -o src/vim-parser.js && cm-buildhelper src/regex.ts"},"_npmUser":{"name":"juicemitapfelndrin","email":"juicemitapfelndrin@gmail.com"},"repository":{"url":"https://codeberg.org/reeven/codemirror-lang-regex","type":"git"},"_npmVersion":"11.6.2","description":"Regular expression support for the CodeMirror code editor, in nineteen engines' dialects","directories":{},"sideEffects":false,"_nodeVersion":"25.0.0","dependencies":{"@lezer/lr":"^1.0.0","@lezer/common":"^1.0.0","@lezer/highlight":"^1.0.0","@codemirror/language":"^6.0.0","@codemirror/autocomplete":"^6.0.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.6.0","@lezer/generator":"^1.7.0","@codemirror/state":"^6.7.1","@codemirror/buildhelper":"^1.0.2"},"_npmOperationalInternal":{"tmp":"tmp/codemirror-lang-regex_0.3.2_1785970822580_0.8386557593478337","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@codincod/codemirror-lang-regex","version":"0.4.0","description":"Regular expression support for the CodeMirror code editor, in nineteen engines' dialects","keywords":["editor","code","regex","regexp","pcre","icu","tcl","xsd","postgres","raku","lua","vim","codemirror"],"author":{"name":"CodinCod","email":"hello@codincod.com"},"license":"MIT","type":"module","main":"dist/index.cjs","exports":{"import":"./dist/index.js","require":"./dist/index.cjs"},"module":"dist/index.js","types":"dist/index.d.ts","sideEffects":false,"scripts":{"build":"rm -rf dist && lezer-generator src/regex.grammar -o src/parser.js && lezer-generator src/raku.grammar -o src/raku-parser.js && lezer-generator src/lua.grammar -o src/lua-parser.js && lezer-generator src/vim.grammar -o src/vim-parser.js && cm-buildhelper src/regex.ts","build-debug":"lezer-generator src/regex.grammar --names -o src/parser.js && lezer-generator src/raku.grammar --names -o src/raku-parser.js && lezer-generator src/lua.grammar --names -o src/lua-parser.js && lezer-generator src/vim.grammar --names -o src/vim-parser.js && cm-buildhelper src/regex.ts","prepare":"npm run build","test":"npm run build && node --test \"test/*.test.ts\"","measure":"npm run build && node test/measure.ts","fuzz":"npm run build && node ../lezer-survey/src/cli.ts fuzz"},"dependencies":{"@codemirror/autocomplete":"^6.0.0","@codemirror/language":"^6.0.0","@lezer/common":"^1.0.0","@lezer/highlight":"^1.0.0","@lezer/lr":"^1.0.0"},"devDependencies":{"@codemirror/buildhelper":"^1.0.2","@codemirror/state":"^6.7.1","@lezer/generator":"^1.7.0","typescript":"^5.6.0"},"homepage":"https://codincod.com/","repository":{"type":"git","url":"https://codeberg.org/reeven/codemirror-lang-regex"},"gitHead":"df429758bb1e9891c54fad74d32f86915552570e","_id":"@codincod/codemirror-lang-regex@0.4.0","_nodeVersion":"25.0.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-EC2FmkQIqWRacpK2ITXZBGuzc8NnjIvExOZQ6wo8dqhytcq0dbXYzru3mOCuk+21fodmyhiyoFy491xnf1QUPg==","shasum":"953982a5653efeca5450e5a1fac0eaa70b786e45","tarball":"https://registry.npmjs.org/@codincod/codemirror-lang-regex/-/codemirror-lang-regex-0.4.0.tgz","fileCount":35,"unpackedSize":512875,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCICCp809uZt24KmYnJLeMGrMri+0oGJLG9XYwpMBu7FjoAiBPeTqT28dUwpfhWaYxHi85ph2BxE2M7/4D2AsxtWumog=="}]},"_npmUser":{"name":"juicemitapfelndrin","email":"juicemitapfelndrin@gmail.com"},"directories":{},"maintainers":[{"name":"juicemitapfelndrin","email":"juicemitapfelndrin@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/codemirror-lang-regex_0.4.0_1786760490058_0.27280445343153903"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-27T00:12:09.544Z","modified":"2026-08-15T02:21:30.427Z","0.1.0":"2026-07-27T00:12:09.929Z","0.2.0":"2026-07-27T00:41:47.220Z","0.3.0":"2026-07-27T12:56:44.750Z","0.3.1":"2026-07-29T01:01:56.338Z","0.3.2":"2026-08-05T23:00:22.788Z","0.4.0":"2026-08-15T02:21:30.232Z"},"author":{"name":"CodinCod","email":"hello@codincod.com"},"license":"MIT","homepage":"https://codincod.com/","keywords":["editor","code","regex","regexp","pcre","icu","tcl","xsd","postgres","raku","lua","vim","codemirror"],"repository":{"type":"git","url":"https://codeberg.org/reeven/codemirror-lang-regex"},"description":"Regular expression support for the CodeMirror code editor, in nineteen engines' dialects","maintainers":[{"name":"juicemitapfelndrin","email":"juicemitapfelndrin@gmail.com"}],"readme":"# @codincod/codemirror-lang-regex [![NPM version](https://img.shields.io/npm/v/@codincod/codemirror-lang-regex.svg)](https://www.npmjs.org/package/@codincod/codemirror-lang-regex)\n\n[ [**CHANGELOG**](https://codeberg.org/reeven/codemirror-lang-regex/src/branch/master/CHANGELOG.md) ]\n\nThis package implements regular expression support for the\n[CodeMirror](https://codemirror.net/) code editor, using a\n[Lezer](https://lezer.codemirror.net/) grammar written for this package. It\nreads a pattern as one named engine reads it, and it knows nineteen of them.\n\nCodeMirror has never shipped a mode for the inside of a regular expression. In\nCodeMirror 5 and 6 alike, a regex literal in a JavaScript file is one token\npainted one colour, and a regex typed into a search box is plain text. That is\nfine until the pattern is the thing you are working on, which is the case on\nevery regex tester ever built.\n\nWritten in part for [CodinCod](https://codincod.com/), a competitive coding\nplatform, where it reads the patterns typed into its\n[regex tester](https://codincod.com/tools/regex).\n\nThis code is released under an\n[MIT license](https://codeberg.org/reeven/codemirror-lang-regex/src/branch/master/LICENSE).\n\n## Usage\n\n```javascript\nimport {EditorView, basicSetup} from \"codemirror\"\nimport {regex} from \"@codincod/codemirror-lang-regex\"\n\nconst view = new EditorView({\n  parent: document.body,\n  doc: String.raw`(?<area>\\d{3})-(\\d{4})`,\n  extensions: [basicSetup, regex()]\n})\n```\n\n`regex()` on its own reads the pattern as a browser would, because a pattern\ntyped into a browser is usually about to be handed to that browser's own\n`RegExp`. Name another engine when you know one:\n\n```javascript\nregex({flavour: \"pcre\"})\nregex({flavour: \"python\"})\nregex({flavour: \"php\"})              // an alias for pcre\nregex({flavour: \"pcre\", flags: \"x\"}) // free spacing, so `#` starts a comment\nregex({flavour: \"javascript\", flags: \"v\"})\nregex({flavour: \"icu\"})              // an alias for swift, objc and mysql\nregex({flavour: \"are\"})              // an alias for tcl and postgres\nregex({flavour: \"cpp\"})              // std::regex, which is not quite ECMAScript\nregex({flavour: \"xsd\"})              // the patterns inside an XML schema\nregex({flavour: \"raku\"})             // a second grammar, in the same package\n```\n\nThe flags are the engine's own letters, so the same string you would pass the\nengine can be passed here. Four of them change what a pattern *is* rather than\nwhat it matches, and the rest are read past: `x` ignores whitespace and takes\n`#` as a comment, PCRE2's `xx` does that inside character classes as well, and\nJavaScript's `u` and `v` each read the pattern more strictly than the flagless\ndialect they replace.\n\n## A regular expression is not one language\n\n`(?P<year>\\d+)` is a named group in Python, a named group in PCRE and a syntax\nerror in a browser. `\\d` is a digit in thirteen of the flavours here and a literal\n`d` in `grep`. `\\v` is vertical whitespace in PCRE and a vertical tab in\nJavaScript, so `[\\v]` matches five characters on a server and one in a browser.\n`[a-z&&[^aeiou]]` is an intersection in Java and, in PCRE, a class holding two\nampersands and a bracket. `(?<=a)*` compiles in Python and PCRE and is an error\nin every browser. `\\b` is a word boundary in fourteen of the flavours here, a\nbackspace in Tcl and PostgreSQL, where the boundary is `\\y` and `\\B` is a\nbackslash, and nothing at all in an XML schema, which has no assertions and no\nanchors either: `^a$` there matches four characters.\n\nSo an engine has three ways to answer, and this grammar gives all three.\n\n| | |\n| --- | --- |\n| **it has this** | the construct gets the node it deserves: `\\d` is a `CharacterClassEscape` |\n| **it reads this differently** | no error, and no node: `\\d` in `grep` is an `Escape`, a literal letter |\n| **it refuses this** | an error node, where a pattern will not compile at all |\n\nThe middle column is the one worth having. A loose engine almost never rejects\nanything, so a parser that only answered yes or no would call `\\p{L}` fine in a\nflagless JavaScript pattern, where it matches a `p` and a brace and no letters\nwhatsoever.\n\n## The nineteen\n\nSixteen of them are one grammar. Raku, Lua and Vim are the other three and are\nnot, so each has a grammar and a parser of its own in the same package: `[abc]`\nis a character class in every other engine here and a non-capturing group in\nRaku, a Lua pattern has `%a` where everyone else has `\\w` and no alternation at\nall, and Vim puts its assertions after the group rather than inside its opener.\n`regex({flavour: \"raku\"})` and its two neighbours reach them, and everything an\neditor does with the result is the same.\n\n| Flavour | Aliases | Notes |\n| --- | --- | --- |\n| `javascript` | `js`, `ecmascript`, `node` | three languages, chosen by the `u` and `v` flags |\n| `pcre` | `pcre2`, `php`, `elixir`, `erlang`, `r` | the widest of them: conditionals, recursion, callouts, verbs |\n| `perl` | `perl5` | PCRE plus code blocks, minus callouts |\n| `python` | `re`, `py` | `(?P<n>)` and `(?P=n)`, no properties, `\\z` since 3.12 |\n| `dotnet` | `csharp`, `c#` | balancing groups, class subtraction with a dash |\n| `java` | `kotlin`, `scala`, `groovy` | class intersection and nesting, `\\Q...\\E`, possessive quantifiers |\n| `icu` | `swift`, `objc`, `mysql`, `icu4c`, `icu4j` | Java's neighbour: `(?#`, `\\U`, POSIX classes, and no `\\pL` |\n| `cpp` | `c++`, `cxx`, `stdregex` | says it reads ECMAScript, and refuses a third of what V8 takes |\n| `ruby` | `onigmo`, `oniguruma` | the absent operator, `\\O`, subroutine calls, `\\h` as a hex digit |\n| `rust` | | class set operations, no backreferences, no lookaround |\n| `go` | `re2`, `golang` | as Rust for what it refuses, and POSIX classes for what it takes |\n| `ere` | `posix`, `egrep`, `awk` | POSIX extended, with the parts GNU added |\n| `bre` | `grep`, `sed` | POSIX basic, where the groups are `\\(escaped\\)` |\n| `are` | `tcl`, `postgres`, `postgresql` | Spencer's advanced: `\\y` is the word boundary, `\\b` a backspace, `***=` a literal |\n| `emacs` | `elisp`, `emacs-lisp` | escaped groups, bare quantifiers, syntax classes, symbol boundaries |\n| `xsd` | `xml`, `xmlschema` | a schema's own: `\\i` and `\\c`, no anchors, no groups but plain ones |\n| `raku` | `perl6`, `rakudo` | a grammar of its own: `<[a..z]>`, `**`, `%`, insignificant whitespace |\n| `lua` | `luajit`, `luau` | a grammar of its own: `%a`, `%b()`, `%f[]`, no alternation |\n| `vim` | `nvim`, `neovim`, `vi` | a grammar of its own, in four levels of magic: `\\(a\\|b\\)\\+`, `\\(a\\)\\@=` |\n\nThe differences between the sixteen are 98 Lezer dialects, and a flavour is a\nset of them: `xsd` switches on 11, `bre` on 17, `are` on 28, `pcre` on 53. The whole matrix is\none line per feature in [`src/dialects.ts`](src/dialects.ts), written as \"who\nspells this\", because the interesting question is never what PCRE has.\n\n## Measured\n\nEight bodies of patterns, none of them written here, and two flavours measured\non somebody else's. Two are read by\n[`test/corpus.ts`](test/corpus.ts): the first is the fixture set of `regexpp`,\nthe regex parser ESLint uses, which records what V8 accepts and the reason V8\ngives when it does not, and the second is CPython's `Lib/test/re_tests.py`, the\n`re` module's correctness suite since Python 1.5.\n\nThe other three grammars, and the three dialect sets whose engines are programs\nin their own right, are measured the same way: against the largest body of\npatterns their own engine will vouch for.\n\nRaku's is `roast`, whose `S05-*` directories are the regex chapter: 2948 patterns\ncome out of them, and whether each one is legal is a question only Rakudo can\nanswer, so [`test/verdicts.raku`](test/verdicts.raku) asks it and\n[`test/roast.ts`](test/roast.ts) keeps the score.\n\nLua's is the test suite from lua.org, where `pm.lua` is the pattern matching file\nand the other thirty-two files use patterns as any program does; 256 come out,\nand [`test/verdicts.lua`](test/verdicts.lua) puts each one to Lua, which has no\nway to compile a pattern without matching one and so is asked with nine subjects.\n\nVim's corpus is Vim. 20,680 patterns come out of the syntax, indent, ftplugin and\nautoload files it ships, which is more than the rest of this measurement put\ntogether, and they are patterns people rely on daily rather than test cases.\n[`test/verdicts.vim`](test/verdicts.vim) asks Vim itself about each one, and\n[`test/vim.ts`](test/vim.ts) reads the magic level off the front of the pattern\nso that each is parsed as the file it lives in would have it read.\n\nEmacs's corpus is Emacs, the same way Vim's is Vim. There is no Emacs installed\non the machine this was written on, but there is one in the image our own code\nrunner runs Emacs Lisp from, which is where both the engine and the lisp come\nfrom: 6821 patterns are read out of the 1655 files it ships, by walking each file\nthe way the reader does and keeping the strings that a regexp function was handed\nor that a `defvar` named a regexp. [`test/verdicts.el`](test/verdicts.el) asks\nEmacs about each one and [`test/emacs.ts`](test/emacs.ts) keeps the score.\n\nEmacs's own lisp holds nothing Emacs refuses, which would leave half of that\nmeasurement with nothing to measure, so the patterns are cut short as well. A\npattern with its tail taken off is either still legal, and must still parse, or it\nis not, and should be caught. It is also what an editor looks at most of the time,\nsince a pattern being typed is a pattern that has not finished yet.\n\nICU's corpus is ICU's own: `regextst.txt`, the file its authors run before a\nrelease, where a case is a pattern, a column of flags and a subject with the\ncapture groups tagged in it. 2107 patterns come out of it, and the verdicts come\nfrom ICU4C itself: [`test/verdicts.cpp`](test/verdicts.cpp) is thirty lines\naround `uregex_open` and [`test/icu.ts`](test/icu.ts) keeps the score. Two kinds\nof case are left out rather than counted, because neither is in this language:\n`Q` puts the whole pattern in quotes, and `e` turns on error-on-unknown-escapes,\nunder which `\\q` stops being a `q`.\n\nARE's corpus is both halves of the lineage. Tcl ships Henry Spencer's own suite\nfor the engine he wrote, `tests/reg.test`, which says which flavour each case is\nin and leaves 290 that are advanced regular expressions rather than POSIX; and\nPostgres ships `src/test/regress/sql/regex.sql`, which is the same engine two\ndecades on. Whether a pattern is legal is that engine's business, and Postgres\nis the half of it that answers questions, so [`test/verdicts.sql`](test/verdicts.sql)\nasks it and [`test/are.ts`](test/are.ts) keeps the score.\n\nThe last two flavours have no suite of their own anywhere, so each is put to the\npatterns of the language it is nearest to, and its own engine says which of them\nit will take. `std::regex` is measured on ECMAScript's fixtures, because the C++\nstandard says `std::regex` reads ECMAScript; the answer is that a third of them\nwill not compile, which is the argument for its being a column rather than an\nalias. XML Schema is measured on both the ECMAScript and the Python patterns,\nsince a schema's regexes live inside `<xs:pattern>` and nobody keeps a file of\nthem; 441 of the 1177 survive, and what survives is a fair sample of the subset a\nschema author is left with.\n\nBoth are asked the same way the others are. [`test/verdicts.cpp`](test/verdicts.cpp)\nanswers for `std::regex` as well as for ICU, since both are asked in C++.\n[`test/xsd.ts`](test/xsd.ts) needs no asker at all: the question is already a\ndocument, so it writes a schema holding one type per pattern and `xmllint` names\nthe lines it will not compile.\n\n| | |\n| --- | --- |\n| patterns V8 accepts, parsed with no error | **499 / 499** |\n| patterns CPython compiles, parsed with no error | **363 / 363** |\n| patterns Rakudo compiles, parsed with no error | **2329 / 2329** |\n| patterns Lua accepts, parsed with no error | **243 / 243** |\n| patterns Vim compiles, parsed with no error | **20535 / 20535** |\n| patterns Emacs accepts, parsed with no error | **6821 / 6821** |\n| the same patterns cut short, where Emacs still accepts them | **3685 / 3685** |\n| patterns ICU accepts, parsed with no error | **2076 / 2076** |\n| patterns Postgres compiles, parsed with no error | **294 / 294** |\n| patterns `std::regex` compiles, parsed with no error | **387 / 387** |\n| patterns a schema compiles, parsed with no error | **441 / 441** |\n| patterns V8 rejects, caught as errors | 149 / 293 |\n| patterns CPython rejects, caught as errors | 32 / 40 |\n| patterns Rakudo refuses, caught as errors | 373 / 419 |\n| patterns Lua refuses, caught as errors | 13 / 13 |\n| patterns Vim refuses, caught as errors | 83 / 83 |\n| the same patterns cut short, where Emacs refuses them | 4817 / 4846 |\n| patterns ICU refuses, caught as errors | 5 / 31 |\n| patterns Postgres refuses, caught as errors | 40 / 71 |\n| patterns `std::regex` refuses, caught as errors | 242 / 405 |\n| patterns a schema refuses, caught as errors | 663 / 736 |\n\nThe first eleven are the pass mark, and 100% is the only acceptable number: an\neditor that paints working code as broken is worse than one that paints nothing\nat all.\n\nThe rest are watched rather than aimed at, because a grammar knows shapes\nand not meanings. Of the eight Python rejections that get through, every one is\nabout meaning: `\\1` with no groups to refer to, `a[b-a]` with its range the\nwrong way round, `((.)\\1+)` referring to a group that is still open. Those are a\nlinter's business, and this package is not a linter.\n\nAnd for contrast, since it is the whole argument for having flavours at all:\n139 of CPython's 363 working patterns are not JavaScript, 182 of the 499 patterns\nV8 compiles are not `std::regex`, and 736 of the 1177 patterns written for the\nother engines are not a schema's.\n\nICU's refusals are the clearest case for that being a linter's line rather than\na parser's: of the 26 this lets through, every one is a name or a number rather\nthan a shape. `[\\p{InBadBlock}]` is a block nobody defined, `x{4294967300}` is a\ncount that will not fit, `(?<a>.)(?<a>.)` names two groups the same, and\n`(?<!(0123456789a){10000000})x` is a lookbehind ICU declines to think about.\n\nThe 73 schema rejections that get through are three shapes, and two of them are\nnames rather than shapes: `\\p{Emoji}` and `\\p{Script=Hiragana}` are properties a\nschema does not define, and `[b-a]` is the usual range the wrong way round. The\nthird is `[A--B]`, which is a difference in a browser's `v` mode and, in a\nschema, a range ending at a hyphen, which is a thing a schema will not have.\n\nThe 29 cut Emacs patterns that get through are two shapes: a repeat left open,\n`^[A-Z]\\{2`, and a `\\s` with its syntax class not yet typed. Both are read as\ntext, which is what Emacs does with most of what it does not recognise and what\nthis grammar does where a flavour has not said otherwise.\n\n## What it will not tell you\n\n**Whether the pattern means anything.** `(a)\\2` refers to a group that does not\nexist, `a{3,2}` counts backwards, `[z-a]` runs the wrong way, and all three are\nwell formed. Counting the groups and comparing the ends of a range are a\nlinter's job.\n\n**Whether a flag letter exists.** `(?i)` and `(?n)` are read the same way,\nthough only .NET has the second. Which letters an engine takes is a table this\ngrammar would rather not carry twice.\n\n**Where an ARE's options are allowed to sit.** `(?i)` has to be the first thing\nin a Tcl or Postgres pattern, and this reads one anywhere, the way it reads a\n`(?i)` anywhere in the nine other engines that have one. Every difference\nbetween the engines here is a token, and where a token may sit is not a\nquestion a token can answer.\n\n**Which escapes a schema names.** XML Schema names the characters that may\nfollow a backslash and refuses every other one, so `\\f` is a form feed in twelve\nof the flavours here and an error in a schema. A backslash before punctuation is\nthat punctuation everywhere in this grammar, which is a rule worth keeping for\nthe other eighteen. Where `libxml2` is looser than the schema grammar this\nfollows the grammar, so `a{2}{2}` is a repeat on a repeat and an error here,\nthough `xmllint` will take it.\n\n**Which magic level a Vim pattern is at halfway through.** `\\v` and its three\nsiblings choose a level, and a Lezer dialect is chosen once for a parse, so a\npattern that starts in one level and switches to another is read at the level it\nstarted with. The switch is in the tree as a `Flags` node, and `vimMagic` reads\nthe level off the front of a pattern for you. 62 of Vim's own 20,680 patterns do\nthis, and they are left out of the measurement above rather than counted as\npasses.\n\n## What it gives an editor\n\nSyntax highlighting where the metacharacters are painted and the literal text is\nnot, which is the way round that makes a pattern readable. Bracket matching that\npairs `)` with whichever of the fourteen group openers began it. Folding and\nindentation for a pattern written over several lines in free-spacing mode.\n\nCompletion, from the engine you named:\n\n- the escapes it has, and only those, with a word on what each one matches\n- the Unicode property names, general categories and scripts, after `\\p{`\n- the POSIX class names after `[[:`\n- the names of the groups in the pattern, after `\\k<`, `\\g<`, `(?&` or `(?P=`\n\n## The tree\n\nLiteral characters are not in it. A pattern is mostly literal text, that text\nwants no highlighting, and a node per character would be a tree ten times the\nsize of the pattern for nothing. What is left is the skeleton:\n\n```\n(?<area>\\d{3})-(\\d{4})\n\nPattern(\n  NamedGroup(\"(?<\", GroupName, \">\", CharacterClassEscape, Quantifier, \")\"),\n  Group(\"(\", CharacterClassEscape, Quantifier, \")\"))\n```\n\nGroup openers are node types named after the text they match, so `(?:`, `(?<=`\nand `(*atomic:` are all there to be styled, and a tree dump reads like the\npattern it came from.\n\nThere are four parsers in the package and they agree about their node names, so a\ntheme written for one paints the others and a tree dump reads the same way.\nRaku's has nodes the others have no need for, `Separator` and `Adverb` and\n`RuleCall` and `Ratchet`, and lacks the ones it has no use for.\n\n`regexLanguage` is the undialected grammar, which is the core all of the engines\nstarted from, POSIX extended. `regexLanguageFor(flavour, flags)` gives one\nengine's language for use with `LanguageSupport`, `parser` is the parser on its\nown, and `flavours`, `toFlavour` and `dialectFor` are exported for a page that\noffers a choice of engine. The Raku half answers to `raku`, `rakuRegexLanguage`,\n`rakuParser` and `rakuCompletion` as well as to the flavour name.\n","readmeFilename":"README.md"}