// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // This module is browser compatible. // 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) => { // 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 RESERVED_CHARS = { "&": "\\x26", "!": "\\x21", "#": "\\x23", $: "\\$", "%": "\\x25", "*": "\\*", "+": "\\+", ",": "\\x2c", ".": "\\.", ":": "\\x3a", ";": "\\x3b", "<": "\\x3c", "=": "\\x3d", ">": "\\x3e", "?": "\\?", "@": "\\x40", "^": "\\^", "`": "\\x60", "~": "\\x7e", "(": "\\(", ")": "\\)", "[": "\\[", "]": "\\]", "{": "\\{", "}": "\\}", "/": "\\/", "-": "\\x2d", "\\": "\\\\", "|": "\\|", } as const; const RX_REGEXP_ESCAPE = new RegExp( `[${Object.values(RESERVED_CHARS).join("")}]`, "gu", ); /** * Escapes arbitrary text for interpolation into a regexp, such that it will * match exactly that text and nothing else. * * @example Usage * ```ts * import { escape } from "@std/regexp/escape"; * import { assertEquals, assertMatch, assertNotMatch } from "@std/assert"; * * const re = new RegExp(`^${escape(".")}$`, "u"); * * assertEquals("^\\.$", re.source); * assertMatch(".", re); * assertNotMatch("a", re); * ``` * * @param str The string to escape. * @returns The escaped string. */ export function escape(str: string): string { return str.replaceAll( RX_REGEXP_ESCAPE, (m) => RESERVED_CHARS[m as keyof typeof RESERVED_CHARS], ); }