#!/usr/bin/env node /** * 从组件源码生成 API 数据。 * * 用 vue-docgen-api 解析 packages/ui/src 下的 .vue 文件, * 提取 props / events / slots 及其 JSDoc 注释,输出到 docs/data/api/<组件名>.json, * 由文档站的 组件读取渲染。 * * 这样 API 表格永远与源码一致,禁止手写。 * 源码改动后执行:pnpm gen:api */ import { mkdir, readdir, writeFile } from 'node:fs/promises' import { basename, dirname, join } from 'node:path' import { fileURLToPath } from 'node:url' import { parse } from 'vue-docgen-api' const root = fileURLToPath(new URL('..', import.meta.url)) const uiSrc = join(root, 'packages/ui/src') const outDir = join(root, 'docs/data/api') /** 递归收集所有 .vue 组件文件 */ async function findComponents(dir) { const found = [] for (const entry of await readdir(dir, { withFileTypes: true })) { const full = join(dir, entry.name) if (entry.isDirectory()) { found.push(...(await findComponents(full))) } else if (entry.name.endsWith('.vue')) { found.push(full) } } return found } /** packages/ui/src/button/Button.vue -> button */ function toKey(file) { return basename(dirname(file)) } /** docgen 给出的值可能带引号,统一剥掉 */ function clean(text = '') { return String(text).replace(/^['"]|['"]$/g, '') } /** 把说明文字压成单行,避免表格里出现换行 */ function oneLine(text = '') { return String(text).replace(/\s+/g, ' ').trim() } function mapMember(item) { return { name: item.name, description: oneLine(item.description), type: item.type?.name ?? '', defaultValue: item.defaultValue ? clean(item.defaultValue.value) : '', } } async function main() { const files = await findComponents(uiSrc) const results = [] for (const file of files) { const info = await parse(file) const key = toKey(file) results.push([ key, { displayName: info.displayName || key, description: oneLine(info.description), props: (info.props ?? []).map(mapMember), events: (info.events ?? []).map(mapMember), slots: (info.slots ?? []).map((slot) => ({ name: slot.name, description: oneLine(slot.description), })), }, ]) } await mkdir(outDir, { recursive: true }) for (const [key, doc] of results) { await writeFile(join(outDir, `${key}.json`), `${JSON.stringify(doc, null, 2)}\n`, 'utf-8') console.log( `✓ ${key.padEnd(12)} props=${doc.props.length} events=${doc.events.length} slots=${doc.slots.length}`, ) } } main().catch((error) => { console.error('[gen-api] 失败:', error) process.exit(1) })