Files
cinny/src/app/utils/htmlEntities.ts
T

39 lines
1.1 KiB
TypeScript
Raw Normal View History

const NAMED: Record<string, string> = {
amp: '&',
lt: '<',
gt: '>',
quot: '"',
apos: "'",
nbsp: ' ',
hellip: '…',
mdash: '—',
ndash: '–',
lsquo: '‘',
rsquo: '’',
ldquo: '“',
rdquo: '”',
trade: '™',
copy: '©',
reg: '®',
};
/**
* Decode HTML character references left in plain text. Link previews need it:
* some sites double-encode their meta tags (Steam: `&amp;quot;`), so after
* Synapse decodes once the card showed a literal `&quot;`. The result is only
* ever rendered as React text, so decoding can't inject markup.
*/
export const decodeHtmlEntities = (text: string): string => {
if (!text.includes('&')) return text;
return text.replace(/&(#x[0-9a-f]+|#[0-9]+|[a-z]+);/gi, (match, ref: string) => {
if (ref[0] === '#') {
const code =
ref[1] === 'x' || ref[1] === 'X' ? parseInt(ref.slice(2), 16) : parseInt(ref.slice(1), 10);
return Number.isFinite(code) && code > 0 && code <= 0x10ffff
? String.fromCodePoint(code)
: match;
}
return NAMED[ref.toLowerCase()] ?? match;
});
};