docfy patch-spec

对一份已经构建好的 OpenAPI 文档打补丁,完全通过静态分析(ts-morph)完成,不会 require() 任何 docs 文件。

为什么需要它

这是一种手动的、由 CI 驱动的方式,用来绕开 DocfyModule 运行时管线在结构上做不到的那件事:在 NestJS CLI 的 webpack: true 构建模式下工作(推荐的自动替代方案见 CLI 插件,它在每次构建时都会计算同样的分析结果,而不需要额外一个步骤)。patch-spec 通过匹配 路径 + HTTP 方法 绕开了 webpack 造成的障碍——计算方式和 check/coverage/lint 已经在用的方式相同,不需要拿到运行中的控制器类引用。

用法

bash
npx nestjs-docfy patch-spec --spec <path-or-url> [options]
bash
# Patch a running app's served document
npx nestjs-docfy patch-spec --spec http://localhost:3000/api-json --out openapi.json

# Patch a file already written to disk
npx nestjs-docfy patch-spec --spec dist/openapi.json --out dist/openapi.json

选项

OptionDefaultDescription
--spec <path|url>(required)A local openapi.json, or a URL (e.g. a running app's /api-json)
--out <path>stdoutWhere to write the patched document
--root <path>.Project root directory
--tsconfig <path>auto-detectedPath to tsconfig.json
--pattern <glob>**/*.controller.tsGlob pattern to find controllers
--format <format>ts要查找的 docs 文件格式:tsjs
--quietfalseSuppress all output except errors

合并了什么

路径 + HTTP 方法与基础文档匹配:

  • ApiTags → 并入 tags(绝不会丢弃基础文档中已有的标签)
  • ApiOperation({ summary, description, deprecated }) → 覆盖这几个字段
  • ApiResponse({ status, description, schema, example, examples }) → 按状态码分别合并(其他状态码不受影响);未提供 schema/type 时,回退使用该方法自身解析出的返回类型,与 generate 已经在用的同一套 DTO/class-validator/接口推断逻辑一致,返回类型是 ≥2 个具名 DTO/实体的联合类型时(比如 Promise<UserDto | AdminDto>),会生成 $refoneOf
  • ApiBody({ schema, examples }) → 设置 requestBody,同样以返回类型式的回退方式解析 @Body() 参数的类型,也包含相同的联合类型 → oneOf 处理(这里故意不读取 example,因为 @nestjs/swagger 真实的 ApiBodyOptions 类型只有 examples,和支持两者的 ApiResponse 不同)
  • ApiBearerAuth() → 追加到 security
  • ApiParam / ApiQuery / ApiHeader → 按名称 + 位置合并进 parameters:真正新增的参数会被追加,但已经存在的参数(比如 @nestjs/swagger 仅凭反射就会为任何 @Query()/@Param() 装饰的参数自动生成一条裸的 required: true 条目)只会被叠加字段,不会被丢弃。enum 可以来自数组字面量(enum: ['a', 'b']),也可以引用一个 TS enum,包括从另一个文件导入的(enum: Role);当解析出的每个值都是数字时,schema 的 type 会被推断为 number,否则为 string

What this does not do

刻意收窄的范围

这个命令刻意收窄了范围,不是对 @nestjs/swagger 装饰器语义的完整重新实现:anyOf(没有哪个 TS 结构能像联合类型天然映射到 oneOf 那样映射到“任意一种”)、links/callbacks@nestjs/swagger 本身对这两者都没有对应的装饰器选项),以及任何不是字面量的装饰器参数(变量、函数调用、展开运算符)都会原样保留,而不是去猜测。让字段保持基础文档原有的样子,好过打上一个错误的补丁。只有当联合类型的每一个分支都能解析为具名 DTO/实体时,联合返回类型或 @Body() payload 才会变成 oneOf。docs 文件里记录了但在 --spec 中不存在的路由,只会作为警告报告出来,不会被静默丢弃或报错。