# 诊断 [English](../DIAGNOSTICS.md) | [简体中文](DIAGNOSTICS.md) 配置、加载、解析、渲染和生命周期问题统一表示为 `KoiDiagnostic`: ```dart class KoiDiagnostic { final String code; final DiagnosticSeverity severity; // info | warning | error final String message; final String? source; final String? location; } ``` `code` 是稳定的机器可读标识;message 文案可能随版本改进。`source` 表示配置 路径、文档 URL/文件或生成文件;`location` 通常是 source 内的 JSONPath、 JSON Pointer 或其他逻辑位置。 ## Severity 行为 - `info`:正常决策,例如跳过未变化的生成; - `warning`:输出仍然可靠,但发生改名、安全降级或明确省略的非阻塞能力; - `error`:继续执行可能产生无效客户端,生成器抛出 `KoiDiagnosticException`。 CLI 默认输出 warning/error;`--verbose` 还会输出 info 和失败堆栈。 library 调用方可检查诊断: ```dart try { final result = await const KoiSwaggerParser().generate(); for (final item in result.diagnostics) { print(item.format()); } } on KoiDiagnosticException catch (error) { for (final item in error.diagnostics) { print(item.format()); } } ``` 自动化应匹配 `code`,不要匹配 message 文本。需要区分上下文时再断言 `source` 或 `location`。 ## 常见 code ### 配置 | Code | 含义和处理 | |---|---| | `config.missing_sources` | 添加至少一个启用的 `input.swagger_urls`。 | | `config.unknown_key` | 修正拼写或删除当前版本不认识的字段;warning。 | | `config.invalid_section` | 把 scalar/list 改成预期 YAML map。 | | `config.invalid_string` / `config.invalid_boolean` | 修正 YAML scalar 类型。 | | `config.invalid_string_list` | include/exclude filter 必须是字符串列表。 | | `config.invalid_filter_regex` | 修正 `regex:` 后的 Dart 表达式。 | | `config.no_outputs_enabled` | API/model 不能同时关闭。 | | `config.api_requires_models` | 当前 API renderer 依赖生成 model。 | | `config.unsupported_api_renderer` | 保持 `use_retrofit: true`;目前没有其他公开 API renderer。 | | `config.external_wrapper_import_required` | 添加 `external_generic.import`。 | | `config.mapping_target_collision` | 为 mapping source 设置不同的 Dart 目标名。 | | `config.import_mapping_conflict` | 同一映射 Dart 类型只能使用一个 import。 | | `config.conflicting_schema_mapping` | 同一 schema 不能既重命名又由外部类型替换。 | | `config.ambiguous_enum_mapping` | 使用类型明确、无歧义的 enum wire value。 | ### 文档与引用 | Code | 含义和处理 | |---|---| | `openapi.missing_version` / `openapi.unsupported_version` | 提供 OpenAPI 3.0.x/3.1.x 文档。 | | `openapi.invalid_info` / `openapi.invalid_paths` | 修正文档对应关键结构。 | | `openapi.source_load_failed` / `openapi.source_http_error` | 检查文件路径、URL、访问权限和响应状态。 | | `openapi.unresolved_ref` | 本地 JSON Pointer 不存在。 | | `openapi.unresolved_external_ref` | 外部资源/fragment 不存在或无法加载。 | | `openapi.external_ref_not_bundled` | ref 归一化失败;检查前序 source/resolver 诊断。 | | `openapi.external_component_renamed` | 外部 component 冲突已确定性改名;warning。 | | `openapi.multisource_component_renamed` | root 间 component 冲突已确定性改名;warning。 | | `openapi.multisource_operation_conflict` | 两个 root 定义相同 method/path;删除或拆分其中一个。 | | `openapi.callbacks_not_supported` / `openapi.webhooks_not_supported` | 不生成反向调用 client;warning。 | | `openapi.links_not_supported` | 不生成 Link Object 调用关系;warning。 | ### Parameter、request 与 response | Code | 含义和处理 | |---|---| | `openapi.invalid_parameter_style` | 使用与 parameter location 匹配的 style。 | | `openapi.deep_object_requires_object` | deepObject parameter 必须使用 object schema。 | | `openapi.delimited_parameter_requires_array` | space/pipe-delimited parameter 必须使用 array schema。 | | `openapi.parameter_content_count` | Parameter Object `content` 必须恰有一个 media type。 | | `openapi.request_body_schema_missing` | 为选中的 request media type 添加 schema。 | | `openapi.unsupported_request_content_type` | 使用已支持 request codec 或手写 endpoint。 | | `openapi.unsupported_response_content_type` | 使用已支持 response codec 或手写 endpoint。 | | `openapi.success_response_missing` | 添加显式 2xx response;`default` 不是 success。 | | `openapi.multiple_success_response_types` | 多个成功 JSON body type 统一为 `Object?`;warning。 | | `openapi.mixed_success_media_types` | 单个生成方法无法安全 decode binary/stream + JSON success。 | | `openapi.path_parameter_forced_required` | 声明为 optional 的 path parameter 被强制为 required;warning。 | ### Schema 与命名 | Code | 含义和处理 | |---|---| | `openapi.property_read_write_only` | property 不能同时 read-only/write-only。 | | `openapi.invalid_additional_properties` | 使用 boolean 或 Schema Object。 | | `openapi.property_name_collision` | 自动 suffix 避免了 Dart field collision;warning。 | | `openapi.operation_name_collision` | 自动 suffix 避免了 method collision;warning。 | | `openapi.operation_argument_name_collision` | parameter 与 body、cancel token 或其他参数冲突。 | | `openapi.duplicate_enum_member_name` | 多个 wire value 映射到同名,已添加 suffix。 | | `openapi.enum_member_name_sanitized` | enum member name 已转换为合法 Dart identifier。 | | `filter.required_model_excluded` | 选中 API 依赖被排除 model;包含该 model 或排除调用方。 | | `filter.model_pattern_unmatched` | `included_models` pattern 没有匹配 schema。 | ### Server 与 security | Code | 含义和处理 | |---|---| | `openapi.server_url_missing` | 添加非空 server URL。 | | `openapi.server_variable_default_missing` | 为每个 server variable 提供 default。 | | `openapi.server_variable_default_invalid` | 让 default 属于声明的 enum value。 | | `openapi.server_variable_unresolved` | 定义 server URL 中的每个 variable。 | | `openapi.unknown_security_scheme` | 在 components 中定义被引用 scheme。 | | `openapi.unsupported_security_scheme` | scheme 只在文档边界内保留或被拒绝。 | | `openapi.http_auth_requires_custom_interceptor` | 在宿主 Dio 层实现凭证注入;warning。 | ### 生成生命周期 | Code | 含义和处理 | |---|---| | `lifecycle.unchanged_skipped` | hash/file 一致,已安全跳过生成。 | | `lifecycle.manifest_invalid` | 旧 manifest 损坏;重建输出但不信任其删除列表。 | | `lifecycle.manifest_version_ignored` | manifest schema 不兼容,其删除列表被忽略。 | | `lifecycle.output_outside_managed_roots` | renderer 输出越过 API/model 根,已拒绝。 | | `lifecycle.duplicate_output_path` | 两个渲染文件以不同内容指向同一路径。 | | `lifecycle.stale_path_outside_roots` | 旧路径位于当前 root 外,因此保留。 | | `lifecycle.stale_file_modified` | stale 生成文件已被编辑,保留供人工处理。 | | `lifecycle.generated_file_missing` | 主生成文件在 fix/format/build 期间消失。 | | `lifecycle.control_file_not_stale` | lifecycle 控制文件永不作为 stale 输出处理。 | ## 设计原则 1. unresolved ref、非法 wire style 和不支持 codec 不会静默变成 `dynamic`; 2. 安全且可编译的自动改名可以 warning 后继续; 3. 不会破坏其他输出的不支持结构会 warning 后明确省略; 4. stale cleanup 在 path containment 或 hash ownership 不确定时保留文件; 5. 可用时诊断会带 component、operation、parameter 或文件上下文。 minor release 可以增加新 code。自动化应把未知 warning 视为需复核,把未知 error 视为阻塞。