import { browser } from "$app/environment"; import { isMarkdownFile } from "$lib/markup/format"; import type { MarkupContext } from "$lib/markup/paths"; // hydration re-runs every load, so the browser hands back the server's render // instead of loading the markdown pipeline again const MARKUP_KEY = "data-markup-key"; // the key is only compared against markup already on this page, so stable and // short is enough, not cryptographic const digest = (value: string): string => { let hash = 5381; for (let i = 0; i < value.length; i += 1) hash = (hash * 33) ^ value.charCodeAt(i); return (hash >>> 0).toString(36); }; const keyOf = (filename: string, contents: string, ctx: MarkupContext): string => [ digest( [ ctx.host ?? "", ctx.repo, ctx.ref, ctx.dir ?? "", String(!!ctx.sourceLines), filename ].join("\n") ), contents.length.toString(36), digest(contents) ].join("."); const mark = (key: string, html: string): string => `
${html}
`; // reads back a render this module wrote for the same contents and context const rendered = (key: string): string | null => { if (!browser) return null; const node = document.querySelector(`[${MARKUP_KEY}="${key}"]`); return node instanceof HTMLElement ? node.innerHTML : null; }; const render = async ( key: string, contents: string, ctx: MarkupContext ): Promise => { const reused = rendered(key); if (reused !== null) return mark(key, reused); const { SOURCE_LIMIT, renderMarkdown } = await import("./markdown"); if (contents.length > SOURCE_LIMIT) return null; const html = await renderMarkdown(contents, ctx); return html === null ? null : mark(key, html); }; export const renderDocument = async ( filename: string, contents: string, ctx: MarkupContext ): Promise => isMarkdownFile(filename) ? render(keyOf(filename, contents, ctx), contents, ctx) : null; // like renderDocument, but for content that is always markdown (issue and // comment bodies) rather than a repo file with an extension to sniff export const renderMarkup = (contents: string, ctx: MarkupContext): Promise => render(keyOf("", contents, ctx), contents, ctx);