Skip to content

Wire APIFactory and Generator to use IRDocument end-to-end#212

Open
MadsBogeskov wants to merge 8 commits intomainfrom
wire-apifactory-to-ir-document
Open

Wire APIFactory and Generator to use IRDocument end-to-end#212
MadsBogeskov wants to merge 8 commits intomainfrom
wire-apifactory-to-ir-document

Conversation

@MadsBogeskov
Copy link
Copy Markdown
Contributor

@MadsBogeskov MadsBogeskov commented Apr 7, 2026

Summary

  • APIFactory.generate() now accepts IRDocument instead of Swagger, removing the direct SwaggerSwiftML dependency from the code generation engine
  • Generator converts Swagger → IRDocument once after parsing, then passes it to the factory
  • Dead extension files deleted: Path, Operation, Parameter, Swagger, Schema, DataFormat — their functionality is handled by IRPathItem/IROperation or was unused dead code
  • Phantom import SwaggerSwiftML removed from 8 model and parser files
  • Generator.swift is the only remaining file in SwaggerSwiftCore that imports SwaggerSwiftML, solely to drive the parse → IR conversion

Test plan

  • All 41 existing tests pass (swift test --parallel)
  • Golden file tests unchanged
  • ResponseConformanceTests still passes (global responses resolved via operation processing)
  • IgnoredPathsTests still passes

🤖 Generated with Claude Code


Note

Medium Risk
Moderate risk because it refactors core code generation to a new SwaggerSwiftIR layer and changes how requests/responses, parameters, and schema composition (e.g. allOf, additionalProperties) are interpreted, which can affect generated API signatures and models.

Overview
Moves code generation to a spec-agnostic intermediate representation. SwaggerSwiftCore now generates APIs/models from IRDocument/IROperation/IRSchema instead of SwaggerSwiftML.Swagger, with Generator converting parsed Swagger into IR once and passing it through.

Adds a new SwaggerSwiftIR target and OpenAPI 3 support plumbing. This introduces IR types (document/paths/operations/params/request bodies/responses/schemas/servers) plus converters for Swagger 2 (SwaggerToIRConverter + schema helpers) and OpenAPI 3 (OpenAPI3Document decoding + OpenAPI3ToIRConverter).

Updates request/model generation semantics to IR. Parameter handling is reworked around requestBody/media types, query array serialization now uses IRParameterStyle, model resolution adds handling for allOf, $ref qualification rules, and dictionary-like additionalProperties; several Swagger-specific extensions/utilities are removed as dead/obsolete.

Also renames CLI/CI flag to --github-token and adds repository guidance in CLAUDE.md.

Reviewed by Cursor Bugbot for commit 7293ada. Bugbot is set up for automated code reviews on this repo. Configure here.

MadsBogeskov and others added 7 commits April 7, 2026 10:39
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Introduces a new `SwaggerSwiftIR` target containing spec-agnostic
intermediate representation types that both Swagger 2.0 and future
OpenAPI 3.x parsers will convert into. Adds `SwaggerToIRConverter`
in `SwaggerSwiftML` to convert the existing `Swagger` struct into
`IRDocument`, including full schema, parameter, request body, and
response mapping.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add OpenAPI3Document and supporting model types (schema, parameter,
  operation, request body, response, components, server, OrRef)
- Add OpenAPI3ToIRConverter converting OAS3 → IRDocument
- Add SwaggerReader.readSpec() with version detection, returning APISpec
  (.swagger2 or .openapi3) — both convert to IRDocument via .toIR()
- Add 33 tests covering parsing, IR conversion, and version detection
- Add BasicOpenAPI3.yaml fixture

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace all SwaggerSwiftML-specific DataFormat/Schema references in the
resolver layer with spec-agnostic IRSchema types. Introduces IRStringFormat,
IRIntegerFormat, and IRNumberFormat; adds Schema.toIR() / Node<Schema>.toIR()
helpers for incremental call-site migration in APIRequestFactory and
RequestParameterFactory. All 41 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both factories now accept IROperation and [IRParameter] instead of
SwaggerSwiftML.Operation, Parameter, Swagger, and SwaggerFile — removing
the SwaggerSwiftML dependency from the factory layer entirely.

Supporting changes:
- Delete SwaggerSwiftCore.HTTPMethod; use SwaggerSwiftIR.HTTPMethod throughout
- Delete ParameterType+ToString.swift; factories use modelTypeResolver.resolve() instead
- QueryElement.ValueType.array now uses IRParameterStyle? instead of CollectionFormat?
- Enumeration drops the dead collectionFormat field
- APIFactory converts each ML operation to IR via Operation.toIR(globalConsumes:globalParameters:)
  before calling the factories
- New OperationToIRConverter in SwaggerToIRConverter.swift handles standalone operation conversion
- Parameter.toIRParameter() bridge extension for path-level parameter conversion

All 41 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
APIFactory.generate() now accepts IRDocument instead of Swagger,
removing the last direct SwaggerSwiftML dependency from the code
generation engine. Generator converts Swagger → IRDocument once
after parsing, then passes it to the factory.

Dead extension files (Path, Operation, Parameter, Swagger, Schema,
DataFormat) are deleted — their functionality is now handled
by IRPathItem/IROperation or was unused. Phantom SwaggerSwiftML
imports are cleaned from 8 model and parser files.

Generator.swift is the only remaining file in SwaggerSwiftCore
that imports SwaggerSwiftML, solely to drive the Swagger 2.0
parse → IRDocument conversion pipeline.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 7, 2026

Test Results (ubuntu-latest)

98 tests  ±0   98 ✅ ±0   3s ⏱️ -1s
 1 suites ±0    0 💤 ±0 
 1 files   ±0    0 ❌ ±0 

Results for commit 7293ada. ± Comparison against base commit b676a08.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 7, 2026

Test Results (macos-latest)

98 tests  ±0   98 ✅ ±0   5s ⏱️ -1s
 1 suites ±0    0 💤 ±0 
 1 files   ±0    0 ❌ ±0 

Results for commit 7293ada. ± Comparison against base commit b676a08.

♻️ This comment has been updated with latest results.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 7293ada. Configure here.


mutating func run() async throws {
guard let token = gitHubToken ?? ProcessInfo.processInfo.environment["GITHUB_TOKEN"] else {
guard let token = githubToken ?? ProcessInfo.processInfo.environment["GITHUB_TOKEN"] else {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error message references old CLI flag name

Medium Severity

The validation error message still references --git-hub-token but the CLI flag was renamed to --github-token (property githubToken generates --github-token via Swift Argument Parser). Users who see this error and follow its guidance will use a flag that doesn't exist.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7293ada. Configure here.

let modelDefinitions = try getModelDefinitions(fromSwagger: swagger)
let responseModelDefinitions = try getResponseModelDefinitions(fromSwagger: swagger)
let modelDefinitions = try getModelDefinitions(from: document)
let responseModelDefinitions = [ModelDefinition]()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Response model definitions always empty breaks optimization seeding

Medium Severity

responseModelDefinitions is hardcoded to an empty array, replacing the old getResponseModelDefinitions call. This means responseModelTypeNames at line 34 is always empty, and the allModelDefinitions at line 33 no longer includes global response model definitions. While inline models are captured during operation processing, the explicit seeding of response types for optimizeModelConformance is lost, potentially changing Codable conformance decisions.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7293ada. Configure here.

guard let schemaNode = schemaNode, let parameter = parameter else {
guard let requestBody = requestBody,
let schema = requestBody.content["application/json"]?.schema
else {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Body parameter lost for non-JSON consume types

High Severity

resolveBodyParameters only checks requestBody.content["application/json"] for the body schema. If the Swagger spec declares a non-JSON consume type (e.g. application/xml, text/plain), the converter stores the schema under that MIME type key, but this lookup returns nil, silently dropping the body parameter entirely from the generated function.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7293ada. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant