Something went wrong. Try again.
My website. cameron.stream
Something went wrong. Try again.
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182import { Marked } from "marked";import footnote from "marked-footnote";import markedKatex from "marked-katex-extension";import { createHighlighter, type Highlighter } from "shiki";import imageMap from "./image-map.json" with { type: "json" };
let highlighterPromise: Promise<Highlighter> | undefined;
function getHighlighter(): Promise<Highlighter> { if (!highlighterPromise) { highlighterPromise = createHighlighter({ themes: ["github-light", "github-dark"], langs: [ "javascript", "typescript", "python", "julia", "rust", "json", "bash", "yaml", "markdown", "html", "css", "sql", "r", "toml", ], }).catch((error) => { highlighterPromise = undefined; throw error; }); } return highlighterPromise;}
export async function renderMarkdown( source: string, options: { allowRawHtml?: boolean } = {},): Promise<string> { const hl = await getHighlighter(); const allowRawHtml = options.allowRawHtml ?? true;
// Rewrite old Franklin image paths to CDN URLs const map = imageMap as Record<string, string>; const withImages = source.replace( /!\[([^\]]*)\]\(([^)]+)\)/g, (match, alt, src) => { const cdnUrl = map[src]; return cdnUrl ? `` : match; } ); const rewritten = allowRawHtml ? withImages.replace( /<leaflet-card\b([^>]*)><\/leaflet-card>/gi, (match, attributes: string) => { const value = (name: string) => { const found = attributes.match(new RegExp(`\\b${name}="([^"]*)"`, "i")); return found?.[1] ?.replace(/"/g, '"') .replace(/</g, "<") .replace(/>/g, ">") .replace(/&/g, "&"); }; const url = safeHttpUrl(value("data-href")); if (!url) return ""; const href = url.toString(); const title = value("data-title") || href; const description = value("data-description"); return `<aside class="leaflet-link-card"><a href="${escapeHtml(href)}" target="_blank" rel="noopener"><strong>${escapeHtml(title)}</strong>${description ? `<span>${escapeHtml(description)}</span>` : ""}<small>${escapeHtml(url.hostname)}</small></a></aside>`; }, ) : withImages;
const marked = new Marked({ renderer: { html({ text }) { return allowRawHtml ? text : escapeHtml(text); }, ...(!allowRawHtml ? { link({ href, title, tokens }) { const safeHref = safeMarkdownUrl(href, true); const label = this.parser.parseInline(tokens); if (!safeHref) return label; const titleAttribute = title ? ` title="${escapeHtml(title)}"` : ""; return `<a href="${escapeHtml(safeHref)}"${titleAttribute}>${label}</a>`; }, image({ href, title, text }) { const safeSrc = safeMarkdownUrl(href, false); if (!safeSrc) return escapeHtml(text); const titleAttribute = title ? ` title="${escapeHtml(title)}"` : ""; return `<img src="${escapeHtml(safeSrc)}" alt="${escapeHtml(text)}"${titleAttribute}>`; }, } : {}), code({ text, lang }) { const language = lang || "text"; try { return hl.codeToHtml(text, { lang: language, themes: { light: "github-light", dark: "github-dark" }, }); } catch { // Unknown language, fall back to plain return `<pre><code>${escapeHtml(text)}</code></pre>`; } }, }, });
marked.use(footnote()); marked.use(markedKatex({ throwOnError: false, output: "mathml", }));
let html = await marked.parse(rewritten);
if (allowRawHtml) { // Replace <bsky-embed> placeholders with oEmbed HTML. const bskyRegex = /<bsky-embed\b[^>]*data-url="([^"]+)"[^>]*><\/bsky-embed>/g; const matches = [...html.matchAll(bskyRegex)]; for (const match of matches) { const url = match[1]; try { const res = await fetch( `https://embed.bsky.app/oembed?url=${encodeURIComponent(url)}` ); if (res.ok) { const data = await res.json(); html = html.replace(match[0], data.html); } } catch { // Keep as link fallback. html = html.replace( match[0], `<p><a href="${url}" target="_blank" rel="noopener">Bluesky post</a></p>` ); } } }
return html;}
function escapeHtml(str: string): string { return str .replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">") .replace(/"/g, """) .replace(/'/g, "'");}
function safeMarkdownUrl(value: string, allowMailto: boolean): string | undefined { const decoded = value .replace(/&#x([0-9a-f]+);?/gi, (_, hex: string) => String.fromCodePoint(Number.parseInt(hex, 16))) .replace(/&#([0-9]+);?/g, (_, decimal: string) => String.fromCodePoint(Number.parseInt(decimal, 10))) .replace(/:/gi, ":") .replace(/&(?:tab|newline);/gi, ""); const compact = decoded.replace(/[\u0000-\u0020\u007f]+/g, "").trim(); if (!compact || compact.includes("\\") || compact.startsWith("//")) return undefined; if (compact.startsWith("/") || compact.startsWith("#") || compact.startsWith("./") || compact.startsWith("../")) { return compact; } const scheme = compact.match(/^([a-z][a-z0-9+.-]*):/i)?.[1]?.toLowerCase(); if (!scheme) return compact; if (scheme === "http" || scheme === "https" || (allowMailto && scheme === "mailto")) { return compact; } return undefined;}
function safeHttpUrl(value: string | undefined): URL | undefined { if (!value) return undefined; try { const url = new URL(value); return url.protocol === "http:" || url.protocol === "https:" ? url : undefined; } catch { return undefined; }}