From 62fd7757f9983fcdf014587eca5c8a84dbff4083 Mon Sep 17 00:00:00 2001 From: yourtion Date: Wed, 1 Jul 2026 09:17:26 +0800 Subject: [PATCH] =?UTF-8?q?feat(docs):=20Markdown=20=E5=B1=95=E7=A4=BA?= =?UTF-8?q?=E8=B7=AF=E7=94=B1=E4=B8=AD=E9=97=B4=E4=BB=B6=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E5=90=8D=20(issue=20#4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit middlewares 此前已通过 .middlewares() 注册并经 DOC_FIELD 采集, 但四个生成器无一渲染。现 Markdown 在「请求地址」下方输出中间件函数名 列表(取具名函数 fn.name,匿名跳过)。Swagger/Postman 不受影响 (OpenAPI 标准无中间件字段)。 - 新增 3 个回归测试(具名中间件 / 无中间件 / 匿名跳过) - bump 版本 3.2.1 → 3.2.5,登记 MIGRATION --- MIGRATION.md | 6 +++ package.json | 2 +- packages/erest-express/package.json | 2 +- packages/erest-gen/package.json | 2 +- packages/erest-koa/package.json | 2 +- packages/erest-leizmweb/package.json | 2 +- src/lib/plugin/generate_markdown/apis.ts | 11 ++++++ src/test/test-docs-plugins.ts | 47 ++++++++++++++++++++++++ 8 files changed, 69 insertions(+), 5 deletions(-) diff --git a/MIGRATION.md b/MIGRATION.md index 0206afe..fe19b20 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -350,3 +350,9 @@ instead」)。`@koa/router` 是官方维护的继任包,API 与 koa-router * ### 影响范围 仅文档生成器(`generate_swagger` / `generate_postman`),不涉及运行时校验、路由绑定或类型推导。已声明 response schema 的项目重新生成文档即可看到变化;未声明的项目输出与之前完全一致。 + +## v3.2.5 — Markdown 文档展示中间件(issue #4) + +### 新增(非 breaking) + +- **Markdown 文档输出路由的中间件函数名列表**:`middlewares` 此前已通过 `.middlewares()` 注册并经 `DOC_FIELD` 采集进文档数据,但四个生成器无一渲染。现 Markdown 在「请求地址」行下方输出 `中间件:``, ```(取具名函数的 `fn.name`,匿名函数跳过),便于在文档中看到路由的处理链。Swagger/Postman 不受影响(OpenAPI 标准无中间件字段,强行加入反而不被消费方识别)。 diff --git a/package.json b/package.json index 0582519..20caf2a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "erest", - "version": "3.2.2", + "version": "3.2.5", "description": "Framework-agnostic REST API framework with Zod validation, auto docs & test scaffolding. Express/Koa/@leizm/web adapters as separate packages.", "type": "module", "main": "dist/lib/index.js", diff --git a/packages/erest-express/package.json b/packages/erest-express/package.json index 0a48c3f..578ed77 100644 --- a/packages/erest-express/package.json +++ b/packages/erest-express/package.json @@ -1,6 +1,6 @@ { "name": "@erest/express", - "version": "3.2.2", + "version": "3.2.5", "description": "Express adapter for erest", "type": "module", "main": "./dist/index.js", diff --git a/packages/erest-gen/package.json b/packages/erest-gen/package.json index a4593cf..3ecff46 100644 --- a/packages/erest-gen/package.json +++ b/packages/erest-gen/package.json @@ -1,6 +1,6 @@ { "name": "@erest/gen", - "version": "3.2.2", + "version": "3.2.5", "description": "erest codegen CLI:从 Zod schema 生成 handler 骨架等(实验性,独立于 erest 主版本演进)", "type": "module", "bin": { diff --git a/packages/erest-koa/package.json b/packages/erest-koa/package.json index d633e95..d10e9f2 100644 --- a/packages/erest-koa/package.json +++ b/packages/erest-koa/package.json @@ -1,6 +1,6 @@ { "name": "@erest/koa", - "version": "3.2.2", + "version": "3.2.5", "description": "Koa adapter for erest", "type": "module", "main": "./dist/index.js", diff --git a/packages/erest-leizmweb/package.json b/packages/erest-leizmweb/package.json index ec8256e..42fa353 100644 --- a/packages/erest-leizmweb/package.json +++ b/packages/erest-leizmweb/package.json @@ -1,6 +1,6 @@ { "name": "@erest/leizmweb", - "version": "3.2.2", + "version": "3.2.5", "description": "@leizm/web adapter for erest", "type": "module", "main": "./dist/index.js", diff --git a/src/lib/plugin/generate_markdown/apis.ts b/src/lib/plugin/generate_markdown/apis.ts index 666f0a6..b474b8a 100644 --- a/src/lib/plugin/generate_markdown/apis.ts +++ b/src/lib/plugin/generate_markdown/apis.ts @@ -109,6 +109,17 @@ export default function apiDocs(data: IDocData) { const line = [`## ${tit} ${tested}`]; line.push(`\n请求地址:**${method}** \`${item.realPath}\``); + // 中间件(issue #4):输出具名中间件的函数名,匿名函数跳过 + const mids = item.middlewares as Set | undefined; + if (mids && mids.size > 0) { + const names = Array.from(mids) + .map((fn) => (typeof fn === "function" ? fn.name : "")) + .filter((n) => n && n !== "anonymous"); + if (names.length > 0) { + line.push(`\n中间件:${names.map((n) => `\`${n}\``).join(", ")}`); + } + } + if (item.description) { line.push( (item.description as string) diff --git a/src/test/test-docs-plugins.ts b/src/test/test-docs-plugins.ts index 610ab5f..687dd5b 100644 --- a/src/test/test-docs-plugins.ts +++ b/src/test/test-docs-plugins.ts @@ -9,6 +9,7 @@ import { describe, expect, test } from "vitest"; import { z } from "zod"; import generateAxios from "../lib/plugin/generate_axios"; +import apiDocs from "../lib/plugin/generate_markdown/apis"; import generatePostman from "../lib/plugin/generate_postman"; import generateSwagger, { buildSwagger } from "../lib/plugin/generate_swagger"; @@ -144,3 +145,49 @@ describe("postman response 示例(issue #6)", () => { expect(item.response).toBeUndefined(); }); }); + +describe("markdown 中间件展示(issue #4)", () => { + function buildWith(middlewares?: Set) { + const data = { + info: {}, + group: { G: "G" }, + types: {}, + apis: { + "get_/test": { + method: "get", + path: "/test", + realPath: "/test", + group: "G", + title: "测试路由", + examples: [], + requiredOneOf: [], + ...(middlewares ? { middlewares } : {}), + }, + }, + } as any; + return apiDocs(data); + } + + test("有具名中间件时,Markdown 输出中间件名列表", () => { + function authCheck() {} + function logRequest() {} + const { list } = buildWith(new Set([authCheck, logRequest])); + const content = list[0].content; + expect(content).toContain("authCheck"); + expect(content).toContain("logRequest"); + }); + + test("无中间件时不报错,且不输出中间件行", () => { + const { list } = buildWith(undefined); + const content = list[0].content; + expect(content).not.toMatch(/中间件/); + }); + + test("匿名中间件不输出空名(跳过无 name 的函数)", () => { + const anon = function () {}; + const { list } = buildWith(new Set([anon])); + const content = list[0].content; + // 不应出现「中间件:」后跟空列表 + expect(content).not.toMatch(/中间件:\s*$/); + }); +});