Complete OpenAPI 3.0/3.1 generation, diagnostics, lifecycle safety, enum and naming mappings, bilingual documentation, examples, and pub.dev release validation.
5.9 KiB
架构
生成流水线有意拆分为多个阶段:
配置
-> source loader
-> external/local $ref resolver
-> multi-source merger
-> validation + parser
-> transport/schema IR
-> preset + Dart renderer
-> manifest lifecycle
-> fix / format / build_runner
核心不变量是:加载阶段产生自包含且依赖可追踪的文档;parser 表达 OpenAPI 语义;renderer 不重新解释规范;lifecycle 只管理 manifest 中声明的文件。
配置
lib/src/config/config.dart:
- 查找
koi_swagger_parser.yaml和兼容的generator_config.yaml名称; - 相对 source/output 路径以配置文件目录解析;
- 从
--cwd或显式配置目录确定宿主项目命令目录; - 在转换 YAML scalar 前完成类型校验;
- 解析 enum、命名、type/import mapping 和 filter;
- 校验不支持的组合、mapping collision、正则和 enum mapping;
- 支持从旧
base_result_import迁移。
未知 key 产生 warning;非法类型和不完整组合产生 error。详见 配置参考。
Loader、resolver 与 merger
对每个 root source,OpenApiReferenceResolver:
- 规范化本地文件、file URL 或 HTTP(S) source;
- 缓存每个加载的文档;
- 解析 local、relative 和 remote
$ref; - 把外部 component bundle 到根文档;
- 为 component 冲突分配确定性名称;
- 记录依赖并诊断无法支持的跨文档循环。
OpenApiDocumentMerger 再按配置顺序合并 root:
- 重复的 operation method/path 是 error;
- 同名但内容不同的 component 会确定性改名,并重写该 source 的 ref;
- 后输入不会静默覆盖冲突;
- 版本、info 和 path parameter 冲突会被报告。
parser 原则上只应收到根文档 JSON Pointer。仍然存在的 external ref 会被视为 resolver error。
Validation 与 parser
OpenApiDocumentParser 负责:
- OpenAPI 3.0/3.1 版本和关键结构校验;
- operation、path、tag 和 model filter;
- parameter location、style、explode、
allowReserved和content; - request media type,以及 response status/content/header;
- server、security scheme 和 security requirement;
- required、nullable、readOnly/writeOnly 和
additionalProperties语义; - enum 配置/vendor extension 优先级;
allOf、discriminator union 和已支持的 generic union;- custom mapping 和 Dart 名称冲突。
无法用可靠 wire 语义渲染的结构不能静默退化为 dynamic。安全但有信息损失的
继续处理会产生 warning,例如不同成功 JSON body type 可能统一为 Object?。
XML、Protobuf 等没有已支持 decoder 的 media type 会产生 error。
中间表示
lib/src/ir/ir.dart 是 parser/renderer 契约,主要节点包括:
ApiOperation:method、path、tag、version、server 和 security;ApiParameter:Dart/wire name、location、style、explode 和allowReserved;ApiRequestBody:JSON、multipart、form-urlencoded 和 binary request;ApiResponse:status/default、body kind/type、content type 和 header;ModelSpec:object、enum、union model,以及 usage category 和 extras;ModelField:required/nullability/read-write flag 和 constraint;DartType:named、list、map、object、dynamic 和 void type graph。
model 按 request、result、shared、enum 分类。包含 readOnly/writeOnly 属性的 component 可投影为 request/response variant,避免 request 强制只读值,也避免 response 暴露 write-only secret。
generic oneOf 要求恰好一个 decoder 匹配。generic anyOf 保留 raw value 和
全部匹配 case。object 分支在 decode 前会用 required key 和 enum constraint
预筛。
Preset 与 renderer
当前 koi_flutter preset 面向 Dio、Retrofit、Freezed 和 json_serializable。
renderer:
- 对 Retrofit 可表达的 parameter 形式使用 Retrofit annotation;
- 当已支持的 style、cookie 或
allowReserved组合需要自定义序列化时,生成 typed public adapter 和 private Retrofit delegate; - 渲染 Freezed object、enum 和 union model;
- 为根级
properties+additionalProperties渲染自定义 map 读写 helper; - 收集 model dependency 和 external type import;
- 按 version/tag 分组 API,并输出 client/index 文件。
renderer 不加载 ref,也不判断 OpenAPI 结构是否合法。
生成生命周期
落盘前,GenerationLifecycle 计算:
- canonical merged spec SHA-256;
- normalized config SHA-256;
- 每个渲染 path/content SHA-256。
manifest 记录 schema/generator version、source root、dependency 和每个主生成 文件的实际 hash。写入使用操作系统 exclusive lock 和同目录临时文件 rename。
安全不变量:
- renderer 输出必须位于配置的 API/model 根;
- stale candidate 必须来自旧 manifest;
- stale path 仍必须位于当前 managed root;
- 删除前当前 hash 必须等于旧 manifest hash;
- 损坏或未知版本 manifest 不参与删除;
- fix/format/build 失败时不写 success manifest;
- watch 在释放生成锁后启动。
.g.dart 和 .freezed.dart 由 build_runner 管理,不进入本生成器的 stale
manifest。
Response wrapper
parser 不硬编码 BaseResult:
passthrough返回 OpenAPI response schema;external_generic检测配置的成功 envelope,并返回ExternalWrapper<Inner>。
default response 仍是错误响应。response_mode: http_response 保留 Dio
status/header。错误 response model 仍保留在 IR 和生成 model 集合中。
扩展边界
IR/preset/renderer 分层为未来的版本化 renderer interface、template override、 semantic diff 和可选 runtime adapter 留出空间。这些是设计方向,不是当前 公开版本的功能。当前实现边界见兼容性。
更多生态对比属于项目内部调研,不随发布 package 交付。