Files
wechatWeb/_docs/_gen_api_doc.js
张成 aac2d4a8d5 1
2026-03-27 15:18:33 +08:00

163 lines
4.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 从 swagger.json 生成带参数的 API 接口清单 MD 文档
* 用法: node _docs/_gen_api_doc.js
*/
const fs = require("fs");
const path = require("path");
const swagger = require("./swagger.json");
const mdRaw = fs.readFileSync(path.join(__dirname, "接口说明文档-完整版-含营销等级.md"), "utf8");
// ========== 1. 解析套餐映射 ==========
const planMap = {};
let curPath = "";
for (const line of mdRaw.split("\n")) {
const m = line.match(/####.*`(POST|GET)\s+(.+?)`/);
if (m) { curPath = m[2].trim(); continue; }
const p = line.match(/对应套餐:\*\*(.+?)\*\*/);
if (p && curPath) { planMap[curPath] = p[1]; curPath = ""; }
}
// ========== 2. 解析 definitions ==========
function resolveRef(ref) {
if (!ref) return null;
const name = ref.replace("#/definitions/", "");
return swagger.definitions[name] || null;
}
function resolveType(prop) {
if (!prop) return "any";
if (prop.$ref) {
const name = prop.$ref.replace("#/definitions/", "");
return name;
}
if (prop.type === "array") {
if (prop.items) {
if (prop.items.$ref) return resolveType(prop.items) + "[]";
return (prop.items.type || "any") + "[]";
}
return "array";
}
let t = prop.type || "any";
if (prop.format) t += `(${prop.format})`;
return t;
}
function getModelFields(def) {
if (!def || !def.properties) return [];
const fields = [];
for (const [name, prop] of Object.entries(def.properties)) {
fields.push({
name,
type: resolveType(prop),
desc: (prop.description || "").trim() || "-",
});
}
return fields;
}
// ========== 3. 按 tag 分组 ==========
const tagNameMap = { "朋友": "好友", "/shop": "微信小店", "管理": "管理/授权" };
function normTag(t) { return tagNameMap[t] || t; }
const tagOrder = [
"登录", "用户", "好友", "标签", "消息", "消息回调",
"群管理", "朋友圈", "收藏", "支付", "公众号/小程序",
"企业微信", "视频号", "设备", "微信小店", "其他", "同步消息", "管理/授权",
];
const groups = {};
for (const [apiPath, methods] of Object.entries(swagger.paths)) {
for (const [method, spec] of Object.entries(methods)) {
const tag = (spec.tags && spec.tags[0]) || "未分类";
if (!groups[tag]) groups[tag] = [];
const params = spec.parameters || [];
const queryParams = params.filter((p) => p.in === "query");
const bodyParam = params.find((p) => p.in === "body");
let bodyModelName = "";
let bodyFields = [];
if (bodyParam && bodyParam.schema && bodyParam.schema.$ref) {
bodyModelName = bodyParam.schema.$ref.replace("#/definitions/", "");
const def = resolveRef(bodyParam.schema.$ref);
bodyFields = getModelFields(def);
}
groups[tag].push({
method: method.toUpperCase(),
path: apiPath,
summary: spec.summary || "",
plan: planMap[apiPath] || "-",
queryParams,
bodyModelName,
bodyFields,
});
}
}
const sortedTags = Object.keys(groups).sort((a, b) => {
const ia = tagOrder.indexOf(normTag(a));
const ib = tagOrder.indexOf(normTag(b));
return (ia === -1 ? 99 : ia) - (ib === -1 ? 99 : ib);
});
// ========== 4. 生成 MD ==========
const totalApis = Object.values(groups).reduce((s, a) => s + a.length, 0);
const planCount = {};
for (const apis of Object.values(groups)) {
for (const a of apis) {
planCount[a.plan] = (planCount[a.plan] || 0) + 1;
}
}
let out = "# API 接口清单(按模块)\n\n";
out += `> 接口总数:**${totalApis}**\n\n`;
out += "## 套餐统计\n\n";
out += "| 套餐 | 接口数 |\n|---|---:|\n";
for (const p of ["初级版", "高级版", "定制版", "白标/OEM"]) {
if (planCount[p]) out += `| ${p} | ${planCount[p]} |\n`;
}
out += "\n---\n\n";
let secIdx = 0;
for (const tag of sortedTags) {
const apis = groups[tag];
secIdx++;
const displayTag = normTag(tag);
out += `## ${secIdx}. ${displayTag}${apis.length} 个接口)\n\n`;
apis.forEach((a, i) => {
const num = `${secIdx}.${i + 1}`;
out += `### ${num} \`${a.method} ${a.path}\` - ${a.summary}\n\n`;
out += `- 套餐:**${a.plan}**\n\n`;
// Query 参数
if (a.queryParams.length > 0) {
out += "**Query 参数**\n\n";
out += "| 参数名 | 类型 | 说明 |\n|---|---|---|\n";
for (const q of a.queryParams) {
out += `| \`${q.name}\` | ${q.type || "string"} | ${q.description || "-"} |\n`;
}
out += "\n";
}
// Body 请求体
if (a.bodyFields.length > 0) {
out += `**请求体 (${a.bodyModelName})**\n\n`;
out += "| 字段名 | 类型 | 说明 |\n|---|---|---|\n";
for (const f of a.bodyFields) {
out += `| \`${f.name}\` | \`${f.type}\` | ${f.desc} |\n`;
}
out += "\n";
}
out += "---\n\n";
});
}
const outPath = path.join(__dirname, "API接口清单-按模块.md");
fs.writeFileSync(outPath, out, "utf8");
console.log(`done: ${outPath}, ${out.split("\n").length} lines`);