feat(docs): Add vitepress for docs & docs workspace
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import MarkdownIt from 'markdown-it'
|
||||
import { highlight } from './highlight'
|
||||
|
||||
interface HoistedTags {
|
||||
script: string[]
|
||||
style: string[]
|
||||
components: string[]
|
||||
}
|
||||
|
||||
type ExtendedMarkdownParsedData = { hoistedTags: HoistedTags }
|
||||
|
||||
let index = 1
|
||||
// hoist <script> and <style> tags out of the returned html
|
||||
// so that they can be placed outside as SFC blocks.
|
||||
export const demoPlugin = (md: MarkdownIt): any => {
|
||||
const RE = /<demo /i
|
||||
|
||||
md.renderer.rules.html_inline = (tokens: any, idx: any) => {
|
||||
const content = tokens[idx].content
|
||||
const data = (md as any).__data as ExtendedMarkdownParsedData
|
||||
const hoistedTags =
|
||||
data.hoistedTags ||
|
||||
(data.hoistedTags = {
|
||||
script: [],
|
||||
style: [],
|
||||
components: [],
|
||||
})
|
||||
|
||||
if (RE.test(content.trim())) {
|
||||
const componentName = `demo${index++}`
|
||||
let language = (content.match(/language=("|')(.*)('|")/) || [])[2] ?? ''
|
||||
const src = (content.match(/src=("|')(\S+)('|")/) || [])[2] ?? ''
|
||||
|
||||
const { realPath, urlPath, importMap } = md as any
|
||||
const absolutePath = path
|
||||
.resolve(realPath ?? urlPath, '../', src)
|
||||
.split(path.sep)
|
||||
.join('/')
|
||||
|
||||
if (!src || !fs.existsSync(absolutePath)) {
|
||||
const warningMsg = `${absolutePath} does not exist!`
|
||||
console.warn(`[vitepress]: ${warningMsg}`)
|
||||
return `<demo src="${absolutePath}" >
|
||||
<p>${warningMsg}</p>`
|
||||
}
|
||||
if (!language) {
|
||||
language = (absolutePath.match(/\.(.+)$/) || [])[1] ?? 'vue'
|
||||
}
|
||||
|
||||
const codeStr = fs.readFileSync(absolutePath).toString()
|
||||
const htmlStr = encodeURIComponent(highlight(codeStr, language))
|
||||
|
||||
hoistedTags.script!.unshift(`import ${componentName} from '${absolutePath}' \n`)
|
||||
hoistedTags.components!.push(componentName)
|
||||
|
||||
return content.replace(
|
||||
'>',
|
||||
` componentName="${componentName}" htmlStr="${htmlStr}" codeStr="${encodeURIComponent(codeStr)}" ${
|
||||
importMap ? `importMap="${encodeURIComponent(JSON.stringify(importMap))}"` : ''
|
||||
} >
|
||||
<${componentName}></${componentName}>
|
||||
`,
|
||||
)
|
||||
} else {
|
||||
return content
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import chalk from 'chalk'
|
||||
import prism from 'prismjs'
|
||||
import loadLanguages from 'prismjs/components/index'
|
||||
import escapeHtml from 'escape-html'
|
||||
|
||||
// required to make embedded highlighting work...
|
||||
loadLanguages(['markup', 'css', 'javascript'])
|
||||
|
||||
function wrap(code: string, lang: string): string {
|
||||
if (lang === 'text') {
|
||||
code = escapeHtml(code)
|
||||
}
|
||||
return `<pre v-pre><code>${code}</code></pre>`
|
||||
}
|
||||
|
||||
export const highlight = (str: string, lang: string) => {
|
||||
if (!lang) {
|
||||
return wrap(str, 'text')
|
||||
}
|
||||
lang = lang.toLowerCase()
|
||||
const rawLang = lang
|
||||
if (lang === 'vue' || lang === 'html') {
|
||||
lang = 'markup'
|
||||
}
|
||||
if (lang === 'md') {
|
||||
lang = 'markdown'
|
||||
}
|
||||
if (lang === 'ts') {
|
||||
lang = 'typescript'
|
||||
}
|
||||
if (lang === 'py') {
|
||||
lang = 'python'
|
||||
}
|
||||
if (!prism.languages[lang]) {
|
||||
try {
|
||||
loadLanguages([lang])
|
||||
} catch (e) {
|
||||
console.warn(chalk.yellow(`[vitepress] Syntax highlight for language "${lang}" is not supported.`))
|
||||
}
|
||||
}
|
||||
if (prism.languages[lang]) {
|
||||
const code = prism.highlight(str, prism.languages[lang], lang)
|
||||
return wrap(code, rawLang)
|
||||
}
|
||||
return wrap(str, 'text')
|
||||
}
|
||||
Reference in New Issue
Block a user