forked from denoland/deno_std
-
Notifications
You must be signed in to change notification settings - Fork 0
/
escape.ts
83 lines (79 loc) · 2.3 KB
/
escape.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
// // For future forward-compatibility with regexp `v` flag, reservedCharMap is
// // autogenerated from the ClassSetReservedDoublePunctuator,
// // ClassSetSyntaxCharacter, and ClassSetReservedPunctuator categories in the
// // draft spec.
// // See https://github.com/tc39/proposal-regexp-v-flag#how-is-the-v-flag-different-from-the-u-flag
// // and https://arai-a.github.io/ecma262-compare/snapshot.html?pr=2418#prod-ClassSetReservedDoublePunctuator
// const reservedChars = [...new Set(['ClassSetReservedDoublePunctuator', 'ClassSetSyntaxCharacter', 'ClassSetReservedPunctuator'].map(n =>
// document.querySelector(`[name=${n}] emu-rhs`).textContent.replaceAll(/\s/g, '')
// ).join(''))]
// const reservedCharMap = Object.fromEntries(reservedChars
// .map(x => {
// try {
// for (const flag of 'gimsuy') {
// new RegExp(`\\${x}`, flag)
// new RegExp(`[\\${x}]`, flag)
// }
// return [x, `\\${x}`]
// } catch (e) {
// return [x, `\\x${x.codePointAt(0).toString(16).padStart(2, '0')}`]
// }
// }))
const reservedCharMap = {
"&": "\\x26",
"!": "\\x21",
"#": "\\x23",
"$": "\\$",
"%": "\\x25",
"*": "\\*",
"+": "\\+",
",": "\\x2c",
".": "\\.",
":": "\\x3a",
";": "\\x3b",
"<": "\\x3c",
"=": "\\x3d",
">": "\\x3e",
"?": "\\?",
"@": "\\x40",
"^": "\\^",
"`": "\\x60",
"~": "\\x7e",
"(": "\\(",
")": "\\)",
"[": "\\[",
"]": "\\]",
"{": "\\{",
"}": "\\}",
"/": "\\/",
"-": "\\x2d",
"\\": "\\\\",
"|": "\\|",
};
const RX_REGEXP_ESCAPE = new RegExp(
`[${Object.values(reservedCharMap).join("")}]`,
"gu",
);
/**
* Escapes arbitrary text for interpolation into a regexp, such that it will
* match exactly that text and nothing else.
*
* @example
* ```ts
* import { escape } from "https://deno.land/std@$STD_VERSION/regexp/mod.ts";
* import { assertEquals, assertMatch, assertNotMatch } from "https://deno.land/std@$STD_VERSION/assert/mod.ts";
*
* const re = new RegExp(`^${escape(".")}$`, "u");
*
* assertEquals("^\\.$", re.source);
* assertMatch(".", re);
* assertNotMatch("a", re);
* ```
*/
export function escape(str: string) {
return str.replaceAll(
RX_REGEXP_ESCAPE,
(m) => reservedCharMap[m as keyof typeof reservedCharMap],
);
}