Last active
April 5, 2026 16:23
-
-
Save webstrand/9782548f24ca5a3cbf68cce68e1cc21b to your computer and use it in GitHub Desktop.
RegExp literal oblivious to unescaped whitespace
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const cacheRegExpx = new WeakMap<readonly string[], string[]>(); | |
| export function RegExpx<T extends { [key: string]: string | undefined }>( | |
| { raw }: TemplateStringsArray, | |
| ...substitutions: unknown[] | |
| ) { | |
| let strs = cacheRegExpx.get(raw); | |
| if (!strs) { | |
| cacheRegExpx.set(raw, (strs = raw.slice())); | |
| for (let i = 0; i < strs.length; i++) { | |
| // We strip all spaces, except for ones preceeded by an unbalanced number of backslashes | |
| // where we retain the space and drop the escape backsclash. | |
| strs[i] = strs[i]!.replace(/(\\*)\s+/g, (m, { length: s }) => m.substring(s & 1, s + (s & 1))); | |
| } | |
| } | |
| // Apply the substitutions, this can't be cached | |
| let acc = strs[0]!; | |
| for (let i = 1; i < strs.length; i++) { | |
| acc += String(substitutions[i - 1]) + strs[i]!; | |
| } | |
| return new RegExp(acc) as Omit<RegExp, "exec"> & { | |
| exec(string: string): RegExpExecArrayWithGroups<T> | null; | |
| }; | |
| } | |
| export interface RegExpExecArrayWithGroups<T extends { [key: string]: string | undefined }> | |
| extends Omit<RegExpExecArray, "groups"> { | |
| groups: T; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment