HTML Entity Encoder/Decoder — TypeScript source
Encode text to HTML entities and decode entities back to text (named + numeric). UTF-8 safe, runs entirely in your browser, with a shareable link to your exact input.
This is the TypeScript implementation — the same logic the interactive tool runs, in a shareable, citable form.
// HTML entity encode / decode. Pure string transforms, never throw.
import { HTML_ENTITY_TABLE } from './htmlEntityTable';
export interface EncodeOptions {
/** When true, also encode every non-ASCII character as a decimal numeric
* reference (e.g. (c) -> ©), producing ASCII-safe output. Default false. */
ascii?: boolean;
}
// Encode escapes the five HTML-significant characters. `&` is replaced first so
// the entities we emit are never re-escaped. With `ascii: true`, every non-ASCII
// code point is additionally converted to a decimal numeric reference.
export function encodeHtml(text: string, options?: EncodeOptions): string {
let out = text
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/'/g, ''')
.replace(/"/g, '"');
if (options?.ascii) {
// \P{ASCII} (u flag) matches each non-ASCII code point as one unit, so
// astral characters like emoji encode as a single reference.
out = out.replace(/\P{ASCII}/gu, (ch) => `&#${ch.codePointAt(0)};`);
}
return out;
}
// Matches a well-formed reference: `&#xHH;`, `&#NN;`, or `&name;`.
const ENTITY = /&(#[xX][0-9a-fA-F]+|#[0-9]+|[A-Za-z][A-Za-z0-9]*);/g;
function decodeReference(match: string, body: string): string {
if (body.charCodeAt(0) === 0x23 /* '#' */) {
const hex = body.charCodeAt(1) === 0x78 /* 'x' */ || body.charCodeAt(1) === 0x58 /* 'X' */;
const num = parseInt(hex ? body.slice(2) : body.slice(1), hex ? 16 : 10);
// Lone surrogates are not valid standalone code points — keep the original.
if (num >= 0xd800 && num <= 0xdfff) return match;
// String.fromCodePoint throws a RangeError for code points > U+10FFFF;
// fall back to the original text in that case (never throw).
try {
return String.fromCodePoint(num);
} catch {
return match;
}
}
return Object.prototype.hasOwnProperty.call(HTML_ENTITY_TABLE, body) ? HTML_ENTITY_TABLE[body] : match;
}
// Decode resolves named (`&`, `©`, ...), decimal (`©`), and hex
// (`©`) references. Unknown / malformed references pass through untouched.
export function decodeHtml(text: string): string {
return text.replace(ENTITY, decodeReference);
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →