Writing archive
使用 Babel 生成自定义的 API 文档
使用 Babel 生成自定义的 API 文档
Babel
Babel 是一个 JavaScript 的编译器。
那么那位先生要问了,你 JavaScript 是解释型语言,为什么需要编译器呢?
实际上,Babel 的最初的功能是为了实现 ES6 到 ES5 的转换(在旧版本的引擎或浏览器中使用新的特性)。也就是说, 源代码和编译后的目标代码都是 js, 只不过编译后的代码不一定是具有人类可读性的代码。
在编译的过程中,babel/parser 会将源代码转换为 AST(抽象语法树),而 babel/generator 则将 AST 转换为目标代码。
我们要做的实际上就是通过 parse 出的 AST,来分析、提取,最后生成我们需要的结构和 API 文档.
如果你观察 babel 的 monorepo 的仓库,你会发现它可与分到三个部分:
parser: 实现 JavaScript 到 AST 的转换generator: 实现 AST 到 JavaScript 的转换traverse: 遍历 AST 的工具
使用 AST Explorer 可以在线解析 JavaScript 代码,并查看 AST 树。
parser
import { parse } from '@babel/parser';
const code = `
function add(a, b) {
return a + b;
}
`;
const ast = parse(code, {
plugins: ['typescript', 'jsx', 'flow'],
});
上述的代码解释了 parse 的使用:
传入一个 string 类型的 js 代码,
parse 将返回 AST 树
parser 插件
可选的 parser 插件有很多,例如:
- typescript 开启 typescript 插件
- flow 开启 flow 插件
- jsx 开启 jsx 插件
也可以使用自己自定义的 parser 插件,参考: https://www.babeljs.cn/docs/plugins
AST 树
通过 parser 解析出的 ast 树为一个Program对象,其
body 属性为一个列表,包含了这个文件从上到下的节点。
Program {
body: [
VariableDeclaration {},
FunctionDeclaration {},
...
]
}
对于一个节点 (Node), 有不同的类型,可以参考 https://babeljs.io/docs/babel-types#api
对于遍历 AST 树的需求,可以使用 babel/traverse 模块。
traverse
便于遍历 AST
traverse(ast, {
enter(path) {
if (path.isIdentifier({ name: "n" })) {
path.node.name = "x";
}
},
});
traverse(ast, {
FunctionDeclaration: function(path) {
path.node.id.name = "x";
},
});
使用 enter 来 进入 一个节点,或者直接使用
node types 来对某种节点进行操作。
访问者模式
访问者模式是一种设计模式。如果有一个复杂的类,就像 AST 树这样的 复杂的树结构,并且每个节点都有可能完全不同, 每个节点上可能有 相同的而不相关的操作。 可以考虑使用访问者模式。
访问者模式将创建一个独立的新的对象(也就是 visitor 对象), 将对 AST 树的操作委托到这个对象上。
generator
这个比较简单,直接给一个 AST 树结构, 和相应的 options 即可生成代码。
FastGPT 后端代码结构
对于每个接口, 其文件路径和 url 是一一对应的, 在遍历的时候可以顺便获得。
import ...
export metadata = {
name: 'example',
description: 'example',
author: 'example',
}
export type ExampleQuery = {}
export type ExampleBody = {}
export type ExampleResponse = {}
function handler(...) {
...
}
export default NextApi(handler)
在 handler 中可能存在鉴权的函数,其参数决定了这个接口的 鉴权方式。
我们需要做的是:
- 获取三个类型的具体定义。
- 获取元数据
- 获取鉴权方式
- 生成目标文档
获取类型定义
类型定义的 Node Type 是 TypeAliasDeclaration。
它有多种类型:
- TypeLiteral 表示这里定义的是一个对象,通过这个 TypeLiteral 的 members 把 properties 拿出来即可
- TypeReference 表示引用来一个其他的类型,这个类型可以直接把名字拿出来
- 其他的,例如 String, Number 等
获取元数据
元数据的 Node Type 是 VariableDeclaration。
OpenAPI 规范
可以进行构建 openapi 对象,然后使用工具 redocly 生成 html
这部分代码在: https://github.com/labring/FastGPT/tree/main/scripts/openapi