Complete OpenAPI 3.0/3.1 generation, diagnostics, lifecycle safety, enum and naming mappings, bilingual documentation, examples, and pub.dev release validation.
155 lines
5.9 KiB
Markdown
155 lines
5.9 KiB
Markdown
# 架构
|
||
|
||
[English](../ARCHITECTURE.md) | [简体中文](ARCHITECTURE.md)
|
||
|
||
生成流水线有意拆分为多个阶段:
|
||
|
||
```text
|
||
配置
|
||
-> 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。详见
|
||
[配置参考](CONFIGURATION.md)。
|
||
|
||
## Loader、resolver 与 merger
|
||
|
||
对每个 root source,`OpenApiReferenceResolver`:
|
||
|
||
1. 规范化本地文件、file URL 或 HTTP(S) source;
|
||
2. 缓存每个加载的文档;
|
||
3. 解析 local、relative 和 remote `$ref`;
|
||
4. 把外部 component bundle 到根文档;
|
||
5. 为 component 冲突分配确定性名称;
|
||
6. 记录依赖并诊断无法支持的跨文档循环。
|
||
|
||
`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。
|
||
|
||
安全不变量:
|
||
|
||
1. renderer 输出必须位于配置的 API/model 根;
|
||
2. stale candidate 必须来自旧 manifest;
|
||
3. stale path 仍必须位于当前 managed root;
|
||
4. 删除前当前 hash 必须等于旧 manifest hash;
|
||
5. 损坏或未知版本 manifest 不参与删除;
|
||
6. fix/format/build 失败时不写 success manifest;
|
||
7. 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 留出空间。这些是设计方向,不是当前
|
||
公开版本的功能。当前实现边界见[兼容性](COMPATIBILITY.md)。
|
||
|
||
更多生态对比属于项目内部调研,不随发布 package 交付。
|