# Architecture `koi_swagger_parser` 采用“加载 -> 解析 -> IR -> 渲染 -> 落盘”的分层设计,避免把 OpenAPI 细节、Koi 业务约定、具体 Dart 输出模板揉在一起。 ## 1. 分层 ### config 负责读取与归一化配置: - 新配置:`koi_swagger_parser.yaml` - 兼容配置:`generator_config.yaml` - 路径归一化、默认值、旧字段兼容映射 - preset 解析(当前内置 `koi_flutter`) ### openapi 负责: - 本地/远程文档加载 - 多 source 深合并 - schema/ref 解析 - OpenAPI 3.1 nullable / anyOf / oneOf / additionalProperties / allOf 归一化 - multipart request body 与 discriminator union 识别 ### ir 产出与 OpenAPI 原文解耦的中间表示: - API operation - request body / parameter - model / enum - Dart type graph IR 是后续接入 `koi_blueprint_flutter` preset 的关键。 ### generator 只关心如何把 IR 渲染成 Dart 文件: - Retrofit API - Freezed model - enums - index/client 聚合文件 这一层不直接处理 OpenAPI 细节。 ### preset 用于把 parser core 的 IR 和具体客户端技术栈解耦。当前先提供一个很薄的 preset 层: - `koi_flutter`:默认面向 Retrofit + Dio + Freezed - 当前主要控制 multipart 二进制字段该生成为 `MultipartFile`、`File`、`Uint8List` 还是 `String` - 后续可以继续扩展 blueprint preset、网络层 preset、命名/包装策略 preset ## 2. Response Wrapper 设计 parser core 不直接写死 `BaseResult`。 当前支持两种模式: - `passthrough` - 返回真实 OpenAPI response schema - 适合你希望保留服务端 envelope 模型的场景 - `external_generic` - 识别标准成功 envelope(默认 `code/message/data`) - 将 `data` 提取为 inner type - API 返回 `ExternalWrapper`,例如 `BaseResult` 这样做的意义是: - parser core 保持通用 - Koi 网络层包裹策略可配置 - 未来可以挂更多 wrapper preset,而不是继续堆服务端补丁 ## 3. 模型分组 模型按使用语义归档: - `request/`:只在请求体根节点使用 - `result/`:只在成功响应根节点使用 - `shared/`:被请求与响应共同依赖,或用于错误响应 - `enums/`:枚举单独分组 这比“按 swagger component 平铺”更符合 Koi 项目结构,也更利于未来蓝图模板整理。 ## 4. 命名原则 - 类名统一 PascalCase。 - 字段统一 camelCase,并保留 `@JsonKey(name: ...)` 对应 wire name。 - 文件名统一 snake_case。 - API 默认按 `version + tag` 分文件。 命名转换统一收口到 util 层,避免每个阶段各写一套字符串处理逻辑。 ## 5. 为什么新建项目而不是继续修补旧生成器 旧生成器的问题不是单点 bug,而是结构性耦合: - OpenAPI 解析和业务输出绑定太深。 - nullable / anyOf / wrapper 规则分散在多个模板与解析阶段。 - 很难为未来 `koi_blueprint_flutter` 抽出复用 IR。 所以这里直接重新收口: - parser core 面向 OpenAPI 语义 - Koi 输出作为 renderer/preset - 兼容旧配置,但不延续旧架构负担 ## 6. 近期路线 - 第一阶段:打通 Koi/FastAPI 场景(已完成) - 第二阶段:补齐 multipart、discriminator union、preset 基础层(当前版本) - 第三阶段:扩更强 union fallback、更多 preset,并服务 `koi_blueprint_flutter`