mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-06-24 21:25:55 +00:00
* feat: add base and radix docs * feat: transform code for display * fix * fix * fix * fix * fix * chore: remove claude files * fix * fix * fix * chore: run format:write * fix * feat: add more examples * fix * feat: add aspect-ratio * feat: add avatar * feat: add badge * feat: add breadcrumb * fix * feat: add button * fix * fix * fix * feat: add calendar and card * feat: add carousel * fix: chart * feat: add checkbox * feat: add collapsible * feat: add combobox * feat: add command * feat: add context menu * feat: add data-table dialog and drawer * feat: dropdown-menu * feat: add date-picker * feat: add empty * feat: add field and hover-card * fix: input * feat: add input * feat: add input-group * feat: add input-otp * feat: add item * feat: add kbd and label * feat: add menubar * feat: add native-select * feat: add more components * feat: more components * feat: more components * feat: add skeleton, slider and sonner * feat: add spinner and switch * feat: add more components * fix: tabs * fix: tabs * feat: add docs for sidebar * fix * fix * fi * docs: update * fix: create page * fix * fix * chore: add changelog * fix
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 overscroll-none 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
|
|
}
|