export type MdxComponent = (props: Record, children: string) => string; const escapeHtml = (value: string) => value.replace( /[&<>"']/g, (character) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[character]!, ); /** Execute explicitly registered MDX components without evaluating arbitrary JavaScript. */ export function renderMdxComponents( source: string, components: Record, ): string { let output = source; const parseProps = (raw: string) => Object.fromEntries( [...raw.matchAll(/([A-Za-z_$][\w$-]*)\s*=\s*["']([^"']*)["']/g)].map((match) => [ match[1]!, match[2]!, ]), ); for (let pass = 0; pass < 20; pass++) { let changed = false; output = output.replace( /<([A-Z][A-Za-z0-9_$]*)\b([^>]*)>([\s\S]*?)<\/\1>|<([A-Z][A-Za-z0-9_$]*)\b([^>]*)\/>/g, (whole, pairedName, pairedProps, children, singleName, singleProps) => { const name = pairedName ?? singleName; const component = components[name]; if (!component) throw new Error(`WRN-CONTENT-MDX-COMPONENT: '${name}' is not registered.`); changed = true; return component(parseProps(pairedProps ?? singleProps ?? ""), children ?? ""); }, ); if (!changed) break; } if (/<[A-Z][A-Za-z0-9_$]*\b/.test(output)) throw new Error("WRN-CONTENT-MDX-DEPTH: component expansion exceeded its bound."); return output; } export interface SyntaxLanguageBundle { highlight(source: string): string; } export function createIncrementalHighlighter( loaders: Record SyntaxLanguageBundle | Promise>, ) { const loaded = new Map>(); return { languages: () => [...loaded.keys()], async highlight(language: string, source: string) { const load = loaders[language]; if (!load) return escapeHtml(source); let bundle = loaded.get(language); if (!bundle) { bundle = Promise.resolve(load()); loaded.set(language, bundle); } return (await bundle).highlight(source); }, async render(html: string) { const matches = [ ...html.matchAll(/
([\s\S]*?)<\/code><\/pre>/g),
      ];
      let output = html;
      for (const match of matches)
        output = output.replace(
          match[0],
          `
${await this.highlight(match[1]!, match[2]!)}
`, ); return output; }, }; } export interface VendorAdapterOptions { fetch?: (input: string | URL | Request, init?: RequestInit) => Promise; token?: string; map?: (entry: any) => { id: string; content: string; source?: string }; } const requestJson = async ( url: string, options: VendorAdapterOptions, headers: HeadersInit = {}, ) => { const response = await (options.fetch ?? globalThis.fetch)(url, { headers }); if (!response.ok) throw new Error(`WRN-CONTENT-CMS: ${response.status}`); return response.json(); }; const normalize = (entry: any, source: string, map?: VendorAdapterOptions["map"]) => map?.(entry) ?? { id: String(entry.id ?? entry.sys?.id ?? entry._id), content: String(entry.content ?? entry.body ?? entry.fields?.body ?? ""), source, }; export function contentfulAdapter( space: string, environment = "master", options: VendorAdapterOptions = {}, ) { return { async list(collection: string) { const url = `https://cdn.contentful.com/spaces/${encodeURIComponent(space)}/environments/${encodeURIComponent(environment)}/entries?content_type=${encodeURIComponent(collection)}`; const value = await requestJson( url, options, options.token ? { authorization: `Bearer ${options.token}` } : {}, ); return (value.items ?? []).map((entry: any) => normalize(entry, `contentful:${space}:${entry.sys?.id}`, options.map), ); }, }; } export function sanityAdapter( project: string, dataset: string, options: VendorAdapterOptions & { apiVersion?: string } = {}, ) { return { async list(collection: string) { const query = encodeURIComponent(`*[_type == $type]`); const url = `https://${encodeURIComponent(project)}.api.sanity.io/v${options.apiVersion ?? "2024-01-01"}/data/query/${encodeURIComponent(dataset)}?query=${query}&$type=${encodeURIComponent(JSON.stringify(collection))}`; const value = await requestJson( url, options, options.token ? { authorization: `Bearer ${options.token}` } : {}, ); return (value.result ?? []).map((entry: any) => normalize(entry, `sanity:${project}:${entry._id}`, options.map), ); }, }; } export function strapiAdapter(baseUrl: string, options: VendorAdapterOptions = {}) { const base = new URL(baseUrl); if (!/^https?:$/.test(base.protocol)) throw new Error("Strapi URL must use HTTP(S)"); return { async list(collection: string) { if (!/^[A-Za-z0-9_-]+$/.test(collection)) throw new Error("Invalid Strapi collection"); const value = await requestJson( new URL(`/api/${collection}`, base).href, options, options.token ? { authorization: `Bearer ${options.token}` } : {}, ); return (value.data ?? []).map((entry: any) => normalize(entry, `strapi:${base.host}:${entry.id}`, options.map), ); }, }; }