UNPKG

@podlite/to-jsx

Version:

Render Podlite markup as React JSX components

147 lines 4.33 kB
const loadShiki = () => import('shiki'); // Configuration const CONFIG = { themes: { light: 'one-light', dark: 'github-dark', }, initialLanguages: ['shell', 'txt'], }; // Language aliases mapping const languageAliases = { text: 'txt', plaintext: 'txt', plain: 'txt', sh: 'shell', bash: 'shell', zsh: 'shell', shellscript: 'shell', 'shell-script': 'shell', console: 'shell', terminal: 'shell', js: 'javascript', node: 'javascript', nodejs: 'javascript', ts: 'typescript', py: 'python', python3: 'python', py3: 'python', rb: 'ruby', md: 'markdown', cpp: 'c++', cc: 'c++', cs: 'c#', csharp: 'c#', htm: 'html', yml: 'yaml', dockerfile: 'docker', styles: 'css', style: 'css', jsonc: 'json', json5: 'json', xaml: 'xml', xhtml: 'xml', svg: 'xml', mysql: 'sql', postgresql: 'sql', postgres: 'sql', pgsql: 'sql', plsql: 'sql', oracle: 'sql', }; // Singleton state const state = { instance: null, initPromise: null, loadedLanguages: new Set(['txt']), pendingLoads: new Map(), warnedLanguages: new Set(), }; // Normalize language to valid Shiki language export async function normalizeLanguage(language) { if (!language) return 'txt'; const normalized = language.toLowerCase(); const { bundledLanguages } = await loadShiki(); if (normalized in bundledLanguages) { return normalized; } if (normalized in languageAliases) { return languageAliases[normalized]; } if (!state.warnedLanguages.has(language)) { console.warn(`[podlite] shiki unrecognized language '${language}', defaulting to [txt]`); state.warnedLanguages.add(language); } return 'txt'; } // Get or create highlighter instance async function getHighlighterInstance() { if (!state.initPromise) { state.initPromise = (async () => { const { createHighlighter } = await loadShiki(); const instance = await createHighlighter({ themes: Object.values(CONFIG.themes), langs: CONFIG.initialLanguages, }); state.instance = instance; CONFIG.initialLanguages.forEach(lang => state.loadedLanguages.add(lang)); return instance; })(); } return state.initPromise; } // Load a language if not already loaded async function ensureLanguageLoaded(instance, lang) { if (state.loadedLanguages.has(lang)) return; let pending = state.pendingLoads.get(lang); if (!pending) { pending = instance .loadLanguage(lang) .then(() => { state.loadedLanguages.add(lang); }) .finally(() => state.pendingLoads.delete(lang)); state.pendingLoads.set(lang, pending); } await pending; } // Main API: get highlighter with language loaded export async function getHighlighter(language) { const lang = await normalizeLanguage(language); const instance = await getHighlighterInstance(); await ensureLanguageLoaded(instance, lang); return instance; } // Convenience: convert code to HTML with dual themes (CSS-based switching) export async function codeToHtml({ code, language }) { const lang = await normalizeLanguage(language); const highlighter = await getHighlighter(language); return highlighter.codeToHtml(code, { lang, themes: CONFIG.themes, }); } // Convert code to HTML with explicit theme selection (for runtime theme detection) export async function codeToThemedHtml({ code, language, theme, decorations, }) { const lang = await normalizeLanguage(language); const highlighter = await getHighlighter(language); if (theme === 'light' || theme === 'dark') { return highlighter.codeToHtml(code, { lang, theme: CONFIG.themes[theme], decorations, }); } return highlighter.codeToHtml(code, { lang, themes: CONFIG.themes, decorations, }); } // Check if a language is loaded (sync — only meaningful after a prior async normalize) export const isLanguageLoaded = (language) => { return state.loadedLanguages.has(language); }; //# sourceMappingURL=shiki.js.map