import type { LotusThemeConfig } from '../theme'; export type JsonLdNode = Record; interface BreadcrumbItem { label: string; href: string; } interface DocsSchemaInput { themeConfig: LotusThemeConfig; baseUrl: URL | string; pageUrl: string; title: string; description?: string; sectionTitle?: string; breadcrumbs: BreadcrumbItem[]; markdownUrl?: string; lastUpdated?: Date | boolean; } function toAbsoluteUrl(href: string, baseUrl: URL | string): string { return new URL(href, baseUrl).toString(); } function getSiteUrl(baseUrl: URL | string): string { const url = new URL(baseUrl); return `${url.origin}/`; } function compactObject(value: T): T { return Object.fromEntries( Object.entries(value).filter(([, entryValue]) => entryValue !== undefined), ) as T; } export function stringifyJsonLd(schema: JsonLdNode | JsonLdNode[]): string { return JSON.stringify(schema).replace(/ ({ label: item.label, href: toAbsoluteUrl(item.href, baseUrl), })); const dateModified = lastUpdated instanceof Date ? lastUpdated.toISOString() : undefined; return { '@context': 'https://schema.org', '@graph': [ compactObject({ '@type': 'WebSite', '@id': websiteId, url: siteUrl, name: themeConfig.name, description: themeConfig.description, }), { '@type': 'BreadcrumbList', '@id': breadcrumbId, itemListElement: absoluteBreadcrumbs.map((item, index) => ({ '@type': 'ListItem', position: index + 1, name: item.label, item: item.href, })), }, compactObject({ '@type': 'WebPage', '@id': webpageId, url: pageUrl, name: title, description, isPartOf: { '@id': websiteId }, breadcrumb: { '@id': breadcrumbId }, }), compactObject({ '@type': 'TechArticle', '@id': articleId, headline: title, description, url: pageUrl, mainEntityOfPage: { '@id': webpageId }, isPartOf: { '@id': websiteId }, articleSection: sectionTitle, dateModified, encoding: markdownUrl ? { '@type': 'MediaObject', encodingFormat: 'text/markdown', contentUrl: markdownUrl, } : undefined, }), ], }; }