Skip to content

Add OpenAPI 3.x parser and IR converter#209

Open
MadsBogeskov wants to merge 1 commit intoadd-swagger-swift-irfrom
add-openapi3-parser
Open

Add OpenAPI 3.x parser and IR converter#209
MadsBogeskov wants to merge 1 commit intoadd-swagger-swift-irfrom
add-openapi3-parser

Conversation

@MadsBogeskov
Copy link
Copy Markdown
Contributor

@MadsBogeskov MadsBogeskov commented Apr 7, 2026

Summary

  • Adds OpenAPI3Document and all supporting model types (OpenAPI3Schema, OpenAPI3Parameter, OpenAPI3Operation, OpenAPI3RequestBody, OpenAPI3Response, OpenAPI3Components, OpenAPI3Server, OpenAPI3OrRef) with Decodable conformance
  • Adds OpenAPI3ToIRConverter converting OAS3 documents → IRDocument (the spec-agnostic IR from the previous PR)
  • Adds SwaggerReader.readSpec() with automatic version detection — returns APISpec (.swagger2 or .openapi3), both of which convert to IRDocument via .toIR()
  • 33 new tests covering parsing, IR conversion, and version detection; all 130 tests pass

Test plan

  • All existing tests pass
  • OpenAPI3ParseTests — verifies parsing of document, info, servers, paths, operations, parameters, request bodies, schemas (object, array, allOf, nullable, enum)
  • OpenAPI3ToIRConverterTests — verifies IR conversion of all the above
  • SwaggerReaderSpecDetectionTests — verifies readSpec() correctly routes OAS3 vs Swagger 2.0

🤖 Generated with Claude Code


Note

Medium Risk
Adds a new OpenAPI 3.x decoding and conversion path plus spec-version auto-detection, which can affect how inputs are interpreted and mapped into the shared IR. Main risk is incomplete/incorrect coverage of OAS3 edge-cases and $ref resolution leading to wrong generated output rather than runtime safety issues.

Overview
Adds first-class OpenAPI 3.x support alongside existing Swagger 2.0 parsing.

Introduces OpenAPI3Document and related Decodable model types (including $ref handling via OpenAPI3OrRef) plus an OpenAPI3ToIRConverter that maps OpenAPI3 paths/operations/parameters/request bodies/responses/schemas (including allOf/oneOf/anyOf, nullable, and additionalProperties) into SwaggerSwiftIR’s IRDocument.

Extends SwaggerReader with readSpec() and an APISpec enum to auto-detect spec version (openapi vs swagger) and provide a unified .toIR() entry point; updates the test target to depend on SwaggerSwiftIR and adds OpenAPI3 fixtures and coverage for parsing, version detection, and IR conversion.

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

- 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>
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 ee859f0. Configure here.

}
return servers.map { server in
IRServer(url: server.url, description: server.description)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Server variables silently dropped during IR conversion

Medium Severity

irServers() creates IRServer with only url and description, discarding server.variables entirely. OpenAPI3Server parses variables, and IRServer has a variables field designed for them, but the converter never maps OpenAPI3ServerVariable to IRServerVariable. Specs using templated server URLs (e.g. https://{env}.api.example.com) lose their variable definitions (allowed values, defaults) in the IR output.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ee859f0. Configure here.

required: required,
allOf: irAllOf
))
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

allOf check ignores explicit schema type field

Low Severity

The comment says "allOf at the top level (with no type) means composed object," but the condition doesn't verify schema.type == nil. Any schema with a non-empty allOf (and no oneOf/anyOf) is unconditionally converted to .object(...), even when the schema has an explicit type like "string" or "integer". This causes schemas with typed allOf composition to lose their declared type.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ee859f0. Configure here.

self.minLength = try container.decodeIfPresent(Int.self, forKey: .minLength)
self.maxLength = try container.decodeIfPresent(Int.self, forKey: .maxLength)
self.pattern = try container.decodeIfPresent(String.self, forKey: .pattern)
self.`enum` = try container.decodeIfPresent([String].self, forKey: .`enum`)
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-string enum values cause hard parse failure

Medium Severity

The enum field is decoded as [String]? using try (not try?), so any OAS3 schema with non-string enum values (e.g., enum: [200, 404] on an integer schema) causes the entire document parse to throw. This contrasts with the default field on lines 108–111 which uses try? for graceful degradation. Since OpenAPI3Schema represents all schema types, a single integer enum anywhere in a spec prevents the whole document from being parsed.

Fix in Cursor Fix in Web

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