mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-02-09 02:49:29 +08:00
107 lines
3.3 KiB
TypeScript
107 lines
3.3 KiB
TypeScript
import { createHash } from "crypto"
|
|
import { LRUCache } from "lru-cache"
|
|
import { codeToHtml } from "shiki"
|
|
import type { ShikiTransformer } from "shiki"
|
|
|
|
// LRU cache for cross-request caching of highlighted code.
|
|
// Shiki highlighting is CPU-intensive and deterministic, so caching is safe.
|
|
const highlightCache = new LRUCache<string, string>({
|
|
max: 500,
|
|
ttl: 1000 * 60 * 60, // 1 hour.
|
|
})
|
|
|
|
export const transformers = [
|
|
{
|
|
code(node) {
|
|
if (node.tagName === "code") {
|
|
const raw = this.source
|
|
node.properties["__raw__"] = raw
|
|
|
|
if (raw.startsWith("npm install")) {
|
|
node.properties["__npm__"] = raw
|
|
node.properties["__yarn__"] = raw.replace("npm install", "yarn add")
|
|
node.properties["__pnpm__"] = raw.replace("npm install", "pnpm add")
|
|
node.properties["__bun__"] = raw.replace("npm install", "bun add")
|
|
}
|
|
|
|
if (raw.startsWith("npx create-")) {
|
|
node.properties["__npm__"] = raw
|
|
node.properties["__yarn__"] = raw.replace(
|
|
"npx create-",
|
|
"yarn create "
|
|
)
|
|
node.properties["__pnpm__"] = raw.replace(
|
|
"npx create-",
|
|
"pnpm create "
|
|
)
|
|
node.properties["__bun__"] = raw.replace("npx", "bunx --bun")
|
|
}
|
|
|
|
// npm create.
|
|
if (raw.startsWith("npm create")) {
|
|
node.properties["__npm__"] = raw
|
|
node.properties["__yarn__"] = raw.replace("npm create", "yarn create")
|
|
node.properties["__pnpm__"] = raw.replace("npm create", "pnpm create")
|
|
node.properties["__bun__"] = raw.replace("npm create", "bun create")
|
|
}
|
|
|
|
// npx.
|
|
if (raw.startsWith("npx")) {
|
|
node.properties["__npm__"] = raw
|
|
node.properties["__yarn__"] = raw.replace("npx", "yarn")
|
|
node.properties["__pnpm__"] = raw.replace("npx", "pnpm dlx")
|
|
node.properties["__bun__"] = raw.replace("npx", "bunx --bun")
|
|
}
|
|
|
|
// npm run.
|
|
if (raw.startsWith("npm run")) {
|
|
node.properties["__npm__"] = raw
|
|
node.properties["__yarn__"] = raw.replace("npm run", "yarn")
|
|
node.properties["__pnpm__"] = raw.replace("npm run", "pnpm")
|
|
node.properties["__bun__"] = raw.replace("npm run", "bun")
|
|
}
|
|
}
|
|
},
|
|
},
|
|
] as ShikiTransformer[]
|
|
|
|
export async function highlightCode(code: string, language: string = "tsx") {
|
|
// Create cache key from code content and language.
|
|
const cacheKey = createHash("sha256")
|
|
.update(`${language}:${code}`)
|
|
.digest("hex")
|
|
|
|
// Check cache first.
|
|
const cached = highlightCache.get(cacheKey)
|
|
if (cached) {
|
|
return cached
|
|
}
|
|
|
|
const html = await codeToHtml(code, {
|
|
lang: language,
|
|
themes: {
|
|
dark: "github-dark",
|
|
light: "github-light",
|
|
},
|
|
transformers: [
|
|
{
|
|
pre(node) {
|
|
node.properties["class"] =
|
|
"no-scrollbar min-w-0 overflow-x-auto overflow-y-auto overscroll-x-contain overscroll-y-auto px-4 py-3.5 outline-none has-[[data-highlighted-line]]:px-0 has-[[data-line-numbers]]:px-0 has-[[data-slot=tabs]]:p-0 !bg-transparent"
|
|
},
|
|
code(node) {
|
|
node.properties["data-line-numbers"] = ""
|
|
},
|
|
line(node) {
|
|
node.properties["data-line"] = ""
|
|
},
|
|
},
|
|
],
|
|
})
|
|
|
|
// Cache the result.
|
|
highlightCache.set(cacheKey, html)
|
|
|
|
return html
|
|
}
|