2024-01-01 21:11:32 +00:00
|
|
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
2024-02-12 20:32:41 +00:00
|
|
|
// This module is browser compatible.
|
2023-05-11 07:26:51 +00:00
|
|
|
|
2024-06-11 07:06:12 +00:00
|
|
|
// For future forward-compatibility with regexp `v` flag, `RESERVED_CHARS` is
|
|
|
|
// autogenerated from the `ClassSetReservedDoublePunctuator`,
|
|
|
|
// `ClassSetSyntaxCharacter`, and `ClassSetReservedPunctuator` categories in the
|
|
|
|
// {@link https://github.com/tc39/proposal-regexp-v-flag#how-is-the-v-flag-different-from-the-u-flag | draft spec}.
|
|
|
|
// ```ts
|
|
|
|
// const reservedChars = [
|
|
|
|
// ...new Set(
|
|
|
|
// [
|
|
|
|
// "ClassSetReservedDoublePunctuator",
|
|
|
|
// "ClassSetSyntaxCharacter",
|
|
|
|
// "ClassSetReservedPunctuator",
|
|
|
|
// ].map((n) =>
|
|
|
|
// document.querySelector(`[name=${n}] emu-rhs`).textContent.replaceAll(
|
|
|
|
// /\s/g,
|
|
|
|
// "",
|
|
|
|
// )
|
|
|
|
// ).join(""),
|
|
|
|
// ),
|
|
|
|
// ];
|
|
|
|
// const RESERVED_CHARS = Object.fromEntries(reservedChars
|
|
|
|
// .map((x) => {
|
2023-05-11 07:26:51 +00:00
|
|
|
// try {
|
2024-06-11 07:06:12 +00:00
|
|
|
// for (const flag of "gimsuy") {
|
|
|
|
// new RegExp(`\\${x}`, flag);
|
|
|
|
// new RegExp(`[\\${x}]`, flag);
|
2023-05-11 07:26:51 +00:00
|
|
|
// }
|
2024-06-11 07:06:12 +00:00
|
|
|
// return [x, `\\${x}`];
|
2023-05-11 07:26:51 +00:00
|
|
|
// } catch (e) {
|
2024-06-11 07:06:12 +00:00
|
|
|
// return [x, `\\x${x.codePointAt(0).toString(16).padStart(2, "0")}`];
|
2023-05-11 07:26:51 +00:00
|
|
|
// }
|
2024-06-11 07:06:12 +00:00
|
|
|
// }));
|
|
|
|
// ```
|
|
|
|
const RESERVED_CHARS = {
|
2023-05-11 07:26:51 +00:00
|
|
|
"&": "\\x26",
|
|
|
|
"!": "\\x21",
|
|
|
|
"#": "\\x23",
|
2024-05-21 16:43:25 +00:00
|
|
|
$: "\\$",
|
2023-05-11 07:26:51 +00:00
|
|
|
"%": "\\x25",
|
|
|
|
"*": "\\*",
|
|
|
|
"+": "\\+",
|
|
|
|
",": "\\x2c",
|
|
|
|
".": "\\.",
|
|
|
|
":": "\\x3a",
|
|
|
|
";": "\\x3b",
|
|
|
|
"<": "\\x3c",
|
|
|
|
"=": "\\x3d",
|
|
|
|
">": "\\x3e",
|
|
|
|
"?": "\\?",
|
|
|
|
"@": "\\x40",
|
|
|
|
"^": "\\^",
|
|
|
|
"`": "\\x60",
|
|
|
|
"~": "\\x7e",
|
|
|
|
"(": "\\(",
|
|
|
|
")": "\\)",
|
|
|
|
"[": "\\[",
|
|
|
|
"]": "\\]",
|
|
|
|
"{": "\\{",
|
|
|
|
"}": "\\}",
|
|
|
|
"/": "\\/",
|
|
|
|
"-": "\\x2d",
|
|
|
|
"\\": "\\\\",
|
|
|
|
"|": "\\|",
|
2024-06-11 07:06:12 +00:00
|
|
|
} as const;
|
2023-05-11 07:26:51 +00:00
|
|
|
|
|
|
|
const RX_REGEXP_ESCAPE = new RegExp(
|
2024-06-11 07:06:12 +00:00
|
|
|
`[${Object.values(RESERVED_CHARS).join("")}]`,
|
2023-05-11 07:26:51 +00:00
|
|
|
"gu",
|
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Escapes arbitrary text for interpolation into a regexp, such that it will
|
|
|
|
* match exactly that text and nothing else.
|
|
|
|
*
|
2024-06-11 07:06:12 +00:00
|
|
|
* @example Usage
|
2023-05-11 07:26:51 +00:00
|
|
|
* ```ts
|
2024-07-12 08:07:33 +00:00
|
|
|
* import { escape } from "@std/regexp/escape";
|
2024-04-29 02:57:30 +00:00
|
|
|
* import { assertEquals, assertMatch, assertNotMatch } from "@std/assert";
|
2023-05-11 07:26:51 +00:00
|
|
|
*
|
|
|
|
* const re = new RegExp(`^${escape(".")}$`, "u");
|
|
|
|
*
|
|
|
|
* assertEquals("^\\.$", re.source);
|
|
|
|
* assertMatch(".", re);
|
|
|
|
* assertNotMatch("a", re);
|
|
|
|
* ```
|
2024-06-11 07:06:12 +00:00
|
|
|
*
|
|
|
|
* @param str The string to escape.
|
|
|
|
* @returns The escaped string.
|
2023-05-11 07:26:51 +00:00
|
|
|
*/
|
2023-12-19 00:26:13 +00:00
|
|
|
export function escape(str: string): string {
|
2023-05-11 07:26:51 +00:00
|
|
|
return str.replaceAll(
|
|
|
|
RX_REGEXP_ESCAPE,
|
2024-06-11 07:06:12 +00:00
|
|
|
(m) => RESERVED_CHARS[m as keyof typeof RESERVED_CHARS],
|
2023-05-11 07:26:51 +00:00
|
|
|
);
|
|
|
|
}
|