/
shiki.ts
87 lines (78 loc) 路 2.34 KB
/
shiki.ts
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import type { HighlightOptions, ShikiHighlighter, ShikiOptions } from './types'
import { unwrapTransformer } from './transforms'
const _importShikiCore = cached(() => import('shiki/core'))
const _importWasm = cached(() => import('shiki/wasm'))
export const createHighlighter = cached<ShikiHighlighter>(
async (_shikiOptions: MaybePromise<ShikiOptions>) => {
const [{ getHighlighterCore }, wasm, shikiOptions] = await Promise.all([
_importShikiCore(),
_importWasm(),
_shikiOptions,
])
const highlighter = (await getHighlighterCore({
...shikiOptions.core,
loadWasm: wasm,
})) as ShikiHighlighter
highlighter.highlight = (
code: string,
highlightOptions: HighlightOptions,
) => _highlight(code, highlightOptions, highlighter, shikiOptions)
return highlighter
},
(args) => {
const globalCache: Record<string, CacheStore<ShikiHighlighter>> = ((
globalThis as any
)['__nuxt_shiki_cache'] ??= {})
const key: string = args[1] || 'default'
return (globalCache[key] ??= {})
},
)
// -- highlight util with defaults --
function _highlight(
code: string,
highlightOptions: HighlightOptions,
highlighter: ShikiHighlighter,
shikiOptions: ShikiOptions,
): string {
return highlighter.codeToHtml(code, {
...shikiOptions.highlight,
...highlightOptions,
lang: highlightOptions.lang || shikiOptions.highlight.lang,
transformers: [
...(highlightOptions.unwrap ? [unwrapTransformer] : []),
...(highlightOptions.transformers || []),
],
})
}
// ---- cache utils ---
type Fn<T> = (...args: any[]) => T
type MaybePromise<T> = T | Promise<T>
type CacheStore<T> = {
promise?: T | Promise<T>
value?: T
}
function cached<T>(
fn: Fn<MaybePromise<T>>,
getStore?: (args: Parameters<typeof fn>) => CacheStore<T>,
): Fn<MaybePromise<T>> {
const _store: CacheStore<T> | undefined = getStore ? undefined : {}
return function (...args: any[]) {
const store = _store || getStore!(args)
if (store.value !== undefined) {
return store.value
}
if (store.promise) {
return store.promise
}
const res = fn(...args)
if (res instanceof Promise) {
store.promise = res.then((value) => {
store.value = value
delete store.promise
return value
})
return store.promise
}
return store.promise!
}
}