From faab271d1e4ca91bd7bcf64dae5c3ef9e7e86988 Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Thu, 18 Apr 2024 00:03:12 +0100 Subject: [PATCH] feat(labs/ssr): use RegExp.exec to escape HTML Switches from using `replace(pattern, fn)` to using the `exec` method of a `RegExp` instead. --- packages/labs/ssr/src/lib/util/escape-html.ts | 63 ++++++++++++++----- 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/packages/labs/ssr/src/lib/util/escape-html.ts b/packages/labs/ssr/src/lib/util/escape-html.ts index d0d66edd62..d4a4e56ab6 100644 --- a/packages/labs/ssr/src/lib/util/escape-html.ts +++ b/packages/labs/ssr/src/lib/util/escape-html.ts @@ -4,22 +4,57 @@ * SPDX-License-Identifier: BSD-3-Clause */ -const replacements = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - // Note ' was not defined in the HTML4 spec, and is not supported by very - // old browsers like IE8, so a codepoint entity is used instead. - "'": ''', -}; +const escapePattern = /[&<>"']/g; /** * Replaces characters which have special meaning in HTML (&<>"') with escaped * HTML entities ("&", "<", etc.). */ -export const escapeHtml = (str: string) => - str.replace( - /[&<>"']/g, - (char) => replacements[char as keyof typeof replacements] - ); +export const escapeHtml = (str: string) => { + let match = escapePattern.exec(str); + + if (!match) { + return str; + } + + let escapeStr; + let html = ''; + let lastIndex = 0; + + while (match) { + switch (str.charCodeAt(match.index)) { + // Character: " + case 34: + escapeStr = '"'; + break; + // Character: & + case 38: + escapeStr = '&'; + break; + // Character: ' + // Note ' was not defined in the HTML4 spec, and is not supported by + // very old browsers like IE8, so a codepoint entity is used instead. + case 39: + escapeStr = '''; + break; + // Character: < + case 60: + escapeStr = '<'; + break; + // Character: > + case 62: + escapeStr = '>'; + break; + } + + html += str.substring(lastIndex, match.index) + escapeStr; + lastIndex = match.index + 1; + match = escapePattern.exec(str); + } + + escapePattern.lastIndex = 0; + + return lastIndex !== str.length - 1 + ? html + str.substring(lastIndex, str.length) + : html; +};