mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
* docs: add component changelog drawer and open issues button * docs: update comp name * docs: optimize code * docs: apply cb review * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * docs: apply cb review * docs: apply cb review * docs: add in-memory cache for issue count requests Cache GitHub API responses for 5 minutes to avoid redundant requests when navigating between component pages. Co-authored-by: GitHub Copilot <noreply@github.com> * Update docs/.vitepress/vitepress/components/globals/vp-component-meta.vue Co-authored-by: btea <2356281422@qq.com> * docs: optimaze code * docs: fix i18n * style: update version color * docs: fix ts error * docs: improve style and display condition * fix: alias comp parser * docs: show the last 20 versions --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: GitHub Copilot <noreply@github.com> Co-authored-by: btea <2356281422@qq.com>
178 lines
4.8 KiB
TypeScript
178 lines
4.8 KiB
TypeScript
import fs from 'fs'
|
|
import path from 'path'
|
|
import { camelize } from '@vue/shared'
|
|
import { glob } from 'tinyglobby'
|
|
import { docRoot, docsDirName, projRoot } from '@element-plus/build-utils'
|
|
import { REPO_BRANCH, REPO_PATH } from '@element-plus/build-constants'
|
|
import { getLang, languages } from '../utils/lang'
|
|
import footerLocale from '../i18n/component/footer.json'
|
|
|
|
import type { Plugin } from 'vite'
|
|
|
|
type Append = Record<'headers' | 'footers' | 'scriptSetups', string[]>
|
|
|
|
let compPaths: string[]
|
|
|
|
export function MarkdownTransform(): Plugin {
|
|
return {
|
|
name: 'element-plus-md-transform',
|
|
|
|
enforce: 'pre',
|
|
|
|
async buildStart() {
|
|
const pattern = `{${[...languages, languages[0]].join(',')}}/component`
|
|
|
|
compPaths = await glob(pattern, {
|
|
cwd: docRoot,
|
|
absolute: true,
|
|
onlyDirectories: true,
|
|
})
|
|
},
|
|
|
|
async transform(code, id) {
|
|
if (!id.endsWith('.md')) return
|
|
|
|
const componentId = path.basename(id, '.md')
|
|
const append: Append = {
|
|
headers: [],
|
|
footers: [],
|
|
scriptSetups: getExampleImports(componentId),
|
|
}
|
|
|
|
code = transformVpScriptSetup(code, append)
|
|
|
|
if (compPaths.some((compPath) => id.startsWith(compPath))) {
|
|
code = transformComponentMarkdown(id, componentId, code, append)
|
|
}
|
|
|
|
return combineMarkdown(
|
|
code,
|
|
[combineScriptSetup(append.scriptSetups), ...append.headers],
|
|
append.footers
|
|
)
|
|
},
|
|
}
|
|
}
|
|
|
|
const combineScriptSetup = (codes: string[]) =>
|
|
`\n<script setup>
|
|
${codes.join('\n')}
|
|
</script>
|
|
`
|
|
|
|
const combineMarkdown = (
|
|
code: string,
|
|
headers: string[],
|
|
footers: string[]
|
|
) => {
|
|
const frontmatterEnds = code.indexOf('---\n\n')
|
|
const firstHeader = code.search(/\n#{1,6}\s.+/)
|
|
const sliceIndex =
|
|
firstHeader < 0
|
|
? frontmatterEnds < 0
|
|
? 0
|
|
: frontmatterEnds + 4
|
|
: firstHeader
|
|
|
|
if (headers.length > 0)
|
|
code =
|
|
code.slice(0, sliceIndex) + headers.join('\n') + code.slice(sliceIndex)
|
|
code += footers.join('\n')
|
|
|
|
return `${code}\n`
|
|
}
|
|
|
|
const vpScriptSetupRE = /<vp-script\s(.*\s)?setup(\s.*)?>([\s\S]*)<\/vp-script>/
|
|
|
|
const transformVpScriptSetup = (code: string, append: Append) => {
|
|
const matches = code.match(vpScriptSetupRE)
|
|
if (matches) code = code.replace(matches[0], '')
|
|
const scriptSetup = matches?.[3] ?? ''
|
|
if (scriptSetup) append.scriptSetups.push(scriptSetup)
|
|
return code
|
|
}
|
|
|
|
const GITHUB_BLOB_URL = `https://github.com/${REPO_PATH}/blob/${REPO_BRANCH}`
|
|
const GITHUB_TREE_URL = `https://github.com/${REPO_PATH}/tree/${REPO_BRANCH}`
|
|
|
|
const EXCLUDE_CHANGELOG_COMPONENTS = new Set(['overview'])
|
|
|
|
const transformComponentMarkdown = (
|
|
id: string,
|
|
componentId: string,
|
|
code: string,
|
|
append: Append
|
|
) => {
|
|
const lang = getLang(id)
|
|
const docUrl = `${GITHUB_BLOB_URL}/${docsDirName}/en-US/component/${componentId}.md`
|
|
const componentUrl = `${GITHUB_TREE_URL}/packages/components/${componentId}`
|
|
const styleUrl = `${GITHUB_TREE_URL}/packages/theme-chalk/src/${componentId}.scss`
|
|
|
|
const componentPath = path.resolve(
|
|
projRoot,
|
|
`packages/components/${componentId}`
|
|
)
|
|
const stylePath = path.resolve(
|
|
projRoot,
|
|
`packages/theme-chalk/src/${componentId}.scss`
|
|
)
|
|
|
|
const isComponent = fs.existsSync(componentPath)
|
|
const isHaveComponentStyle = fs.existsSync(stylePath)
|
|
|
|
// Inject changelog component after H1 title
|
|
if (!EXCLUDE_CHANGELOG_COMPONENTS.has(componentId)) {
|
|
const h1Match = code.match(/^#\s+.+$/m)
|
|
if (h1Match) {
|
|
const h1End = code.indexOf(h1Match[0]) + h1Match[0].length
|
|
const componentMetaTag = `\n\n<VpComponentMeta component="${componentId}" />\n`
|
|
code = code.slice(0, h1End) + componentMetaTag + code.slice(h1End)
|
|
}
|
|
}
|
|
|
|
const links = [[footerLocale[lang].docs, docUrl]]
|
|
|
|
if (isComponent && isHaveComponentStyle)
|
|
links.unshift([footerLocale[lang].style, styleUrl])
|
|
|
|
if (isComponent) links.unshift([footerLocale[lang].component, componentUrl])
|
|
|
|
const linksText = links
|
|
.filter((i) => i)
|
|
.map(([text, link]) => `[${text}](${link})`)
|
|
.join(' • ')
|
|
|
|
const sourceSection = `
|
|
## ${footerLocale[lang].source}
|
|
|
|
${linksText}`
|
|
|
|
const contributorsSection = `
|
|
## ${footerLocale[lang].contributors}
|
|
|
|
<Contributors id="${componentId}" />`
|
|
|
|
append.footers.push(sourceSection, isComponent ? contributorsSection : '')
|
|
|
|
return code
|
|
}
|
|
|
|
const getExampleImports = (componentId: string) => {
|
|
const examplePath = path.resolve(docRoot, 'examples', componentId)
|
|
if (!fs.existsSync(examplePath)) return []
|
|
const files = fs.readdirSync(examplePath)
|
|
const imports: string[] = []
|
|
|
|
for (const item of files) {
|
|
if (!/\.vue$/.test(item)) continue
|
|
const file = item.replace(/\.vue$/, '')
|
|
const name = camelize(`Ep-${componentId}-${file}`)
|
|
|
|
imports.push(
|
|
`import ${name} from '../../examples/${componentId}/${file}.vue'`
|
|
)
|
|
}
|
|
|
|
return imports
|
|
}
|