/**
* Decode HTML entities in strings
* Converts ' " & < > etc. to their actual characters
*/
export function decodeHtmlEntities(text: string): string {
if (!text || typeof text !== 'string') {
return text;
}
// Create a temporary element to decode HTML entities
const textarea = document.createElement('textarea');
textarea.innerHTML = text;
return textarea.value;
}
/**
* Server-side HTML entity decoding (for Node.js/Next.js API routes)
*/
export function decodeHtmlEntitiesServer(text: string): string {
if (!text || typeof text !== 'string') {
return text;
}
// Map of common HTML entities (including all variations of apostrophe)
const entityMap: Record = {
''': "'",
'"': '"',
'&': '&',
'<': '<',
'>': '>',
''': "'",
''': "'",
'/': '/',
'`': '`',
'=': '=',
'’': "'",
'‘': "'",
'”': '"',
'“': '"',
};
// First replace known entities
let decoded = text;
for (const [entity, replacement] of Object.entries(entityMap)) {
decoded = decoded.replace(new RegExp(entity, 'gi'), replacement);
}
// Then handle numeric entities (' ' etc.)
decoded = decoded.replace(/(\d+);/g, (match, num) => {
return String.fromCharCode(parseInt(num, 10));
});
decoded = decoded.replace(/([0-9a-f]+);/gi, (match, hex) => {
return String.fromCharCode(parseInt(hex, 16));
});
return decoded;
}