/** * HTML 텍스트 콘텐츠 이스케이프 * , <p> 등 텍스트 노드에 들어갈 문자열을 안전하게 처리. * 속성값과 달리 " ' 는 이스케이프 불필요. */ export function escapeHtmlText(value: string): string { return value .replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">"); } /** * Decode the small HTML entity set React can emit inside text metadata. * Callers should still escape the returned string before writing HTML. */ export function decodeHtmlText(value: string): string { return value.replace(/&(#x[0-9a-f]+|#\d+|amp|lt|gt|quot|apos|#39);/gi, (match, entity: string) => { const normalized = entity.toLowerCase(); if (normalized === "amp") return "&"; if (normalized === "lt") return "<"; if (normalized === "gt") return ">"; if (normalized === "quot") return '"'; if (normalized === "apos" || normalized === "#39") return "'"; if (normalized.startsWith("#x")) { const codePoint = Number.parseInt(normalized.slice(2), 16); return isValidCodePoint(codePoint) ? String.fromCodePoint(codePoint) : match; } if (normalized.startsWith("#")) { const codePoint = Number.parseInt(normalized.slice(1), 10); return isValidCodePoint(codePoint) ? String.fromCodePoint(codePoint) : match; } return match; }); } function isValidCodePoint(value: number): boolean { return Number.isInteger(value) && value >= 0 && value <= 0x10ffff; } /** * HTML 속성값 이스케이프 * XSS 방지를 위해 HTML 속성값에 들어갈 문자열을 안전하게 처리 */ export function escapeHtmlAttr(value: string): string { return value .replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } /** * Inline script의 JSON 데이터 이스케이프 * <script> 태그 내부의 JSON을 안전하게 처리 */ export function escapeJsonForInlineScript(value: string): string { return value .replace(/</g, "\\u003c") .replace(/>/g, "\\u003e") .replace(/&/g, "\\u0026") .replace(/'/g, "\\u0027") .replace(/\u2028/g, "\\u2028") .replace(/\u2029/g, "\\u2029"); } /** * JavaScript 문자열 리터럴 이스케이프 * JS 코드 내부의 문자열 보간에 사용 */ export function escapeJsString(value: string): string { return value .replace(/\\/g, "\\\\") .replace(/\n/g, "\\n") .replace(/\r/g, "\\r") .replace(/"/g, "\\u0022") .replace(/'/g, "\\u0027") .replace(/</g, "\\u003c") .replace(/>/g, "\\u003e") .replace(/&/g, "\\u0026") .replace(/\u2028/g, "\\u2028") .replace(/\u2029/g, "\\u2029"); }