63 lines
1.6 KiB
TypeScript
63 lines
1.6 KiB
TypeScript
/**
|
|
* JSON-LD Helper Utilities for Next.js
|
|
*
|
|
* Following Next.js best practices for structured data:
|
|
* - Sanitizes output to prevent XSS attacks
|
|
* - Uses TypeScript with schema-dts for type safety
|
|
* - Implements proper escaping of < characters
|
|
*/
|
|
|
|
import { WithContext, Thing } from 'schema-dts'
|
|
|
|
/**
|
|
* Safely stringify JSON-LD data with XSS protection
|
|
* Replaces < with \u003c to prevent script injection
|
|
*/
|
|
export function safeJsonLdStringify(data: WithContext<Thing> | any): string {
|
|
return JSON.stringify(data).replace(/</g, '\\u003c')
|
|
}
|
|
|
|
/**
|
|
* Creates a JSON-LD script tag props object
|
|
* Use with dangerouslySetInnerHTML in Next.js components
|
|
*
|
|
* @example
|
|
* ```tsx
|
|
* <script
|
|
* type="application/ld+json"
|
|
* dangerouslySetInnerHTML={createJsonLdScriptProps(jsonLd)}
|
|
* />
|
|
* ```
|
|
*/
|
|
export function createJsonLdScriptProps(data: WithContext<Thing> | any) {
|
|
return {
|
|
__html: safeJsonLdStringify(data)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Type guard to check if data is valid JSON-LD
|
|
*/
|
|
export function isValidJsonLd(data: any): data is WithContext<Thing> {
|
|
return (
|
|
typeof data === 'object' &&
|
|
data !== null &&
|
|
'@context' in data &&
|
|
'@type' in data
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Merge multiple JSON-LD objects into a graph
|
|
* Useful when you need to include multiple structured data types on one page
|
|
*/
|
|
export function mergeJsonLd(...items: Array<WithContext<Thing>>): { '@context': string; '@graph': any[] } {
|
|
return {
|
|
'@context': 'https://schema.org',
|
|
'@graph': items.map(item => {
|
|
const { '@context': _, ...rest } = item as any
|
|
return rest
|
|
})
|
|
}
|
|
}
|