Merge branch 'vuejs:main' into main

pull/3640/head
Timothy Lau 2 months ago committed by GitHub
commit 6bcf94604d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -2,12 +2,13 @@ name: Lock Threads
on:
schedule:
- cron: 0 0 * * *
- cron: 38 4 * * *
workflow_dispatch:
permissions:
issues: write
pull-requests: write
discussions: write
concurrency:
group: lock

@ -1,3 +1,15 @@
## [1.1.4](https://github.com/vuejs/vitepress/compare/v1.1.3...v1.1.4) (2024-04-27)
### Bug Fixes
- **dev:** multiple server instances being created when editing config too quickly ([#3835](https://github.com/vuejs/vitepress/issues/3835)) ([729a890](https://github.com/vuejs/vitepress/commit/729a890669c363895cfac39ece046926cad36d01))
- **theme/a11y:** add unique name to footer prev / next navigation landmark ([e60c101](https://github.com/vuejs/vitepress/commit/e60c101e50fa56d4cd54d434c5628cc7e2231318))
- **theme/a11y:** remove duplicate assistive text from outline nav ([#3803](https://github.com/vuejs/vitepress/issues/3803)) ([733d986](https://github.com/vuejs/vitepress/commit/733d986a84f614484b04235546dc4cda0769e833))
- **theme/i18n:** 404 page not showing localized text ([#3833](https://github.com/vuejs/vitepress/issues/3833)) ([cc11b8e](https://github.com/vuejs/vitepress/commit/cc11b8e41ec481320b03902bdc307d479a8ba838))
- **theme:** disable keypress effect on search button ([ccc37bb](https://github.com/vuejs/vitepress/commit/ccc37bb80e4147b9ab91b0f5d7dfae9d51533460))
- **theme:** don't use Chinese quotes on non-Chinese documents ([#3834](https://github.com/vuejs/vitepress/issues/3834)) ([75115f4](https://github.com/vuejs/vitepress/commit/75115f4f8223d67dab2dc82fadaf2941aabf6330))
- **theme:** leaking event listener when going back/forward on Safari on iOS ([#3658](https://github.com/vuejs/vitepress/issues/3658)) ([#3671](https://github.com/vuejs/vitepress/issues/3671)) ([1a72181](https://github.com/vuejs/vitepress/commit/1a72181c06d78e5e6f293e3f6abdb15caa4d2f53))
## [1.1.3](https://github.com/vuejs/vitepress/compare/v1.1.1...v1.1.3) (2024-04-18)
### Bug Fixes

@ -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
}
}
})
}
```

@ -1,6 +1,6 @@
{
"name": "vitepress",
"version": "1.1.3",
"version": "1.1.4",
"description": "Vite & Vue powered static site generator",
"keywords": [
"vite",
@ -104,19 +104,20 @@
"dependencies": {
"@docsearch/css": "^3.6.0",
"@docsearch/js": "^3.6.0",
"@shikijs/core": "^1.3.0",
"@shikijs/transformers": "^1.3.0",
"@types/markdown-it": "^14.0.1",
"@shikijs/core": "^1.4.0",
"@shikijs/transformers": "^1.4.0",
"@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",
"focus-trap": "^7.5.4",
"mark.js": "8.11.1",
"minisearch": "^6.3.0",
"shiki": "^1.3.0",
"vite": "^5.2.9",
"vue": "^3.4.23"
"shiki": "^1.4.0",
"vite": "^5.2.11",
"vue": "^3.4.26"
},
"devDependencies": {
"@clack/prompts": "^0.7.0",
@ -141,13 +142,12 @@
"@types/mark.js": "^8.11.12",
"@types/markdown-it-attrs": "^4.1.3",
"@types/markdown-it-container": "^2.0.10",
"@types/markdown-it-emoji": "^2.0.5",
"@types/markdown-it-emoji": "^3.0.1",
"@types/micromatch": "^4.0.7",
"@types/minimist": "^1.2.5",
"@types/node": "^20.12.7",
"@types/node": "^20.12.8",
"@types/postcss-prefix-selector": "^1.16.3",
"@types/prompts": "^2.4.9",
"@vue/shared": "^3.4.23",
"chokidar": "^3.6.0",
"conventional-changelog-cli": "^4.1.0",
"cross-spawn": "^7.0.3",
@ -161,7 +161,7 @@
"gray-matter": "^4.0.3",
"lint-staged": "^15.2.2",
"lodash.template": "^4.5.0",
"lru-cache": "^10.2.0",
"lru-cache": "^10.2.2",
"markdown-it": "^14.1.0",
"markdown-it-anchor": "^8.6.7",
"markdown-it-attrs": "^4.1.6",
@ -179,12 +179,12 @@
"pkg-dir": "^8.0.0",
"playwright-chromium": "^1.43.1",
"polka": "1.0.0-next.25",
"postcss-prefix-selector": "^1.16.0",
"postcss-prefix-selector": "^1.16.1",
"prettier": "^3.2.5",
"prompts": "^2.4.2",
"punycode": "^2.3.1",
"rimraf": "^5.0.5",
"rollup": "^4.14.3",
"rollup": "^4.17.2",
"rollup-plugin-dts": "^6.1.0",
"rollup-plugin-esbuild": "^6.1.1",
"semver": "^7.6.0",
@ -194,8 +194,8 @@
"sort-package-json": "^2.10.0",
"supports-color": "^9.4.0",
"typescript": "^5.4.5",
"vitest": "^1.5.0",
"vue-tsc": "^2.0.13",
"vitest": "^1.5.3",
"vue-tsc": "2.0.14",
"wait-on": "^7.2.0"
},
"peerDependencies": {
@ -210,7 +210,7 @@
"optional": true
}
},
"packageManager": "pnpm@9.0.2",
"packageManager": "pnpm@9.0.6",
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
@ -223,8 +223,8 @@
"ora>string-width": "^5"
},
"patchedDependencies": {
"@types/markdown-it@14.0.1": "patches/@types__markdown-it@14.0.1.patch",
"markdown-it-anchor@8.6.7": "patches/markdown-it-anchor@8.6.7.patch"
"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,13 +0,0 @@
diff --git a/package.json b/package.json
index 3b3cdfc4427a1a64fdd3b37604a7174e4646e423..afaea16b115554fcf15a905642562e881ece7ca6 100644
--- a/package.json
+++ b/package.json
@@ -27,7 +27,7 @@
}
],
"main": "",
- "types": "index.d.ts",
+ "types": "index.d.mts",
"exports": {
".": {
"import": "./index.d.mts",

@ -0,0 +1,13 @@
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

@ -11,15 +11,15 @@ import replace from '@rollup/plugin-replace'
import alias from '@rollup/plugin-alias'
import dts from 'rollup-plugin-dts'
const ROOT = fileURLToPath(import.meta.url)
const r = (p: string) => resolve(ROOT, '..', p)
const require = createRequire(import.meta.url)
const pkg = require('./package.json')
const pkg = require(r('package.json'))
const DEV = !!process.env.DEV
const PROD = !DEV
const ROOT = fileURLToPath(import.meta.url)
const r = (p: string) => resolve(ROOT, '..', p)
const external = [
...Object.keys(pkg.dependencies),
...Object.keys(pkg.peerDependencies),
@ -29,11 +29,7 @@ const external = [
]
const plugins = [
alias({
entries: {
'readable-stream': 'stream'
}
}),
alias({ entries: { 'readable-stream': 'stream' } }),
replace({
// polyfill broken browser check from bundled deps
'navigator.userAgentData': 'undefined',
@ -69,21 +65,34 @@ const typesExternal = [
'fast-glob'
]
const dtsNode = dts({
respectExternal: true,
tsconfig: r('src/node/tsconfig.json')
})
const originalResolveId = dtsNode.resolveId
dtsNode.resolveId = async function (source, importer) {
const res = await (originalResolveId as Function).call(this, source, importer)
if (res?.id) res.id = await fs.realpath(res.id)
return res
}
const nodeTypes: RollupOptions = {
input: r('src/node/index.ts'),
output: {
format: 'esm',
file: 'dist/node/index.d.ts'
file: r('dist/node/index.d.ts')
},
external: typesExternal,
plugins: [dts({ respectExternal: true })]
plugins: [dtsNode]
}
const clientTypes: RollupOptions = {
input: r('dist/client-types/index.d.ts'),
output: {
format: 'esm',
file: 'dist/client/index.d.ts'
file: r('dist/client/index.d.ts')
},
external: typesExternal,
plugins: [
@ -99,10 +108,4 @@ const clientTypes: RollupOptions = {
]
}
const config = defineConfig([])
config.push(esmBuild)
config.push(nodeTypes)
config.push(clientTypes)
export default config
export default defineConfig([esmBuild, nodeTypes, clientTypes])

@ -137,8 +137,21 @@ function newRouter(): Router {
pageFilePath = pageFilePath.replace(/\.js$/, '.lean.js')
}
if (import.meta.env.SSR) {
pageModule = import(/*@vite-ignore*/ pageFilePath + '?t=' + Date.now())
if (import.meta.env.DEV) {
pageModule = import(/*@vite-ignore*/ pageFilePath).catch(() => {
// try with/without trailing slash
// in prod this is handled in src/client/app/utils.ts#pathToFile
const url = new URL(pageFilePath!, 'http://a.com')
const path =
(url.pathname.endsWith('/index.md')
? url.pathname.slice(0, -9) + '.md'
: url.pathname.slice(0, -3) + '/index.md') +
url.search +
url.hash
return import(/*@vite-ignore*/ path)
})
} else if (import.meta.env.SSR) {
pageModule = import(/*@vite-ignore*/ `${pageFilePath}?t=${Date.now()}`)
} else {
pageModule = import(/*@vite-ignore*/ pageFilePath)
}

@ -156,7 +156,13 @@ export function createRouter(
latestPendingPath = null
route.path = inBrowser ? pendingPath : withBase(pendingPath)
route.component = fallbackComponent ? markRaw(fallbackComponent) : null
route.data = notFoundPageData
const relativePath = inBrowser
? pendingPath
.replace(/(^|\/)$/, '$1index')
.replace(/(\.html)?$/, '.md')
.replace(/^\//, '')
: '404.md'
route.data = { ...notFoundPageData, relativePath }
}
}
}

@ -1,55 +1,31 @@
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { withBase } from 'vitepress'
import { useData } from './composables/data'
import { useLangs } from './composables/langs'
const { site } = useData()
const { localeLinks } = useLangs({ removeCurrent: false })
const locale = ref({
link: '/',
index: 'root'
})
onMounted(() => {
const path = window.location.pathname
.replace(site.value.base, '')
.replace(/(^.*?\/).*$/, '/$1')
if (localeLinks.value.length) {
locale.value =
localeLinks.value.find(({ link }) => link.startsWith(path)) ||
localeLinks.value[0]
}
})
const notFound = computed(() => ({
code: 404,
title: 'PAGE NOT FOUND',
quote:
"But if you don't change your direction, and if you keep looking, you may end up where you are heading.",
linkLabel: 'go to home',
linkText: 'Take me home',
...(locale.value.index === 'root'
? site.value.themeConfig?.notFound
: site.value.locales?.[locale.value.index]?.themeConfig?.notFound)
}))
const { theme } = useData()
const { currentLang } = useLangs()
</script>
<template>
<div class="NotFound">
<p class="code">{{ notFound.code }}</p>
<h1 class="title">{{ notFound.title }}</h1>
<p class="code">{{ theme.notFound?.code ?? '404' }}</p>
<h1 class="title">{{ theme.notFound?.title ?? 'PAGE NOT FOUND' }}</h1>
<div class="divider" />
<blockquote class="quote">{{ notFound.quote }}</blockquote>
<blockquote class="quote">
{{
theme.notFound?.quote ??
"But if you don't change your direction, and if you keep looking, you may end up where you are heading."
}}
</blockquote>
<div class="action">
<a
class="link"
:href="withBase(locale.link)"
:aria-label="notFound.linkLabel"
:href="withBase(currentLang.link)"
:aria-label="theme.notFound?.linkLabel ?? 'go to home'"
>
{{ notFound.linkText }}
{{ theme.notFound?.linkText ?? 'Take me home' }}
</a>
</div>
</div>

@ -1,7 +1,10 @@
<script setup lang="ts">
import { useWindowSize } from '@vueuse/core'
const { width: vw } = useWindowSize({ includeScrollbar: false })
const { width: vw } = useWindowSize({
initialWidth: 0,
includeScrollbar: false
})
</script>
<template>
@ -46,7 +49,7 @@ const { width: vw } = useWindowSize({ includeScrollbar: false })
}
.vp-doc :deep(.VPHomeSponsors a),
.vp-doc :deep(.VPTeamPage a){
.vp-doc :deep(.VPTeamPage a) {
text-decoration: none;
}
</style>

@ -12,7 +12,11 @@ const props = defineProps<{
}>()
const tag = computed(() => props.tag ?? (props.href ? 'a' : 'span'))
const isExternal = computed(() => props.href && EXTERNAL_URL_RE.test(props.href))
const isExternal = computed(
() =>
(props.href && EXTERNAL_URL_RE.test(props.href)) ||
props.target === '_blank'
)
</script>
<template>

@ -291,11 +291,7 @@ watch(results, (r) => {
function scrollToSelectedResult() {
nextTick(() => {
const selectedEl = document.querySelector('.result.selected')
if (selectedEl) {
selectedEl.scrollIntoView({
block: 'nearest'
})
}
selectedEl?.scrollIntoView({ block: 'nearest' })
})
}

@ -2,13 +2,9 @@ import { computed } from 'vue'
import { ensureStartingSlash } from '../support/utils'
import { useData } from './data'
export function useLangs({
removeCurrent = true,
correspondingLink = false
} = {}) {
export function useLangs({ correspondingLink = false } = {}) {
const { site, localeIndex, page, theme, hash } = useData()
const currentLang = computed(() => ({
index: localeIndex.value,
label: site.value.locales[localeIndex.value]?.label,
link:
site.value.locales[localeIndex.value]?.link ||
@ -17,10 +13,9 @@ export function useLangs({
const localeLinks = computed(() =>
Object.entries(site.value.locales).flatMap(([key, value]) =>
removeCurrent && currentLang.value.label === value.label
currentLang.value.label === value.label
? []
: {
index: key,
text: value.label,
link:
normalizeLink(

@ -146,12 +146,40 @@ html body {
U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Chinese quotes rendering fix. 中英文弯引号共享 Unicode 码位,确保引号使用中文字体渲染 */
@font-face {
font-family: 'Chinese Quotes';
src: local('PingFang SC Regular'), local('PingFang SC'), local('SimHei'),
local('Source Han Sans SC');
unicode-range: U+2018, U+2019, U+201C, U+201D; /* 分别是 ‘’“” */
font-family: 'Punctuation SC';
font-weight: 400;
src: local('PingFang SC Regular'), local('Noto Sans CJK SC'),
local('Microsoft YaHei');
unicode-range: U+201C, U+201D, U+2018, U+2019, U+2E3A, U+2014, U+2013, U+2026,
U+00B7, U+007E, U+002F;
}
@font-face {
font-family: 'Punctuation SC';
font-weight: 500;
src: local('PingFang SC Medium'), local('Noto Sans CJK SC'),
local('Microsoft YaHei');
unicode-range: U+201C, U+201D, U+2018, U+2019, U+2E3A, U+2014, U+2013, U+2026,
U+00B7, U+007E, U+002F;
}
@font-face {
font-family: 'Punctuation SC';
font-weight: 600;
src: local('PingFang SC Semibold'), local('Noto Sans CJK SC Bold'),
local('Microsoft YaHei Bold');
unicode-range: U+201C, U+201D, U+2018, U+2019, U+2E3A, U+2014, U+2013, U+2026,
U+00B7, U+007E, U+002F;
}
@font-face {
font-family: 'Punctuation SC';
font-weight: 700;
src: local('PingFang SC Semibold'), local('Noto Sans CJK SC Bold'),
local('Microsoft YaHei Bold');
unicode-range: U+201C, U+201D, U+2018, U+2019, U+2E3A, U+2014, U+2013, U+2026,
U+00B7, U+007E, U+002F;
}
/* Generate the subsetted fonts using: `pyftsubset <file>.woff2 --unicodes="<range>" --output-file="inter-<style>-<subset>.woff2" --flavor=woff2` */

@ -261,14 +261,20 @@
* -------------------------------------------------------------------------- */
:root {
--vp-font-family-base: 'Chinese Quotes', Inter, ui-sans-serif, system-ui,
sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
'Noto Color Emoji';
--vp-font-family-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
--vp-font-family-base: 'Inter', ui-sans-serif, system-ui, sans-serif,
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
--vp-font-family-mono: ui-monospace, 'Menlo', 'Monaco', 'Consolas',
'Liberation Mono', 'Courier New', monospace;
font-optical-sizing: auto;
}
: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';
}
/**
* Shadows
* -------------------------------------------------------------------------- */

@ -3,11 +3,8 @@
"compilerOptions": {
"baseUrl": ".",
"outDir": "../../dist/client",
"moduleResolution": "bundler",
"declaration": true,
"declarationDir": "../../dist/client-types",
"jsx": "preserve",
"lib": ["esnext", "dom", "dom.iterable"],
"types": ["vite/client"],
"paths": {
"vitepress": ["index.ts"],

@ -180,7 +180,7 @@ export async function renderPage(
${await renderHead(head)}
</head>
<body>${teleports?.body || ''}
<div id="app">${content}</div>
<div id="app">${page === '404.md' ? '' : content}</div>
${metadataScript.inHead ? '' : metadataScript.html}
${inlinedScript}
</body>

@ -20,6 +20,8 @@ if (root) {
argv.root = root
}
let restartPromise: Promise<void> | undefined
if (!command || command === 'dev') {
if (argv.force) {
delete argv.force
@ -28,8 +30,16 @@ if (!command || command === 'dev') {
const createDevServer = async () => {
const server = await createServer(root, argv, async () => {
await server.close()
await createDevServer()
if (!restartPromise) {
restartPromise = (async () => {
await server.close()
await createDevServer()
})().finally(() => {
restartPromise = undefined
})
}
return restartPromise
})
await server.listen()
logVersion(server.config.logger)
@ -38,7 +48,7 @@ if (!command || command === 'dev') {
}
createDevServer().catch((err) => {
createLogger().error(
`${c.red(`failed to start server. error:`)}\n${err.stack}`
`${c.red(`failed to start server. error:`)}\n${err.message}\n${err.stack}`
)
process.exit(1)
})
@ -49,13 +59,15 @@ if (!command || command === 'dev') {
logVersion()
if (command === 'build') {
build(root, argv).catch((err) => {
createLogger().error(`${c.red(`build error:`)}\n${err.stack}`)
createLogger().error(
`${c.red(`build error:`)}\n${err.message}\n${err.stack}`
)
process.exit(1)
})
} else if (command === 'serve' || command === 'preview') {
serve(argv).catch((err) => {
createLogger().error(
`${c.red(`failed to start server. error:`)}\n${err.stack}`
`${c.red(`failed to start server. error:`)}\n${err.message}\n${err.stack}`
)
process.exit(1)
})

@ -18,7 +18,6 @@ import type { Options } from 'markdown-it'
import MarkdownIt from 'markdown-it'
import anchorPlugin from 'markdown-it-anchor'
import attrsPlugin from 'markdown-it-attrs'
// @ts-expect-error: types of markdown-it-emoji are not up-to-date
import { full as emojiPlugin } from 'markdown-it-emoji'
import type {
BuiltinTheme,
@ -112,6 +111,11 @@ export interface MarkdownOptions extends Options {
* Setup Shiki instance
*/
shikiSetup?: (shiki: Highlighter) => void | Promise<void>
/**
* The tooltip text for the copy button in code blocks
* @default 'Copy Code'
*/
codeCopyButtonTitle?: string
/* ==================== Markdown It Plugins ==================== */
@ -196,6 +200,7 @@ export const createMarkdownRenderer = async (
logger: Pick<Logger, 'warn'> = console
): Promise<MarkdownRenderer> => {
const theme = options.theme ?? { light: 'github-light', dark: 'github-dark' }
const codeCopyButtonTitle = options.codeCopyButtonTitle || 'Copy Code'
const hasSingleTheme = typeof theme === 'string' || 'name' in theme
const md = MarkdownIt({
@ -215,7 +220,7 @@ export const createMarkdownRenderer = async (
// custom plugins
md.use(componentPlugin, { ...options.component })
.use(highlightLinePlugin)
.use(preWrapperPlugin, { hasSingleTheme })
.use(preWrapperPlugin, { codeCopyButtonTitle, hasSingleTheme })
.use(snippetPlugin, srcDir)
.use(containerPlugin, { hasSingleTheme }, options.container)
.use(imagePlugin, options.image)
@ -230,7 +235,7 @@ export const createMarkdownRenderer = async (
md.use(gitHubAlertsPlugin)
}
// 3rd party plugins
// third party plugins
if (!options.attrs?.disable) {
md.use(attrsPlugin, options.attrs)
}

@ -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)
@ -86,7 +88,7 @@ function createCodeGroup(options: Options): ContainerArgs {
if (tokens[idx].nesting === 1) {
const name = nanoid(5)
let tabs = ''
let checked = 'checked="checked"'
let checked = 'checked'
for (
let i = idx + 1;

@ -1,6 +1,7 @@
import type MarkdownIt from 'markdown-it'
export interface Options {
codeCopyButtonTitle: string
hasSingleTheme: boolean
}
@ -17,10 +18,14 @@ export function preWrapperPlugin(md: MarkdownIt, options: Options) {
token.info = token.info.replace(/ active$/, '').replace(/ active /, ' ')
const lang = extractLang(token.info)
const rawCode = fence(...args)
return `<div class="language-${lang}${getAdaptiveThemeMarker(
options
)}${active}"><button title="Copy Code" class="copy"></button><span class="lang">${lang}</span>${rawCode}</div>`
return (
`<div class="language-${lang}${getAdaptiveThemeMarker(options)}${active}">` +
`<button title="${options.codeCopyButtonTitle}" class="copy"></button>` +
`<span class="lang">${lang}</span>` +
fence(...args) +
'</div>'
)
}
}

@ -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 {

@ -200,8 +200,10 @@ export async function resolveDynamicRoutes(
'silent'
)) as RouteModule
routeModuleCache.set(pathsFile, mod)
} catch (e: any) {
logger.warn(`${c.yellow(`Failed to load ${pathsFile}:`)}\n${e.stack}`)
} catch (err: any) {
logger.warn(
`${c.yellow(`Failed to load ${pathsFile}:`)}\n${err.message}\n${err.stack}`
)
continue
}
}

@ -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)

@ -1,10 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"target": "es2022",
"baseUrl": ".",
"outDir": "../../dist/node",
"module": "esnext",
"types": ["node"],
"sourceMap": true
},

@ -24,7 +24,7 @@ const INDEX_OR_EXT_RE = /(?:(^|\/)index)?\.(?:md|html)$/
export const inBrowser = typeof document !== 'undefined'
export const notFoundPageData: PageData = {
relativePath: '',
relativePath: '404.md',
filePath: '',
title: '404',
description: 'Not Found',
@ -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,

@ -2,7 +2,7 @@
"compilerOptions": {
"module": "esnext",
"target": "esnext",
"moduleResolution": "node",
"moduleResolution": "bundler",
"esModuleInterop": true,
"strict": true,
"skipLibCheck": true,

7
types/shared.d.ts vendored

@ -7,7 +7,11 @@ export type Awaitable<T> = T | PromiseLike<T>
export interface PageData {
relativePath: string
filePath: string // differs from relativePath in case of path rewrites
/**
* differs from relativePath in case of path rewrites
* empty string if the page is virtual (e.g. 404 page)
*/
filePath: string
title: string
titleTemplate?: string | boolean
description: string
@ -196,4 +200,5 @@ export interface MarkdownEnv {
links?: string[]
includes?: string[]
realPath?: string
localeIndex?: string
}

Loading…
Cancel
Save