shadcn-vue/apps/www/.vitepress/theme/plugins/utils.ts
2023-09-04 22:36:40 +08:00

72 lines
1.8 KiB
TypeScript

// Credit to @hairyf https://github.com/hairyf/markdown-it-vitepress-demo
import type { MarkdownEnv, MarkdownRenderer } from 'vitepress'
import { baseParse } from '@vue/compiler-core'
import type { AttributeNode, ElementNode } from '@vue/compiler-core'
export interface GenerateOptions {
attrs?: string
props: Record<string, any>
path: string
code: string
}
export function parse(
md: MarkdownRenderer,
env: MarkdownEnv,
{ code, attrs: _attrs, props }: GenerateOptions,
) {
const highlightedHtml = md.options.highlight!(code, 'vue', _attrs || '')
const sfcTsHtml = highlightedHtml
const attrs
= `sfcTsCode="${encodeURIComponent(code)}"\n`
+ `sfcTsHtml="${encodeURIComponent(sfcTsHtml)}"\n`
+ `v-bind='${JSON.stringify(props)}'\n`
return {
attrs,
highlightedHtml,
sfcTsCode: code,
sfcTsHtml,
}
}
export function generateDemoComponent(
md: MarkdownRenderer,
env: MarkdownEnv,
options: GenerateOptions,
) {
const { attrs } = parse(md, env, options)
return `<ComponentPreview \n${attrs}></ComponentPreview>`.trim()
}
export function isUndefined(v: any): v is undefined {
return v === undefined || v === null
}
function getPropsMap(attrs: any[]) {
const map: Record<string, any> = {}
for (const { name, value, exp, arg } of attrs) {
if (name === 'bind') {
if (!isUndefined(arg?.content))
map[arg.content] = JSON.parse(exp.content)
continue
}
if (isUndefined(value?.content) || value?.content === '')
map[name] = true
else if (['true', 'false'].includes(value?.content || ''))
map[name] = value?.content === 'true'
else
map[name] = value?.content
}
return map
}
export function parseProps(content: string) {
const ast = baseParse(content)
const demoElement = ast.children[0] as ElementNode
return getPropsMap(demoElement.props as AttributeNode[])
}