markdown-transform.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import fs from 'fs'
  2. import path from 'path'
  3. import { camelize } from '@vue/shared'
  4. import glob from 'fast-glob'
  5. import { docRoot } from '../../../internal/build-utils/src'
  6. import type { Plugin } from 'vite'
  7. type Append = Record<'headers' | 'footers' | 'scriptSetups', string[]>
  8. let compPaths: string[]
  9. export function MarkdownTransform(): Plugin {
  10. return {
  11. name: 'antd-xv-md-transform',
  12. enforce: 'pre',
  13. async buildStart() {
  14. const pattern = `/component`
  15. compPaths = await glob(pattern, {
  16. cwd: docRoot,
  17. absolute: true,
  18. onlyDirectories: true,
  19. })
  20. },
  21. async transform(code, id) {
  22. if (!id.endsWith('.md')) return
  23. if (!id.includes('/component')) return
  24. const componentId = path.basename(id, '.md')
  25. const append: Append = {
  26. headers: [],
  27. footers: [],
  28. scriptSetups: getExampleImports(componentId),
  29. }
  30. code = transformVpScriptSetup(code, append)
  31. if (compPaths.some((compPath) => id.startsWith(compPath))) {
  32. code = transformComponentMarkdown(id, componentId, code, append)
  33. }
  34. return combineMarkdown(
  35. code,
  36. [combineScriptSetup(append.scriptSetups), ...append.headers],
  37. append.footers
  38. )
  39. },
  40. }
  41. }
  42. const combineScriptSetup = (codes: string[]) =>
  43. `\n<script setup>
  44. ${codes.join('\n')}
  45. </script>
  46. `
  47. const combineMarkdown = (
  48. code: string,
  49. headers: string[],
  50. footers: string[]
  51. ) => {
  52. const frontmatterEnds = code.indexOf('---\n\n')
  53. const firstHeader = code.search(/\n#{1,6}\s.+/)
  54. const sliceIndex =
  55. firstHeader < 0
  56. ? frontmatterEnds < 0
  57. ? 0
  58. : frontmatterEnds + 4
  59. : firstHeader
  60. if (headers.length > 0)
  61. code =
  62. code.slice(0, sliceIndex) + headers.join('\n') + code.slice(sliceIndex)
  63. code += footers.join('\n')
  64. return `${code}\n`
  65. }
  66. const vpScriptSetupRE = /<vp-script\s(.*\s)?setup(\s.*)?>([\s\S]*)<\/vp-script>/
  67. const transformVpScriptSetup = (code: string, append: Append) => {
  68. const matches = code.match(vpScriptSetupRE)
  69. if (matches) code = code.replace(matches[0], '')
  70. const scriptSetup = matches?.[3] ?? ''
  71. if (scriptSetup) append.scriptSetups.push(scriptSetup)
  72. return code
  73. }
  74. const transformComponentMarkdown = (
  75. id: string,
  76. componentId: string,
  77. code: string,
  78. append: Append
  79. ) => {
  80. return code
  81. }
  82. const getExampleImports = (componentId: string) => {
  83. const examplePath = path.resolve(docRoot, 'examples', componentId)
  84. if (!fs.existsSync(examplePath)) return []
  85. const files = fs.readdirSync(examplePath)
  86. const imports: string[] = []
  87. for (const item of files) {
  88. if (!/\.vue$/.test(item)) continue
  89. const file = item.replace(/\.vue$/, '')
  90. const name = camelize(`Ax-${componentId}-${file}`)
  91. imports.push(
  92. `import ${name} from '../examples/${componentId}/${file}.vue'`,
  93. `import ${name}Setup from '../examples-setup/${componentId}/${file}.vue'`
  94. )
  95. }
  96. return imports
  97. }