Merge branch 'main' into translate_vitepress

pull/3934/head
Camilo Parra 1 year ago committed by GitHub
commit f5ea57409b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -1,3 +1,35 @@
## [1.2.2](https://github.com/vuejs/vitepress/compare/v1.2.1...v1.2.2) (2024-05-21)
### Bug Fixes
- dont escape ampersand twice in title ([7ea3572](https://github.com/vuejs/vitepress/commit/7ea357256c855ae0a9a142c14bbd5e7d344ef865))
## [1.2.1](https://github.com/vuejs/vitepress/compare/v1.2.0...v1.2.1) (2024-05-21)
### Bug Fixes
- **a11y:** make code blocks accessible with keyboard ([#3902](https://github.com/vuejs/vitepress/issues/3902)) ([cb308b9](https://github.com/vuejs/vitepress/commit/cb308b9295e1e661c2c72fa4229b5c7d83278d49))
- escape title properly in build ([49b1233](https://github.com/vuejs/vitepress/commit/49b1233378436054c07a6ef646d0029096124021))
- **theme:** remove unnecessary navigation role on nav element ([af4717d](https://github.com/vuejs/vitepress/commit/af4717d6820233a011200d44abba53d0f66bfad3))
# [1.2.0](https://github.com/vuejs/vitepress/compare/v1.1.4...v1.2.0) (2024-05-18)
### Bug Fixes
- **build:** show file info on error ([f0debd2](https://github.com/vuejs/vitepress/commit/f0debd20f48ab7eb58cfd142147531509d6c0209))
- **dev:** match dev and prod routing behavior ([#3837](https://github.com/vuejs/vitepress/issues/3837)) ([b360ac8](https://github.com/vuejs/vitepress/commit/b360ac88df3bfd60e3498cc19066c0c90261ee4f))
- **markdown:** entities and escapes not working properly ([#3882](https://github.com/vuejs/vitepress/issues/3882)) ([d5dbd70](https://github.com/vuejs/vitepress/commit/d5dbd704ceb215ebf3ce9b23deec6e6c90634f0a))
- render 404 page completely on client to infer locale from browser path ([#3858](https://github.com/vuejs/vitepress/issues/3858)) ([728cb15](https://github.com/vuejs/vitepress/commit/728cb15677f4f84b33bed6bb2f70f47600ea1057))
- **style:** prefer YaHei over DengXian ([f0a37b4](https://github.com/vuejs/vitepress/commit/f0a37b4b8445ec914700df054c0897721382e5b1))
- **theme/regression:** custom font not applying in Chinese docs because of specificity ([fa2f38a](https://github.com/vuejs/vitepress/commit/fa2f38a0c3bd121dcb7e07420566087c19b10f96)), closes [#3864](https://github.com/vuejs/vitepress/issues/3864)
- **theme:** external link icon not visible for target \_blank links ([d08eeed](https://github.com/vuejs/vitepress/commit/d08eeed89726572f7ea341df59864cc72716751c)), closes [#3327](https://github.com/vuejs/vitepress/issues/3327)
- **theme:** fix invalid vp-offset in ssr ([9794877](https://github.com/vuejs/vitepress/commit/9794877347140c7b4955d735cd8867c260a5089d))
### Features
- **build/i18n:** support customizing copy code button's tooltip text ([#3854](https://github.com/vuejs/vitepress/issues/3854)) ([ed6ada7](https://github.com/vuejs/vitepress/commit/ed6ada7a688c466920f3e0ef33b7176b8eb01eee))
- **build:** add localeIndex to md.env ([#3862](https://github.com/vuejs/vitepress/issues/3862)) ([0cbb469](https://github.com/vuejs/vitepress/commit/0cbb469842d74381ad56d44b7975f34c405b78f8))
## [1.1.4](https://github.com/vuejs/vitepress/compare/v1.1.3...v1.1.4) (2024-04-27)
### Bug Fixes

@ -29,6 +29,10 @@ $ pnpm add -D vitepress
$ yarn add -D vitepress
```
```sh [yarn (pnp)]
$ yarn add -D vitepress vue
```
```sh [bun]
$ bun add -D vitepress
```

@ -3,13 +3,11 @@
VitePress comes with out-of-the-box support for generating a `sitemap.xml` file for your site. To enable it, add the following to your `.vitepress/config.js`:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
export default {
sitemap: {
hostname: 'https://example.com'
}
})
}
```
To have `<lastmod>` tags in your `sitemap.xml`, you can enable the [`lastUpdated`](../reference/default-theme-last-updated) option.
@ -19,14 +17,23 @@ To have `<lastmod>` tags in your `sitemap.xml`, you can enable the [`lastUpdated
Sitemap support is powered by the [`sitemap`](https://www.npmjs.com/package/sitemap) module. You can pass any options supported by it to the `sitemap` option in your config file. These will be passed directly to the `SitemapStream` constructor. Refer to the [`sitemap` documentation](https://www.npmjs.com/package/sitemap#options-you-can-pass) for more details. Example:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
export default {
sitemap: {
hostname: 'https://example.com',
lastmodDateOnly: false
}
})
}
```
If you're using `base` in your config, you should append it to the `hostname` option:
```ts
export default {
base: '/my-site/',
sitemap: {
hostname: 'https://example.com/my-site/'
}
}
```
## `transformItems` Hook
@ -34,9 +41,7 @@ export default defineConfig({
You can use the `sitemap.transformItems` hook to modify the sitemap items before they are written to the `sitemap.xml` file. This hook is called with an array of sitemap items and expects an array of sitemap items to be returned. Example:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
export default {
sitemap: {
hostname: 'https://example.com',
transformItems: (items) => {
@ -49,5 +54,5 @@ export default defineConfig({
return items
}
}
})
}
```

@ -10,7 +10,7 @@
"preview": "vitepress preview"
},
"devDependencies": {
"@lunariajs/core": "^0.0.32",
"@lunariajs/core": "^0.1.0",
"markdown-it-mathjax3": "^4.3.2",
"open-cli": "^8.0.0",
"vitepress": "workspace:*"

@ -29,6 +29,10 @@ $ pnpm add -D vitepress
$ yarn add -D vitepress
```
```sh [yarn (pnp)]
$ yarn add -D vitepress vue
```
```sh [bun]
$ bun add -D vitepress
```

@ -29,6 +29,10 @@ $ pnpm add -D vitepress
$ yarn add -D vitepress
```
```sh [yarn (pnp)]
$ yarn add -D vitepress vue
```
```sh [bun]
$ bun add -D vitepress
```

@ -3,13 +3,11 @@
VitePress поставляется с готовой поддержкой генерации файла `sitemap.xml` для вашего сайта. Чтобы включить её, добавьте следующее в файл `.vitepress/config.js`:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
export default {
sitemap: {
hostname: 'https://example.com'
}
})
}
```
Чтобы теги `<lastmod>` присутствовали в вашем файле `sitemap.xml`, вы можете включить опцию [`lastUpdated`](../reference/default-theme-last-updated).
@ -19,14 +17,23 @@ export default defineConfig({
Поддержка карты сайта осуществляется с помощью модуля [`sitemap`](https://www.npmjs.com/package/sitemap). Вы можете передать любые поддерживаемые им параметры в опцию `sitemap` в вашем конфигурационном файле. Они будут переданы непосредственно в конструктор `SitemapStream`. Более подробную информацию см. в документации [`sitemap`](https://www.npmjs.com/package/sitemap#options-you-can-pass). Пример:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
export default {
sitemap: {
hostname: 'https://example.com',
lastmodDateOnly: false
}
})
}
```
При использовании параметра `base` в своей конфигурации обязательно добавьте его в адрес `hostname`:
```ts
export default {
base: '/my-site/',
sitemap: {
hostname: 'https://example.com/my-site/'
}
}
```
## Хук `transformItems` {#transformitems-hook}
@ -34,9 +41,7 @@ export default defineConfig({
Вы можете использовать хук `sitemap.transformItems` для изменения элементов карты сайта перед их записью в файл `sitemap.xml`. Этот хук вызывается с массивом элементов sitemap и ожидает возвращения массива элементов sitemap. Пример:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
export default {
sitemap: {
hostname: 'https://example.com',
transformItems: (items) => {
@ -49,5 +54,5 @@ export default defineConfig({
return items
}
}
})
}
```

@ -28,7 +28,7 @@ export default defineConfig({
### i18n {#local-search-i18n}
Вы можете использовать подобную конфигурацию для использования многоязычного поиска:
Пример конфигурации для использования многоязычного поиска:
```ts
import { defineConfig } from 'vitepress'
@ -199,7 +199,7 @@ export default defineConfig({
### i18n {#algolia-search-i18n}
Вы можете использовать подобную конфигурацию для использования многоязычного поиска:
Пример конфигурации для использования многоязычного поиска:
```ts
import { defineConfig } from 'vitepress'

@ -287,3 +287,51 @@ Cache-Control: max-age=31536000,immutable
### Kinsta 静态站点托管 {#kinsta-static-site-hosting}
你可以按照这些[说明](https://kinsta.com/docs/vitepress-static-site-example/) 在 [Kinsta](https://kinsta.com/static-site-hosting/) 上部署 Vitepress 站点。
### Stormkit
你可以按照这些[说明](https://stormkit.io/blog/how-to-deploy-vitepress)将你的 VitePress 项目部署到 [Stormkit](https://www.stormkit.io)。
### Nginx
下面是一个 Nginx 服务器块配置示例。此配置包括对基于文本的常见资源的 gzip 压缩、使用适当缓存头为 VitePress 站点静态文件提供服务的规则以及处理 `cleanUrls: true` 的方法。
```nginx
server {
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
listen 80;
server_name _;
index index.html;
location / {
# content location
root /app;
# exact matches -> reverse clean urls -> folders -> not found
try_files $uri $uri.html $uri/ =404;
# non existent pages
error_page 404 /404.html;
# a folder without index.html raises 403 in this setup
error_page 403 /404.html;
# adjust caching headers
# files in the assets folder have hashes filenames
location ~* ^/assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
}
```
本配置默认已构建的 VitePress 站点位于服务器上的 `/app` 目录中。如果站点文件位于其他位置,请相应调整 `root` 指令。
::: warning 不要默认为 index.html
try_files 解析不能像其他 Vue 应用那样默认为 index.html。这会导致页面状态处于无效。
:::
更多信息请参见 [nginx 官方文档](https://nginx.org/en/docs/)、这些 GitHub Issue [#2837](https://github.com/vuejs/vitepress/discussions/2837)、[#3235](https://github.com/vuejs/vitepress/issues/3235)以及 Mehdi Merah 发表的[博客](https://blog.mehdi.cc/articles/vitepress-cleanurls-on-nginx-environment#readings)。

@ -29,6 +29,10 @@ $ pnpm add -D vitepress
$ yarn add -D vitepress
```
```sh [yarn (pnp)]
$ yarn add -D vitepress vue
```
```sh [bun]
$ bun add -D vitepress
```
@ -86,7 +90,7 @@ $ bun vitepress init
<<< @/snippets/init.ansi
:::tip Vue 作为 peer dependency
如果打算使用 Vue 组件或 API 进行自定义,还应该明确地将 `vue` 安装为 peer dependency。
如果打算使用 Vue 组件或 API 进行自定义,还应该明确地将 `vue` 安装为 dependency。
:::
## 文件结构 {#file-structure}

@ -3,13 +3,11 @@
VitePress 提供开箱即用的配置,为站点生成 `sitemap.xml` 文件。要启用它,请将以下内容添加到 `.vitepress/config.js` 中:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
export default {
sitemap: {
hostname: 'https://example.com'
}
})
}
```
要在 `sitemap.xml` 中包含 `<lastmod>` 标签,可以启用 [`lastUpdated`](../reference/default-theme-last-updated) 选项。
@ -19,14 +17,23 @@ export default defineConfig({
VitePress 的 sitemap 由 [`sitemap`](https://www.npmjs.com/package/sitemap) 模块提供支持。可以将该模块支持的选项传递给配置文件中的 `sitemap` 选项。这些选项将直接传递给 `SitemapStream` 构造函数。有关更多详细信息,请参阅 [`sitemap` 文档](https://www.npmjs.com/package/sitemap#options-you-can-pass)。例如:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
export default {
sitemap: {
hostname: 'https://example.com',
lastmodDateOnly: false
}
})
}
```
如果在配置中使用 `base`,则应将其追加到 `hostname` 选项中:
```ts
export default {
base: '/my-site/',
sitemap: {
hostname: 'https://example.com/my-site/'
}
}
```
## `transformItems` Hook
@ -34,13 +41,11 @@ export default defineConfig({
在将 sitemap 写入 `sitemap.xml` 文件之前,可以使用 `sitemap.transformItems` 钩子来修改 sitemap。使用 sitemap 调用该钩子,应返回 sitemap 数组。例如:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
export default {
sitemap: {
hostname: 'https://example.com',
transformItems: (items) => {
// 添加新选项或修改/过滤现有选项
// 添加新项目或修改/筛选现有选项
items.push({
url: '/extra-page',
changefreq: 'monthly',
@ -49,5 +54,5 @@ export default defineConfig({
return items
}
}
})
}
```

@ -1,20 +1,17 @@
{
"name": "vitepress",
"version": "1.1.4",
"version": "1.2.2",
"description": "Vite & Vue powered static site generator",
"keywords": [
"vite",
"vue",
"vitepress"
],
"homepage": "https://github.com/vuejs/vitepress/tree/main/#readme",
"homepage": "https://vitepress.dev/",
"bugs": {
"url": "https://github.com/vuejs/vitepress/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/vuejs/vitepress.git"
},
"repository": "github:vuejs/vitepress",
"license": "MIT",
"author": "Evan You",
"type": "module",
@ -104,39 +101,38 @@
"dependencies": {
"@docsearch/css": "^3.6.0",
"@docsearch/js": "^3.6.0",
"@shikijs/core": "^1.4.0",
"@shikijs/transformers": "^1.4.0",
"@shikijs/core": "^1.6.1",
"@shikijs/transformers": "^1.6.1",
"@types/markdown-it": "^14.1.1",
"@vitejs/plugin-vue": "^5.0.4",
"@vue/devtools-api": "^7.0.27",
"@vue/shared": "^3.4.26",
"@vueuse/core": "^10.9.0",
"@vueuse/integrations": "^10.9.0",
"@vitejs/plugin-vue": "^5.0.5",
"@vue/devtools-api": "^7.2.0",
"@vue/shared": "^3.4.27",
"@vueuse/core": "^10.10.0",
"@vueuse/integrations": "^10.10.0",
"focus-trap": "^7.5.4",
"mark.js": "8.11.1",
"minisearch": "^6.3.0",
"shiki": "^1.4.0",
"vite": "^5.2.11",
"vue": "^3.4.26"
"shiki": "^1.6.1",
"vite": "^5.2.12",
"vue": "^3.4.27"
},
"devDependencies": {
"@clack/prompts": "^0.7.0",
"@mdit-vue/plugin-component": "^2.1.2",
"@mdit-vue/plugin-frontmatter": "^2.1.2",
"@mdit-vue/plugin-headers": "^2.1.2",
"@mdit-vue/plugin-sfc": "^2.1.2",
"@mdit-vue/plugin-title": "^2.1.2",
"@mdit-vue/plugin-toc": "^2.1.2",
"@mdit-vue/shared": "^2.1.2",
"@mdit-vue/plugin-component": "^2.1.3",
"@mdit-vue/plugin-frontmatter": "^2.1.3",
"@mdit-vue/plugin-headers": "^2.1.3",
"@mdit-vue/plugin-sfc": "^2.1.3",
"@mdit-vue/plugin-title": "^2.1.3",
"@mdit-vue/plugin-toc": "^2.1.3",
"@mdit-vue/shared": "^2.1.3",
"@polka/compression": "1.0.0-next.25",
"@rollup/plugin-alias": "^5.1.0",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-commonjs": "^25.0.8",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-replace": "^5.0.5",
"@types/cross-spawn": "^6.0.6",
"@types/debug": "^4.1.12",
"@types/escape-html": "^1.0.4",
"@types/fs-extra": "^11.0.4",
"@types/lodash.template": "^4.5.3",
"@types/mark.js": "^8.11.12",
@ -145,57 +141,56 @@
"@types/markdown-it-emoji": "^3.0.1",
"@types/micromatch": "^4.0.7",
"@types/minimist": "^1.2.5",
"@types/node": "^20.12.8",
"@types/node": "^20.12.13",
"@types/postcss-prefix-selector": "^1.16.3",
"@types/prompts": "^2.4.9",
"chokidar": "^3.6.0",
"conventional-changelog-cli": "^4.1.0",
"conventional-changelog-cli": "^5.0.0",
"cross-spawn": "^7.0.3",
"debug": "^4.3.4",
"esbuild": "^0.20.2",
"escape-html": "^1.0.3",
"execa": "^8.0.1",
"debug": "^4.3.5",
"esbuild": "^0.21.4",
"execa": "^9.1.0",
"fast-glob": "^3.3.2",
"fs-extra": "^11.2.0",
"get-port": "^7.1.0",
"gray-matter": "^4.0.3",
"lint-staged": "^15.2.2",
"lint-staged": "^15.2.5",
"lodash.template": "^4.5.0",
"lru-cache": "^10.2.2",
"markdown-it": "^14.1.0",
"markdown-it-anchor": "^8.6.7",
"markdown-it-anchor": "^9.0.1",
"markdown-it-attrs": "^4.1.6",
"markdown-it-container": "^4.0.0",
"markdown-it-emoji": "^3.0.0",
"markdown-it-mathjax3": "^4.3.2",
"micromatch": "^4.0.5",
"micromatch": "^4.0.7",
"minimist": "^1.2.8",
"nanoid": "^5.0.7",
"npm-run-all": "^4.1.5",
"ora": "^8.0.1",
"p-map": "^7.0.2",
"path-to-regexp": "^6.2.2",
"picocolors": "^1.0.0",
"picocolors": "^1.0.1",
"pkg-dir": "^8.0.0",
"playwright-chromium": "^1.43.1",
"playwright-chromium": "^1.44.1",
"polka": "1.0.0-next.25",
"postcss-prefix-selector": "^1.16.1",
"prettier": "^3.2.5",
"prompts": "^2.4.2",
"punycode": "^2.3.1",
"rimraf": "^5.0.5",
"rollup": "^4.17.2",
"rollup-plugin-dts": "^6.1.0",
"rimraf": "^5.0.7",
"rollup": "^4.18.0",
"rollup-plugin-dts": "^6.1.1",
"rollup-plugin-esbuild": "^6.1.1",
"semver": "^7.6.0",
"semver": "^7.6.2",
"simple-git-hooks": "^2.11.1",
"sirv": "^2.0.4",
"sitemap": "^7.1.1",
"sitemap": "^8.0.0",
"sort-package-json": "^2.10.0",
"supports-color": "^9.4.0",
"typescript": "^5.4.5",
"vitest": "^1.5.3",
"vue-tsc": "2.0.14",
"vitest": "^1.6.0",
"vue-tsc": "^2.0.19",
"wait-on": "^7.2.0"
},
"peerDependencies": {
@ -210,7 +205,7 @@
"optional": true
}
},
"packageManager": "pnpm@9.0.6",
"packageManager": "pnpm@9.1.4",
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
@ -221,10 +216,6 @@
},
"overrides": {
"ora>string-width": "^5"
},
"patchedDependencies": {
"markdown-it-anchor@8.6.7": "patches/markdown-it-anchor@8.6.7.patch",
"rollup-plugin-dts@6.1.0": "patches/rollup-plugin-dts@6.1.0.patch"
}
}
}

@ -1,29 +0,0 @@
diff --git a/types/index.d.ts b/types/index.d.ts
index 7c94aae194faa66ca006ace98cdb0dee82a3e471..0377cace7c4a9653d4ecf963babffd4bd68494b0 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -1,10 +1,10 @@
-import MarkdownIt = require('markdown-it');
-import Token = require('markdown-it/lib/token');
-import State = require('markdown-it/lib/rules_core/state_core');
+import MarkdownIt from 'markdown-it';
+import Token from 'markdown-it/lib/token.mjs';
+import StateCore from 'markdown-it/lib/rules_core/state_core.mjs';
declare namespace anchor {
- export type RenderHref = (slug: string, state: State) => string;
- export type RenderAttrs = (slug: string, state: State) => Record<string, string | number>;
+ export type RenderHref = (slug: string, state: StateCore) => string;
+ export type RenderAttrs = (slug: string, state: StateCore) => Record<string, string | number>;
export interface PermalinkOptions {
class?: string,
@@ -37,7 +37,7 @@ declare namespace anchor {
placement?: 'before' | 'after'
}
- export type PermalinkGenerator = (slug: string, opts: PermalinkOptions, state: State, index: number) => void;
+ export type PermalinkGenerator = (slug: string, opts: PermalinkOptions, state: StateCore, index: number) => void;
export interface AnchorInfo {
slug: string;

@ -1,13 +0,0 @@
diff --git a/dist/rollup-plugin-dts.mjs b/dist/rollup-plugin-dts.mjs
index 4a9412285c48c37d03340a086c771f8e61fd82ac..c73cba3bf47550f69011366e37d2ae974f0c9fc0 100644
--- a/dist/rollup-plugin-dts.mjs
+++ b/dist/rollup-plugin-dts.mjs
@@ -675,6 +675,8 @@ function preProcess({ sourceFile }) {
const nextToken = children[idx + 1];
const isPunctuation = nextToken.kind >= ts.SyntaxKind.FirstPunctuation && nextToken.kind <= ts.SyntaxKind.LastPunctuation;
if (isPunctuation) {
+ const addSpace = code.slice(token.getEnd(), nextToken.getStart()) != " ";
+ code.appendLeft(nextToken.getStart(), `${addSpace ? " " : ""}${defaultExport}`);
code.appendLeft(nextToken.getStart(), defaultExport);
}
else {

File diff suppressed because it is too large Load Diff

@ -13,7 +13,7 @@ import {
type AsyncComponentLoader
} from 'vue'
export { inBrowser } from '../shared'
export { inBrowser, escapeHtml as _escapeHtml } from '../shared'
/**
* Join two paths by resolving the slash collision.

@ -21,7 +21,8 @@ export {
onContentUpdated,
defineClientComponent,
withBase,
getScrollOffset
getScrollOffset,
_escapeHtml
} from './app/utils'
// components

@ -30,7 +30,6 @@ useActiveAnchor(container, marker)
class="VPDocAsideOutline"
:class="{ 'has-outline': headers.length > 0 }"
ref="container"
role="navigation"
>
<div class="content">
<div class="outline-marker" ref="marker" />

@ -242,8 +242,7 @@ vite-error-overlay {
}
mjx-container {
display: inline-block;
margin: auto 2px -2px;
overflow-x: auto;
}
mjx-container > svg {

@ -268,11 +268,11 @@
font-optical-sizing: auto;
}
:root:lang(zh) {
:root:where(:lang(zh)) {
--vp-font-family-base: 'Punctuation SC', 'Inter', ui-sans-serif, system-ui,
'PingFang SC', 'Noto Sans CJK SC', 'Noto Sans SC', 'Heiti SC', 'DengXian',
'Microsoft YaHei', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
'Segoe UI Symbol', 'Noto Color Emoji';
'PingFang SC', 'Noto Sans CJK SC', 'Noto Sans SC', 'Heiti SC',
'Microsoft YaHei', 'DengXian', sans-serif, 'Apple Color Emoji',
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
}
/**

@ -1,13 +1,14 @@
import { isBooleanAttr } from '@vue/shared'
import escape from 'escape-html'
import fs from 'fs-extra'
import path from 'path'
import { pathToFileURL } from 'url'
import { normalizePath, transformWithEsbuild, type Rollup } from 'vite'
import { version } from '../../../package.json'
import type { SiteConfig } from '../config'
import {
EXTERNAL_URL_RE,
createTitle,
escapeHtml,
mergeHead,
notFoundPageData,
resolveSiteDataByRoute,
@ -17,7 +18,6 @@ import {
type PageData,
type SSGContext
} from '../shared'
import { version } from '../../../package.json'
export async function renderPage(
render: (path: string) => Promise<SSGContext>,
@ -163,7 +163,7 @@ export async function renderPage(
? ''
: '<meta name="viewport" content="width=device-width,initial-scale=1">'
}
<title>${title}</title>
<title>${escapeHtml(title)}</title>
${
isDescriptionOverridden(head)
? ''
@ -260,7 +260,7 @@ function renderAttrs(attrs: Record<string, string>): string {
return Object.keys(attrs)
.map((key) => {
if (isBooleanAttr(key)) return ` ${key}`
return ` ${key}="${escape(attrs[key] as string)}"`
return ` ${key}="${escapeHtml(attrs[key] as string)}"`
})
.join('')
}

@ -231,6 +231,10 @@ export const createMarkdownRenderer = async (
)
.use(lineNumberPlugin, options.lineNumbers)
md.renderer.rules.table_open = function (tokens, idx, options, env, self) {
return '<table tabindex="0">\n'
}
if (options.gfmAlerts !== false) {
md.use(gitHubAlertsPlugin)
}
@ -287,6 +291,13 @@ export const createMarkdownRenderer = async (
md.use(mathPlugin.default ?? mathPlugin, {
...(typeof options.math === 'boolean' ? {} : options.math)
})
const orig = md.renderer.rules.math_block!
md.renderer.rules.math_block = (tokens, idx, options, env, self) => {
return orig(tokens, idx, options, env, self).replace(
/^<mjx-container /,
'<mjx-container tabindex="0" '
)
}
} catch (error) {
throw new Error(
'You need to install `markdown-it-mathjax3` to use math support.'

@ -1,8 +1,10 @@
import type MarkdownIt from 'markdown-it'
import container from 'markdown-it-container'
import type { RenderRule } from 'markdown-it/lib/renderer.mjs'
import type Token from 'markdown-it/lib/token.mjs'
import container from 'markdown-it-container'
import { nanoid } from 'nanoid'
import type { MarkdownEnv } from '../../shared'
import {
extractTitle,
getAdaptiveThemeMarker,
@ -60,7 +62,7 @@ function createContainer(
container,
klass,
{
render(tokens, idx, _options, env) {
render(tokens, idx, _options, env: MarkdownEnv & { references?: any }) {
const token = tokens[idx]
const info = token.info.trim().slice(klass.length).trim()
const attrs = md.renderer.renderAttrs(token)

@ -85,7 +85,6 @@ export async function highlight(
{
name: 'vitepress:clean-up',
pre(node) {
delete node.properties.tabindex
delete node.properties.style
}
}

@ -1,11 +1,50 @@
import type MarkdownIt from 'markdown-it'
import type StateCore from 'markdown-it/lib/rules_core/state_core.mjs'
import type Token from 'markdown-it/lib/token.mjs'
import { escapeHtml } from '../../shared'
export function restoreEntities(md: MarkdownIt): void {
md.core.ruler.disable('text_join')
md.renderer.rules.text_special = (tokens, idx) => {
if (tokens[idx].info === 'entity') {
return tokens[idx].markup // leave as is so Vue can handle it
}
return md.utils.escapeHtml(tokens[idx].content)
md.core.ruler.at('text_join', text_join)
md.renderer.rules.text = (tokens, idx) => escapeHtml(tokens[idx].content)
}
function text_join(state: StateCore): void {
let curr, last
const blockTokens = state.tokens
const l = blockTokens.length
for (let j = 0; j < l; ++j) {
if (blockTokens[j].type !== 'inline') continue
const tokens = blockTokens[j].children || []
const max = tokens.length
for (curr = 0; curr < max; ++curr)
if (tokens[curr].type === 'text_special') tokens[curr].type = 'text'
for (curr = last = 0; curr < max; ++curr)
if (
tokens[curr].type === 'text' &&
curr + 1 < max &&
tokens[curr + 1].type === 'text'
) {
tokens[curr + 1].content =
getContent(tokens[curr]) + getContent(tokens[curr + 1])
tokens[curr + 1].info = ''
tokens[curr + 1].markup = ''
} else {
if (curr !== last) tokens[last] = tokens[curr]
++last
}
if (curr !== last) tokens.length = last
}
}
function getContent(token: Token): string {
return token.info === 'entity'
? token.markup
: token.info === 'escape' && token.content === '&'
? '&amp;'
: token.content
}

@ -11,11 +11,12 @@ import {
} from './markdown/markdown'
import {
EXTERNAL_URL_RE,
getLocaleForPath,
slash,
treatAsHtml,
type HeadConfig,
type MarkdownEnv,
type PageData,
treatAsHtml
type PageData
} from './shared'
import { getGitTimestamp } from './utils/getGitTimestamp'
import { processIncludes } from './utils/processIncludes'
@ -95,13 +96,16 @@ export async function createMarkdownToVueRenderFn(
let includes: string[] = []
src = processIncludes(srcDir, src, fileOrig, includes)
const localeIndex = getLocaleForPath(siteConfig?.site, relativePath)
// reset env before render
const env: MarkdownEnv = {
path: file,
relativePath,
cleanUrls,
includes,
realPath: fileOrig
realPath: fileOrig,
localeIndex
}
const html = md.render(src, env)
const {

@ -87,7 +87,7 @@ export async function createVitePressPlugin(
if (markdown?.math) {
isCustomElement = (tag) => {
if (['mjx-container', 'mjx-assistive-mml'].includes(tag)) {
if (tag.startsWith('mjx-')) {
return true
}
return userCustomElementChecker?.(tag) ?? false

@ -7,7 +7,7 @@ import type { Plugin, ViteDevServer } from 'vite'
import type { SiteConfig } from '../config'
import { createMarkdownRenderer } from '../markdown/markdown'
import {
resolveSiteDataByRoute,
getLocaleForPath,
slash,
type DefaultTheme,
type MarkdownEnv
@ -83,12 +83,6 @@ export async function localSearchPlugin(
return index
}
function getLocaleForPath(file: string) {
const relativePath = slash(path.relative(siteConfig.srcDir, file))
const siteData = resolveSiteDataByRoute(siteConfig.site, relativePath)
return siteData?.localeIndex ?? 'root'
}
let server: ViteDevServer | undefined
function onIndexUpdated() {
@ -126,7 +120,7 @@ export async function localSearchPlugin(
const file = path.join(siteConfig.srcDir, page)
// get file metadata
const fileId = getDocId(file)
const locale = getLocaleForPath(file)
const locale = getLocaleForPath(siteConfig.site, page)
const index = getIndexByLocale(locale)
// retrieve file and split into "sections"
const html = await render(file)

@ -72,6 +72,20 @@ export function isExternal(path: string): boolean {
return EXTERNAL_URL_RE.test(path)
}
export function getLocaleForPath(
siteData: SiteData | undefined,
relativePath: string
): string {
return (
Object.keys(siteData?.locales || {}).find(
(key) =>
key !== 'root' &&
!isExternal(key) &&
isActive(relativePath, `/${key}/`, true)
) || 'root'
)
}
/**
* this merges the locales data to the main data by the route
*/
@ -79,13 +93,7 @@ export function resolveSiteDataByRoute(
siteData: SiteData,
relativePath: string
): SiteData {
const localeIndex =
Object.keys(siteData.locales).find(
(key) =>
key !== 'root' &&
!isExternal(key) &&
isActive(relativePath, `/${key}/`, true)
) || 'root'
const localeIndex = getLocaleForPath(siteData, relativePath)
return Object.assign({}, siteData, {
localeIndex,
@ -211,3 +219,14 @@ export function treatAsHtml(filename: string): boolean {
export function escapeRegExp(str: string) {
return str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d')
}
/**
* @internal
*/
export function escapeHtml(str: string): string {
return str
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/&(?![\w#]+;)/g, '&amp;')
}

1
types/shared.d.ts vendored

@ -200,4 +200,5 @@ export interface MarkdownEnv {
links?: string[]
includes?: string[]
realPath?: string
localeIndex?: string
}

Loading…
Cancel
Save