pr_01m47d15m3e54sn21z27rpy5n9/apps/web/app/lib/highlight.server.ts

78 lines2,201 bytesCodeBlame

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

API and MCP server, Rust identity service, registration, site redesign1import { type HighlighterCore, createHighlighterCore } from "shiki/core";
2import { createJavaScriptRegexEngine } from "shiki/engine/javascript";
3
4/** File extension (or whole file name) to Shiki language. */
5const LANGUAGES: Record<string, string> = {
6 rs: "rust",
7 ts: "typescript",
8 tsx: "tsx",
9 js: "javascript",
10 mjs: "javascript",
11 jsx: "jsx",
12 json: "json",
13 jsonc: "jsonc",
14 toml: "toml",
15 yaml: "yaml",
16 yml: "yaml",
17 md: "markdown",
18 css: "css",
19 html: "html",
20 sql: "sql",
21 sh: "shellscript",
22 bash: "shellscript",
23 py: "python",
24 go: "go",
25 dockerfile: "docker",
26};
27
28const MAX_HIGHLIGHT_CHARS = 200_000;
29
30let highlighter: Promise<HighlighterCore> | undefined;
31
32function getHighlighter(): Promise<HighlighterCore> {
33 highlighter ??= createHighlighterCore({
34 themes: [import("shiki/themes/vitesse-dark.mjs")],
35 langs: [
36 import("shiki/langs/rust.mjs"),
37 import("shiki/langs/typescript.mjs"),
38 import("shiki/langs/tsx.mjs"),
39 import("shiki/langs/javascript.mjs"),
40 import("shiki/langs/jsx.mjs"),
41 import("shiki/langs/json.mjs"),
42 import("shiki/langs/jsonc.mjs"),
43 import("shiki/langs/toml.mjs"),
44 import("shiki/langs/yaml.mjs"),
45 import("shiki/langs/markdown.mjs"),
46 import("shiki/langs/css.mjs"),
47 import("shiki/langs/html.mjs"),
48 import("shiki/langs/sql.mjs"),
49 import("shiki/langs/shellscript.mjs"),
50 import("shiki/langs/python.mjs"),
51 import("shiki/langs/go.mjs"),
52 import("shiki/langs/docker.mjs"),
53 ],
54 engine: createJavaScriptRegexEngine(),
55 });
56 return highlighter;
57}
58
59/**
60 * Highlighted HTML for a file, or null when its language is unknown or it
61 * is too large, in which case the caller shows plain text.
62 */
63export async function highlight(
64 path: string,
65 text: string,
66): Promise<string | null> {
67 const name = path.split("/").pop()!.toLowerCase();
68 const lang = LANGUAGES[name.includes(".") ? name.split(".").pop()! : name];
69 if (!lang || text.length > MAX_HIGHLIGHT_CHARS) return null;
70 try {
71 return (await getHighlighter()).codeToHtml(text.replace(/\n$/, ""), {
72 lang,
73 theme: "vitesse-dark",
74 });
75 } catch {
76 return null;
77 }
78}