Skip to content

Commit af6b069

Browse files
feat(text): add unescapeHtml function
Reverses HTML entity escaping, converting named entities and numeric character references back to their original characters.
1 parent 81c80b7 commit af6b069

2 files changed

Lines changed: 58 additions & 0 deletions

File tree

text/unescape_html.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2018-2026 the Deno authors. MIT license.
2+
// This module is browser compatible.
3+
4+
const HTML_UNESCAPE_MAP: Record<string, string> = {
5+
"&amp;": "&",
6+
"&lt;": "<",
7+
"&gt;": ">",
8+
"&quot;": '"',
9+
"&#39;": "'",
10+
"&#x27;": "'",
11+
"&#x2F;": "/",
12+
};
13+
14+
const HTML_UNESCAPE_REGEXP = /&(?:amp|lt|gt|quot|#(?:39|x27|x2F));/g;
15+
16+
/**
17+
* Unescapes HTML special characters in a string.
18+
*
19+
* @param input The string to unescape
20+
* @returns The unescaped string
21+
*
22+
* @example Usage
23+
* ```ts
24+
* import { unescapeHtml } from "@std/text/unescape-html";
25+
* import { assertEquals } from "@std/assert";
26+
*
27+
* assertEquals(unescapeHtml("&lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;"), "<script>alert('xss')</script>");
28+
* ```
29+
*/
30+
export function unescapeHtml(input: string): string {
31+
return input.replace(
32+
HTML_UNESCAPE_REGEXP,
33+
(entity) => HTML_UNESCAPE_MAP[entity]!,
34+
);
35+
}

text/unescape_html_test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2018-2026 the Deno authors. MIT license.
2+
3+
import { assertEquals } from "@std/assert";
4+
import { unescapeHtml } from "./unescape_html.ts";
5+
6+
Deno.test("unescapeHtml() unescapes HTML entities", () => {
7+
assertEquals(
8+
unescapeHtml("&lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;"),
9+
"<script>alert('xss')</script>",
10+
);
11+
});
12+
13+
Deno.test("unescapeHtml() unescapes ampersand", () => {
14+
assertEquals(unescapeHtml("a &amp; b"), "a & b");
15+
});
16+
17+
Deno.test("unescapeHtml() handles strings without entities", () => {
18+
assertEquals(unescapeHtml("hello"), "hello");
19+
});
20+
21+
Deno.test("unescapeHtml() handles empty string", () => {
22+
assertEquals(unescapeHtml(""), "");
23+
});

0 commit comments

Comments
 (0)