Files
ermnvldmr.com/packages/ui/src/components/Code/lib/highlighter/highlighter.ts
T

114 lines
2.3 KiB
TypeScript

import { createHighlighter } from 'shiki';
import type { Highlighter } from 'shiki';
/**
* Supported languages for syntax highlighting.
*/
export type CodeLanguage =
| 'typescript'
| 'javascript'
| 'tsx'
| 'jsx'
| 'bash'
| 'shell'
| 'json'
| 'css'
| 'html'
| 'markdown'
| 'yaml'
| 'dockerfile'
| 'toml'
| 'rust'
| 'go'
| 'python';
export const SUPPORTED_LANGUAGES: CodeLanguage[] = [
'typescript',
'javascript',
'tsx',
'jsx',
'bash',
'shell',
'json',
'css',
'html',
'markdown',
'yaml',
'dockerfile',
'toml',
'rust',
'go',
'python',
];
/**
* A singleton highlighter service for code blocks.
*/
class CodeHighlighter {
private static instance: CodeHighlighter;
private highlighter: Highlighter | null = null;
private initializingPromise: Promise<Highlighter> | null = null;
private constructor() {}
/**
* Gets the singleton instance of the highlighter.
*/
public static getInstance(): CodeHighlighter {
if (!CodeHighlighter.instance) {
CodeHighlighter.instance = new CodeHighlighter();
}
return CodeHighlighter.instance;
}
/**
* Initializes the highlighter if it hasn't been already.
*/
private async getHighlighter(): Promise<Highlighter> {
if (this.highlighter) {
return this.highlighter;
}
if (this.initializingPromise) {
return this.initializingPromise;
}
this.initializingPromise = createHighlighter({
themes: ['github-dark', 'github-light'],
langs: SUPPORTED_LANGUAGES,
}).then((highlighter) => {
this.highlighter = highlighter;
this.initializingPromise = null;
return highlighter;
});
return this.initializingPromise;
}
/**
* Highlights the given code.
*
* @param code - The raw source code to highlight
* @param lang - The language of the code
* @returns A promise resolving to the highlighted HTML
*/
public async highlight(code: string, lang: CodeLanguage): Promise<string> {
try {
const highlighter = await this.getHighlighter();
return highlighter.codeToHtml(code, {
lang,
themes: {
light: 'github-light',
dark: 'github-dark',
},
});
} catch (err) {
console.error('Failed to highlight code:', err);
throw err;
}
}
}
export const codeHighlighter = CodeHighlighter.getInstance();