import type { ReactElement } from 'react' /** * Characters that break out of an inline HTML ``); `>` and `&` are * escaped for completeness, and the JS line/paragraph separators (U+2028/U+2029) * keep the payload valid inside inline scripts. */ const HTML_ESCAPES: Record = { '<': '\\u003c', '>': '\\u003e', '&': '\\u0026', [String.fromCharCode(0x2028)]: '\\u2028', [String.fromCharCode(0x2029)]: '\\u2029', } const UNSAFE_HTML_CHARS = new RegExp(`[<>&${String.fromCharCode(0x2028, 0x2029)}]`, 'g') /** * Serialize structured data for an inline `application/ld+json` script. Plain * `JSON.stringify` does not HTML-escape, so a `` (or stray `<`) in the * data would break out of the script tag and become an XSS sink. Escaping these * characters as unicode escapes keeps the JSON valid and semantically identical, * so crawlers read the exact same graph — SEO output is unchanged. */ function serializeJsonLd(data: JsonLdData): string { return JSON.stringify(data).replace(UNSAFE_HTML_CHARS, (char) => HTML_ESCAPES[char]) } export type JsonLdData = Record interface JsonLdProps { data: JsonLdData } /** * Server-rendered JSON-LD `