Skip to content

Instantly share code, notes, and snippets.

@webstrand
Last active April 5, 2026 16:23
Show Gist options
  • Select an option

  • Save webstrand/9782548f24ca5a3cbf68cce68e1cc21b to your computer and use it in GitHub Desktop.

Select an option

Save webstrand/9782548f24ca5a3cbf68cce68e1cc21b to your computer and use it in GitHub Desktop.
RegExp literal oblivious to unescaped whitespace
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