# Architecture [English](ARCHITECTURE.md) | [Chinese (Simplified)](zh-CN/ARCHITECTURE.md) The generation pipeline is deliberately split into stages: ```text configuration -> source loader -> external/local $ref resolver -> multi-source merger -> validation + parser -> transport/schema IR -> preset + Dart renderer -> manifest lifecycle -> fix / format / build_runner ``` The main invariant is that loading produces a self-contained document with traceable dependencies; the parser represents OpenAPI semantics; the renderer does not reinterpret the specification; and the lifecycle manages only files declared in its manifest. ## Configuration `lib/src/config/config.dart`: - discovers `koi_swagger_parser.yaml` and compatible `generator_config.yaml` names; - resolves source and output paths against the configuration directory; - chooses the host-project command directory from `--cwd` or the explicit configuration directory; - validates YAML scalar types before casting; - parses enum, naming, type/import mappings, and filters; - validates unsupported combinations, mapping collisions, regular expressions, and enum mappings; - supports migration from the legacy `base_result_import` setting. Unknown keys produce warnings. Invalid types and incomplete combinations produce errors. See [Configuration](CONFIGURATION.md). ## Loader, resolver, and merger For each root source, `OpenApiReferenceResolver`: 1. normalizes a local file, file URL, or HTTP(S) source; 2. caches each loaded document; 3. resolves local, relative, and remote `$ref` values; 4. bundles external components into the root document; 5. assigns deterministic names to component conflicts; 6. records dependencies and diagnoses unsupported cross-document cycles. `OpenApiDocumentMerger` then merges roots in configuration order: - a duplicate operation method/path is an error; - components with the same name but different content are renamed deterministically, and references from that source are rewritten; - later inputs never silently overwrite conflicts; - version, info, and path-parameter conflicts are reported. The parser should receive only root-document JSON Pointers. A remaining external reference is treated as a resolver error. ## Validation and parsing `OpenApiDocumentParser` handles: - OpenAPI 3.0/3.1 version and core structure checks; - operation, path, tag, and model filters; - parameter location, style, explode, `allowReserved`, and `content`; - request media types and response status, content, and headers; - servers, security schemes, and security requirements; - required, nullable, read-only/write-only, and `additionalProperties` semantics; - enum configuration/vendor-extension precedence; - `allOf`, discriminated unions, and supported generic unions; - custom mappings and Dart name collisions. A structure that cannot be rendered with reliable wire semantics must not silently become `dynamic`. A safe but lossy continuation produces a warning; for example, different successful JSON body types may converge on `Object?`. A media type without a supported decoder, such as XML or Protobuf, produces an error. ## Intermediate representation `lib/src/ir/ir.dart` is the parser/renderer contract. Its main nodes include: - `ApiOperation`: method, path, tag, version, server, and security data; - `ApiParameter`: Dart/wire name, location, style, explode, and `allowReserved`; - `ApiRequestBody`: JSON, multipart, form-urlencoded, and binary requests; - `ApiResponse`: status/default, body kind/type, content type, and headers; - `ModelSpec`: object, enum, and union models with usage category and extras; - `ModelField`: required/nullability/read-write flags and constraints; - `DartType`: named, list, map, object, dynamic, and void type graphs. Models are grouped as request, result, shared, or enum models. A component with read-only/write-only properties can be projected into request and response variants so that read-only values are not required in requests and write-only secrets are not exposed in responses. A generic `oneOf` requires exactly one decoder match. A generic `anyOf` retains the raw value and all matching cases. Object branches are prefiltered by required keys and enum constraints before decoding. ## Preset and renderer The current `koi_flutter` preset targets Dio, Retrofit, Freezed, and json_serializable. The renderer: - uses Retrofit annotations for parameter forms Retrofit can represent; - emits a typed public adapter and private Retrofit delegate when a supported style, cookie, or `allowReserved` combination needs custom serialization; - renders Freezed object, enum, and union models; - renders custom root-map read/write helpers for `properties` plus `additionalProperties`; - collects model dependencies and external type imports; - groups API files by version and tag and emits client/index files. The renderer does not load references or decide whether an OpenAPI structure is valid. ## Generation lifecycle Before writing, `GenerationLifecycle` calculates: - the canonical merged-spec SHA-256; - the normalized configuration SHA-256; - each rendered path and content SHA-256. The manifest records its schema/generator version, source roots, dependencies, and the actual hash of each primary generated file. Writes use an operating system exclusive lock and same-directory temporary-file rename. Safety invariants: 1. Renderer output must stay inside the configured API/model roots. 2. A stale candidate must come from the previous manifest. 3. Its path must still be inside the current managed roots. 4. Its current hash must equal the previous manifest hash before deletion. 5. A corrupt or unknown-version manifest is never trusted for deletion. 6. A failed fix, format, or build step does not write a success manifest. 7. Watch mode starts after the generation lock is released. build_runner owns `.g.dart` and `.freezed.dart` files; they are not included in this generator's stale-file manifest. ## Response wrappers The parser does not hard-code `BaseResult`: - `passthrough` returns the OpenAPI response schema; - `external_generic` detects configured success envelopes and returns `ExternalWrapper`. A `default` response remains an error response. `response_mode: http_response` retains Dio status and headers. Error response models remain in the IR and generated model set. ## Extension boundaries The IR/preset/renderer split leaves room for a versioned renderer interface, template overrides, semantic-diff tooling, and optional runtime adapters. Those are design directions, not features of the current public release. The current implementation boundaries are documented in [Compatibility](COMPATIBILITY.md). Additional ecosystem comparisons are kept as internal project research and are not part of the published package.