Prepare the OpenAPI parser and Dart generator as a publishable Koi package with CLI entrypoint, docs, examples, tests, and pub.dev release metadata. Constraint: Initial GitHub import follows koi_blueprint_flutter identity mr.koi <i@mrkoi.is>. Rejected: Keep local runtime state in the initial repository | .dart_tool, .omx, and pubspec.lock are ignored for a reusable package source tree. Confidence: high Scope-risk: moderate Directive: Keep generated-output behavior covered by parser and generator tests before changing rendering rules. Tested: dart analyze; dart test; PUB_HOSTED_URL=https://pub.dev dart pub publish --dry-run Not-tested: End-to-end downstream build_runner compilation of generated Retrofit/Freezed output.
115 lines
3.3 KiB
Markdown
115 lines
3.3 KiB
Markdown
# 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<Inner>`,例如 `BaseResult<KoiStoreResponse>`
|
||
|
||
这样做的意义是:
|
||
|
||
- 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`
|