markdown-transform.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import fs from 'fs'
  2. import path from 'path'
  3. import glob from 'fast-glob'
  4. import { docRoot, docsDirName, projRoot } from '@kankan/build-utils'
  5. import { REPO_BRANCH, REPO_PATH } from '@kankan/build-constants'
  6. import { getLang, languages } from '../utils/lang'
  7. import footerLocale from '../i18n/component/footer.json'
  8. import type { Plugin } from 'vite'
  9. type Append = Record<'headers' | 'footers' | 'scriptSetups', string[]>
  10. export function MarkdownTransform(): Plugin {
  11. return {
  12. name: 'element-plus-md-transform',
  13. enforce: 'pre',
  14. async transform(code, id) {
  15. if (!id.endsWith('.md')) return
  16. const componentId = path.basename(id, '.md')
  17. const append: Append = {
  18. headers: [],
  19. footers: [],
  20. scriptSetups: [`const demos = import.meta.globEager('../../examples/${componentId}/*.vue')`],
  21. }
  22. code = transformVpScriptSetup(code, append)
  23. const pattern = `{${[...languages, languages[0]].join(',')}}/component`
  24. const compPaths = await glob(pattern, {
  25. cwd: docRoot,
  26. absolute: true,
  27. onlyDirectories: true,
  28. })
  29. if (compPaths.some(compPath => id.startsWith(compPath))) {
  30. code = transformComponentMarkdown(id, componentId, code, append)
  31. }
  32. return combineMarkdown(code, [combineScriptSetup(append.scriptSetups), ...append.headers], append.footers)
  33. },
  34. }
  35. }
  36. const combineScriptSetup = (codes: string[]) =>
  37. `\n<script setup>
  38. ${codes.join('\n')}
  39. </script>
  40. `
  41. const combineMarkdown = (code: string, headers: string[], footers: string[]) => {
  42. const frontmatterEnds = code.indexOf('---\n\n') + 4
  43. const firstSubheader = code.search(/\n## \w/)
  44. const sliceIndex = firstSubheader < 0 ? frontmatterEnds : firstSubheader
  45. if (headers.length > 0) code = code.slice(0, sliceIndex) + headers.join('\n') + code.slice(sliceIndex)
  46. code += footers.join('\n')
  47. return `${code}\n`
  48. }
  49. const vpScriptSetupRE = /<vp-script\s(.*\s)?setup(\s.*)?>([\s\S]*)<\/vp-script>/
  50. const transformVpScriptSetup = (code: string, append: Append) => {
  51. const matches = code.match(vpScriptSetupRE)
  52. if (matches) code = code.replace(matches[0], '')
  53. const scriptSetup = matches?.[3] ?? ''
  54. if (scriptSetup) append.scriptSetups.push(scriptSetup)
  55. return code
  56. }
  57. const GITHUB_BLOB_URL = `https://github.com/${REPO_PATH}/blob/${REPO_BRANCH}`
  58. const GITHUB_TREE_URL = `https://github.com/${REPO_PATH}/tree/${REPO_BRANCH}`
  59. const transformComponentMarkdown = (id: string, componentId: string, code: string, append: Append) => {
  60. const lang = getLang(id)
  61. const docUrl = `${GITHUB_BLOB_URL}/${docsDirName}/en-US/component/${componentId}.md`
  62. const componentUrl = `${GITHUB_TREE_URL}/packages/components/${componentId}`
  63. const componentPath = path.resolve(projRoot, `packages/components/${componentId}`)
  64. const isComponent = fs.existsSync(componentPath)
  65. const links = [[footerLocale[lang].docs, docUrl]]
  66. if (isComponent) links.unshift([footerLocale[lang].component, componentUrl])
  67. const linksText = links
  68. .filter(i => i)
  69. .map(([text, link]) => `[${text}](${link})`)
  70. .join(' • ')
  71. const sourceSection = `
  72. ## ${footerLocale[lang].source}
  73. ${linksText}
  74. `
  75. const contributorsSection = `
  76. ## ${footerLocale[lang].contributors}
  77. <Contributors id="${componentId}" />
  78. `
  79. append.footers.push(sourceSection, isComponent ? contributorsSection : '')
  80. return code
  81. }