diff --git a/CHANGELOG.md b/CHANGELOG.md index 99edf822..7d630958 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## [2.0.0-alpha.2](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.1...v2.0.0-alpha.2) (2025-01-23) + +### Bug Fixes + +- fix docsearch navigation and rendering ([e035027](https://github.com/vuejs/vitepress/commit/e0350275b39258a61ee867840ce1c6f5b2cecf2a)) +- **types:** support preload built-in shiki languages as string ([#4513](https://github.com/vuejs/vitepress/issues/4513)) ([4f77b4f](https://github.com/vuejs/vitepress/commit/4f77b4fdfdbe945e482348a57731bff5fb4672fc)) + +### Features + +- allow `markdown.config` and `markdown.preConfig` to accept async function ([#4512](https://github.com/vuejs/vitepress/issues/4512)) ([b88ae8d](https://github.com/vuejs/vitepress/commit/b88ae8d4a11a20104b2007c2631eb7aeb123d965)) +- support same page navigation in `router.go` and expose decoded hash and query from the `route` object ([#4511](https://github.com/vuejs/vitepress/issues/4511)) ([23d3281](https://github.com/vuejs/vitepress/commit/23d3281ed6f1111ab15708ca1fd86202674f8ef7)) + ## [2.0.0-alpha.1](https://github.com/vuejs/vitepress/compare/v1.6.2...v2.0.0-alpha.1) (2025-01-22) ### Features diff --git a/__tests__/e2e/.vitepress/config.ts b/__tests__/e2e/.vitepress/config.ts index 65f845ab..43dbfa84 100644 --- a/__tests__/e2e/.vitepress/config.ts +++ b/__tests__/e2e/.vitepress/config.ts @@ -165,8 +165,8 @@ export default defineConfig({ search: { provider: 'local', options: { - _render(src, env, md) { - const html = md.render(src, env) + async _render(src, env, md) { + const html = await md.renderAsync(src, env) if (env.frontmatter?.search === false) return '' if (env.relativePath.startsWith('local-search/excluded')) return '' return html diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts index 7208825e..0e7ba37f 100644 --- a/docs/.vitepress/theme/index.ts +++ b/docs/.vitepress/theme/index.ts @@ -1,4 +1,5 @@ import Theme from 'vitepress/theme' import 'virtual:group-icons.css' +import './styles.css' export default Theme diff --git a/docs/.vitepress/theme/styles.css b/docs/.vitepress/theme/styles.css new file mode 100644 index 00000000..1c4b3af5 --- /dev/null +++ b/docs/.vitepress/theme/styles.css @@ -0,0 +1,40 @@ +@import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@100..900&display=swap'); + +:root:where(:lang(fa)) { + --vp-font-family-base: 'Vazirmatn', 'Inter', ui-sans-serif, system-ui, + sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', + 'Noto Color Emoji'; +} + +:root { + --vp-home-hero-name-color: transparent; + --vp-home-hero-name-background: -webkit-linear-gradient( + 120deg, + #bd34fe 30%, + #41d1ff + ); + --vp-home-hero-image-background-image: linear-gradient( + -45deg, + #bd34fe 50%, + #47caff 50% + ); + --vp-home-hero-image-filter: blur(44px); +} + +@media (min-width: 640px) { + :root { + --vp-home-hero-image-filter: blur(56px); + } +} + +@media (min-width: 960px) { + :root { + --vp-home-hero-image-filter: blur(68px); + } +} + +/* used in reference/default-theme-search */ +img[src='/search.png'] { + width: 100%; + aspect-ratio: 1 / 1; +} diff --git a/docs/en/index.md b/docs/en/index.md index 9be32c3e..d65ee07b 100644 --- a/docs/en/index.md +++ b/docs/en/index.md @@ -36,25 +36,3 @@ features: title: Ship Fast Sites details: Fast initial load with static HTML, fast post-load navigation with client-side routing. --- - - diff --git a/docs/en/reference/default-theme-search.md b/docs/en/reference/default-theme-search.md index 16bb9289..d647e32e 100644 --- a/docs/en/reference/default-theme-search.md +++ b/docs/en/reference/default-theme-search.md @@ -124,9 +124,9 @@ export default defineConfig({ /** * @param {string} src * @param {import('vitepress').MarkdownEnv} env - * @param {import('markdown-it')} md + * @param {import('markdown-it-async')} md */ - _render(src, env, md) { + async _render(src, env, md) { // return html string } } @@ -149,8 +149,8 @@ export default defineConfig({ search: { provider: 'local', options: { - _render(src, env, md) { - const html = md.render(src, env) + async _render(src, env, md) { + const html = await md.renderAsync(src, env) if (env.frontmatter?.search === false) return '' if (env.relativePath.startsWith('some/path')) return '' return html @@ -162,7 +162,7 @@ export default defineConfig({ ``` ::: warning Note -In case a custom `_render` function is provided, you need to handle the `search: false` frontmatter yourself. Also, the `env` object won't be completely populated before `md.render` is called, so any checks on optional `env` properties like `frontmatter` should be done after that. +In case a custom `_render` function is provided, you need to handle the `search: false` frontmatter yourself. Also, the `env` object won't be completely populated before `md.renderAsync` is called, so any checks on optional `env` properties like `frontmatter` should be done after that. ::: #### Example: Transforming content - adding anchors @@ -175,10 +175,10 @@ export default defineConfig({ search: { provider: 'local', options: { - _render(src, env, md) { - const html = md.render(src, env) + async _render(src, env, md) { + const html = await md.renderAsync(src, env) if (env.frontmatter?.title) - return md.render(`# ${env.frontmatter.title}`) + html + return await md.renderAsync(`# ${env.frontmatter.title}`) + html return html } } @@ -381,10 +381,3 @@ new Crawler({ } }) ``` - - diff --git a/docs/es/index.md b/docs/es/index.md index bf9701e5..6ced6057 100644 --- a/docs/es/index.md +++ b/docs/es/index.md @@ -36,25 +36,3 @@ features: title: Entrega rápida de sitios details: Carga inicial rápida con HTML estático, navegación rápida con enrutamiento del lado del cliente. --- - - diff --git a/docs/es/reference/default-theme-search.md b/docs/es/reference/default-theme-search.md index 5a654705..3059b0ba 100644 --- a/docs/es/reference/default-theme-search.md +++ b/docs/es/reference/default-theme-search.md @@ -113,9 +113,9 @@ export default defineConfig({ /** * @param {string} src * @param {import('vitepress').MarkdownEnv} env - * @param {import('markdown-it')} md + * @param {import('markdown-it-async')} md */ - _render(src, env, md) { + async _render(src, env, md) { // retorne un string HTML } } @@ -138,8 +138,8 @@ export default defineConfig({ search: { provider: 'local', options: { - _render(src, env, md) { - const html = md.render(src, env) + async _render(src, env, md) { + const html = await md.renderAsync(src, env) if (env.frontmatter?.search === false) return '' if (env.relativePath.startsWith('algum/caminho')) return '' return html @@ -151,7 +151,7 @@ export default defineConfig({ ``` ::: warning Nota -En este caso, una función `_render` se proporciona, es necesario manipular el `search: false` desde el frente por su cuenta. Además, el objeto `env` no estará completamente poblado antes que `md.render` se llama, luego verifica las propiedades opcionales `env`, como `frontmatter`, debe hacerse después de eso. +En este caso, una función `_render` se proporciona, es necesario manipular el `search: false` desde el frente por su cuenta. Además, el objeto `env` no estará completamente poblado antes que `md.renderAsync` se llama, luego verifica las propiedades opcionales `env`, como `frontmatter`, debe hacerse después de eso. ::: #### Ejemplo: Transformar contenido - agregar anclajes {#example-transforming-content-adding-anchors} @@ -164,10 +164,10 @@ export default defineConfig({ search: { provider: 'local', options: { - _render(src, env, md) { - const html = md.render(src, env) + async _render(src, env, md) { + const html = await md.renderAsync(src, env) if (env.frontmatter?.title) - return md.render(`# ${env.frontmatter.title}`) + html + return await md.renderAsync(`# ${env.frontmatter.title}`) + html return html } } @@ -370,10 +370,3 @@ new Crawler({ } }) ``` - - diff --git a/docs/fa/index.md b/docs/fa/index.md index 3b0fabd7..1637397f 100644 --- a/docs/fa/index.md +++ b/docs/fa/index.md @@ -36,30 +36,3 @@ features: title: ارسال سایت های سریع details: بارگذاری اولیه سریع با HTML ایستا، ناوبری سریع پس از بارگیری با مسیریابی سمت کلاینت --- - - diff --git a/docs/fa/reference/default-theme-search.md b/docs/fa/reference/default-theme-search.md index dd325c9f..2694a291 100644 --- a/docs/fa/reference/default-theme-search.md +++ b/docs/fa/reference/default-theme-search.md @@ -120,9 +120,9 @@ export default defineConfig({ /** * @param {string} src * @param {import('vitepress').MarkdownEnv} env - * @param {import('markdown-it')} md + * @param {import('markdown-it-async')} md */ - _render(src, env, md) { + async _render(src, env, md) { // بازگشت رشته HTML } } @@ -145,8 +145,8 @@ export default defineConfig({ search: { provider: 'local', options: { - _render(src, env, md) { - const html = md.render(src, env) + async _render(src, env, md) { + const html = await md.renderAsync(src, env) if (env.frontmatter?.search === false) return '' if (env.relativePath.startsWith('some/path')) return '' return html @@ -158,7 +158,7 @@ export default defineConfig({ ``` ::: warning توجه -در صورت ارائه تابع `_render` سفارشی، باید خودتان بررسی کنید که آیا frontmatter `search: false` را مدیریت می‌کند یا خیر. همچنین، شی env قبل از فراخوانی `md.render` کاملاً پر نمی‌شود، بنابراین هر بررسی‌ای روی ویژگی‌های اختیاری env مانند `frontmatter` باید بعد از آن انجام شود. +در صورت ارائه تابع `_render` سفارشی، باید خودتان بررسی کنید که آیا frontmatter `search: false` را مدیریت می‌کند یا خیر. همچنین، شی env قبل از فراخوانی `md.renderAsync` کاملاً پر نمی‌شود، بنابراین هر بررسی‌ای روی ویژگی‌های اختیاری env مانند `frontmatter` باید بعد از آن انجام شود. ::: #### مثال: تبدیل محتوا - افزودن لینک‌های صفحه {#example-transforming-content-adding-anchors} @@ -171,10 +171,10 @@ export default defineConfig({ search: { provider: 'local', options: { - _render(src, env, md) { - const html = md.render(src, env) + async _render(src, env, md) { + const html = await md.renderAsync(src, env) if (env.frontmatter?.title) - return md.render(`# ${env.frontmatter.title}`) + html + return await md.renderAsync(`# ${env.frontmatter.title}`) + html return html } } @@ -377,10 +377,3 @@ new Crawler({ } }) ``` - - \ No newline at end of file diff --git a/docs/ko/index.md b/docs/ko/index.md index 50e56e4c..6a16ff49 100644 --- a/docs/ko/index.md +++ b/docs/ko/index.md @@ -36,25 +36,3 @@ features: title: 웹사이트를 빠르게 제공 details: 정적 HTML로 빠른 초기 로딩, 클라이언트 측 라우팅을 통한 빠른 탐색. --- - - diff --git a/docs/ko/reference/default-theme-search.md b/docs/ko/reference/default-theme-search.md index da1feb42..69b633aa 100644 --- a/docs/ko/reference/default-theme-search.md +++ b/docs/ko/reference/default-theme-search.md @@ -120,9 +120,9 @@ export default defineConfig({ /** * @param {string} src * @param {import('vitepress').MarkdownEnv} env - * @param {import('markdown-it')} md + * @param {import('markdown-it-async')} md */ - _render(src, env, md) { + async _render(src, env, md) { // return html string } } @@ -145,8 +145,8 @@ export default defineConfig({ search: { provider: 'local', options: { - _render(src, env, md) { - const html = md.render(src, env) + async _render(src, env, md) { + const html = await md.renderAsync(src, env) if (env.frontmatter?.search === false) return '' if (env.relativePath.startsWith('some/path')) return '' return html @@ -158,7 +158,7 @@ export default defineConfig({ ``` ::: warning 참고 -커스텀 `_render` 함수가 제공된 경우, `search: false` 전문을 직접 처리해야 합니다. 또한, `md.render`가 호출되기 전에 `env` 객체가 완전히 채워지지 않으므로, `frontmatter`와 같은 선택적 `env` 프로퍼티에 대한 검사는 그 이후에 수행해야 합니다. +커스텀 `_render` 함수가 제공된 경우, `search: false` 전문을 직접 처리해야 합니다. 또한, `md.renderAsync`가 호출되기 전에 `env` 객체가 완전히 채워지지 않으므로, `frontmatter`와 같은 선택적 `env` 프로퍼티에 대한 검사는 그 이후에 수행해야 합니다. ::: #### 예제: 콘텐츠 변환 - 앵커 추가 {#example-transforming-content-adding-anchors} @@ -171,10 +171,10 @@ export default defineConfig({ search: { provider: 'local', options: { - _render(src, env, md) { - const html = md.render(src, env) + async _render(src, env, md) { + const html = await md.renderAsync(src, env) if (env.frontmatter?.title) - return md.render(`# ${env.frontmatter.title}`) + html + return await md.renderAsync(`# ${env.frontmatter.title}`) + html return html } } @@ -377,10 +377,3 @@ new Crawler({ } }) ``` - - diff --git a/docs/pt/index.md b/docs/pt/index.md index 3f979dca..fccf03a0 100644 --- a/docs/pt/index.md +++ b/docs/pt/index.md @@ -36,25 +36,3 @@ features: title: Entregue Sites Rápidos details: Carregamento inicial rápido com HTML estático, navegação rápida com roteamento no lado do cliente. --- - - diff --git a/docs/pt/reference/default-theme-search.md b/docs/pt/reference/default-theme-search.md index e7347afa..c16406cb 100644 --- a/docs/pt/reference/default-theme-search.md +++ b/docs/pt/reference/default-theme-search.md @@ -113,9 +113,9 @@ export default defineConfig({ /** * @param {string} src * @param {import('vitepress').MarkdownEnv} env - * @param {import('markdown-it')} md + * @param {import('markdown-it-async')} md */ - _render(src, env, md) { + async _render(src, env, md) { // retorne a string HTML } } @@ -138,8 +138,8 @@ export default defineConfig({ search: { provider: 'local', options: { - _render(src, env, md) { - const html = md.render(src, env) + async _render(src, env, md) { + const html = await md.renderAsync(src, env) if (env.frontmatter?.search === false) return '' if (env.relativePath.startsWith('algum/caminho')) return '' return html @@ -151,7 +151,7 @@ export default defineConfig({ ``` ::: warning Nota -No caso uma função `_render` personalizada ser fornecida, você precisa manipular o `search: false` do frontmatter por conta própria. Além disso, o objeto `env` não estará completamente populado antes que `md.render` seja chamado, então verificações em propriedades opcionais `env`, como `frontmatter`, devem ser feitas após isso. +No caso uma função `_render` personalizada ser fornecida, você precisa manipular o `search: false` do frontmatter por conta própria. Além disso, o objeto `env` não estará completamente populado antes que `md.renderAsync` seja chamado, então verificações em propriedades opcionais `env`, como `frontmatter`, devem ser feitas após isso. ::: #### Exemplo: Transformando conteúdo - adicionando âncoras {#example-transforming-content-adding-anchors} @@ -164,10 +164,10 @@ export default defineConfig({ search: { provider: 'local', options: { - _render(src, env, md) { - const html = md.render(src, env) + async _render(src, env, md) { + const html = await md.renderAsync(src, env) if (env.frontmatter?.title) - return md.render(`# ${env.frontmatter.title}`) + html + return await md.renderAsync(`# ${env.frontmatter.title}`) + html return html } } @@ -370,10 +370,3 @@ new Crawler({ } }) ``` - - diff --git a/docs/ru/index.md b/docs/ru/index.md index 5d2e52e5..ecddc946 100644 --- a/docs/ru/index.md +++ b/docs/ru/index.md @@ -36,25 +36,3 @@ features: title: Быстрый запуск веб-сайтов details: Быстрая начальная загрузка с помощью статического HTML, быстрая навигация после загрузки с помощью маршрутизации на стороне клиента. --- - - diff --git a/docs/ru/reference/default-theme-search.md b/docs/ru/reference/default-theme-search.md index c91e4be4..bab3fa9e 100644 --- a/docs/ru/reference/default-theme-search.md +++ b/docs/ru/reference/default-theme-search.md @@ -124,9 +124,9 @@ export default defineConfig({ /** * @param {string} src * @param {import('vitepress').MarkdownEnv} env - * @param {import('markdown-it')} md + * @param {import('markdown-it-async')} md */ - _render(src, env, md) { + async _render(src, env, md) { // возвращаем html } } @@ -149,8 +149,8 @@ export default defineConfig({ search: { provider: 'local', options: { - _render(src, env, md) { - const html = md.render(src, env) + async _render(src, env, md) { + const html = await md.renderAsync(src, env) if (env.frontmatter?.search === false) return '' if (env.relativePath.startsWith('some/path')) return '' return html @@ -162,7 +162,7 @@ export default defineConfig({ ``` ::: warning ПРИМЕЧАНИЕ -В случае, если предоставляется пользовательская функция `_render`, вам нужно самостоятельно обработать заголовок `search: false`. Кроме того, объект `env` не будет полностью заполнен до вызова `md.render`, поэтому любые проверки необязательных свойств `env`, таких как `frontmatter`, должны быть выполнены после этого. +В случае, если предоставляется пользовательская функция `_render`, вам нужно самостоятельно обработать заголовок `search: false`. Кроме того, объект `env` не будет полностью заполнен до вызова `md.renderAsync`, поэтому любые проверки необязательных свойств `env`, таких как `frontmatter`, должны быть выполнены после этого. ::: #### Пример: Преобразование содержимого - добавление якорей {#example-transforming-content-adding-anchors} @@ -175,10 +175,10 @@ export default defineConfig({ search: { provider: 'local', options: { - _render(src, env, md) { - const html = md.render(src, env) + async _render(src, env, md) { + const html = await md.renderAsync(src, env) if (env.frontmatter?.title) - return md.render(`# ${env.frontmatter.title}`) + html + return await md.renderAsync(`# ${env.frontmatter.title}`) + html return html } } @@ -384,10 +384,3 @@ new Crawler({ } }) ``` - - diff --git a/docs/zh/index.md b/docs/zh/index.md index 23299c1f..81f71c16 100644 --- a/docs/zh/index.md +++ b/docs/zh/index.md @@ -36,24 +36,3 @@ features: title: 速度真的很快! details: 采用静态 HTML 实现快速的页面初次加载,使用客户端路由实现快速的页面切换导航。 --- - diff --git a/docs/zh/reference/default-theme-search.md b/docs/zh/reference/default-theme-search.md index e19f052a..31af2c9d 100644 --- a/docs/zh/reference/default-theme-search.md +++ b/docs/zh/reference/default-theme-search.md @@ -113,9 +113,9 @@ export default defineConfig({ /** * @param {string} src * @param {import('vitepress').MarkdownEnv} env - * @param {import('markdown-it')} md + * @param {import('markdown-it-async')} md */ - _render(src, env, md) { + async _render(src, env, md) { // 返回 html 字符串 } } @@ -138,8 +138,8 @@ export default defineConfig({ search: { provider: 'local', options: { - _render(src, env, md) { - const html = md.render(src, env) + async _render(src, env, md) { + const html = await md.renderAsync(src, env) if (env.frontmatter?.search === false) return '' if (env.relativePath.startsWith('some/path')) return '' return html @@ -151,7 +151,7 @@ export default defineConfig({ ``` ::: warning 注意 -如果提供了自定义的 `_render` 函数,你需要自己处理 `search: false` 的 frontmatter。此外,在调用 `md.render` 之前,`env` 对象不会完全填充,因此对可选 `env` 属性 (如 `frontmatter`) 的任何检查都应该在此之后完成。 +如果提供了自定义的 `_render` 函数,你需要自己处理 `search: false` 的 frontmatter。此外,在调用 `md.renderAsync` 之前,`env` 对象不会完全填充,因此对可选 `env` 属性 (如 `frontmatter`) 的任何检查都应该在此之后完成。 ::: #### 示例:转换内容——添加锚点 {#example-transforming-content-adding-anchors} @@ -164,10 +164,10 @@ export default defineConfig({ search: { provider: 'local', options: { - _render(src, env, md) { - const html = md.render(src, env) + async _render(src, env, md) { + const html = await md.renderAsync(src, env) if (env.frontmatter?.title) - return md.render(`# ${env.frontmatter.title}`) + html + return await md.renderAsync(`# ${env.frontmatter.title}`) + html return html } } @@ -370,10 +370,3 @@ new Crawler({ } }) ``` - - diff --git a/package.json b/package.json index 167ffb98..d43c1684 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vitepress", - "version": "2.0.0-alpha.1", + "version": "2.0.0-alpha.2", "description": "Vite & Vue powered static site generator", "keywords": [ "vite", @@ -101,12 +101,11 @@ "@shikijs/core": "^2.1.0", "@shikijs/transformers": "^2.1.0", "@shikijs/types": "^2.1.0", - "@types/markdown-it": "^14.1.2", "@vitejs/plugin-vue": "^5.2.1", "@vue/devtools-api": "^7.7.0", "@vue/shared": "^3.5.13", - "@vueuse/core": "^12.4.0", - "@vueuse/integrations": "^12.4.0", + "@vueuse/core": "^12.5.0", + "@vueuse/integrations": "^12.5.0", "focus-trap": "^7.6.4", "mark.js": "8.11.1", "minisearch": "^7.1.1", @@ -135,11 +134,12 @@ "@types/fs-extra": "^11.0.4", "@types/lodash.template": "^4.5.3", "@types/mark.js": "^8.11.12", + "@types/markdown-it": "^14.1.2", "@types/markdown-it-attrs": "^4.1.3", "@types/markdown-it-container": "^2.0.10", "@types/markdown-it-emoji": "^3.0.1", "@types/minimist": "^1.2.5", - "@types/node": "^22.10.7", + "@types/node": "^22.10.9", "@types/picomatch": "^3.0.2", "@types/postcss-prefix-selector": "^1.16.3", "@types/prompts": "^2.4.9", @@ -152,11 +152,12 @@ "fs-extra": "^11.3.0", "get-port": "^7.1.0", "gray-matter": "^4.0.3", - "lint-staged": "^15.4.1", + "lint-staged": "^15.4.2", "lodash.template": "^4.5.0", "lru-cache": "^11.0.2", "markdown-it": "^14.1.0", "markdown-it-anchor": "^9.2.0", + "markdown-it-async": "^2.0.0", "markdown-it-attrs": "^4.3.1", "markdown-it-container": "^4.0.0", "markdown-it-emoji": "^3.0.0", @@ -169,7 +170,7 @@ "picocolors": "^1.1.1", "picomatch": "^4.0.2", "pkg-dir": "^8.0.0", - "playwright-chromium": "^1.49.1", + "playwright-chromium": "^1.50.0", "polka": "^1.0.0-next.28", "postcss-prefix-selector": "^2.1.0", "prettier": "^3.4.2", @@ -183,10 +184,9 @@ "simple-git-hooks": "^2.11.1", "sirv": "^3.0.0", "sitemap": "^8.0.0", - "synckit": "^0.9.2", "tinyglobby": "^0.2.10", "typescript": "^5.7.3", - "vitest": "^3.0.3", + "vitest": "^3.0.4", "vue-tsc": "^2.2.0", "wait-on": "^8.0.2" }, @@ -215,7 +215,8 @@ "ora>string-width": "^5" }, "patchedDependencies": { - "@types/mdurl@2.0.0": "patches/@types__mdurl@2.0.0.patch" + "@types/mdurl@2.0.0": "patches/@types__mdurl@2.0.0.patch", + "markdown-it-anchor@9.2.0": "patches/markdown-it-anchor@9.2.0.patch" } } } diff --git a/patches/markdown-it-anchor@9.2.0.patch b/patches/markdown-it-anchor@9.2.0.patch new file mode 100644 index 00000000..ac4498e4 --- /dev/null +++ b/patches/markdown-it-anchor@9.2.0.patch @@ -0,0 +1,17 @@ +diff --git a/types/index.d.ts b/types/index.d.ts +index 40c25c0be1add8b0fc2c51489c25a423dbc49d2c..807bc1b0e434d660c6a298b1dee1c87935bfac86 100644 +--- a/types/index.d.ts ++++ b/types/index.d.ts +@@ -1,10 +1,8 @@ + import MarkdownIt from 'markdown-it'; +-import { default as MarkdownItToken } from 'markdown-it/lib/token.mjs'; +-import { default as MarkdownItState} from 'markdown-it/lib/rules_core/state_core.mjs'; ++import { default as Token } from 'markdown-it/lib/token.mjs'; ++import { default as State } from 'markdown-it/lib/rules_core/state_core.mjs'; + + declare namespace anchor { +- export type Token = MarkdownItToken +- export type State = MarkdownItState + export type RenderHref = (slug: string, state: State) => string; + export type RenderAttrs = (slug: string, state: State) => Record; + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 33fc3990..d4bdaf17 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ patchedDependencies: '@types/mdurl@2.0.0': hash: ztuyknm7z4pyl4jot5hljjv5bm path: patches/@types__mdurl@2.0.0.patch + markdown-it-anchor@9.2.0: + hash: ivrlfano2jj27ilcyyknwlzzfu + path: patches/markdown-it-anchor@9.2.0.patch importers: @@ -21,7 +24,7 @@ importers: version: 3.8.3 '@docsearch/js': specifier: ^3.8.3 - version: 3.8.3(@algolia/client-search@5.19.0) + version: 3.8.3(@algolia/client-search@5.20.0) '@iconify-json/simple-icons': specifier: ^1.2.21 version: 1.2.21 @@ -34,12 +37,9 @@ importers: '@shikijs/types': specifier: ^2.1.0 version: 2.1.0 - '@types/markdown-it': - specifier: ^14.1.2 - version: 14.1.2 '@vitejs/plugin-vue': specifier: ^5.2.1 - version: 5.2.1(vite@6.0.11(@types/node@22.10.7)(jiti@1.21.7)(yaml@2.6.1))(vue@3.5.13(typescript@5.7.3)) + version: 5.2.1(vite@6.0.11(@types/node@22.10.9)(jiti@1.21.7)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3)) '@vue/devtools-api': specifier: ^7.7.0 version: 7.7.0 @@ -47,11 +47,11 @@ importers: specifier: ^3.5.13 version: 3.5.13 '@vueuse/core': - specifier: ^12.4.0 - version: 12.4.0(typescript@5.7.3) + specifier: ^12.5.0 + version: 12.5.0(typescript@5.7.3) '@vueuse/integrations': - specifier: ^12.4.0 - version: 12.4.0(axios@1.7.9(debug@4.4.0))(focus-trap@7.6.4)(typescript@5.7.3) + specifier: ^12.5.0 + version: 12.5.0(axios@1.7.9(debug@4.4.0))(focus-trap@7.6.4)(typescript@5.7.3) focus-trap: specifier: ^7.6.4 version: 7.6.4 @@ -66,7 +66,7 @@ importers: version: 2.1.0 vite: specifier: ^6.0.11 - version: 6.0.11(@types/node@22.10.7)(jiti@1.21.7)(yaml@2.6.1) + version: 6.0.11(@types/node@22.10.9)(jiti@1.21.7)(yaml@2.7.0) vue: specifier: ^3.5.13 version: 3.5.13(typescript@5.7.3) @@ -131,6 +131,9 @@ importers: '@types/mark.js': specifier: ^8.11.12 version: 8.11.12 + '@types/markdown-it': + specifier: ^14.1.2 + version: 14.1.2 '@types/markdown-it-attrs': specifier: ^4.1.3 version: 4.1.3 @@ -144,8 +147,8 @@ importers: specifier: ^1.2.5 version: 1.2.5 '@types/node': - specifier: ^22.10.7 - version: 22.10.7 + specifier: ^22.10.9 + version: 22.10.9 '@types/picomatch': specifier: ^3.0.2 version: 3.0.2 @@ -183,8 +186,8 @@ importers: specifier: ^4.0.3 version: 4.0.3 lint-staged: - specifier: ^15.4.1 - version: 15.4.1 + specifier: ^15.4.2 + version: 15.4.2 lodash.template: specifier: ^4.5.0 version: 4.5.0 @@ -196,7 +199,10 @@ importers: version: 14.1.0 markdown-it-anchor: specifier: ^9.2.0 - version: 9.2.0(@types/markdown-it@14.1.2)(markdown-it@14.1.0) + version: 9.2.0(patch_hash=ivrlfano2jj27ilcyyknwlzzfu)(@types/markdown-it@14.1.2)(markdown-it@14.1.0) + markdown-it-async: + specifier: ^2.0.0 + version: 2.0.0 markdown-it-attrs: specifier: ^4.3.1 version: 4.3.1(markdown-it@14.1.0) @@ -234,8 +240,8 @@ importers: specifier: ^8.0.0 version: 8.0.0 playwright-chromium: - specifier: ^1.49.1 - version: 1.49.1 + specifier: ^1.50.0 + version: 1.50.0 polka: specifier: ^1.0.0-next.28 version: 1.0.0-next.28 @@ -275,9 +281,6 @@ importers: sitemap: specifier: ^8.0.0 version: 8.0.0 - synckit: - specifier: ^0.9.2 - version: 0.9.2 tinyglobby: specifier: ^0.2.10 version: 0.2.10 @@ -285,8 +288,8 @@ importers: specifier: ^5.7.3 version: 5.7.3 vitest: - specifier: ^3.0.3 - version: 3.0.3(@types/node@22.10.7)(jiti@1.21.7)(yaml@2.6.1) + specifier: ^3.0.4 + version: 3.0.4(@types/debug@4.1.12)(@types/node@22.10.9)(jiti@1.21.7)(yaml@2.7.0) vue-tsc: specifier: ^2.2.0 version: 2.2.0(typescript@5.7.3) @@ -349,56 +352,56 @@ packages: '@algolia/client-search': '>= 4.9.1 < 6' algoliasearch: '>= 4.9.1 < 6' - '@algolia/client-abtesting@5.19.0': - resolution: {integrity: sha512-dMHwy2+nBL0SnIsC1iHvkBao64h4z+roGelOz11cxrDBrAdASxLxmfVMop8gmodQ2yZSacX0Rzevtxa+9SqxCw==} + '@algolia/client-abtesting@5.20.0': + resolution: {integrity: sha512-YaEoNc1Xf2Yk6oCfXXkZ4+dIPLulCx8Ivqj0OsdkHWnsI3aOJChY5qsfyHhDBNSOhqn2ilgHWxSfyZrjxBcAww==} engines: {node: '>= 14.0.0'} - '@algolia/client-analytics@5.19.0': - resolution: {integrity: sha512-CDW4RwnCHzU10upPJqS6N6YwDpDHno7w6/qXT9KPbPbt8szIIzCHrva4O9KIfx1OhdsHzfGSI5hMAiOOYl4DEQ==} + '@algolia/client-analytics@5.20.0': + resolution: {integrity: sha512-CIT9ni0+5sYwqehw+t5cesjho3ugKQjPVy/iPiJvtJX4g8Cdb6je6SPt2uX72cf2ISiXCAX9U3cY0nN0efnRDw==} engines: {node: '>= 14.0.0'} - '@algolia/client-common@5.19.0': - resolution: {integrity: sha512-2ERRbICHXvtj5kfFpY5r8qu9pJII/NAHsdgUXnUitQFwPdPL7wXiupcvZJC7DSntOnE8AE0lM7oDsPhrJfj5nQ==} + '@algolia/client-common@5.20.0': + resolution: {integrity: sha512-iSTFT3IU8KNpbAHcBUJw2HUrPnMXeXLyGajmCL7gIzWOsYM4GabZDHXOFx93WGiXMti1dymz8k8R+bfHv1YZmA==} engines: {node: '>= 14.0.0'} - '@algolia/client-insights@5.19.0': - resolution: {integrity: sha512-xPOiGjo6I9mfjdJO7Y+p035aWePcbsItizIp+qVyfkfZiGgD+TbNxM12g7QhFAHIkx/mlYaocxPY/TmwPzTe+A==} + '@algolia/client-insights@5.20.0': + resolution: {integrity: sha512-w9RIojD45z1csvW1vZmAko82fqE/Dm+Ovsy2ElTsjFDB0HMAiLh2FO86hMHbEXDPz6GhHKgGNmBRiRP8dDPgJg==} engines: {node: '>= 14.0.0'} - '@algolia/client-personalization@5.19.0': - resolution: {integrity: sha512-B9eoce/fk8NLboGje+pMr72pw+PV7c5Z01On477heTZ7jkxoZ4X92dobeGuEQop61cJ93Gaevd1of4mBr4hu2A==} + '@algolia/client-personalization@5.20.0': + resolution: {integrity: sha512-p/hftHhrbiHaEcxubYOzqVV4gUqYWLpTwK+nl2xN3eTrSW9SNuFlAvUBFqPXSVBqc6J5XL9dNKn3y8OA1KElSQ==} engines: {node: '>= 14.0.0'} - '@algolia/client-query-suggestions@5.19.0': - resolution: {integrity: sha512-6fcP8d4S8XRDtVogrDvmSM6g5g6DndLc0pEm1GCKe9/ZkAzCmM3ZmW1wFYYPxdjMeifWy1vVEDMJK7sbE4W7MA==} + '@algolia/client-query-suggestions@5.20.0': + resolution: {integrity: sha512-m4aAuis5vZi7P4gTfiEs6YPrk/9hNTESj3gEmGFgfJw3hO2ubdS4jSId1URd6dGdt0ax2QuapXufcrN58hPUcw==} engines: {node: '>= 14.0.0'} - '@algolia/client-search@5.19.0': - resolution: {integrity: sha512-Ctg3xXD/1VtcwmkulR5+cKGOMj4r0wC49Y/KZdGQcqpydKn+e86F6l3tb3utLJQVq4lpEJud6kdRykFgcNsp8Q==} + '@algolia/client-search@5.20.0': + resolution: {integrity: sha512-KL1zWTzrlN4MSiaK1ea560iCA/UewMbS4ZsLQRPoDTWyrbDKVbztkPwwv764LAqgXk0fvkNZvJ3IelcK7DqhjQ==} engines: {node: '>= 14.0.0'} - '@algolia/ingestion@1.19.0': - resolution: {integrity: sha512-LO7w1MDV+ZLESwfPmXkp+KLeYeFrYEgtbCZG6buWjddhYraPQ9MuQWLhLLiaMlKxZ/sZvFTcZYuyI6Jx4WBhcg==} + '@algolia/ingestion@1.20.0': + resolution: {integrity: sha512-shj2lTdzl9un4XJblrgqg54DoK6JeKFO8K8qInMu4XhE2JuB8De6PUuXAQwiRigZupbI0xq8aM0LKdc9+qiLQA==} engines: {node: '>= 14.0.0'} - '@algolia/monitoring@1.19.0': - resolution: {integrity: sha512-Mg4uoS0aIKeTpu6iv6O0Hj81s8UHagi5TLm9k2mLIib4vmMtX7WgIAHAcFIaqIZp5D6s5EVy1BaDOoZ7buuJHA==} + '@algolia/monitoring@1.20.0': + resolution: {integrity: sha512-aF9blPwOhKtWvkjyyXh9P5peqmhCA1XxLBRgItT+K6pbT0q4hBDQrCid+pQZJYy4HFUKjB/NDDwyzFhj/rwKhw==} engines: {node: '>= 14.0.0'} - '@algolia/recommend@5.19.0': - resolution: {integrity: sha512-PbgrMTbUPlmwfJsxjFhal4XqZO2kpBNRjemLVTkUiti4w/+kzcYO4Hg5zaBgVqPwvFDNQ8JS4SS3TBBem88u+g==} + '@algolia/recommend@5.20.0': + resolution: {integrity: sha512-T6B/WPdZR3b89/F9Vvk6QCbt/wrLAtrGoL8z4qPXDFApQ8MuTFWbleN/4rHn6APWO3ps+BUePIEbue2rY5MlRw==} engines: {node: '>= 14.0.0'} - '@algolia/requester-browser-xhr@5.19.0': - resolution: {integrity: sha512-GfnhnQBT23mW/VMNs7m1qyEyZzhZz093aY2x8p0era96MMyNv8+FxGek5pjVX0b57tmSCZPf4EqNCpkGcGsmbw==} + '@algolia/requester-browser-xhr@5.20.0': + resolution: {integrity: sha512-t6//lXsq8E85JMenHrI6mhViipUT5riNhEfCcvtRsTV+KIBpC6Od18eK864dmBhoc5MubM0f+sGpKOqJIlBSCg==} engines: {node: '>= 14.0.0'} - '@algolia/requester-fetch@5.19.0': - resolution: {integrity: sha512-oyTt8ZJ4T4fYvW5avAnuEc6Laedcme9fAFryMD9ndUTIUe/P0kn3BuGcCLFjN3FDmdrETHSFkgPPf1hGy3sLCw==} + '@algolia/requester-fetch@5.20.0': + resolution: {integrity: sha512-FHxYGqRY+6bgjKsK4aUsTAg6xMs2S21elPe4Y50GB0Y041ihvw41Vlwy2QS6K9ldoftX4JvXodbKTcmuQxywdQ==} engines: {node: '>= 14.0.0'} - '@algolia/requester-node-http@5.19.0': - resolution: {integrity: sha512-p6t8ue0XZNjcRiqNkb5QAM0qQRAKsCiebZ6n9JjWA+p8fWf8BvnhO55y2fO28g3GW0Imj7PrAuyBuxq8aDVQwQ==} + '@algolia/requester-node-http@5.20.0': + resolution: {integrity: sha512-kmtQClq/w3vtPteDSPvaW9SPZL/xrIgMrxZyAgsFwrJk0vJxqyC5/hwHmrCraDnStnGSADnLpBf4SpZnwnkwWw==} engines: {node: '>= 14.0.0'} '@antfu/install-pkg@0.4.1': @@ -701,10 +704,6 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@pkgr/core@0.1.1': - resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@polka/compression@1.0.0-next.28': resolution: {integrity: sha512-aDmrBhgHJtxE+jy145WfhW9WmTAFmES/dNnn1LAs8UnnkFgBUj4T8I4ScQ9+rOkpDZStvnVP5iqhN3tvt7O1NA==} engines: {node: '>=6'} @@ -964,8 +963,8 @@ packages: '@types/node@17.0.45': resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} - '@types/node@22.10.7': - resolution: {integrity: sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==} + '@types/node@22.10.9': + resolution: {integrity: sha512-Ir6hwgsKyNESl/gLOcEz3krR4CBGgliDqBQ2ma4wIhEx0w+xnoeTq3tdrNw15kU3SxogDjOgv9sqdtLW8mIHaw==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -997,8 +996,8 @@ packages: '@types/web-bluetooth@0.0.20': resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} - '@ungap/structured-clone@1.2.1': - resolution: {integrity: sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==} + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} '@vitejs/plugin-vue@5.2.1': resolution: {integrity: sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==} @@ -1007,11 +1006,11 @@ packages: vite: ^5.0.0 || ^6.0.0 vue: ^3.2.25 - '@vitest/expect@3.0.3': - resolution: {integrity: sha512-SbRCHU4qr91xguu+dH3RUdI5dC86zm8aZWydbp961aIR7G8OYNN6ZiayFuf9WAngRbFOfdrLHCGgXTj3GtoMRQ==} + '@vitest/expect@3.0.4': + resolution: {integrity: sha512-Nm5kJmYw6P2BxhJPkO3eKKhGYKRsnqJqf+r0yOGRKpEP+bSCBDsjXgiu1/5QFrnPMEgzfC38ZEjvCFgaNBC0Eg==} - '@vitest/mocker@3.0.3': - resolution: {integrity: sha512-XT2XBc4AN9UdaxJAeIlcSZ0ILi/GzmG5G8XSly4gaiqIvPV3HMTSIDZWJVX6QRJ0PX1m+W8Cy0K9ByXNb/bPIA==} + '@vitest/mocker@3.0.4': + resolution: {integrity: sha512-gEef35vKafJlfQbnyOXZ0Gcr9IBUsMTyTLXsEQwuyYAerpHqvXhzdBnDFuHLpFqth3F7b6BaFr4qV/Cs1ULx5A==} peerDependencies: msw: ^2.4.9 vite: ^5.0.0 || ^6.0.0 @@ -1021,20 +1020,20 @@ packages: vite: optional: true - '@vitest/pretty-format@3.0.3': - resolution: {integrity: sha512-gCrM9F7STYdsDoNjGgYXKPq4SkSxwwIU5nkaQvdUxiQ0EcNlez+PdKOVIsUJvh9P9IeIFmjn4IIREWblOBpP2Q==} + '@vitest/pretty-format@3.0.4': + resolution: {integrity: sha512-ts0fba+dEhK2aC9PFuZ9LTpULHpY/nd6jhAQ5IMU7Gaj7crPCTdCFfgvXxruRBLFS+MLraicCuFXxISEq8C93g==} - '@vitest/runner@3.0.3': - resolution: {integrity: sha512-Rgi2kOAk5ZxWZlwPguRJFOBmWs6uvvyAAR9k3MvjRvYrG7xYvKChZcmnnpJCS98311CBDMqsW9MzzRFsj2gX3g==} + '@vitest/runner@3.0.4': + resolution: {integrity: sha512-dKHzTQ7n9sExAcWH/0sh1elVgwc7OJ2lMOBrAm73J7AH6Pf9T12Zh3lNE1TETZaqrWFXtLlx3NVrLRb5hCK+iw==} - '@vitest/snapshot@3.0.3': - resolution: {integrity: sha512-kNRcHlI4txBGztuJfPEJ68VezlPAXLRT1u5UCx219TU3kOG2DplNxhWLwDf2h6emwmTPogzLnGVwP6epDaJN6Q==} + '@vitest/snapshot@3.0.4': + resolution: {integrity: sha512-+p5knMLwIk7lTQkM3NonZ9zBewzVp9EVkVpvNta0/PlFWpiqLaRcF4+33L1it3uRUCh0BGLOaXPPGEjNKfWb4w==} - '@vitest/spy@3.0.3': - resolution: {integrity: sha512-7/dgux8ZBbF7lEIKNnEqQlyRaER9nkAL9eTmdKJkDO3hS8p59ATGwKOCUDHcBLKr7h/oi/6hP+7djQk8049T2A==} + '@vitest/spy@3.0.4': + resolution: {integrity: sha512-sXIMF0oauYyUy2hN49VFTYodzEAu744MmGcPR3ZBsPM20G+1/cSW/n1U+3Yu/zHxX2bIDe1oJASOkml+osTU6Q==} - '@vitest/utils@3.0.3': - resolution: {integrity: sha512-f+s8CvyzPtMFY1eZKkIHGhPsQgYo5qCm6O8KZoim9qm1/jT64qBgGpO5tHscNH6BzRHM+edLNOP+3vO8+8pE/A==} + '@vitest/utils@3.0.4': + resolution: {integrity: sha512-8BqC1ksYsHtbWH+DfpOAKrFw3jl3Uf9J7yeFh85Pz52IWuh1hBBtyfEbRNNZNjl8H8A5yMLH9/t+k7HIKzQcZQ==} '@volar/language-core@2.4.11': resolution: {integrity: sha512-lN2C1+ByfW9/JRPpqScuZt/4OrUUse57GLI6TbLgTIqBVemdl1wNcZ1qYGEo2+Gw8coYLgCy7SuKqn6IrQcQgg==} @@ -1094,11 +1093,11 @@ packages: '@vue/shared@3.5.13': resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} - '@vueuse/core@12.4.0': - resolution: {integrity: sha512-XnjQYcJwCsyXyIafyA6SvyN/OBtfPnjvJmbxNxQjCcyWD198urwm5TYvIUUyAxEAN0K7HJggOgT15cOlWFyLeA==} + '@vueuse/core@12.5.0': + resolution: {integrity: sha512-GVyH1iYqNANwcahAx8JBm6awaNgvR/SwZ1fjr10b8l1HIgDp82ngNbfzJUgOgWEoxjL+URAggnlilAEXwCOZtg==} - '@vueuse/integrations@12.4.0': - resolution: {integrity: sha512-EZm+TLoZMeEwDnccnEqB54CvvcVKbVnJubOF380HqdyZAxWfQ8egnFCESdlXWEIbxFgjfhcGfZUvQx5Nqw9Ofw==} + '@vueuse/integrations@12.5.0': + resolution: {integrity: sha512-HYLt8M6mjUfcoUOzyBcX2RjpfapIwHPBmQJtTmXOQW845Y/Osu9VuTJ5kPvnmWJ6IUa05WpblfOwZ+P0G4iZsQ==} peerDependencies: async-validator: ^4 axios: ^1 @@ -1138,11 +1137,11 @@ packages: universal-cookie: optional: true - '@vueuse/metadata@12.4.0': - resolution: {integrity: sha512-AhPuHs/qtYrKHUlEoNO6zCXufu8OgbR8S/n2oMw1OQuBQJ3+HOLQ+EpvXs+feOlZMa0p8QVvDWNlmcJJY8rW2g==} + '@vueuse/metadata@12.5.0': + resolution: {integrity: sha512-Ui7Lo2a7AxrMAXRF+fAp9QsXuwTeeZ8fIB9wsLHqzq9MQk+2gMYE2IGJW48VMJ8ecvCB3z3GsGLKLbSasQ5Qlg==} - '@vueuse/shared@12.4.0': - resolution: {integrity: sha512-9yLgbHVIF12OSCojnjTIoZL1+UA10+O4E1aD6Hpfo/DKVm5o3SZIwz6CupqGy3+IcKI8d6Jnl26EQj/YucnW0Q==} + '@vueuse/shared@12.5.0': + resolution: {integrity: sha512-vMpcL1lStUU6O+kdj6YdHDixh0odjPAUM15uJ9f7MY781jcYkIwFA4iv2EfoIPO6vBmvutI1HxxAwmf0cx5ISQ==} acorn@8.14.0: resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} @@ -1152,8 +1151,8 @@ packages: add-stream@1.0.0: resolution: {integrity: sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==} - algoliasearch@5.19.0: - resolution: {integrity: sha512-zrLtGhC63z3sVLDDKGW+SlCRN9eJHFTgdEmoAOpsVh6wgGL1GgTTDou7tpCBjevzgIvi3AIyDAQO3Xjbg5eqZg==} + algoliasearch@5.20.0: + resolution: {integrity: sha512-groO71Fvi5SWpxjI9Ia+chy0QBwT61mg6yxJV27f5YFf+Mw+STT75K6SHySpP8Co5LsCrtsbCH5dJZSRtkSKaQ==} engines: {node: '>= 14.0.0'} alien-signals@0.4.14: @@ -1290,8 +1289,8 @@ packages: comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} - commander@12.1.0: - resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + commander@13.1.0: + resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} engines: {node: '>=18'} commander@6.2.1: @@ -1840,8 +1839,8 @@ packages: linkify-it@5.0.0: resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} - lint-staged@15.4.1: - resolution: {integrity: sha512-P8yJuVRyLrm5KxCtFx+gjI5Bil+wO7wnTl7C3bXhvtTaAFGirzeB24++D0wGoUwxrUKecNiehemgCob9YL39NA==} + lint-staged@15.4.2: + resolution: {integrity: sha512-gCqzB/Li281uZJgReNci+oXXqUEdrFAQAzTE/LwoxxiEuP41vozNe4BATS+4ehdqkWn+Z6bGc3EDcBja3npBVw==} engines: {node: '>=18.12.0'} hasBin: true @@ -1895,6 +1894,9 @@ packages: '@types/markdown-it': '*' markdown-it: '*' + markdown-it-async@2.0.0: + resolution: {integrity: sha512-jBthmQR5MwXR9Y8Y0teRoZAenaKQMdjuTfpbNARqMBSRPvyzyXCVduHZHakyyhL3ugIacCobXJrO07t277sIjw==} + markdown-it-attrs@4.3.1: resolution: {integrity: sha512-/ko6cba+H6gdZ0DOw7BbNMZtfuJTRp9g/IrGIuz8lYc/EfnmWRpaR3CFPnNbVz0LDvF8Gf1hFGPqrQqq7De0rg==} engines: {node: '>=6'} @@ -2164,13 +2166,13 @@ packages: pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - playwright-chromium@1.49.1: - resolution: {integrity: sha512-XAQDkZ1Eem1OONhfS8B2LM2mgHG/i5jIxooxjvqjbF/9GnLnRTJHdQamNjo1e4FZvt7J0BFD/15+qAcT0eKlfA==} + playwright-chromium@1.50.0: + resolution: {integrity: sha512-gyI1ATjSCn0kCHCV8lGS65h0tRSlJvdlwgvXwY5EyUHW+YLPnOtnMaCiNmHgrcVK8ofsXWq3alaUfnmirNzBlA==} engines: {node: '>=18'} hasBin: true - playwright-core@1.49.1: - resolution: {integrity: sha512-BzmpVcs4kE2CH15rWfzpjzVGhWERJfmnXmniSyKeRZUs9Ws65m+RGIi7mjJK/euCegfn3i7jvqWeWyHe9y3Vgg==} + playwright-core@1.50.0: + resolution: {integrity: sha512-CXkSSlr4JaZs2tZHI40DsZUN/NIwgaUPsyLuOAaIZp2CyF2sN5MM5NJsyB188lFSSozFxQ5fPT4qM+f0tH/6wQ==} engines: {node: '>=18'} hasBin: true @@ -2482,10 +2484,6 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - synckit@0.9.2: - resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==} - engines: {node: ^14.18.0 || >=16.0.0} - tabbable@6.2.0: resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} @@ -2629,8 +2627,8 @@ packages: vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - vite-node@3.0.3: - resolution: {integrity: sha512-0sQcwhwAEw/UJGojbhOrnq3HtiZ3tC7BzpAa0lx3QaTX0S3YX70iGcik25UBdB96pmdwjyY2uyKNYruxCDmiEg==} + vite-node@3.0.4: + resolution: {integrity: sha512-7JZKEzcYV2Nx3u6rlvN8qdo3QV7Fxyt6hx+CCKz9fbWxdX5IvUOmTWEAxMrWxaiSf7CKGLJQ5rFu8prb/jBjOA==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true @@ -2677,20 +2675,23 @@ packages: vitepress-plugin-group-icons@1.3.5: resolution: {integrity: sha512-1f1NP7osRYlNTR0yS5CAqcaasKHRSAzFKpeCUOfCPwYLAFxhCxsEbRtPBm0U1CfrDVa303MsjX18ngGpFGxIMA==} - vitest@3.0.3: - resolution: {integrity: sha512-dWdwTFUW9rcnL0LyF2F+IfvNQWB0w9DERySCk8VMG75F8k25C7LsZoh6XfCjPvcR8Nb+Lqi9JKr6vnzH7HSrpQ==} + vitest@3.0.4: + resolution: {integrity: sha512-6XG8oTKy2gnJIFTHP6LD7ExFeNLxiTkK3CfMvT7IfR8IN+BYICCf0lXUQmX7i7JoxUP8QmeP4mTnWXgflu4yjw==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - '@vitest/browser': 3.0.3 - '@vitest/ui': 3.0.3 + '@vitest/browser': 3.0.4 + '@vitest/ui': 3.0.4 happy-dom: '*' jsdom: '*' peerDependenciesMeta: '@edge-runtime/vm': optional: true + '@types/debug': + optional: true '@types/node': optional: true '@vitest/browser': @@ -2766,8 +2767,8 @@ packages: resolution: {integrity: sha512-f9s+fUkX04BxQf+7mMWAp5zk61pciie+fFLC9hX9UVvCeJQfNHRHXpeo5MPcR0EUf57PYLdt+ZO4f3Ipk2oZUw==} engines: {node: '>=0.1'} - yaml@2.6.1: - resolution: {integrity: sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==} + yaml@2.7.0: + resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==} engines: {node: '>= 14'} hasBin: true @@ -2783,109 +2784,109 @@ packages: snapshots: - '@algolia/autocomplete-core@1.17.9(@algolia/client-search@5.19.0)(algoliasearch@5.19.0)': + '@algolia/autocomplete-core@1.17.9(@algolia/client-search@5.20.0)(algoliasearch@5.20.0)': dependencies: - '@algolia/autocomplete-plugin-algolia-insights': 1.17.9(@algolia/client-search@5.19.0)(algoliasearch@5.19.0) - '@algolia/autocomplete-shared': 1.17.9(@algolia/client-search@5.19.0)(algoliasearch@5.19.0) + '@algolia/autocomplete-plugin-algolia-insights': 1.17.9(@algolia/client-search@5.20.0)(algoliasearch@5.20.0) + '@algolia/autocomplete-shared': 1.17.9(@algolia/client-search@5.20.0)(algoliasearch@5.20.0) transitivePeerDependencies: - '@algolia/client-search' - algoliasearch - search-insights - '@algolia/autocomplete-plugin-algolia-insights@1.17.9(@algolia/client-search@5.19.0)(algoliasearch@5.19.0)': + '@algolia/autocomplete-plugin-algolia-insights@1.17.9(@algolia/client-search@5.20.0)(algoliasearch@5.20.0)': dependencies: - '@algolia/autocomplete-shared': 1.17.9(@algolia/client-search@5.19.0)(algoliasearch@5.19.0) + '@algolia/autocomplete-shared': 1.17.9(@algolia/client-search@5.20.0)(algoliasearch@5.20.0) transitivePeerDependencies: - '@algolia/client-search' - algoliasearch - '@algolia/autocomplete-preset-algolia@1.17.9(@algolia/client-search@5.19.0)(algoliasearch@5.19.0)': + '@algolia/autocomplete-preset-algolia@1.17.9(@algolia/client-search@5.20.0)(algoliasearch@5.20.0)': dependencies: - '@algolia/autocomplete-shared': 1.17.9(@algolia/client-search@5.19.0)(algoliasearch@5.19.0) - '@algolia/client-search': 5.19.0 - algoliasearch: 5.19.0 + '@algolia/autocomplete-shared': 1.17.9(@algolia/client-search@5.20.0)(algoliasearch@5.20.0) + '@algolia/client-search': 5.20.0 + algoliasearch: 5.20.0 - '@algolia/autocomplete-shared@1.17.9(@algolia/client-search@5.19.0)(algoliasearch@5.19.0)': + '@algolia/autocomplete-shared@1.17.9(@algolia/client-search@5.20.0)(algoliasearch@5.20.0)': dependencies: - '@algolia/client-search': 5.19.0 - algoliasearch: 5.19.0 + '@algolia/client-search': 5.20.0 + algoliasearch: 5.20.0 - '@algolia/client-abtesting@5.19.0': + '@algolia/client-abtesting@5.20.0': dependencies: - '@algolia/client-common': 5.19.0 - '@algolia/requester-browser-xhr': 5.19.0 - '@algolia/requester-fetch': 5.19.0 - '@algolia/requester-node-http': 5.19.0 + '@algolia/client-common': 5.20.0 + '@algolia/requester-browser-xhr': 5.20.0 + '@algolia/requester-fetch': 5.20.0 + '@algolia/requester-node-http': 5.20.0 - '@algolia/client-analytics@5.19.0': + '@algolia/client-analytics@5.20.0': dependencies: - '@algolia/client-common': 5.19.0 - '@algolia/requester-browser-xhr': 5.19.0 - '@algolia/requester-fetch': 5.19.0 - '@algolia/requester-node-http': 5.19.0 + '@algolia/client-common': 5.20.0 + '@algolia/requester-browser-xhr': 5.20.0 + '@algolia/requester-fetch': 5.20.0 + '@algolia/requester-node-http': 5.20.0 - '@algolia/client-common@5.19.0': {} + '@algolia/client-common@5.20.0': {} - '@algolia/client-insights@5.19.0': + '@algolia/client-insights@5.20.0': dependencies: - '@algolia/client-common': 5.19.0 - '@algolia/requester-browser-xhr': 5.19.0 - '@algolia/requester-fetch': 5.19.0 - '@algolia/requester-node-http': 5.19.0 + '@algolia/client-common': 5.20.0 + '@algolia/requester-browser-xhr': 5.20.0 + '@algolia/requester-fetch': 5.20.0 + '@algolia/requester-node-http': 5.20.0 - '@algolia/client-personalization@5.19.0': + '@algolia/client-personalization@5.20.0': dependencies: - '@algolia/client-common': 5.19.0 - '@algolia/requester-browser-xhr': 5.19.0 - '@algolia/requester-fetch': 5.19.0 - '@algolia/requester-node-http': 5.19.0 + '@algolia/client-common': 5.20.0 + '@algolia/requester-browser-xhr': 5.20.0 + '@algolia/requester-fetch': 5.20.0 + '@algolia/requester-node-http': 5.20.0 - '@algolia/client-query-suggestions@5.19.0': + '@algolia/client-query-suggestions@5.20.0': dependencies: - '@algolia/client-common': 5.19.0 - '@algolia/requester-browser-xhr': 5.19.0 - '@algolia/requester-fetch': 5.19.0 - '@algolia/requester-node-http': 5.19.0 + '@algolia/client-common': 5.20.0 + '@algolia/requester-browser-xhr': 5.20.0 + '@algolia/requester-fetch': 5.20.0 + '@algolia/requester-node-http': 5.20.0 - '@algolia/client-search@5.19.0': + '@algolia/client-search@5.20.0': dependencies: - '@algolia/client-common': 5.19.0 - '@algolia/requester-browser-xhr': 5.19.0 - '@algolia/requester-fetch': 5.19.0 - '@algolia/requester-node-http': 5.19.0 + '@algolia/client-common': 5.20.0 + '@algolia/requester-browser-xhr': 5.20.0 + '@algolia/requester-fetch': 5.20.0 + '@algolia/requester-node-http': 5.20.0 - '@algolia/ingestion@1.19.0': + '@algolia/ingestion@1.20.0': dependencies: - '@algolia/client-common': 5.19.0 - '@algolia/requester-browser-xhr': 5.19.0 - '@algolia/requester-fetch': 5.19.0 - '@algolia/requester-node-http': 5.19.0 + '@algolia/client-common': 5.20.0 + '@algolia/requester-browser-xhr': 5.20.0 + '@algolia/requester-fetch': 5.20.0 + '@algolia/requester-node-http': 5.20.0 - '@algolia/monitoring@1.19.0': + '@algolia/monitoring@1.20.0': dependencies: - '@algolia/client-common': 5.19.0 - '@algolia/requester-browser-xhr': 5.19.0 - '@algolia/requester-fetch': 5.19.0 - '@algolia/requester-node-http': 5.19.0 + '@algolia/client-common': 5.20.0 + '@algolia/requester-browser-xhr': 5.20.0 + '@algolia/requester-fetch': 5.20.0 + '@algolia/requester-node-http': 5.20.0 - '@algolia/recommend@5.19.0': + '@algolia/recommend@5.20.0': dependencies: - '@algolia/client-common': 5.19.0 - '@algolia/requester-browser-xhr': 5.19.0 - '@algolia/requester-fetch': 5.19.0 - '@algolia/requester-node-http': 5.19.0 + '@algolia/client-common': 5.20.0 + '@algolia/requester-browser-xhr': 5.20.0 + '@algolia/requester-fetch': 5.20.0 + '@algolia/requester-node-http': 5.20.0 - '@algolia/requester-browser-xhr@5.19.0': + '@algolia/requester-browser-xhr@5.20.0': dependencies: - '@algolia/client-common': 5.19.0 + '@algolia/client-common': 5.20.0 - '@algolia/requester-fetch@5.19.0': + '@algolia/requester-fetch@5.20.0': dependencies: - '@algolia/client-common': 5.19.0 + '@algolia/client-common': 5.20.0 - '@algolia/requester-node-http@5.19.0': + '@algolia/requester-node-http@5.20.0': dependencies: - '@algolia/client-common': 5.19.0 + '@algolia/client-common': 5.20.0 '@antfu/install-pkg@0.4.1': dependencies: @@ -2939,9 +2940,9 @@ snapshots: '@docsearch/css@3.8.3': {} - '@docsearch/js@3.8.3(@algolia/client-search@5.19.0)': + '@docsearch/js@3.8.3(@algolia/client-search@5.20.0)': dependencies: - '@docsearch/react': 3.8.3(@algolia/client-search@5.19.0) + '@docsearch/react': 3.8.3(@algolia/client-search@5.20.0) preact: 10.25.4 transitivePeerDependencies: - '@algolia/client-search' @@ -2950,12 +2951,12 @@ snapshots: - react-dom - search-insights - '@docsearch/react@3.8.3(@algolia/client-search@5.19.0)': + '@docsearch/react@3.8.3(@algolia/client-search@5.20.0)': dependencies: - '@algolia/autocomplete-core': 1.17.9(@algolia/client-search@5.19.0)(algoliasearch@5.19.0) - '@algolia/autocomplete-preset-algolia': 1.17.9(@algolia/client-search@5.19.0)(algoliasearch@5.19.0) + '@algolia/autocomplete-core': 1.17.9(@algolia/client-search@5.20.0)(algoliasearch@5.20.0) + '@algolia/autocomplete-preset-algolia': 1.17.9(@algolia/client-search@5.20.0)(algoliasearch@5.20.0) '@docsearch/css': 3.8.3 - algoliasearch: 5.19.0 + algoliasearch: 5.20.0 transitivePeerDependencies: - '@algolia/client-search' @@ -3162,8 +3163,6 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.18.0 - '@pkgr/core@0.1.1': {} - '@polka/compression@1.0.0-next.28': {} '@polka/url@1.0.0-next.28': {} @@ -3328,7 +3327,7 @@ snapshots: '@types/cross-spawn@6.0.6': dependencies: - '@types/node': 22.10.7 + '@types/node': 22.10.9 '@types/debug@4.1.12': dependencies: @@ -3339,7 +3338,7 @@ snapshots: '@types/fs-extra@11.0.4': dependencies: '@types/jsonfile': 6.1.4 - '@types/node': 22.10.7 + '@types/node': 22.10.9 '@types/hast@3.0.4': dependencies: @@ -3351,7 +3350,7 @@ snapshots: '@types/jsonfile@6.1.4': dependencies: - '@types/node': 22.10.7 + '@types/node': 22.10.9 '@types/linkify-it@5.0.0': {} @@ -3394,7 +3393,7 @@ snapshots: '@types/node@17.0.45': {} - '@types/node@22.10.7': + '@types/node@22.10.9': dependencies: undici-types: 6.20.0 @@ -3408,14 +3407,14 @@ snapshots: '@types/prompts@2.4.9': dependencies: - '@types/node': 22.10.7 + '@types/node': 22.10.9 kleur: 3.0.3 '@types/resolve@1.20.2': {} '@types/sax@1.2.7': dependencies: - '@types/node': 22.10.7 + '@types/node': 22.10.9 '@types/semver@7.5.8': {} @@ -3425,50 +3424,50 @@ snapshots: '@types/web-bluetooth@0.0.20': {} - '@ungap/structured-clone@1.2.1': {} + '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-vue@5.2.1(vite@6.0.11(@types/node@22.10.7)(jiti@1.21.7)(yaml@2.6.1))(vue@3.5.13(typescript@5.7.3))': + '@vitejs/plugin-vue@5.2.1(vite@6.0.11(@types/node@22.10.9)(jiti@1.21.7)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3))': dependencies: - vite: 6.0.11(@types/node@22.10.7)(jiti@1.21.7)(yaml@2.6.1) + vite: 6.0.11(@types/node@22.10.9)(jiti@1.21.7)(yaml@2.7.0) vue: 3.5.13(typescript@5.7.3) - '@vitest/expect@3.0.3': + '@vitest/expect@3.0.4': dependencies: - '@vitest/spy': 3.0.3 - '@vitest/utils': 3.0.3 + '@vitest/spy': 3.0.4 + '@vitest/utils': 3.0.4 chai: 5.1.2 tinyrainbow: 2.0.0 - '@vitest/mocker@3.0.3(vite@6.0.11(@types/node@22.10.7)(jiti@1.21.7)(yaml@2.6.1))': + '@vitest/mocker@3.0.4(vite@6.0.11(@types/node@22.10.9)(jiti@1.21.7)(yaml@2.7.0))': dependencies: - '@vitest/spy': 3.0.3 + '@vitest/spy': 3.0.4 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 6.0.11(@types/node@22.10.7)(jiti@1.21.7)(yaml@2.6.1) + vite: 6.0.11(@types/node@22.10.9)(jiti@1.21.7)(yaml@2.7.0) - '@vitest/pretty-format@3.0.3': + '@vitest/pretty-format@3.0.4': dependencies: tinyrainbow: 2.0.0 - '@vitest/runner@3.0.3': + '@vitest/runner@3.0.4': dependencies: - '@vitest/utils': 3.0.3 + '@vitest/utils': 3.0.4 pathe: 2.0.2 - '@vitest/snapshot@3.0.3': + '@vitest/snapshot@3.0.4': dependencies: - '@vitest/pretty-format': 3.0.3 + '@vitest/pretty-format': 3.0.4 magic-string: 0.30.17 pathe: 2.0.2 - '@vitest/spy@3.0.3': + '@vitest/spy@3.0.4': dependencies: tinyspy: 3.0.2 - '@vitest/utils@3.0.3': + '@vitest/utils@3.0.4': dependencies: - '@vitest/pretty-format': 3.0.3 + '@vitest/pretty-format': 3.0.4 loupe: 3.1.2 tinyrainbow: 2.0.0 @@ -3574,19 +3573,19 @@ snapshots: '@vue/shared@3.5.13': {} - '@vueuse/core@12.4.0(typescript@5.7.3)': + '@vueuse/core@12.5.0(typescript@5.7.3)': dependencies: '@types/web-bluetooth': 0.0.20 - '@vueuse/metadata': 12.4.0 - '@vueuse/shared': 12.4.0(typescript@5.7.3) + '@vueuse/metadata': 12.5.0 + '@vueuse/shared': 12.5.0(typescript@5.7.3) vue: 3.5.13(typescript@5.7.3) transitivePeerDependencies: - typescript - '@vueuse/integrations@12.4.0(axios@1.7.9(debug@4.4.0))(focus-trap@7.6.4)(typescript@5.7.3)': + '@vueuse/integrations@12.5.0(axios@1.7.9(debug@4.4.0))(focus-trap@7.6.4)(typescript@5.7.3)': dependencies: - '@vueuse/core': 12.4.0(typescript@5.7.3) - '@vueuse/shared': 12.4.0(typescript@5.7.3) + '@vueuse/core': 12.5.0(typescript@5.7.3) + '@vueuse/shared': 12.5.0(typescript@5.7.3) vue: 3.5.13(typescript@5.7.3) optionalDependencies: axios: 1.7.9(debug@4.4.0) @@ -3594,9 +3593,9 @@ snapshots: transitivePeerDependencies: - typescript - '@vueuse/metadata@12.4.0': {} + '@vueuse/metadata@12.5.0': {} - '@vueuse/shared@12.4.0(typescript@5.7.3)': + '@vueuse/shared@12.5.0(typescript@5.7.3)': dependencies: vue: 3.5.13(typescript@5.7.3) transitivePeerDependencies: @@ -3606,21 +3605,21 @@ snapshots: add-stream@1.0.0: {} - algoliasearch@5.19.0: - dependencies: - '@algolia/client-abtesting': 5.19.0 - '@algolia/client-analytics': 5.19.0 - '@algolia/client-common': 5.19.0 - '@algolia/client-insights': 5.19.0 - '@algolia/client-personalization': 5.19.0 - '@algolia/client-query-suggestions': 5.19.0 - '@algolia/client-search': 5.19.0 - '@algolia/ingestion': 1.19.0 - '@algolia/monitoring': 1.19.0 - '@algolia/recommend': 5.19.0 - '@algolia/requester-browser-xhr': 5.19.0 - '@algolia/requester-fetch': 5.19.0 - '@algolia/requester-node-http': 5.19.0 + algoliasearch@5.20.0: + dependencies: + '@algolia/client-abtesting': 5.20.0 + '@algolia/client-analytics': 5.20.0 + '@algolia/client-common': 5.20.0 + '@algolia/client-insights': 5.20.0 + '@algolia/client-personalization': 5.20.0 + '@algolia/client-query-suggestions': 5.20.0 + '@algolia/client-search': 5.20.0 + '@algolia/ingestion': 1.20.0 + '@algolia/monitoring': 1.20.0 + '@algolia/recommend': 5.20.0 + '@algolia/requester-browser-xhr': 5.20.0 + '@algolia/requester-fetch': 5.20.0 + '@algolia/requester-node-http': 5.20.0 alien-signals@0.4.14: {} @@ -3747,7 +3746,7 @@ snapshots: comma-separated-tokens@2.0.3: {} - commander@12.1.0: {} + commander@13.1.0: {} commander@6.2.1: {} @@ -4305,10 +4304,10 @@ snapshots: dependencies: uc.micro: 2.1.0 - lint-staged@15.4.1: + lint-staged@15.4.2: dependencies: chalk: 5.4.1 - commander: 12.1.0 + commander: 13.1.0 debug: 4.4.0 execa: 8.0.1 lilconfig: 3.1.3 @@ -4316,7 +4315,7 @@ snapshots: micromatch: 4.0.8 pidtree: 0.6.0 string-argv: 0.3.2 - yaml: 2.6.1 + yaml: 2.7.0 transitivePeerDependencies: - supports-color @@ -4372,7 +4371,12 @@ snapshots: mark.js@8.11.1: {} - markdown-it-anchor@9.2.0(@types/markdown-it@14.1.2)(markdown-it@14.1.0): + markdown-it-anchor@9.2.0(patch_hash=ivrlfano2jj27ilcyyknwlzzfu)(@types/markdown-it@14.1.2)(markdown-it@14.1.0): + dependencies: + '@types/markdown-it': 14.1.2 + markdown-it: 14.1.0 + + markdown-it-async@2.0.0: dependencies: '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 @@ -4412,7 +4416,7 @@ snapshots: dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 - '@ungap/structured-clone': 1.2.1 + '@ungap/structured-clone': 1.3.0 devlop: 1.1.0 micromark-util-sanitize-uri: 2.0.1 trim-lines: 3.0.1 @@ -4630,11 +4634,11 @@ snapshots: mlly: 1.7.4 pathe: 2.0.2 - playwright-chromium@1.49.1: + playwright-chromium@1.50.0: dependencies: - playwright-core: 1.49.1 + playwright-core: 1.50.0 - playwright-core@1.49.1: {} + playwright-core@1.50.0: {} polka@1.0.0-next.28: dependencies: @@ -4962,11 +4966,6 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - synckit@0.9.2: - dependencies: - '@pkgr/core': 0.1.1 - tslib: 2.8.1 - tabbable@6.2.0: {} temp-dir@3.0.0: {} @@ -5089,13 +5088,13 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.2 - vite-node@3.0.3(@types/node@22.10.7)(jiti@1.21.7)(yaml@2.6.1): + vite-node@3.0.4(@types/node@22.10.9)(jiti@1.21.7)(yaml@2.7.0): dependencies: cac: 6.7.14 debug: 4.4.0 es-module-lexer: 1.6.0 pathe: 2.0.2 - vite: 6.0.11(@types/node@22.10.7)(jiti@1.21.7)(yaml@2.6.1) + vite: 6.0.11(@types/node@22.10.9)(jiti@1.21.7)(yaml@2.7.0) transitivePeerDependencies: - '@types/node' - jiti @@ -5110,16 +5109,16 @@ snapshots: - tsx - yaml - vite@6.0.11(@types/node@22.10.7)(jiti@1.21.7)(yaml@2.6.1): + vite@6.0.11(@types/node@22.10.9)(jiti@1.21.7)(yaml@2.7.0): dependencies: esbuild: 0.24.2 postcss: 8.5.1 rollup: 4.31.0 optionalDependencies: - '@types/node': 22.10.7 + '@types/node': 22.10.9 fsevents: 2.3.3 jiti: 1.21.7 - yaml: 2.6.1 + yaml: 2.7.0 vitepress-plugin-group-icons@1.3.5: dependencies: @@ -5129,15 +5128,15 @@ snapshots: transitivePeerDependencies: - supports-color - vitest@3.0.3(@types/node@22.10.7)(jiti@1.21.7)(yaml@2.6.1): + vitest@3.0.4(@types/debug@4.1.12)(@types/node@22.10.9)(jiti@1.21.7)(yaml@2.7.0): dependencies: - '@vitest/expect': 3.0.3 - '@vitest/mocker': 3.0.3(vite@6.0.11(@types/node@22.10.7)(jiti@1.21.7)(yaml@2.6.1)) - '@vitest/pretty-format': 3.0.3 - '@vitest/runner': 3.0.3 - '@vitest/snapshot': 3.0.3 - '@vitest/spy': 3.0.3 - '@vitest/utils': 3.0.3 + '@vitest/expect': 3.0.4 + '@vitest/mocker': 3.0.4(vite@6.0.11(@types/node@22.10.9)(jiti@1.21.7)(yaml@2.7.0)) + '@vitest/pretty-format': 3.0.4 + '@vitest/runner': 3.0.4 + '@vitest/snapshot': 3.0.4 + '@vitest/spy': 3.0.4 + '@vitest/utils': 3.0.4 chai: 5.1.2 debug: 4.4.0 expect-type: 1.1.0 @@ -5148,11 +5147,12 @@ snapshots: tinyexec: 0.3.2 tinypool: 1.0.2 tinyrainbow: 2.0.0 - vite: 6.0.11(@types/node@22.10.7)(jiti@1.21.7)(yaml@2.6.1) - vite-node: 3.0.3(@types/node@22.10.7)(jiti@1.21.7)(yaml@2.6.1) + vite: 6.0.11(@types/node@22.10.9)(jiti@1.21.7)(yaml@2.7.0) + vite-node: 3.0.4(@types/node@22.10.9)(jiti@1.21.7)(yaml@2.7.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.10.7 + '@types/debug': 4.1.12 + '@types/node': 22.10.9 transitivePeerDependencies: - jiti - less @@ -5246,7 +5246,7 @@ snapshots: xmldom-sre@0.1.31: {} - yaml@2.6.1: {} + yaml@2.7.0: {} yoctocolors@2.1.1: {} diff --git a/rollup.config.ts b/rollup.config.ts index 8a996b01..6bf7ff1b 100644 --- a/rollup.config.ts +++ b/rollup.config.ts @@ -8,7 +8,6 @@ import { builtinModules, createRequire } from 'node:module' import { type RollupOptions, defineConfig } from 'rollup' import dts from 'rollup-plugin-dts' import esbuild from 'rollup-plugin-esbuild' -import { globSync } from 'tinyglobby' const require = createRequire(import.meta.url) const pkg = require('./package.json') @@ -39,11 +38,7 @@ const plugins = [ ] const esmBuild: RollupOptions = { - input: [ - 'src/node/index.ts', - 'src/node/cli.ts', - ...globSync('src/node/worker_*.ts') - ], + input: ['src/node/index.ts', 'src/node/cli.ts'], output: { format: 'esm', entryFileNames: `[name].js`, diff --git a/src/client/app/index.ts b/src/client/app/index.ts index 5acb3be5..1f1e8069 100644 --- a/src/client/app/index.ts +++ b/src/client/app/index.ts @@ -159,19 +159,14 @@ function newRouter(): Router { if (inBrowser) { createApp().then(({ app, router, data }) => { // wait until page component is fetched before mounting - router.go().then(() => { + router.go(location.href, { initialLoad: true }).then(() => { // dynamically update head tags useUpdateHead(router.route, data.site) app.mount('#app') // scroll to hash on new tab during dev if (import.meta.env.DEV && location.hash) { - const target = document.getElementById( - decodeURIComponent(location.hash).slice(1) - ) - if (target) { - scrollTo(target, location.hash) - } + scrollTo(location.hash) } }) }) diff --git a/src/client/app/router.ts b/src/client/app/router.ts index 0cffc700..8b09339d 100644 --- a/src/client/app/router.ts +++ b/src/client/app/router.ts @@ -7,6 +7,8 @@ import { getScrollOffset, inBrowser, withBase } from './utils' export interface Route { path: string + hash: string + query: string data: PageData component: Component | null } @@ -19,7 +21,15 @@ export interface Router { /** * Navigate to a new URL. */ - go: (to?: string) => Promise + go: ( + to: string, + options?: { + // @internal + initialLoad?: boolean + // Whether to smoothly scroll to the target position. + smoothScroll?: boolean + } + ) => Promise /** * Called before the route changes. Return `false` to cancel the navigation. */ @@ -37,10 +47,6 @@ export interface Router { * Called after the route changes. */ onAfterRouteChange?: (to: string) => Awaitable - /** - * @deprecated use `onAfterRouteChange` instead - */ - onAfterRouteChanged?: (to: string) => Awaitable } export const RouterSymbol: InjectionKey = Symbol() @@ -51,6 +57,8 @@ const fakeHost = 'http://a.com' const getDefaultRoute = (): Route => ({ path: '/', + hash: '', + query: '', component: null, data: notFoundPageData }) @@ -68,39 +76,32 @@ export function createRouter( const router: Router = { route, - go - } - - async function go(href: string = inBrowser ? location.href : '/') { - href = normalizeHref(href) - if ((await router.onBeforeRouteChange?.(href)) === false) return - if (inBrowser && href !== normalizeHref(location.href)) { - // save scroll position before changing url - history.replaceState({ scrollPosition: window.scrollY }, '') - history.pushState({}, '', href) + async go(href, options) { + href = normalizeHref(href) + if ((await router.onBeforeRouteChange?.(href)) === false) return + if (!inBrowser || (await changeRoute(href, options))) await loadPage(href) + syncRouteQueryAndHash() + await router.onAfterRouteChange?.(href) } - await loadPage(href) - await (router.onAfterRouteChange ?? router.onAfterRouteChanged)?.(href) } let latestPendingPath: string | null = null async function loadPage(href: string, scrollPosition = 0, isRetry = false) { if ((await router.onBeforePageLoad?.(href)) === false) return + const targetLoc = new URL(href, fakeHost) const pendingPath = (latestPendingPath = targetLoc.pathname) + try { let page = await loadPageModule(pendingPath) - if (!page) { - throw new Error(`Page not found: ${pendingPath}`) - } + if (!page) throw new Error(`Page not found: ${pendingPath}`) + if (latestPendingPath === pendingPath) { latestPendingPath = null const { default: comp, __pageData } = page - if (!comp) { - throw new Error(`Invalid route component: ${comp}`) - } + if (!comp) throw new Error(`Invalid route component: ${comp}`) await router.onAfterPageLoad?.(href) @@ -109,36 +110,25 @@ export function createRouter( route.data = import.meta.env.PROD ? markRaw(__pageData) : (readonly(__pageData) as PageData) + syncRouteQueryAndHash(targetLoc) if (inBrowser) { nextTick(() => { let actualPathname = siteDataRef.value.base + __pageData.relativePath.replace(/(?:(^|\/)index)?\.md$/, '$1') + if (!siteDataRef.value.cleanUrls && !actualPathname.endsWith('/')) { actualPathname += '.html' } + if (actualPathname !== targetLoc.pathname) { targetLoc.pathname = actualPathname href = actualPathname + targetLoc.search + targetLoc.hash history.replaceState({}, '', href) } - if (targetLoc.hash && !scrollPosition) { - let target: HTMLElement | null = null - try { - target = document.getElementById( - decodeURIComponent(targetLoc.hash).slice(1) - ) - } catch (e) { - console.warn(e) - } - if (target) { - scrollTo(target, targetLoc.hash) - return - } - } - window.scrollTo(0, scrollPosition) + return scrollTo(targetLoc.hash, false, scrollPosition) }) } } @@ -173,14 +163,22 @@ export function createRouter( .replace(/^\//, '') : '404.md' route.data = { ...notFoundPageData, relativePath } + syncRouteQueryAndHash(targetLoc) } } } + function syncRouteQueryAndHash( + loc: { search: string; hash: string } = inBrowser + ? location + : { search: '', hash: '' } + ) { + route.query = loc.search + route.hash = decodeURIComponent(loc.hash) + } + if (inBrowser) { - if (history.state === null) { - history.replaceState({}, '') - } + if (history.state === null) history.replaceState({}, '') window.addEventListener( 'click', (e) => { @@ -193,8 +191,9 @@ export function createRouter( e.shiftKey || e.altKey || e.metaKey - ) + ) { return + } const link = e.target.closest('a') if ( @@ -202,47 +201,24 @@ export function createRouter( link.closest('.vp-raw') || link.hasAttribute('download') || link.hasAttribute('target') - ) + ) { return + } const linkHref = link.getAttribute('href') ?? (link instanceof SVGAElement ? link.getAttribute('xlink:href') : null) if (linkHref == null) return - const { href, origin, pathname, hash, search } = new URL( - linkHref, - link.baseURI - ) - const currentUrl = new URL(location.href) // copy to keep old data + const { href, origin, pathname } = new URL(linkHref, link.baseURI) + const currentLoc = new URL(location.href) // copy to keep old data // only intercept inbound html links - if (origin === currentUrl.origin && treatAsHtml(pathname)) { + if (origin === currentLoc.origin && treatAsHtml(pathname)) { e.preventDefault() - if ( - pathname === currentUrl.pathname && - search === currentUrl.search - ) { - // scroll between hash anchors in the same page - // avoid duplicate history entries when the hash is same - if (hash !== currentUrl.hash) { - history.pushState({}, '', href) - // still emit the event so we can listen to it in themes - window.dispatchEvent( - new HashChangeEvent('hashchange', { - oldURL: currentUrl.href, - newURL: href - }) - ) - } - if (hash) { - // use smooth scroll when clicking on header anchor links - scrollTo(link, hash, link.classList.contains('header-anchor')) - } else { - window.scrollTo(0, 0) - } - } else { - go(href) - } + router.go(href, { + // use smooth scroll when clicking on header anchor links + smoothScroll: link.classList.contains('header-anchor') + }) } }, { capture: true } @@ -252,11 +228,13 @@ export function createRouter( if (e.state === null) return const href = normalizeHref(location.href) await loadPage(href, (e.state && e.state.scrollPosition) || 0) - await (router.onAfterRouteChange ?? router.onAfterRouteChanged)?.(href) + syncRouteQueryAndHash() + await router.onAfterRouteChange?.(href) }) window.addEventListener('hashchange', (e) => { e.preventDefault() + syncRouteQueryAndHash() }) } @@ -267,9 +245,7 @@ export function createRouter( export function useRouter(): Router { const router = inject(RouterSymbol) - if (!router) { - throw new Error('useRouter() is called without provider.') - } + if (!router) throw new Error('useRouter() is called without provider.') return router } @@ -277,13 +253,16 @@ export function useRoute(): Route { return useRouter().route } -export function scrollTo(el: Element, hash: string, smooth = false) { +export function scrollTo(hash: string, smooth = false, scrollPosition = 0) { + if (!hash || scrollPosition) { + window.scrollTo(0, scrollPosition) + return + } + let target: Element | null = null try { - target = el.classList.contains('header-anchor') - ? el - : document.getElementById(decodeURIComponent(hash).slice(1)) + target = document.getElementById(decodeURIComponent(hash).slice(1)) } catch (e) { console.warn(e) } @@ -293,17 +272,20 @@ export function scrollTo(el: Element, hash: string, smooth = false) { window.getComputedStyle(target).paddingTop, 10 ) + const targetTop = window.scrollY + target.getBoundingClientRect().top - getScrollOffset() + targetPadding + function scrollToTarget() { // only smooth scroll if distance is smaller than screen height. if (!smooth || Math.abs(targetTop - window.scrollY) > window.innerHeight) window.scrollTo(0, targetTop) else window.scrollTo({ left: 0, top: targetTop, behavior: 'smooth' }) } + requestAnimationFrame(scrollToTarget) } } @@ -313,9 +295,7 @@ function handleHMR(route: Route): void { if (import.meta.hot) { // hot reload pageData import.meta.hot.on('vitepress:pageData', (payload: PageDataPayload) => { - if (shouldHotReload(payload)) { - route.data = payload.pageData - } + if (shouldHotReload(payload)) route.data = payload.pageData }) } } @@ -332,9 +312,47 @@ function normalizeHref(href: string): string { const url = new URL(href, fakeHost) url.pathname = url.pathname.replace(/(^|\/)index(\.html)?$/, '$1') // ensure correct deep link so page refresh lands on correct files. - if (siteDataRef.value.cleanUrls) + if (siteDataRef.value.cleanUrls) { url.pathname = url.pathname.replace(/\.html$/, '') - else if (!url.pathname.endsWith('/') && !url.pathname.endsWith('.html')) + } else if (!url.pathname.endsWith('/') && !url.pathname.endsWith('.html')) { url.pathname += '.html' + } return url.pathname + url.search + url.hash } + +async function changeRoute( + href: string, + { smoothScroll = false, initialLoad = false } = {} +): Promise { + const loc = normalizeHref(location.href) + const { pathname, hash } = new URL(href, fakeHost) + const currentLoc = new URL(loc, fakeHost) + + if (href === loc) { + if (!initialLoad) { + scrollTo(hash, smoothScroll) + return false + } + } else { + // save scroll position before changing URL + history.replaceState({ scrollPosition: window.scrollY }, '') + history.pushState({}, '', href) + + if (pathname === currentLoc.pathname) { + // scroll between hash anchors on the same page, avoid duplicate entries + if (hash !== currentLoc.hash) { + window.dispatchEvent( + new HashChangeEvent('hashchange', { + oldURL: currentLoc.href, + newURL: href + }) + ) + scrollTo(hash, smoothScroll) + } + + return false + } + } + + return true +} diff --git a/src/node/build/bundle.ts b/src/node/build/bundle.ts index e4d2556c..662e9593 100644 --- a/src/node/build/bundle.ts +++ b/src/node/build/bundle.ts @@ -88,13 +88,7 @@ export async function bundle( ssr, ssrEmitAssets: config.mpa, // minify with esbuild in MPA mode (for CSS) - minify: ssr - ? config.mpa - ? 'esbuild' - : false - : typeof options.minify === 'boolean' - ? options.minify - : !process.env.DEBUG, + minify: ssr ? !!config.mpa : (options.minify ?? !process.env.DEBUG), outDir: ssr ? config.tempDir : config.outDir, cssCodeSplit: false, rollupOptions: { diff --git a/src/node/cli.ts b/src/node/cli.ts index 5e0be858..cf8ce305 100644 --- a/src/node/cli.ts +++ b/src/node/cli.ts @@ -12,6 +12,14 @@ if (process.env.DEBUG) { const argv: any = minimist(process.argv.slice(2)) +Object.keys(argv).forEach((key) => { + if (argv[key] === 'true') { + argv[key] = true + } else if (argv[key] === 'false') { + argv[key] = false + } +}) + const logVersion = (logger: Logger) => { logger.info(`\n ${c.green(`${c.bold('vitepress')} v${version}`)}\n`, { clear: !logger.hasWarned diff --git a/src/node/config.ts b/src/node/config.ts index ffffa5ab..5f1698fe 100644 --- a/src/node/config.ts +++ b/src/node/config.ts @@ -10,14 +10,9 @@ import { type ConfigEnv } from 'vite' import { DEFAULT_THEME_PATH } from './alias' +import type { DefaultTheme } from './defaultTheme' import { resolvePages } from './plugins/dynamicRoutesPlugin' -import { - APPEARANCE_KEY, - slash, - type DefaultTheme, - type HeadConfig, - type SiteData -} from './shared' +import { APPEARANCE_KEY, slash, type HeadConfig, type SiteData } from './shared' import type { RawConfigExports, SiteConfig, UserConfig } from './siteConfig' export { resolvePages } from './plugins/dynamicRoutesPlugin' diff --git a/src/node/contentLoader.ts b/src/node/contentLoader.ts index e3bee2e8..cbd12e1c 100644 --- a/src/node/contentLoader.ts +++ b/src/node/contentLoader.ts @@ -144,9 +144,9 @@ export function createContentLoader( normalizePath(path.relative(config.srcDir, file)) .replace(/(^|\/)index\.md$/, '$1') .replace(/\.md$/, config.cleanUrls ? '' : '.html') - const html = render ? md.render(src) : undefined + const html = render ? await md.renderAsync(src) : undefined const renderedExcerpt = renderExcerpt - ? excerpt && md.render(excerpt) + ? excerpt && (await md.renderAsync(excerpt)) : undefined const data: ContentData = { src: includeSrc ? src : undefined, diff --git a/src/node/defaultTheme.ts b/src/node/defaultTheme.ts new file mode 100644 index 00000000..7b50e1b6 --- /dev/null +++ b/src/node/defaultTheme.ts @@ -0,0 +1,47 @@ +// this file contains node-only types of default theme +// (functions starting with _ are node-only) +// in most of the cases these will leak to client too +// but these can import types from dev deps + +import type { MarkdownItAsync } from 'markdown-it-async' +import type { DefaultTheme } from '../../types/default-theme' +import type { PageSplitSection } from '../../types/local-search' +import type { Awaitable, MarkdownEnv } from './shared' + +declare module '../../types/default-theme.js' { + namespace DefaultTheme { + interface LocalSearchOptions { + /** + * Allows transformation of content before indexing (node only) + * Return empty string to skip indexing + */ + _render?: ( + src: string, + env: MarkdownEnv, + md: MarkdownItAsync + ) => Awaitable + } + + interface MiniSearchOptions { + /** + * Overrides the default regex based page splitter. + * Supports async generator, making it possible to run in true parallel + * (when used along with `node:child_process` or `worker_threads`) + * --- + * This should be especially useful for scalability reasons. + * --- + * @param {string} path - absolute path to the markdown source file + * @param {string} html - document page rendered as html + */ + _splitIntoSections?: ( + path: string, + html: string + ) => + | AsyncGenerator + | Generator + | Awaitable + } + } +} + +export type { DefaultTheme } diff --git a/src/node/index.ts b/src/node/index.ts index 90c0956a..63ee79f8 100644 --- a/src/node/index.ts +++ b/src/node/index.ts @@ -8,11 +8,7 @@ export { defineLoader, type LoaderModule } from './plugins/staticDataPlugin' export * from './postcss/isolateStyles' export * from './serve/serve' export * from './server' +export type { DefaultTheme } from './defaultTheme' // shared types -export type { - DefaultTheme, - HeadConfig, - Header, - SiteData -} from '../../types/shared' +export type { HeadConfig, Header, SiteData } from '../../types/shared' diff --git a/src/node/markdown/markdown.ts b/src/node/markdown/markdown.ts index c7b74d9e..a39832a4 100644 --- a/src/node/markdown/markdown.ts +++ b/src/node/markdown/markdown.ts @@ -20,7 +20,7 @@ import type { ThemeRegistrationAny } from '@shikijs/types' import type { Options } from 'markdown-it' -import MarkdownIt from 'markdown-it' +import { MarkdownItAsync } from 'markdown-it-async' import anchorPlugin from 'markdown-it-anchor' import attrsPlugin from 'markdown-it-attrs' import { full as emojiPlugin } from 'markdown-it-emoji' @@ -53,11 +53,11 @@ export interface MarkdownOptions extends Options { /** * Setup markdown-it instance before applying plugins */ - preConfig?: (md: MarkdownIt) => Awaited + preConfig?: (md: MarkdownItAsync) => Awaited /** * Setup markdown-it instance */ - config?: (md: MarkdownIt) => Awaited + config?: (md: MarkdownItAsync) => Awaited /** * Disable cache (experimental) */ @@ -190,7 +190,7 @@ export interface MarkdownOptions extends Options { gfmAlerts?: boolean } -export type MarkdownRenderer = MarkdownIt +export type MarkdownRenderer = MarkdownItAsync let md: MarkdownRenderer | undefined let _disposeHighlighter: (() => void) | undefined @@ -223,7 +223,7 @@ export async function createMarkdownRenderer( _disposeHighlighter = dispose - md = MarkdownIt({ html: true, linkify: true, highlight, ...options }) + md = new MarkdownItAsync({ html: true, linkify: true, highlight, ...options }) md.linkify.set({ fuzzyLink: false }) md.use(restoreEntities) diff --git a/src/node/markdown/plugins/highlight.ts b/src/node/markdown/plugins/highlight.ts index fb276055..f0a0170e 100644 --- a/src/node/markdown/plugins/highlight.ts +++ b/src/node/markdown/plugins/highlight.ts @@ -7,20 +7,12 @@ import { type TransformerCompactLineOption } from '@shikijs/transformers' import { customAlphabet } from 'nanoid' -import { createRequire } from 'node:module' -import c from 'picocolors' import type { LanguageRegistration, ShikiTransformer } from 'shiki' import { createHighlighter, isSpecialLang } from 'shiki' -import { createSyncFn } from 'synckit' import type { Logger } from 'vite' -import type { ShikiResolveLang } from 'worker_shikiResolveLang' import type { MarkdownOptions, ThemeOptions } from '../markdown' +import c from 'picocolors' -const require = createRequire(import.meta.url) - -const resolveLangSync = createSyncFn( - require.resolve('vitepress/dist/node/worker_shikiResolveLang.js') -) const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz', 10) /** @@ -59,7 +51,9 @@ export async function highlight( theme: ThemeOptions, options: MarkdownOptions, logger: Pick = console -): Promise<[(str: string, lang: string, attrs: string) => string, () => void]> { +): Promise< + [(str: string, lang: string, attrs: string) => Promise, () => void] +> { const { defaultHighlightLang: defaultLang = 'txt', codeTransformers: userTransformers = [] @@ -77,25 +71,14 @@ export async function highlight( langAlias: options.languageAlias }) - function loadLanguage(name: string | LanguageRegistration) { + async function loadLanguage(name: string | LanguageRegistration) { const lang = typeof name === 'string' ? name : name.name if ( !isSpecialLang(lang) && !highlighter.getLoadedLanguages().includes(lang) ) { - const resolvedLang = resolveLangSync(lang) - if (resolvedLang.length) highlighter.loadLanguageSync(resolvedLang) - else return false + await highlighter.loadLanguage(lang as any) } - return true - } - - // patch for twoslash - https://github.com/vuejs/vitepress/issues/4334 - const internal = highlighter.getInternalContext() - const getLanguage = internal.getLanguage - internal.getLanguage = (name) => { - loadLanguage(name) - return getLanguage.call(internal, name) } await options?.shikiSetup?.(highlighter) @@ -136,7 +119,7 @@ export async function highlight( const mustacheRE = /\{\{.*?\}\}/g return [ - (str: string, lang: string, attrs: string) => { + async (str: string, lang: string, attrs: string) => { const vPre = vueRE.test(lang) ? '' : 'v-pre' lang = lang @@ -145,7 +128,9 @@ export async function highlight( .replace(vueRE, '') .toLowerCase() || defaultLang - if (!loadLanguage(lang)) { + try { + await loadLanguage(lang) + } catch { logger.warn( c.yellow( `\nThe language '${lang}' is not loaded, falling back to '${defaultLang}' for syntax highlighting.` diff --git a/src/node/markdownToVue.ts b/src/node/markdownToVue.ts index 98f236c7..a4f8a20d 100644 --- a/src/node/markdownToVue.ts +++ b/src/node/markdownToVue.ts @@ -119,7 +119,7 @@ export async function createMarkdownToVueRenderFn( realPath: fileOrig, localeIndex } - const html = md.render(src, env) + const html = await md.renderAsync(src, env) const { frontmatter = {}, headers = [], diff --git a/src/node/plugin.ts b/src/node/plugin.ts index 563bbdf3..078fd2a6 100644 --- a/src/node/plugin.ts +++ b/src/node/plugin.ts @@ -75,7 +75,6 @@ export async function createVitePressPlugin( site, vue: userVuePluginOptions, vite: userViteConfig, - pages, lastUpdated, cleanUrls } = siteConfig @@ -131,7 +130,7 @@ export async function createVitePressPlugin( markdownToVue = await createMarkdownToVueRenderFn( srcDir, markdown, - pages, + siteConfig.pages, config.command === 'build', config.base, lastUpdated, diff --git a/src/node/plugins/localSearchPlugin.ts b/src/node/plugins/localSearchPlugin.ts index d3b37b42..bffe74e8 100644 --- a/src/node/plugins/localSearchPlugin.ts +++ b/src/node/plugins/localSearchPlugin.ts @@ -5,13 +5,9 @@ import path from 'node:path' import pMap from 'p-map' import type { Plugin, ViteDevServer } from 'vite' import type { SiteConfig } from '../config' +import type { DefaultTheme } from '../defaultTheme' import { createMarkdownRenderer } from '../markdown/markdown' -import { - getLocaleForPath, - slash, - type DefaultTheme, - type MarkdownEnv -} from '../shared' +import { getLocaleForPath, slash, type MarkdownEnv } from '../shared' import { processIncludes } from '../utils/processIncludes' const debug = _debug('vitepress:local-search') @@ -61,9 +57,10 @@ export async function localSearchPlugin( const env: MarkdownEnv = { path: file, relativePath, cleanUrls } const md_raw = await fs.promises.readFile(file, 'utf-8') const md_src = processIncludes(srcDir, md_raw, file, []) - if (options._render) return await options._render(md_src, env, md) - else { - const html = md.render(md_src, env) + if (options._render) { + return await options._render(md_src, env, md) + } else { + const html = await md.renderAsync(md_src, env) return env.frontmatter?.search === false ? '' : html } } diff --git a/src/node/worker_shikiResolveLang.ts b/src/node/worker_shikiResolveLang.ts deleted file mode 100644 index 644caf9e..00000000 --- a/src/node/worker_shikiResolveLang.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { - bundledLanguages, - type DynamicImportLanguageRegistration, - type LanguageRegistration -} from 'shiki' -import { runAsWorker } from 'synckit' - -async function resolveLang(lang: string) { - return ( - ( - bundledLanguages as Record< - string, - DynamicImportLanguageRegistration | undefined - > - ) - [lang]?.() - .then((m) => m.default) || ([] as LanguageRegistration[]) - ) -} - -runAsWorker(resolveLang) - -export type ShikiResolveLang = typeof resolveLang diff --git a/types/default-theme.d.ts b/types/default-theme.d.ts index 10681a84..5a669c49 100644 --- a/types/default-theme.d.ts +++ b/types/default-theme.d.ts @@ -1,12 +1,8 @@ -import type MarkdownIt from 'markdown-it' -import type { Options as MiniSearchOptions } from 'minisearch' +import type { Options as _MiniSearchOptions } from 'minisearch' import type { ComputedRef, Ref, ShallowRef } from 'vue' import type { DocSearchProps } from './docsearch.js' -import type { - LocalSearchTranslations, - PageSplitSection -} from './local-search.js' -import type { Awaitable, MarkdownEnv, PageData } from './shared.js' +import type { LocalSearchTranslations } from './local-search.js' +import type { PageData } from './shared.js' export namespace DefaultTheme { export interface Config { @@ -413,46 +409,21 @@ export namespace DefaultTheme { translations?: LocalSearchTranslations locales?: Record>> - miniSearch?: { - /** - * @see https://lucaong.github.io/minisearch/types/MiniSearch.Options.html - */ - options?: Pick< - MiniSearchOptions, - 'extractField' | 'tokenize' | 'processTerm' - > - /** - * @see https://lucaong.github.io/minisearch/types/MiniSearch.SearchOptions.html - */ - searchOptions?: MiniSearchOptions['searchOptions'] - - /** - * Overrides the default regex based page splitter. - * Supports async generator, making it possible to run in true parallel - * (when used along with `node:child_process` or `worker_threads`) - * --- - * This should be especially useful for scalability reasons. - * --- - * @param {string} path - absolute path to the markdown source file - * @param {string} html - document page rendered as html - */ - _splitIntoSections?: ( - path: string, - html: string - ) => - | AsyncGenerator - | Generator - | Awaitable - } - /** - * Allows transformation of content before indexing (node only) - * Return empty string to skip indexing - */ - _render?: ( - src: string, - env: MarkdownEnv, - md: MarkdownIt - ) => Awaitable + miniSearch?: MiniSearchOptions + } + + interface MiniSearchOptions { + /** + * @see https://lucaong.github.io/minisearch/types/MiniSearch.Options.html + */ + options?: Pick< + _MiniSearchOptions, + 'extractField' | 'tokenize' | 'processTerm' + > + /** + * @see https://lucaong.github.io/minisearch/types/MiniSearch.SearchOptions.html + */ + searchOptions?: _MiniSearchOptions['searchOptions'] } // algolia -------------------------------------------------------------------