From 5bcf1421d176d55ba37c89da46e250532d4207ad Mon Sep 17 00:00:00 2001 From: JounQin Date: Tue, 17 Dec 2024 14:12:15 +0800 Subject: [PATCH] feat: bump shiki to v1, migrate to official transformers --- e2e/fixtures/plugin-shiki/package.json | 1 + e2e/fixtures/plugin-shiki/rspress.config.ts | 22 ++- .../docs/en/plugin/official-plugins/shiki.mdx | 87 ++------- .../docs/zh/plugin/official-plugins/shiki.mdx | 87 ++------- packages/plugin-shiki/package.json | 2 +- packages/plugin-shiki/shiki.css | 9 +- packages/plugin-shiki/src/rehypePlugin.ts | 9 +- .../plugin-shiki/src/shiki/highlighter.ts | 44 ++--- .../plugin-shiki/src/shiki/pluginShiki.ts | 58 ++++-- .../plugin-shiki/src/shiki/rehypePlugin.ts | 32 +-- .../plugin-shiki/src/shiki/transformer.ts | 54 ----- .../src/shiki/transformers/diff.ts | 50 ----- .../src/shiki/transformers/focus.ts | 40 ---- .../transformers/highlight-error-level.ts | 40 ---- .../src/shiki/transformers/highlight.ts | 34 ---- .../src/shiki/transformers/index.ts | 4 - .../src/shiki/transformers/line-number.ts | 28 +-- packages/plugin-shiki/src/shiki/types.ts | 31 --- .../plugin-shiki/src/shiki/utils/add-class.ts | 13 -- .../src/shiki/utils/check-class.ts | 5 - .../shiki/utils/create-range-transformer.ts | 55 ------ .../plugin-shiki/src/shiki/utils/index.ts | 2 - pnpm-lock.yaml | 184 +++++++++++++++++- 23 files changed, 324 insertions(+), 567 deletions(-) delete mode 100644 packages/plugin-shiki/src/shiki/transformer.ts delete mode 100644 packages/plugin-shiki/src/shiki/transformers/diff.ts delete mode 100644 packages/plugin-shiki/src/shiki/transformers/focus.ts delete mode 100644 packages/plugin-shiki/src/shiki/transformers/highlight-error-level.ts delete mode 100644 packages/plugin-shiki/src/shiki/transformers/highlight.ts delete mode 100644 packages/plugin-shiki/src/shiki/types.ts delete mode 100644 packages/plugin-shiki/src/shiki/utils/add-class.ts delete mode 100644 packages/plugin-shiki/src/shiki/utils/check-class.ts delete mode 100644 packages/plugin-shiki/src/shiki/utils/create-range-transformer.ts delete mode 100644 packages/plugin-shiki/src/shiki/utils/index.ts diff --git a/e2e/fixtures/plugin-shiki/package.json b/e2e/fixtures/plugin-shiki/package.json index 26002a1c0..b691a45e0 100644 --- a/e2e/fixtures/plugin-shiki/package.json +++ b/e2e/fixtures/plugin-shiki/package.json @@ -9,6 +9,7 @@ }, "dependencies": { "@rspress/plugin-shiki": "workspace:*", + "@shikijs/transformers": "1.24.2", "rspress": "workspace:*" }, "devDependencies": { diff --git a/e2e/fixtures/plugin-shiki/rspress.config.ts b/e2e/fixtures/plugin-shiki/rspress.config.ts index a2bee0abb..4c210bf64 100644 --- a/e2e/fixtures/plugin-shiki/rspress.config.ts +++ b/e2e/fixtures/plugin-shiki/rspress.config.ts @@ -1,24 +1,26 @@ -import path from 'node:path'; -import { defineConfig } from 'rspress/config'; import { - createTransformerDiff, - createTransformerErrorLevel, - createTransformerFocus, - createTransformerHighlight, createTransformerLineNumber, pluginShiki, } from '@rspress/plugin-shiki'; +import { + transformerNotationDiff, + transformerNotationErrorLevel, + transformerNotationFocus, + transformerNotationHighlight, +} from '@shikijs/transformers'; +import path from 'node:path'; +import { defineConfig } from 'rspress/config'; export default defineConfig({ root: path.join(__dirname, 'doc'), plugins: [ pluginShiki({ transformers: [ - createTransformerDiff(), + transformerNotationDiff(), + transformerNotationErrorLevel(), + transformerNotationHighlight(), + transformerNotationFocus(), createTransformerLineNumber(), - createTransformerErrorLevel(), - createTransformerHighlight(), - createTransformerFocus(), ], }), ], diff --git a/packages/document/docs/en/plugin/official-plugins/shiki.mdx b/packages/document/docs/en/plugin/official-plugins/shiki.mdx index 1b5cf743e..af4408fbc 100644 --- a/packages/document/docs/en/plugin/official-plugins/shiki.mdx +++ b/packages/document/docs/en/plugin/official-plugins/shiki.mdx @@ -36,19 +36,21 @@ export default defineConfig({ This plugin supports passing in an object configuration. The properties of this object configuration are as follows: ```ts -interface PluginShikiOptions { +import type { BuiltinLanguage, BuiltinTheme, ShikiTransformer, SpecialLanguage } from 'shiki'; + +export interface PluginShikiOptions { /** - * Code highlighting theme + * Code highlighting theme, @see https://shiki.style/themes */ - theme: string; + theme: BuiltinTheme | 'css-variables'; /** - * Code highlighting language + * Code highlighting language, @see https://shiki.style/languages */ - langs: string[]; + langs: Array; /** - * Add custom transformer + * Custom shiki transformer, @see https://shiki.style/guide/transformers */ - transformers: Transformer[]; + transformers: ShikiTransformer[]; } ``` @@ -64,81 +66,34 @@ Transformer is a concept in this plugin, its function is to transform specific s A few Transformers are built into this plugin, including: -- `createTransformerDiff`: Implementation of the diff highlighting effect of the code block. - `createTransformerLineNumber`: Implement the display of the line number of the code block. -- `createTransformerErrorLevel`: Implement the display of the error level of the corresponding line of the code block, including `error` and `warning`. -- `createTransformerHighlight`: Implement line highlighting display of the code block. -- `createTransformerFocus`: Implement line focus display of the code block. You can enable these Transformers by configuring the `transformers` attribute, such as: ```ts title="rspress.config.ts" import { defineConfig } from 'rspress/config'; import { pluginShiki, createTransformerDiff } from '@rspress/plugin-shiki'; +import { + transformerNotationDiff, + transformerNotationErrorLevel, + transformerNotationFocus, + transformerNotationHighlight, +} from '@shikijs/transformers'; export default defineConfig({ plugins: [ pluginShiki({ transformers: [ // Add as needed - createTransformerDiff(), - // createTransformerLineNumber(), - // createTransformerErrorLevel(), - // createTransformerHighlight(), - // createTransformerFocus(), + createTransformerLineNumber(), + // transformerNotationDiff(), + // transformerNotationErrorLevel(), + // transformerNotationHighlight(), + // transformerNotationFocus(), ], }), ], }); ``` -Then let us introduce how to use the syntax corresponding to these Transformers. - -#### Diff highlighting - -Use the `diff` syntax in the markdown code block, such as: - -```ts -export function foo() { - console.log('Diff remove'); // [!code --] - console.log('Diff add'); // [!code ++] -} -``` - -This will automatically apply the diff highlighting effect to the corresponding line of code. - -#### Line number display - -Use the `hl` syntax in the markdown code block, such as: - -```ts -export function foo() { - console.log('Line number'); // [!code hl] -} -``` - -This will automatically display the line number for the corresponding line of code. - -#### Error level display - -Use the `error` or `warning` syntax in the markdown code block, such as: - -```ts -export function foo() { - console.log('Error level'); // [!code error] -} -``` - -This will automatically display the error level for the corresponding line of code. - -#### Line focus display - -Use the `focus` syntax in the markdown code block, such as: - -```ts -export function foo() { - console.log('Focus'); // [!code focus] -} -``` - -This will automatically display the focus effect for the corresponding line of code. +Please view [Shiki Transformers documentation](https://shiki.style/guide/transformers) for more information. diff --git a/packages/document/docs/zh/plugin/official-plugins/shiki.mdx b/packages/document/docs/zh/plugin/official-plugins/shiki.mdx index 1259dfa9a..9a6eec7f0 100644 --- a/packages/document/docs/zh/plugin/official-plugins/shiki.mdx +++ b/packages/document/docs/zh/plugin/official-plugins/shiki.mdx @@ -36,19 +36,21 @@ export default defineConfig({ 该插件支持传入一个对象配置,该对象配置的属性如下: ```ts -interface PluginShikiOptions { +import type { BuiltinLanguage, BuiltinTheme, ShikiTransformer, SpecialLanguage } from 'shiki'; + +export interface PluginShikiOptions { /** - * 代码高亮主题 + * 代码高亮主题,@see https://shiki.style/themes */ - theme: string; + theme: BuiltinTheme | 'css-variables'; /** - * 代码高亮的语言 + * 代码高亮的语言,@see https://shiki.style/languages */ - langs: string[]; + langs: Array; /** - * 添加自定义 transformer + * 自定义 shiki transformer,@see https://shiki.style/guide/transformers */ - transformers: Transformer[]; + transformers: ShikiTransformer[]; } ``` @@ -64,81 +66,34 @@ Transformer 是本插件中的一个概念,它的作用是对代码块的特 本插件中内置了一些 Transformer,包括: -- `createTransformerDiff`:实现代码块的 diff 高亮效果。 - `createTransformerLineNumber`:实现代码块的行号显示。 -- `createTransformerErrorLevel`:实现代码块对应行的错误等级显示,包括 `error` 和 `warning`。 -- `createTransformerHighlight`:实现代码块的行高亮显示。 -- `createTransformerFocus`: 实现代码块的行聚焦显示。 你可以通过配置 `transformers` 属性来启用这些 Transformer,比如: ```ts title="rspress.config.ts" import { defineConfig } from 'rspress/config'; import { pluginShiki, createTransformerDiff } from '@rspress/plugin-shiki'; +import { + transformerNotationDiff, + transformerNotationErrorLevel, + transformerNotationFocus, + transformerNotationHighlight, +} from '@shikijs/transformers'; export default defineConfig({ plugins: [ pluginShiki({ transformers: [ // 按需加入即可 - createTransformerDiff(), - // createTransformerLineNumber(), - // createTransformerErrorLevel(), - // createTransformerHighlight(), - // createTransformerFocus(), + createTransformerLineNumber(), + // transformerNotationDiff(), + // transformerNotationErrorLevel(), + // transformerNotationHighlight(), + // transformerNotationFocus(), ], }), ], }); ``` -接着我们来介绍一下如何使用这些 Transformer 对应的语法。 - -#### diff 高亮 - -在 markdown 的代码块中使用 `diff` 语法,比如: - -```ts -export function foo() { - console.log('Diff remove'); // [!code --] - console.log('Diff add'); // [!code ++] -} -``` - -这样会自动对相应行的代码应用 diff 高亮效果。 - -#### 行号显示 - -在 markdown 的代码块中使用 `hl` 语法,比如: - -```ts -export function foo() { - console.log('Line number'); // [!code hl] -} -``` - -这样会自动对相应行的代码显示行号。 - -#### 错误等级显示 - -在 markdown 的代码块中使用 `error` 或 `warning` 语法,比如: - -```ts -export function foo() { - console.log('Error level'); // [!code error] -} -``` - -这样会自动对相应行的代码显示错误等级。 - -#### 行聚焦显示 - -在 markdown 的代码块中使用 `focus` 语法,比如: - -```ts -export function foo() { - console.log('Focus'); // [!code focus] -} -``` - -这样会自动对相应行的代码显示聚焦效果。 +请查看 [Shiki Transformers 文档](https://shiki.style/guide/transformers) 获取更多信息。 diff --git a/packages/plugin-shiki/package.json b/packages/plugin-shiki/package.json index 52541a440..12ed1a0c6 100644 --- a/packages/plugin-shiki/package.json +++ b/packages/plugin-shiki/package.json @@ -54,7 +54,7 @@ "dependencies": { "@rspress/shared": "workspace:*", "hast-util-from-html": "2.0.3", - "shiki": "0.14.7", + "shiki": "1.24.2", "unist-util-visit": "5.0.0" } } diff --git a/packages/plugin-shiki/shiki.css b/packages/plugin-shiki/shiki.css index f5ec693c6..02f122a7d 100644 --- a/packages/plugin-shiki/shiki.css +++ b/packages/plugin-shiki/shiki.css @@ -4,8 +4,8 @@ * -------------------------------------------------------------------------- */ :root { - --shiki-color-text: #414141; - --shiki-color-background: transparent; + --shiki-foreground: #414141; + --shiki-background: transparent; --shiki-token-constant: #1976d2; --shiki-token-string: #31a94d; --shiki-token-comment: rgb(182, 180, 180); @@ -18,7 +18,7 @@ } .dark { - --shiki-color-text: #cac7c7; + --shiki-foreground: #cac7c7; --shiki-token-constant: #6fb0fa; --shiki-token-string: #f9a86e; --shiki-token-comment: #6a727b; @@ -37,9 +37,8 @@ .diff, .code-line-highlighted { transition: background-color 0.5s; - margin: 0 -20px; padding: 0 20px; - width: calc(100% + 40px); + width: 100%; display: inline-block; position: relative; } diff --git a/packages/plugin-shiki/src/rehypePlugin.ts b/packages/plugin-shiki/src/rehypePlugin.ts index 1b8d88edd..680717eab 100644 --- a/packages/plugin-shiki/src/rehypePlugin.ts +++ b/packages/plugin-shiki/src/rehypePlugin.ts @@ -2,10 +2,10 @@ import { visit } from 'unist-util-visit'; import type { Plugin } from 'unified'; import type { Text, Root, ElementContent } from 'hast'; import { fromHtml } from 'hast-util-from-html'; -import type shiki from 'shiki'; +import type { Highlighter } from 'shiki'; interface Options { - highlighter: shiki.Highlighter; + highlighter: Highlighter; } export const rehypePluginShiki: Plugin<[Options], Root> = function ({ @@ -49,7 +49,10 @@ export const rehypePluginShiki: Plugin<[Options], Root> = function ({ if (!lang) { return; } - const highlightedCode = highlighter.codeToHtml(codeContent, { lang }); + const highlightedCode = highlighter.codeToHtml(codeContent, { + lang, + theme: 'css-variables', + }); const fragmentAst = fromHtml(highlightedCode, { fragment: true }); const preElement = fragmentAst.children[0] as unknown as any; const codeElement = preElement.children[0]; diff --git a/packages/plugin-shiki/src/shiki/highlighter.ts b/packages/plugin-shiki/src/shiki/highlighter.ts index cd6e73e84..fc601d215 100644 --- a/packages/plugin-shiki/src/shiki/highlighter.ts +++ b/packages/plugin-shiki/src/shiki/highlighter.ts @@ -1,43 +1,31 @@ import { - getHighlighter as getShikiHighlighter, + type BuiltinLanguage, + type BuiltinTheme, type Highlighter, - type HighlighterOptions as ShikiHighlighterOptions, + type BundledHighlighterOptions as ShikiHighlighterOptions, + type ShikiTransformer, + createHighlighter as createShikiHighlighter, } from 'shiki'; -import { postTransformer, transformer } from './transformer'; -import type { ITransformer } from './types'; - -export interface HighlighterOptions extends ShikiHighlighterOptions { - transformers?: ITransformer[]; +export interface HighlighterOptions + extends ShikiHighlighterOptions { + transformers?: ShikiTransformer[]; } export async function getHighlighter( - options: HighlighterOptions = {}, + options: HighlighterOptions, ): Promise { - const highlighter = await getShikiHighlighter(options); - const transformers = options.transformers ?? []; + const highlighter = await createShikiHighlighter(options); + const baseTransformers = options.transformers ?? []; return { ...highlighter, - codeToHtml: (str, htmlOptions) => { - const lang = - typeof htmlOptions === 'object' ? htmlOptions.lang! : htmlOptions!; - - const baseLineOptions = - typeof htmlOptions === 'object' ? (htmlOptions.lineOptions ?? []) : []; - - const theme = - typeof htmlOptions === 'object' ? htmlOptions.theme : undefined; - - const { code, lineOptions } = transformer(transformers, str, lang); - - const highlighted = highlighter.codeToHtml(code, { - lang, - theme, - lineOptions: [...lineOptions, ...baseLineOptions], + codeToHtml: (code, htmlOptions) => { + const transformers = htmlOptions.transformers ?? []; + return highlighter.codeToHtml(code, { + ...htmlOptions, + transformers: [...baseTransformers, ...transformers], }); - - return postTransformer(transformers, highlighted, lang); }, }; } diff --git a/packages/plugin-shiki/src/shiki/pluginShiki.ts b/packages/plugin-shiki/src/shiki/pluginShiki.ts index bf15185ef..a467afe63 100644 --- a/packages/plugin-shiki/src/shiki/pluginShiki.ts +++ b/packages/plugin-shiki/src/shiki/pluginShiki.ts @@ -1,36 +1,40 @@ -import { join } from 'node:path'; -import { getHighlighter } from './highlighter'; +import type { RspressPlugin } from '@rspress/shared'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { + type BuiltinLanguage, + type BuiltinTheme, + type ShikiTransformer, + type SpecialLanguage, + createCssVariablesTheme, +} from 'shiki'; + import { rehypePluginShiki } from './rehypePlugin'; import { SHIKI_TRANSFORMER_LINE_NUMBER, createTransformerLineNumber, } from './transformers/line-number'; -import { fileURLToPath } from 'node:url'; -import { dirname } from 'node:path'; +import { getHighlighter } from './highlighter'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); -import type { Lang } from 'shiki'; -import type { RspressPlugin } from '@rspress/shared'; -import type { ITransformer } from './types'; - export interface PluginShikiOptions { /** - * The theme of shiki. + * Code highlighting theme, @see https://shiki.style/themes */ - theme?: string; + theme: BuiltinTheme | 'css-variables'; /** - * The languages to highlight. + * Code highlighting language, @see https://shiki.style/languages */ - langs?: Lang[]; + langs: Array; /** - * The transformers to transform the code block. + * Custom shiki transformer, @see https://shiki.style/guide/transformers */ - transformers?: ITransformer[]; + transformers: ShikiTransformer[]; } -export const SHIKI_DEFAULT_HIGHLIGHT_LANGUAGES = [ +export const SHIKI_DEFAULT_HIGHLIGHT_LANGUAGES: BuiltinLanguage[] = [ 'js', 'ts', 'jsx', @@ -47,10 +51,19 @@ export const SHIKI_DEFAULT_HIGHLIGHT_LANGUAGES = [ 'bash', ]; +const cssVariablesTheme = createCssVariablesTheme({ + name: 'css-variables', + variablePrefix: '--shiki-', + variableDefaults: {}, + fontStyle: true, +}); + /** * The plugin is used to add the last updated time to the page. */ -export function pluginShiki(options?: PluginShikiOptions): RspressPlugin { +export function pluginShiki( + options?: Partial, +): RspressPlugin { const { theme = 'css-variables', langs = [], @@ -68,20 +81,23 @@ export function pluginShiki(options?: PluginShikiOptions): RspressPlugin { config.markdown.rehypePlugins = config.markdown.rehypePlugins || []; if ( config.markdown.showLineNumbers && - !transformers.includes( - (transformerItem: ITransformer) => + !transformers.some( + transformerItem => transformerItem.name === SHIKI_TRANSFORMER_LINE_NUMBER, ) ) { transformers.push(createTransformerLineNumber()); } const highlighter = await getHighlighter({ - theme, - langs: [...SHIKI_DEFAULT_HIGHLIGHT_LANGUAGES, ...langs] as Lang[], + themes: [cssVariablesTheme], + langs: [...SHIKI_DEFAULT_HIGHLIGHT_LANGUAGES, ...langs], transformers, }); - config.markdown.rehypePlugins.push([rehypePluginShiki, { highlighter }]); + config.markdown.rehypePlugins.push([ + rehypePluginShiki, + { highlighter, theme }, + ]); return config; }, globalStyles: join(__dirname, '../shiki.css'), diff --git a/packages/plugin-shiki/src/shiki/rehypePlugin.ts b/packages/plugin-shiki/src/shiki/rehypePlugin.ts index 1445c6ae4..2cb140b30 100644 --- a/packages/plugin-shiki/src/shiki/rehypePlugin.ts +++ b/packages/plugin-shiki/src/shiki/rehypePlugin.ts @@ -1,17 +1,18 @@ import { visit } from 'unist-util-visit'; import type { Plugin } from 'unified'; -import type { Text, Root, ElementContent } from 'hast'; +import type { Element, Text, Root, ElementContent } from 'hast'; import { fromHtml } from 'hast-util-from-html'; -import type shiki from 'shiki'; +import type { BuiltinTheme, Highlighter } from 'shiki'; interface Options { - highlighter: shiki.Highlighter; + highlighter: Highlighter; + theme: BuiltinTheme; } -export const rehypePluginShiki: Plugin<[Options], Root> = function ({ - highlighter, -}) { - return (tree: Root) => { +// TODO: migrate to official @shikijs/rehype plugin after upgrading unified/remark/rehype packages +export const rehypePluginShiki: Plugin<[Options], Root> = + ({ highlighter, theme }) => + (tree: Root) => { visit(tree, 'element', (node, index, parent) => { //
...
if ( @@ -32,7 +33,7 @@ export const rehypePluginShiki: Plugin<[Options], Root> = function ({ highlightLines = highlightMatch ?.replace(/[{}]/g, '') .split(',') - .map(item => { + .flatMap(item => { const [start, end] = item.split('-'); if (end) { return Array.from( @@ -41,18 +42,20 @@ export const rehypePluginShiki: Plugin<[Options], Root> = function ({ ); } return Number(start); - }) - .flat(); + }); } // for example: language-js {1,2,3-5} const lang = codeClassName.split(' ')[0].split('-')[1]; if (!lang) { return; } - const highlightedCode = highlighter.codeToHtml(codeContent, { lang }); + const highlightedCode = highlighter.codeToHtml(codeContent, { + lang, + theme, + }); const fragmentAst = fromHtml(highlightedCode, { fragment: true }); - const preElement = fragmentAst.children[0] as unknown as any; - const codeElement = preElement.children[0]; + const preElement = fragmentAst.children[0] as Element; + const codeElement = preElement.children[0] as Element; codeElement.properties.className = `language-${lang}`; codeElement.properties.meta = codeMeta; const codeLines = codeElement.children; @@ -66,7 +69,7 @@ export const rehypePluginShiki: Plugin<[Options], Root> = function ({ }); // Strip the final empty span - const lastLine = codeLines[codeLines.length - 1]; + const lastLine = codeLines[codeLines.length - 1] as Element; if (lastLine?.children.length === 0) { codeLines.pop(); } @@ -82,4 +85,3 @@ export const rehypePluginShiki: Plugin<[Options], Root> = function ({ } }); }; -}; diff --git a/packages/plugin-shiki/src/shiki/transformer.ts b/packages/plugin-shiki/src/shiki/transformer.ts deleted file mode 100644 index 42c779283..000000000 --- a/packages/plugin-shiki/src/shiki/transformer.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { ITransformer, ITransformerResult } from './types'; - -/** - * Defines a transformer. - */ -export function defineTransformer(transformer: ITransformer): ITransformer { - return transformer; -} - -/** - * Transforms code through the given transformer. - */ -export function transformer( - transformers: ITransformer[], - code: string, - lang: string, -) { - return transformers.reduce( - (options, transformer) => { - const { code, lineOptions } = - transformer?.preTransformer?.({ - code: options.code, - lang, - }) ?? options; - - return { - code, - lineOptions: [...options.lineOptions, ...lineOptions], - }; - }, - { - code, - lineOptions: [], - } as ITransformerResult, - ); -} - -/** - * Transforms final code through the given Transformers. - */ -export function postTransformer( - transformers: ITransformer[], - code: string, - lang: string, -) { - return transformers.reduce( - (code, transformer) => - transformer?.postTransformer?.({ - code, - lang, - }) ?? code, - code, - ); -} diff --git a/packages/plugin-shiki/src/shiki/transformers/diff.ts b/packages/plugin-shiki/src/shiki/transformers/diff.ts deleted file mode 100644 index 3001973de..000000000 --- a/packages/plugin-shiki/src/shiki/transformers/diff.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { checkClass } from '../utils/check-class'; -import type { IRangeTransformerOptions, ITransformer } from '../types'; -import { addClass } from '../utils'; -import { createRangeTransformer } from '../utils/create-range-transformer'; - -export interface ITransformerDiffOptions extends IRangeTransformerOptions { - /** - * Class for added lines - */ - classLineAdd?: string; - /** - * Class for removed lines - */ - classLineRemove?: string; - /** - * Class added to the
 element when the current code has diff
-   */
-  classActivePre?: string;
-}
-
-export function createTransformerDiff(
-  options: ITransformerDiffOptions = {},
-): ITransformer {
-  const {
-    classLineAdd = 'diff add',
-    classLineRemove = 'diff remove',
-    classActivePre = 'has-diff',
-  } = options;
-
-  return {
-    name: 'shiki-transformer:diff',
-    preTransformer: createRangeTransformer(
-      {
-        '++': classLineAdd,
-        '--': classLineRemove,
-      },
-      options,
-    ),
-    postTransformer: ({ code }) => {
-      if (
-        !checkClass(code, classLineAdd) &&
-        !checkClass(code, classLineRemove)
-      ) {
-        return code;
-      }
-
-      return addClass(code, classActivePre, 'pre');
-    },
-  };
-}
diff --git a/packages/plugin-shiki/src/shiki/transformers/focus.ts b/packages/plugin-shiki/src/shiki/transformers/focus.ts
deleted file mode 100644
index 87adcc5b7..000000000
--- a/packages/plugin-shiki/src/shiki/transformers/focus.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import { checkClass } from '../utils/check-class';
-import type { IRangeTransformerOptions, ITransformer } from '../types';
-import { addClass } from '../utils/add-class';
-import { createRangeTransformer } from '../utils/create-range-transformer';
-
-export interface ITransformerFocusOptions extends IRangeTransformerOptions {
-  /**
-   * Class for focused lines
-   */
-  classActiveLine?: string;
-  /**
-   * Class added to the root element when the code has focused lines
-   */
-  classActivePre?: string;
-}
-
-export function createTransformerFocus(
-  options: ITransformerFocusOptions = {},
-): ITransformer {
-  const { classActiveLine = 'focused', classActivePre = 'has-focused' } =
-    options;
-
-  return {
-    name: 'shiki-transformer:focus',
-    preTransformer: createRangeTransformer(
-      {
-        focus: classActiveLine,
-        fc: classActiveLine,
-      },
-      options,
-    ),
-    postTransformer: ({ code }) => {
-      if (!checkClass(code, classActiveLine)) {
-        return code;
-      }
-
-      return addClass(code, classActivePre, 'pre');
-    },
-  };
-}
diff --git a/packages/plugin-shiki/src/shiki/transformers/highlight-error-level.ts b/packages/plugin-shiki/src/shiki/transformers/highlight-error-level.ts
deleted file mode 100644
index 1e415b66b..000000000
--- a/packages/plugin-shiki/src/shiki/transformers/highlight-error-level.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import { checkClass } from '../utils/check-class';
-import type { IRangeTransformerOptions, ITransformer } from '../types';
-import { addClass } from '../utils/add-class';
-import { createRangeTransformer } from '../utils/create-range-transformer';
-
-export interface ITransformerErrorLevelOptions
-  extends IRangeTransformerOptions {
-  classMap?: Record;
-  /**
-   * Class added to the 
 element when the current code has diff
-   */
-  classActivePre?: string;
-}
-
-export function createTransformerErrorLevel(
-  options: ITransformerErrorLevelOptions = {},
-): ITransformer {
-  const {
-    classMap = {
-      error: ['highlighted', 'error'],
-      warning: ['highlighted', 'warning'],
-    },
-    classActivePre = 'has-highlight',
-  } = options;
-
-  return {
-    name: 'shiki-transformer:highlight-error',
-    preTransformer: createRangeTransformer(classMap, options),
-    postTransformer: ({ code }) => {
-      if (
-        !checkClass(code, classMap.error) &&
-        !checkClass(code, classMap.warning)
-      ) {
-        return code;
-      }
-
-      return addClass(code, classActivePre, 'pre');
-    },
-  };
-}
diff --git a/packages/plugin-shiki/src/shiki/transformers/highlight.ts b/packages/plugin-shiki/src/shiki/transformers/highlight.ts
deleted file mode 100644
index be08c14e5..000000000
--- a/packages/plugin-shiki/src/shiki/transformers/highlight.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { checkClass } from '../utils/check-class';
-import type { IRangeTransformerOptions, ITransformer } from '../types';
-import { addClass } from '../utils/add-class';
-import { createRangeTransformer } from '../utils/create-range-transformer';
-
-export interface ITransformerHighlightOptions extends IRangeTransformerOptions {
-  classActivePre?: string;
-  classActiveLine?: string;
-}
-
-export function createTransformerHighlight(
-  options: ITransformerHighlightOptions = {},
-): ITransformer {
-  const { classActiveLine = 'highlighted', classActivePre = 'has-highlight' } =
-    options;
-
-  return {
-    name: 'shiki-transformer:highlight',
-    preTransformer: createRangeTransformer(
-      {
-        highlight: classActiveLine,
-        hl: classActiveLine,
-      },
-      options,
-    ),
-    postTransformer: ({ code }) => {
-      if (!checkClass(code, classActiveLine)) {
-        return code;
-      }
-
-      return addClass(code, classActivePre, 'pre');
-    },
-  };
-}
diff --git a/packages/plugin-shiki/src/shiki/transformers/index.ts b/packages/plugin-shiki/src/shiki/transformers/index.ts
index c7e308abd..711c65ad2 100644
--- a/packages/plugin-shiki/src/shiki/transformers/index.ts
+++ b/packages/plugin-shiki/src/shiki/transformers/index.ts
@@ -1,5 +1 @@
-export * from './diff';
-export * from './focus';
-export * from './highlight';
-export * from './highlight-error-level';
 export * from './line-number';
diff --git a/packages/plugin-shiki/src/shiki/transformers/line-number.ts b/packages/plugin-shiki/src/shiki/transformers/line-number.ts
index bd23c28e1..55fdcae00 100644
--- a/packages/plugin-shiki/src/shiki/transformers/line-number.ts
+++ b/packages/plugin-shiki/src/shiki/transformers/line-number.ts
@@ -1,5 +1,4 @@
-import type { ITransformer, TLineOptions } from '../types';
-import { addClass } from '../utils';
+import type { ShikiTransformer } from 'shiki';
 
 export interface ITransformerLineNumberOptions {
   classActivePre?: string;
@@ -10,7 +9,7 @@ export const SHIKI_TRANSFORMER_LINE_NUMBER = 'shiki-transformer:line-number';
 
 export function createTransformerLineNumber(
   options: ITransformerLineNumberOptions = {},
-): ITransformer {
+): ShikiTransformer {
   const {
     classActiveLine = 'line-number',
     classActivePre = 'has-line-number',
@@ -18,26 +17,11 @@ export function createTransformerLineNumber(
 
   return {
     name: SHIKI_TRANSFORMER_LINE_NUMBER,
-    preTransformer: ({ code }) => {
-      const lineOptions = [] as TLineOptions;
-
-      code.split('\n').forEach((_, idx) => {
-        const lineNumber = idx + 1;
-        lineOptions.push({
-          line: lineNumber,
-          classes: [classActiveLine],
-        });
-      });
-
-      lineOptions.pop();
-
-      return {
-        code,
-        lineOptions,
-      };
+    pre(pre) {
+      return this.addClassToHast(pre, classActivePre);
     },
-    postTransformer: ({ code }) => {
-      return addClass(code, classActivePre, 'pre');
+    line(node, line) {
+      this.addClassToHast(node, classActiveLine);
     },
   };
 }
diff --git a/packages/plugin-shiki/src/shiki/types.ts b/packages/plugin-shiki/src/shiki/types.ts
deleted file mode 100644
index 7ca7e9e14..000000000
--- a/packages/plugin-shiki/src/shiki/types.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import type { HtmlRendererOptions } from 'shiki';
-
-export type TLineOptions = NonNullable;
-export interface ITransformerResult {
-  code: string;
-  lineOptions: TLineOptions;
-}
-
-export type TPostTransformerResult = string | undefined;
-
-export interface ITransformerOptions {
-  code: string;
-  lang: string;
-}
-
-export type TPreTransformer = (
-  options: ITransformerOptions,
-) => ITransformerResult;
-export type TPostTransformerHandler = (
-  options: ITransformerOptions,
-) => TPostTransformerResult;
-
-export interface IRangeTransformerOptions {
-  tagRegExp?: RegExp;
-}
-
-export interface ITransformer {
-  name: string;
-  preTransformer?: TPreTransformer;
-  postTransformer?: TPostTransformerHandler;
-}
diff --git a/packages/plugin-shiki/src/shiki/utils/add-class.ts b/packages/plugin-shiki/src/shiki/utils/add-class.ts
deleted file mode 100644
index 5b4550bf6..000000000
--- a/packages/plugin-shiki/src/shiki/utils/add-class.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-export function addClass(
-  code: string,
-  classes: string | string[],
-  tag?: string,
-): string {
-  const classRE = new RegExp(`<${tag ?? 'w+'}[^>]*class="([\\w+-:;\\/* ]*)"`);
-  // eslint-disable-next-line no-param-reassign
-  classes = Array.isArray(classes) ? classes : [classes];
-
-  return code.replace(classRE, (match, previousClasses) => {
-    return match.replace(previousClasses, `${previousClasses} ${classes}`);
-  });
-}
diff --git a/packages/plugin-shiki/src/shiki/utils/check-class.ts b/packages/plugin-shiki/src/shiki/utils/check-class.ts
deleted file mode 100644
index 2f93f4667..000000000
--- a/packages/plugin-shiki/src/shiki/utils/check-class.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export const checkClass = (code: string, className: string | string[]) => {
-  const classes = Array.isArray(className) ? className.join('') : className;
-
-  return code.search(classes) !== -1;
-};
diff --git a/packages/plugin-shiki/src/shiki/utils/create-range-transformer.ts b/packages/plugin-shiki/src/shiki/utils/create-range-transformer.ts
deleted file mode 100644
index 9fb33fa18..000000000
--- a/packages/plugin-shiki/src/shiki/utils/create-range-transformer.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import type {
-  TLineOptions,
-  TPreTransformer,
-  ITransformerOptions,
-  IRangeTransformerOptions,
-} from '../types';
-
-export function createRangeTransformer(
-  classMap: Record,
-  options: IRangeTransformerOptions = {},
-): TPreTransformer {
-  return ({ code }: ITransformerOptions) => {
-    // https://regex101.com/r/mUxvfx/1
-    const tagRE =
-      options.tagRegExp ??
-      /(?:\/\/|\/\*{1,2}) *\[!code ([\w+-]+)(?::(\d+))?] *(?:\*{1,2}\/)?/;
-    const lineOptions: TLineOptions = [];
-
-    const tags = Object.keys(classMap);
-
-    const codeFormat = code
-      .split('\n')
-      .map((lineOfCode, lineNumber) => {
-        const [match, tag, range] = lineOfCode.match(tagRE) ?? [];
-
-        if (!match) {
-          return lineOfCode;
-        }
-
-        if (!tags.includes(tag)) {
-          return lineOfCode;
-        }
-
-        for (const [rangeOffset] of Array.from({
-          length: Number(range ?? 1),
-        }).entries()) {
-          lineOptions.push({
-            line: lineNumber + rangeOffset + 1,
-            classes:
-              typeof classMap[tag] === 'string'
-                ? ([classMap[tag]] as string[])
-                : (classMap[tag as any] as any),
-          });
-        }
-
-        return lineOfCode.replace(tagRE, '');
-      })
-      .join('\n');
-
-    return {
-      code: codeFormat,
-      lineOptions,
-    };
-  };
-}
diff --git a/packages/plugin-shiki/src/shiki/utils/index.ts b/packages/plugin-shiki/src/shiki/utils/index.ts
deleted file mode 100644
index 12bfbb96f..000000000
--- a/packages/plugin-shiki/src/shiki/utils/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from './add-class';
-export * from './create-range-transformer';
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 9e3faeeab..e2be0fcd4 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -430,6 +430,9 @@ importers:
       '@rspress/plugin-shiki':
         specifier: workspace:*
         version: link:../../../packages/plugin-shiki
+      '@shikijs/transformers':
+        specifier: 1.24.2
+        version: 1.24.2
       rspress:
         specifier: workspace:*
         version: link:../../../packages/cli
@@ -1321,8 +1324,8 @@ importers:
         specifier: 2.0.3
         version: 2.0.3
       shiki:
-        specifier: 0.14.7
-        version: 0.14.7
+        specifier: 1.24.2
+        version: 1.24.2
       unist-util-visit:
         specifier: 5.0.0
         version: 5.0.0
@@ -2989,6 +2992,24 @@ packages:
   '@selderee/plugin-htmlparser2@0.11.0':
     resolution: {integrity: sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==}
 
+  '@shikijs/core@1.24.2':
+    resolution: {integrity: sha512-BpbNUSKIwbKrRRA+BQj0BEWSw+8kOPKDJevWeSE/xIqGX7K0xrCZQ9kK0nnEQyrzsUoka1l81ZtJ2mGaCA32HQ==}
+
+  '@shikijs/engine-javascript@1.24.2':
+    resolution: {integrity: sha512-EqsmYBJdLEwEiO4H+oExz34a5GhhnVp+jH9Q/XjPjmBPc6TE/x4/gD0X3i0EbkKKNqXYHHJTJUpOLRQNkEzS9Q==}
+
+  '@shikijs/engine-oniguruma@1.24.2':
+    resolution: {integrity: sha512-ZN6k//aDNWRJs1uKB12pturKHh7GejKugowOFGAuG7TxDRLod1Bd5JhpOikOiFqPmKjKEPtEA6mRCf7q3ulDyQ==}
+
+  '@shikijs/transformers@1.24.2':
+    resolution: {integrity: sha512-cIwn8YSwO3bsWKJ+pezcXY1Vq0BVwvuLes1TZSC5+Awi6Tsfqhf3vBahOIqZK1rraMKOti2VEAEF/95oXMig1w==}
+
+  '@shikijs/types@1.24.2':
+    resolution: {integrity: sha512-bdeWZiDtajGLG9BudI0AHet0b6e7FbR0EsE4jpGaI0YwHm/XJunI9+3uZnzFtX65gsyJ6ngCIWUfA4NWRPnBkQ==}
+
+  '@shikijs/vscode-textmate@9.3.1':
+    resolution: {integrity: sha512-79QfK1393x9Ho60QFyLti+QfdJzRQCVLFb97kOIV7Eo9vQU/roINgk7m24uv0a7AUvN//RDH36FLjjK48v0s9g==}
+
   '@sinclair/typebox@0.27.8':
     resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
 
@@ -3812,6 +3833,9 @@ packages:
   electron-to-chromium@1.5.38:
     resolution: {integrity: sha512-VbeVexmZ1IFh+5EfrYz1I0HTzHVIlJa112UEWhciPyeOcKJGeTv6N8WnG4wsQB81DGCaVEGhpSb6o6a8WYFXXg==}
 
+  emoji-regex-xs@1.0.0:
+    resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==}
+
   emoji-regex@10.4.0:
     resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==}
 
@@ -4244,12 +4268,18 @@ packages:
   hast-util-to-html@8.0.4:
     resolution: {integrity: sha512-4tpQTUOr9BMjtYyNlt0P50mH7xj0Ks2xpo8M943Vykljf99HW6EzulIoJP1N3eKOSScEHzyzi9dm7/cn0RfGwA==}
 
+  hast-util-to-html@9.0.4:
+    resolution: {integrity: sha512-wxQzXtdbhiwGAUKrnQJXlOPmHnEehzphwkK7aluUPQ+lEc1xefC8pblMgpp2w5ldBTEfveRIrADcrhGIWrlTDA==}
+
   hast-util-to-parse5@7.1.0:
     resolution: {integrity: sha512-YNRgAJkH2Jky5ySkIqFXTQiaqcAtJyVE+D5lkN6CdtOqrnkLfGYYrEcKuHOJZlp+MwjSwuD3fZuawI+sic/RBw==}
 
   hast-util-whitespace@2.0.1:
     resolution: {integrity: sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==}
 
+  hast-util-whitespace@3.0.0:
+    resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==}
+
   hastscript@6.0.0:
     resolution: {integrity: sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==}
 
@@ -4290,6 +4320,9 @@ packages:
   html-void-elements@2.0.1:
     resolution: {integrity: sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==}
 
+  html-void-elements@3.0.0:
+    resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
+
   htmlparser2@6.1.0:
     resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==}
 
@@ -4767,6 +4800,9 @@ packages:
   mdast-util-to-hast@12.3.0:
     resolution: {integrity: sha512-pits93r8PhnIoU4Vy9bjW39M2jJ6/tdHyja9rrot9uujkN7UTU9SDnE6WNJz/IGyQk3XHX6yNNtrBH6cQzm8Hw==}
 
+  mdast-util-to-hast@13.2.0:
+    resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==}
+
   mdast-util-to-markdown@1.5.0:
     resolution: {integrity: sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A==}
 
@@ -4849,6 +4885,9 @@ packages:
   micromark-util-character@1.2.0:
     resolution: {integrity: sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==}
 
+  micromark-util-character@2.1.1:
+    resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==}
+
   micromark-util-chunked@1.1.0:
     resolution: {integrity: sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==}
 
@@ -4867,6 +4906,9 @@ packages:
   micromark-util-encode@1.1.0:
     resolution: {integrity: sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==}
 
+  micromark-util-encode@2.0.1:
+    resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==}
+
   micromark-util-events-to-acorn@1.2.3:
     resolution: {integrity: sha512-ij4X7Wuc4fED6UoLWkmo0xJQhsktfNh1J0m8g4PbIMPlx+ek/4YdW5mvbye8z/aZvAPUoxgXHrwVlXAPKMRp1w==}
 
@@ -4882,15 +4924,24 @@ packages:
   micromark-util-sanitize-uri@1.2.0:
     resolution: {integrity: sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==}
 
+  micromark-util-sanitize-uri@2.0.1:
+    resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==}
+
   micromark-util-subtokenize@1.1.0:
     resolution: {integrity: sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==}
 
   micromark-util-symbol@1.1.0:
     resolution: {integrity: sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==}
 
+  micromark-util-symbol@2.0.1:
+    resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==}
+
   micromark-util-types@1.1.0:
     resolution: {integrity: sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==}
 
+  micromark-util-types@2.0.1:
+    resolution: {integrity: sha512-534m2WhVTddrcKVepwmVEVnUAmtrx9bfIjNoQHRqfnvdaHQiFytEhJoTgpWJvDEXCO5gLTQh3wYC1PgOJA4NSQ==}
+
   micromark@3.2.0:
     resolution: {integrity: sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==}
 
@@ -5029,6 +5080,9 @@ packages:
     resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==}
     engines: {node: '>=18'}
 
+  oniguruma-to-es@0.7.0:
+    resolution: {integrity: sha512-HRaRh09cE0gRS3+wi2zxekB+I5L8C/gN60S+vb11eADHUaB/q4u8wGGOX3GvwvitG8ixaeycZfeoyruKQzUgNg==}
+
   open@8.4.2:
     resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==}
     engines: {node: '>=12'}
@@ -5473,6 +5527,15 @@ packages:
   regenerator-runtime@0.14.0:
     resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==}
 
+  regex-recursion@4.3.0:
+    resolution: {integrity: sha512-5LcLnizwjcQ2ALfOj95MjcatxyqF5RPySx9yT+PaXu3Gox2vyAtLDjHB8NTJLtMGkvyau6nI3CfpwFCjPUIs/A==}
+
+  regex-utilities@2.3.0:
+    resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==}
+
+  regex@5.0.2:
+    resolution: {integrity: sha512-/pczGbKIQgfTMRV0XjABvc5RzLqQmwqxLHdQao2RTXPk+pmTXB2P0IaUHYdYyk412YLwUIkaeMd5T+RzVgTqnQ==}
+
   rehype-external-links@3.0.0:
     resolution: {integrity: sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==}
 
@@ -5818,6 +5881,9 @@ packages:
   shiki@0.14.7:
     resolution: {integrity: sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg==}
 
+  shiki@1.24.2:
+    resolution: {integrity: sha512-TR1fi6mkRrzW+SKT5G6uKuc32Dj2EEa7Kj0k8kGqiBINb+C1TiflVOiT9ta6GqOJtC4fraxO5SLUaKBcSY38Fg==}
+
   siginfo@2.0.0:
     resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
 
@@ -6206,6 +6272,9 @@ packages:
   unist-util-position@4.0.4:
     resolution: {integrity: sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg==}
 
+  unist-util-position@5.0.0:
+    resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==}
+
   unist-util-remove-position@4.0.2:
     resolution: {integrity: sha512-TkBb0HABNmxzAcfLf4qsIbFbaPDvMO6wa3b3j4VcEzFVaw1LBKwnW4/sRJ/atSLSzoIg41JWEdnE7N6DIhGDGQ==}
 
@@ -7944,6 +8013,37 @@ snapshots:
       domhandler: 5.0.3
       selderee: 0.11.0
 
+  '@shikijs/core@1.24.2':
+    dependencies:
+      '@shikijs/engine-javascript': 1.24.2
+      '@shikijs/engine-oniguruma': 1.24.2
+      '@shikijs/types': 1.24.2
+      '@shikijs/vscode-textmate': 9.3.1
+      '@types/hast': 3.0.4
+      hast-util-to-html: 9.0.4
+
+  '@shikijs/engine-javascript@1.24.2':
+    dependencies:
+      '@shikijs/types': 1.24.2
+      '@shikijs/vscode-textmate': 9.3.1
+      oniguruma-to-es: 0.7.0
+
+  '@shikijs/engine-oniguruma@1.24.2':
+    dependencies:
+      '@shikijs/types': 1.24.2
+      '@shikijs/vscode-textmate': 9.3.1
+
+  '@shikijs/transformers@1.24.2':
+    dependencies:
+      shiki: 1.24.2
+
+  '@shikijs/types@1.24.2':
+    dependencies:
+      '@shikijs/vscode-textmate': 9.3.1
+      '@types/hast': 3.0.4
+
+  '@shikijs/vscode-textmate@9.3.1': {}
+
   '@sinclair/typebox@0.27.8': {}
 
   '@swc/helpers@0.5.13':
@@ -8849,6 +8949,8 @@ snapshots:
 
   electron-to-chromium@1.5.38: {}
 
+  emoji-regex-xs@1.0.0: {}
+
   emoji-regex@10.4.0: {}
 
   emoji-regex@8.0.0: {}
@@ -9408,6 +9510,20 @@ snapshots:
       stringify-entities: 4.0.3
       zwitch: 2.0.4
 
+  hast-util-to-html@9.0.4:
+    dependencies:
+      '@types/hast': 3.0.4
+      '@types/unist': 3.0.2
+      ccount: 2.0.1
+      comma-separated-tokens: 2.0.3
+      hast-util-whitespace: 3.0.0
+      html-void-elements: 3.0.0
+      mdast-util-to-hast: 13.2.0
+      property-information: 6.2.0
+      space-separated-tokens: 2.0.2
+      stringify-entities: 4.0.3
+      zwitch: 2.0.4
+
   hast-util-to-parse5@7.1.0:
     dependencies:
       '@types/hast': 2.3.4
@@ -9419,6 +9535,10 @@ snapshots:
 
   hast-util-whitespace@2.0.1: {}
 
+  hast-util-whitespace@3.0.0:
+    dependencies:
+      '@types/hast': 3.0.4
+
   hastscript@6.0.0:
     dependencies:
       '@types/hast': 2.3.4
@@ -9470,6 +9590,8 @@ snapshots:
 
   html-void-elements@2.0.1: {}
 
+  html-void-elements@3.0.0: {}
+
   htmlparser2@6.1.0:
     dependencies:
       domelementtype: 2.3.0
@@ -10005,6 +10127,18 @@ snapshots:
       unist-util-position: 4.0.4
       unist-util-visit: 4.1.2
 
+  mdast-util-to-hast@13.2.0:
+    dependencies:
+      '@types/hast': 3.0.4
+      '@types/mdast': 4.0.4
+      '@ungap/structured-clone': 1.2.0
+      devlop: 1.1.0
+      micromark-util-sanitize-uri: 2.0.1
+      trim-lines: 3.0.1
+      unist-util-position: 5.0.0
+      unist-util-visit: 5.0.0
+      vfile: 6.0.1
+
   mdast-util-to-markdown@1.5.0:
     dependencies:
       '@types/mdast': 3.0.15
@@ -10214,6 +10348,11 @@ snapshots:
       micromark-util-symbol: 1.1.0
       micromark-util-types: 1.1.0
 
+  micromark-util-character@2.1.1:
+    dependencies:
+      micromark-util-symbol: 2.0.1
+      micromark-util-types: 2.0.1
+
   micromark-util-chunked@1.1.0:
     dependencies:
       micromark-util-symbol: 1.1.0
@@ -10242,6 +10381,8 @@ snapshots:
 
   micromark-util-encode@1.1.0: {}
 
+  micromark-util-encode@2.0.1: {}
+
   micromark-util-events-to-acorn@1.2.3:
     dependencies:
       '@types/acorn': 4.0.6
@@ -10269,6 +10410,12 @@ snapshots:
       micromark-util-encode: 1.1.0
       micromark-util-symbol: 1.1.0
 
+  micromark-util-sanitize-uri@2.0.1:
+    dependencies:
+      micromark-util-character: 2.1.1
+      micromark-util-encode: 2.0.1
+      micromark-util-symbol: 2.0.1
+
   micromark-util-subtokenize@1.1.0:
     dependencies:
       micromark-util-chunked: 1.1.0
@@ -10278,8 +10425,12 @@ snapshots:
 
   micromark-util-symbol@1.1.0: {}
 
+  micromark-util-symbol@2.0.1: {}
+
   micromark-util-types@1.1.0: {}
 
+  micromark-util-types@2.0.1: {}
+
   micromark@3.2.0:
     dependencies:
       '@types/debug': 4.1.8
@@ -10453,6 +10604,12 @@ snapshots:
     dependencies:
       mimic-function: 5.0.1
 
+  oniguruma-to-es@0.7.0:
+    dependencies:
+      emoji-regex-xs: 1.0.0
+      regex: 5.0.2
+      regex-recursion: 4.3.0
+
   open@8.4.2:
     dependencies:
       define-lazy-prop: 2.0.0
@@ -10913,6 +11070,16 @@ snapshots:
 
   regenerator-runtime@0.14.0: {}
 
+  regex-recursion@4.3.0:
+    dependencies:
+      regex-utilities: 2.3.0
+
+  regex-utilities@2.3.0: {}
+
+  regex@5.0.2:
+    dependencies:
+      regex-utilities: 2.3.0
+
   rehype-external-links@3.0.0:
     dependencies:
       '@types/hast': 3.0.4
@@ -11265,6 +11432,15 @@ snapshots:
       vscode-oniguruma: 1.7.0
       vscode-textmate: 8.0.0
 
+  shiki@1.24.2:
+    dependencies:
+      '@shikijs/core': 1.24.2
+      '@shikijs/engine-javascript': 1.24.2
+      '@shikijs/engine-oniguruma': 1.24.2
+      '@shikijs/types': 1.24.2
+      '@shikijs/vscode-textmate': 9.3.1
+      '@types/hast': 3.0.4
+
   siginfo@2.0.0: {}
 
   signal-exit@3.0.7: {}
@@ -11662,6 +11838,10 @@ snapshots:
     dependencies:
       '@types/unist': 2.0.7
 
+  unist-util-position@5.0.0:
+    dependencies:
+      '@types/unist': 3.0.2
+
   unist-util-remove-position@4.0.2:
     dependencies:
       '@types/unist': 2.0.7