import { dirname, resolve } from 'node:path' import { readdirSync } from 'node:fs' import type { MarkdownEnv, MarkdownRenderer } from 'vitepress' export const rawPathRegexp = /^(.+?(?:\.([a-z0-9]+))?)(#[\w-]+)?(?: ?\{(\d+(?:[,-]\d+)*)? ?(\S+)?\})? ?(?:\[(.+)\])?$/ function rawPathToToken(rawPath: string) { const [ filepath = '', extension = '', region = '', lines = '', lang = '', rawTitle = '', ] = (rawPathRegexp.exec(rawPath) || []).slice(1) const title = rawTitle || filepath.split('/').pop() || '' return { filepath, extension, region, lines, lang, title } } export default function (md: MarkdownRenderer) { md.core.ruler.after('inline', 'component-preview', (state) => { const insertComponentImport = (importString: string) => { const index = state.tokens.findIndex(i => i.type === 'html_block' && i.content.match(/\n` state.tokens.splice(0, 0, importComponent) } else { const content = state.tokens[index].content state.tokens[index].content = content.replace('', `${importString}\n`) } } // Define the regular expression to match the desired pattern const regex = /]+)\/>/g // Iterate through the Markdown content and replace the pattern state.src = state.src.replace(regex, (_, bindingValue) => { // Define a regex pattern to match props and their values const propPattern = /(\w+)="([^"]*)"/g // Create an object to store the props and their values const props: { [key: string]: string } = {} // Use matchAll to find all matches in the input string const matches = bindingValue.matchAll(propPattern) // Iterate through the matches and populate the props object for (const match of matches) { const [, propName, propValue] = match props[propName] = propValue } const pathName = props.type === 'example' ? `../../components/examples/${props.name}` : `../../../components/demo/${props.name}` insertComponentImport(props.type === 'example' ? `import ${props.name} from '${pathName}/index.vue'` : `import ${props.name} from '${pathName}/tailwind/index.vue'`) const index = state.tokens.findIndex(i => i.content.match(regex)) const { realPath, path: _path } = state.env as MarkdownEnv const childFiles = readdirSync(resolve(dirname(realPath ?? _path), pathName), { withFileTypes: false, recursive: true }) .map(file => typeof file === 'string' ? file.split(/[/\\]/).join('/') : file) const groupedFiles = props.type === 'example' ? { tailwind: childFiles } : childFiles.reduce((prev, curr) => { if (typeof curr !== 'string') return prev if (!curr.includes('/')) { prev[curr] = [] } else { const folder = curr.split('/')[0] prev[folder].push(curr) } return prev }, {} as { [key: string]: string[] }) state.tokens[index].content = `<${props.name} />` const dummyToken = new state.Token('', '', 0) const tokenArray: Array = [] Object.entries(groupedFiles).forEach(([key, value]) => { const templateStart = new state.Token('html_inline', '', 0) templateStart.content = `' tokenArray.push(templateEnd) }) const endTag = new state.Token('html_inline', '', 0) endTag.content = '' tokenArray.push(endTag) state.tokens.splice(index + 1, 0, ...tokenArray) // Return an empty string to replace the original pattern return '' }) }) }