From e11037c06d110575bda056f9a8200049d7d303b2 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 ++- test.diff | 1228 +++++++++++++++++ 24 files changed, 1552 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 create mode 100644 test.diff 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
diff --git a/test.diff b/test.diff
new file mode 100644
index 000000000..317c5aa69
--- /dev/null
+++ b/test.diff
@@ -0,0 +1,1228 @@
+diff --git a/e2e/fixtures/plugin-shiki/package.json b/e2e/fixtures/plugin-shiki/package.json
+index 26002a1c..b691a45e 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 a2bee0ab..4c210bf6 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/plugin-shiki/package.json b/packages/plugin-shiki/package.json
+index 52541a44..12ed1a0c 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 f5ec693c..8edf838e 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;
+diff --git a/packages/plugin-shiki/src/rehypePlugin.ts b/packages/plugin-shiki/src/rehypePlugin.ts
+index 1b8d88ed..680717ea 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 cd6e73e8..fc601d21 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 bf15185e..041ea0f1 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.
+    */
+-  theme?: string;
++  theme?: BuiltinTheme;
+   /**
+    * The languages to highlight.
+    */
+-  langs?: Lang[];
++  langs?: Array;
+   /**
+    * The transformers to transform the code block.
+    */
+-  transformers?: ITransformer[];
++  transformers?: ShikiTransformer[];
+ }
+ 
+-export const SHIKI_DEFAULT_HIGHLIGHT_LANGUAGES = [
++export const SHIKI_DEFAULT_HIGHLIGHT_LANGUAGES: BuiltinLanguage[] = [
+   'js',
+   'ts',
+   'jsx',
+@@ -47,6 +51,13 @@ 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.
+  */
+@@ -68,20 +79,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 1445c6ae..faadc5d7 100644
+--- a/packages/plugin-shiki/src/shiki/rehypePlugin.ts
++++ b/packages/plugin-shiki/src/shiki/rehypePlugin.ts
+@@ -1,17 +1,17 @@
+ 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) => {
++export const rehypePluginShiki: Plugin<[Options], Root> =
++  ({ highlighter, theme }) =>
++  (tree: Root) => {
+     visit(tree, 'element', (node, index, parent) => {
+       // 
...
+ if ( +@@ -32,7 +32,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 +41,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 +68,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 +84,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 42c77928..00000000 +--- 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 3001973d..00000000 +--- 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 87adcc5b..00000000
+--- 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 1e415b66..00000000
+--- 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 be08c14e..00000000
+--- 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 c7e308ab..711c65ad 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 bd23c28e..366b1742 100644
+--- a/packages/plugin-shiki/src/shiki/transformers/line-number.ts
++++ b/packages/plugin-shiki/src/shiki/transformers/line-number.ts
+@@ -1,5 +1,12 @@
+-import type { ITransformer, TLineOptions } from '../types';
+-import { addClass } from '../utils';
++import type { ShikiTransformer } from 'shiki';
++
++export interface TransformerCompactLineOption {
++  /**
++   * 1-based line number.
++   */
++  line: number;
++  classes?: string[];
++}
+ 
+ export interface ITransformerLineNumberOptions {
+   classActivePre?: string;
+@@ -10,17 +17,18 @@ 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',
+   } = options;
+ 
++  const lineOptionsMapper = new Map();
++
+   return {
+     name: SHIKI_TRANSFORMER_LINE_NUMBER,
+-    preTransformer: ({ code }) => {
+-      const lineOptions = [] as TLineOptions;
+-
++    preprocess: code => {
++      const lineOptions: TransformerCompactLineOption[] = [];
+       code.split('\n').forEach((_, idx) => {
+         const lineNumber = idx + 1;
+         lineOptions.push({
+@@ -28,16 +36,21 @@ export function createTransformerLineNumber(
+           classes: [classActiveLine],
+         });
+       });
+-
+       lineOptions.pop();
+-
+-      return {
+-        code,
+-        lineOptions,
+-      };
++      lineOptionsMapper.set(code, lineOptions);
++      return code;
++    },
++    pre(pre) {
++      return this.addClassToHast(pre, classActivePre);
+     },
+-    postTransformer: ({ code }) => {
+-      return addClass(code, classActivePre, 'pre');
++    line(node, line) {
++      const lineOption = lineOptionsMapper
++        .get(this.source)
++        ?.find(o => o.line === line);
++      if (lineOption?.classes) {
++        this.addClassToHast(node, lineOption.classes);
++      }
++      return node;
+     },
+   };
+ }
+diff --git a/packages/plugin-shiki/src/shiki/types.ts b/packages/plugin-shiki/src/shiki/types.ts
+deleted file mode 100644
+index 7ca7e9e1..00000000
+--- 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 5b4550bf..00000000
+--- 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 2f93f466..00000000
+--- 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 9fb33fa1..00000000
+--- 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 12bfbb96..00000000
+--- 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 0dd42b84..22cd2c81 100644
+--- a/pnpm-lock.yaml
++++ b/pnpm-lock.yaml
+@@ -420,6 +420,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
+@@ -1311,8 +1314,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
+@@ -2976,6 +2979,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==}
+ 
+@@ -3799,6 +3820,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==}
+ 
+@@ -4231,12 +4255,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==}
+ 
+@@ -4277,6 +4307,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==}
+ 
+@@ -4754,6 +4787,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==}
+ 
+@@ -4836,6 +4872,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==}
+ 
+@@ -4854,6 +4893,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==}
+ 
+@@ -4869,15 +4911,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==}
+ 
+@@ -5016,6 +5067,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'}
+@@ -5460,6 +5514,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==}
+ 
+@@ -5805,6 +5868,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==}
+ 
+@@ -6193,6 +6259,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==}
+ 
+@@ -7931,6 +8000,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':
+@@ -8836,6 +8936,8 @@ snapshots:
+ 
+   electron-to-chromium@1.5.38: {}
+ 
++  emoji-regex-xs@1.0.0: {}
++
+   emoji-regex@10.4.0: {}
+ 
+   emoji-regex@8.0.0: {}
+@@ -9395,6 +9497,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
+@@ -9406,6 +9522,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
+@@ -9457,6 +9577,8 @@ snapshots:
+ 
+   html-void-elements@2.0.1: {}
+ 
++  html-void-elements@3.0.0: {}
++
+   htmlparser2@6.1.0:
+     dependencies:
+       domelementtype: 2.3.0
+@@ -9992,6 +10114,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
+@@ -10201,6 +10335,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
+@@ -10229,6 +10368,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
+@@ -10256,6 +10397,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
+@@ -10265,8 +10412,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
+@@ -10440,6 +10591,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
+@@ -10900,6 +11057,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
+@@ -11252,6 +11419,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: {}
+@@ -11649,6 +11825,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