import type { AppThemeAppearance } from "@/lib/app/appTheme"; export type SqlHighlighter = (content: string, appearance?: AppThemeAppearance) => string; interface ShikiSqlHighlighterOptions { appearance: () => AppThemeAppearance; } const SHIKI_THEMES = { dark: "github-dark", light: "github-light", } as const; type ShikiHighlighter = Awaited>; type ShikiCodeHighlighter = Pick; let highlighterPromise: Promise | undefined; export async function createShikiSqlHighlighter(options: ShikiSqlHighlighterOptions): Promise { try { const highlighter = await getShikiSqlHighlighter(); return createSafeSqlHighlighter(highlighter, options); } catch (error) { console.warn("[DBX][sqlHighlighter] Failed to initialize SQL highlighter:", error); return escapeHtml; } } export function createSafeSqlHighlighter(highlighter: ShikiCodeHighlighter, options: ShikiSqlHighlighterOptions): SqlHighlighter { return (content, appearance = options.appearance()) => { try { return highlighter.codeToHtml(content, { lang: "sql", structure: "inline", theme: SHIKI_THEMES[appearance], }); } catch (error) { console.warn("[DBX][sqlHighlighter] Failed to highlight SQL:", error); return escapeHtml(content); } }; } export function escapeHtml(content: string): string { return content.replace(/[&<>"']/g, (char) => { switch (char) { case "&": return "&"; case "<": return "<"; case ">": return ">"; case '"': return """; default: return "'"; } }); } function getShikiSqlHighlighter(): Promise { highlighterPromise ??= loadShikiSqlHighlighter(); return highlighterPromise; } async function loadShikiSqlHighlighter(): Promise { const [{ createHighlighterCore }, { createJavaScriptRegexEngine }, githubDark, githubLight, sql] = await Promise.all([import("shiki/core"), import("shiki/engine/javascript"), import("shiki/themes/github-dark.mjs"), import("shiki/themes/github-light.mjs"), import("shiki/langs/sql.mjs")]); return createHighlighterCore({ engine: createJavaScriptRegexEngine(), langs: [sql.default], themes: [githubDark.default, githubLight.default], }); }