| 1 | import type { ResolvedSlidevUtils, ShikiSetup } from '@slidev/types' |
| 2 | import fs from 'node:fs/promises' |
| 3 | import { createBundledHighlighter, createSingletonShorthands } from 'shiki/core' |
| 4 | import { createJavaScriptRegexEngine } from 'shiki/engine/javascript' |
| 5 | import { resolveShikiOptions } from '../../../client/setup/shiki-options' |
| 6 | import { loadSetups } from './load' |
| 7 | |
| 8 | let cachedRoots: string[] | undefined |
| 9 | let cachedShiki: Pick<ResolvedSlidevUtils, 'shiki' | 'shikiOptions'> | undefined |
| 10 | |
| 11 | export default async function setupShiki(roots: string[]) { |
| 12 | // Here we use shallow equality because when server is restarted, the roots will be different object. |
| 13 | if (cachedRoots === roots) |
| 14 | return cachedShiki! |
| 15 | |
| 16 | const optionsRaw = await loadSetups<ShikiSetup>( |
| 17 | roots, |
| 18 | 'shiki.ts', |
| 19 | [{ |
| 20 | /** @deprecated */ |
| 21 | async loadTheme(path: string) { |
| 22 | console.warn('[slidev] `loadTheme` in `setup/shiki.ts` is deprecated. Pass directly the theme name it\'s supported by Shiki. For custom themes, load it manually via `JSON.parse(fs.readFileSync(path, \'utf-8\'))` and pass the raw JSON object instead.') |
| 23 | return JSON.parse(await fs.readFile(path, 'utf-8')) |
| 24 | }, |
| 25 | }], |
| 26 | ) |
| 27 | const { options, languageInput, themeInput } = resolveShikiOptions(optionsRaw) |
| 28 | |
| 29 | const createHighlighter = createBundledHighlighter<string, string>({ |
| 30 | engine: createJavaScriptRegexEngine, |
| 31 | langs: languageInput, |
| 32 | themes: themeInput, |
| 33 | }) |
| 34 | |
| 35 | cachedRoots = roots |
| 36 | return cachedShiki = { |
| 37 | shiki: createSingletonShorthands(createHighlighter), |
| 38 | shikiOptions: options, |
| 39 | } |
| 40 | } |
| 41 |