Skip to content

Migrate APIRequestFactory and RequestParameterFactory to IR types#211

Open
MadsBogeskov wants to merge 7 commits intomainfrom
migrate-factories-to-ir
Open

Migrate APIRequestFactory and RequestParameterFactory to IR types#211
MadsBogeskov wants to merge 7 commits intomainfrom
migrate-factories-to-ir

Conversation

@MadsBogeskov
Copy link
Copy Markdown
Contributor

@MadsBogeskov MadsBogeskov commented Apr 7, 2026

Summary

  • Both factories now accept IROperation and [IRParameter] instead of SwaggerSwiftML.Operation, Parameter, Swagger, and SwaggerFile — removing SwaggerSwiftML dependency from the factory layer
  • Deletes SwaggerSwiftCore.HTTPMethod; uses SwaggerSwiftIR.HTTPMethod throughout (adds trace)
  • Deletes ParameterType+ToString.swift; factories use modelTypeResolver.resolve(forSchema:...) 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 handles standalone single-operation conversion without a full Swagger context
  • Parameter.toIRParameter() bridge extension for path-level parameter conversion

Test plan

  • swift test --parallel — all 41 tests pass (including golden file snapshot)
  • Form data parameter order is now alphabetical (deterministic)

🤖 Generated with Claude Code


Note

Medium Risk
Moderate risk because it refactors core codegen type resolution and request/response/parameter parsing (including consumes, query array serialization, and form-data handling), which can subtly change generated API signatures and models. Adds new IR/OpenAPI3 conversion paths that may expose edge cases around $ref qualification, allOf, and non-JSON media types.

Overview
Migrates SwaggerSwift’s codegen pipeline to a new spec-agnostic intermediate representation (SwaggerSwiftIR), adding a dedicated SwaggerSwiftIR target and new converters from both Swagger 2.0 and OpenAPI 3.x into IRDocument/IROperation/IRSchema.

APIRequestFactory, RequestParameterFactory, ModelTypeResolver, and ObjectModelFactory are refactored to consume IR types (dropping direct SwaggerSwiftML/SwaggerFile dependencies), including updated handling for request bodies, form-data via requestBody content, query array serialization via IRParameterStyle, allOf/additionalProperties, and service-qualified $ref typing.

Cleans up related plumbing: removes SwaggerSwiftCore.HTTPMethod in favor of SwaggerSwiftIR.HTTPMethod (adds trace), deletes ParameterType+ToString.swift, simplifies Enumeration by removing collectionFormat, and updates CLI/CI flag naming from --git-hub-token to --github-token (note: CLI validation error string still references the old flag).

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

MadsBogeskov and others added 6 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>
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 7, 2026

Test Results (ubuntu-latest)

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

Results for commit cc0bc44. ± 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   7s ⏱️ +3s
 1 suites ±0    0 💤 ±0 
 1 files   ±0    0 ❌ ±0 

Results for commit cc0bc44. ± Comparison against base commit b676a08.

♻️ This comment has been updated with latest results.


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

Renaming gitHubToken to githubToken changes the auto-generated CLI flag from --git-hub-token to --github-token (Swift ArgumentParser derives kebab-case from camelCase). The error message on line 31 still references --git-hub-token, so users who see this error will try a flag that doesn't exist.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 10a1582. Configure here.

let queryParameters = parameters.filter {
if case ParameterLocation.query = $0.location {
return true
} 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.

Non-deterministic dictionary key selection for MIME type

Medium Severity

consumeMimeType selects the MIME type via operation.requestBody?.content.keys.first, but content is a [String: IRMediaType] dictionary whose iteration order is non-deterministic. When a request body defines multiple content types (valid in OpenAPI 3.x), the chosen MIME type varies between runs, producing non-deterministic code generation output.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 10a1582. Configure here.

requestBody: operation.requestBody,
typePrefix: typeName,
swagger: swagger
serviceName: serviceName
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 and form-data parameters both emitted for same request

Medium Severity

resolveBodyParameters and resolveFormDataParameters are both called unconditionally with the same operation.requestBody. When a request body has both an application/json entry and a form-data entry (possible in OpenAPI 3.x), both methods produce parameters, yielding a body parameter alongside form-data parameters for the same request.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 10a1582. Configure here.

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 2 potential issues.

There are 5 total unresolved issues (including 3 from previous reviews).

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 cc0bc44. 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 parameters silently dropped for non-JSON consumes

Medium Severity

resolveBodyParameters hardcodes requestBody.content["application/json"] to find the body schema, but the IR converter (irRequestBody(fromBodyParam:)) stores the body under consumes.first ?? "application/json". When a Swagger spec declares a non-JSON consume type (e.g. application/xml), the body is keyed by that MIME type in the IR, so the hardcoded "application/json" lookup returns nil and the body parameter is silently dropped. The old code found body parameters by location regardless of MIME type.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit cc0bc44. Configure here.

let queryParameters = parameters.filter {
if case ParameterLocation.query = $0.location {
return true
} 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.

Unsupported MIME types silently default to JSON

Medium Severity

consumeMimeType silently returns .json when the request body's MIME type isn't recognized by APIRequestConsumes. The old code threw APIRequestFactoryError.unsupportedMimeType, preventing generation of incorrect code. Now an endpoint with e.g. application/xml body silently gets JSON serialization, producing broken generated code with no warning.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit cc0bc44. 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