diff --git a/app/[locale]/layout.tsx b/app/[locale]/layout.tsx index 3549b16..256631d 100644 --- a/app/[locale]/layout.tsx +++ b/app/[locale]/layout.tsx @@ -12,6 +12,7 @@ import { BackToTopButton } from '@/components/ui/BackToTopButton'; import { LocaleProvider } from '@/components/providers/LocaleProvider'; import { MotionProvider } from '@/components/providers/MotionProvider'; import { getMessages, isValidLocale, locales, type Locale } from '@/lib/i18n'; +import { toJsonLd } from '@/lib/json-ld'; type Props = { children: React.ReactNode; params: Promise<{ locale: string }> }; @@ -76,7 +77,7 @@ export default async function LocaleLayout({ children, params }: Props) { ' }); + expect(out).not.toContain(''); + expect(out).not.toContain('<'); + }); + + it('preserves the escaped value semantically', () => { + const payload = { name: '' }; + expect(JSON.parse(toJsonLd(payload))).toEqual(payload); + }); + + it('escapes every angle bracket occurrence, not just the first', () => { + const out = toJsonLd({ a: '<<<', b: '<' }); + expect(out).not.toContain('<'); + expect(JSON.parse(out)).toEqual({ a: '<<<', b: '<' }); + }); +}); diff --git a/lib/json-ld.ts b/lib/json-ld.ts new file mode 100644 index 0000000..b224189 --- /dev/null +++ b/lib/json-ld.ts @@ -0,0 +1,21 @@ +/** + * Serialize a value for embedding inside a `