-
-
Notifications
You must be signed in to change notification settings - Fork 28
Expand file tree
/
Copy pathvite-plugin-shiki.ts
More file actions
45 lines (36 loc) · 1.2 KB
/
Copy pathvite-plugin-shiki.ts
File metadata and controls
45 lines (36 loc) · 1.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import type { Plugin } from "vite";
import { readFile } from "fs/promises";
import shiki from "./shiki";
function escapeForTemplate(str: string): string {
return str
.replaceAll("\\", "\\\\")
.replaceAll("`", "\\`")
.replaceAll("$", "\\$")
.replaceAll("<", "\\x3C");
}
// Match /* lang */ `code` pattern
const langTemplateRegex = /\/\*\s*(\w+)\s*\*\/\s*`([\s\S]*?)`/g;
export const shikiPlugin = (): Plugin => {
return {
name: "vite-plugin-shiki",
async load(id) {
if (!id.endsWith(".svelte")) return;
const code = await readFile(id, "utf-8");
if (!code.includes("/*")) return;
let newCode = code;
const matches = [...code.matchAll(langTemplateRegex)];
for (const m of matches) {
const [fullMatch, lang, codeContent] = m;
// Handle ${"<"} escapes
const resolvedCode = codeContent.replace(/\$\{"(<?\/?)"?\}/g, "$1");
const highlighted = await shiki(resolvedCode, lang);
const escapedHtml = escapeForTemplate(highlighted);
const replacement = `\`${escapedHtml}\``;
newCode = newCode.replace(fullMatch, replacement);
}
if (newCode != code) {
return newCode;
}
},
};
};