背景
最近在做一个组件库的项目,对第三方库进行二次封装并暴露自定义属性,每个组件都有一份默认数据的 JSON格式
。如何根据默认数据生成组件 API 文档
?本文将教你如何使用 json-to-ts、prettier、ShellJS、TypeDoc、fs-extra、ora、path 等 JS 库优雅生成接口文档。
方案
方案非常直接,只需要两步:
- JSON 转 TypeScript
- 通过 TypeScript 生成组件 API 文档
原本以为这个需求已经有现成的轮子,但找了一下午都没有找到,只能自己实现一个
准备工作
首先,我们需要安装以下依赖:
bash
npm install json-to-ts prettier shelljs typedoc fs-extra ora path --save-dev
我们所有的脚本文件都用 ts 来写,这样可以避免很多 类型 和 引用 问题
生成 TypeScript 接口
我们可以使用 json-to-ts 库 将 JSON 数据转换为 TypeScript 接口。首先,创建一个名为 json-to-interface.ts
的文件,并编写以下代码:
typescript
import * as jsonToTs from "json-to-ts";
import * as fs from "fs-extra";
import * as path from "path";
import prettier from "prettier";
// 获取目标文件夹下的定义的 默认数据文件
export const getTargetFiles = (targetPath) => {
let components = [];
const files = fs.readdirSync(targetPath);
files.forEach((item, index) => {
let stat = fs.statSync(`${targetPath}/` + item);
let isBool = true;
try {
fs.statSync(`${targetPath}/` + item + "/defaultProps.ts");
} catch (error) {
isBool = false;
}
if (stat.isDirectory() === true && isBool) {
components.push(item);
}
});
return components;
};
const transform = () => {
// 获取待处理的组件名. targetPath 为存放默认数据的文件夹路径
let components = getTargetFiles(targetPath);
// 开始处理组件
components.forEach((name) => {
console.log(`当前处理组件的 - ${name}`);
const jsonFilePath = path.resolve(
__dirname,
`${targetPath}/${name}/defaultProps.ts`
);
// 获取数据
const { defaultProps: json } = require(jsonFilePath);
// 可以先对默认数据做一下前置处理
// ...
// 获取 interface 数据
const interfaceData: string[] = JsonToTS(json, { rootName: "DefaultProps" });
// 可以对生成的 interfaceData 进行自定义配置处理
// ...
// interface 文件路径
let filePath = `${targetPath}/${name}/interface.ts`;
filePath = path.resolve(__dirname, filePath);
// 使用 Prettier 格式化代码
const formatData = prettier.format(interfaceData, {
singleQuote: true,
parser: "typescript",
});
// 写 interface 文件
fs.outputFileSync(filePath, formatData);
});
}
这段代码首先从我们的目标文件夹中读取名为 defaultProps.ts
的 默认数据
文件(json 格式),然后使用 json-to-ts
库将 JSON 数据转换为 TypeScript 接口,并将结果写入名为 interfaces.ts
的文件中。
由于 json-to-ts
提供的 api 较少,如果我们需要给生成的接口上添加 自定义的数据
,可以通过遍历 interfaceData
来动态添加
typescript
interfaceData.map(item => {
if (item.includes("interface DefaultProps {")) {
const linkName = item.split(" ")[1];
return `
/**
* @module ${title}
* @see 点击此处查看区块详细 props -> {@link ${linkName}}
*/
${item}
`;
}
return item;
})
生成的 interfaces.ts
内容如下
生成接口文档
我们可以使用 TypeDoc 库 将生成的 TypeScript 接口转换为 HTML 文档。创建一个名为 generate-doc.ts
的文件,并编写以下代码:
typescript
// 从 json-to-interface.ts 中导出相关的方法和属性
...
const generateDoc = () => {
// 获取 typeDoc 配置文件
const typeDocConfigPath = path.resolve(__dirname, "../../typedoc.json");
let configJson = require(typeDocConfigPath);
/** 将待生成文档的组件地址,注入到 typeDoc 配置文件中
* basePath、name、components:是在上个阶段【生成 TypeScript 接口】获取的
*/
configJson["entryPoints"] = components.map(
(name) => `.${basePath}/${name}/interface.ts`
);
// 格式化 json 代码
configJson = prettier.format(JSON.stringify(configJson), { parser: "json" });
// 更新 typeDoc 配置文件
fs.writeFileSync(typeDocConfigPath, configJson);
// 生成文档
shell.exec("typedoc --tsconfig ./tsconfig.json");
}
最终生成的 typedoc.json
大概如下图:
json
{
"entryPoints": [
"./src/components/AboutUs/interface.ts",
"./src/components/Contact/interface.ts",
...
],
"out": "demo-docs",
"name": "demo 组件 api",
"exclude": [
"**/__tests__/**/*",
"**/node_modules/**/*"
],
"theme": "default",
"excludeExternals": true,
"excludePrivate": true,
"excludeProtected": true,
"skipErrorChecking": true,
"disableSources": true,
"readme": "./scripts/generate/readme.md"
}
修改 package.json
文件,添加以下脚本:
json
"scripts": {
"docs": "npx tsx ./generate-doc.ts",
}
然后,执行以下命令生成接口文档:
bash
npm run docs
这将在项目根目录下生成一个名为 demo-docs
的文件夹,其中包含接口文档的 HTML 文件。
可以定制 文档首页 的显示内容,通过一份
readme.md
来定制
最后
通过 json-to-ts
、TypeDoc
两个组件库的配合,以及多项交互优化,让你轻松生成组件 API