68 lines
1.9 KiB
TypeScript
68 lines
1.9 KiB
TypeScript
import type { Markdown, MarkdownEnv } from 'vuepress/markdown'
|
|
|
|
/**
|
|
* Regular expression for matching h1 heading
|
|
*
|
|
* 匹配 h1 标题的正则表达式
|
|
*/
|
|
const REG_HEADING = /^#\s*?([^#\s].*)?\n/
|
|
|
|
/**
|
|
* Docs title plugin - Extract h1 title from markdown to frontmatter
|
|
*
|
|
* 文档标题插件 - 从 markdown 中提取 h1 标题到 frontmatter
|
|
*
|
|
* Adapts to theme's document page title by extracting h1 title from markdown to frontmatter
|
|
* and removing it from content to avoid duplicate display.
|
|
*
|
|
* 适配主题的文档页面标题,将 markdown 中的 h1 标题提取到 frontmatter 中,并将其删除,
|
|
* 以避免重复显示标题。
|
|
*
|
|
* @param md - Markdown instance / Markdown 实例
|
|
*/
|
|
export function docsTitlePlugin(md: Markdown): void {
|
|
const render = md.render.bind(md)
|
|
md.render = (source, env: MarkdownEnv) => {
|
|
if (!env.filePathRelative)
|
|
return render(source, env)
|
|
|
|
let { matter, content } = parseSource(source.trim())
|
|
let title = ''
|
|
content = content.trim().replace(REG_HEADING, (_, match) => {
|
|
title = match.trim()
|
|
return ''
|
|
})
|
|
source = `${matter}\n${content}`
|
|
const result = render(source, env)
|
|
if (title) {
|
|
env.frontmatter ??= {}
|
|
env.frontmatter.title ??= title
|
|
}
|
|
return result
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parse markdown source to separate frontmatter and content
|
|
*
|
|
* 解析 markdown 源文件,分离 frontmatter 和内容
|
|
*
|
|
* @param source - Markdown source / Markdown 源文件
|
|
* @returns Object with matter and content / 包含 matter 和 content 的对象
|
|
*/
|
|
function parseSource(source: string) {
|
|
const char = '---'
|
|
|
|
if (!source.startsWith(char)) {
|
|
return { matter: '', content: source }
|
|
}
|
|
else {
|
|
const end = source.indexOf(`\n${char}`)
|
|
const len = char.length + 1
|
|
return {
|
|
matter: source.slice(0, end + len),
|
|
content: source.slice(end + len),
|
|
}
|
|
}
|
|
}
|