Skip to content

feat: PoC Support OpenAPI 3.1#6781

Draft
ZhongpinWang wants to merge 10 commits into
mainfrom
support-openapi-3.1
Draft

feat: PoC Support OpenAPI 3.1#6781
ZhongpinWang wants to merge 10 commits into
mainfrom
support-openapi-3.1

Conversation

@ZhongpinWang

@ZhongpinWang ZhongpinWang commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Vibe coded solution to support openapi 3.1

Most changes verified. There might be some generated non-sense though that I missed. But overall this PR shows the possibility and effort to keep maintaining our own generator.

OAI Spec Releases

@ZhongpinWang ZhongpinWang changed the title poc: Support OpenAPI 3.1 feat: PoC Support OpenAPI 3.1 Jul 16, 2026
@ZhongpinWang

ZhongpinWang commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

(Generated, but looks pretty legit to me)

OpenAPI 3.1 Branch — Change Analysis & Coverage Report

What the Branch Contains

The support-openapi-3.1 branch adds OpenAPI 3.1.0 support to @sap-cloud-sdk/openapi-generator.


Root Cause Fixed

The original generator silently accepted 3.1 documents but parsed them as 3.0, producing broken or any output. Two root causes:

  1. swagger2openapi only converts Swagger 2.0 → OAS 3.0. For any 3.x document it short-circuits and passes the document through unchanged — including 3.1, which then got cast to OpenAPIV3.Document and parsed with 3.0 assumptions.
  2. No version detection existed anywhere; swagger-parser would accept 3.1 without complaint, hiding the problem.

Feature-by-Feature Changes

1. Type System — JSON Schema 2020-12 Alignment

New input type OpenApiV3xSchema (src/openapi-types.ts)

A permissive input interface that accepts both 3.0 and 3.1 schema shapes. It carries an index signature ([key: string]: any) so any JSON Schema 2020-12 keyword can flow through even if not explicitly modeled. All parser functions (parseSchema, parseObjectSchema, etc.) now take this type instead of OpenAPIV3.SchemaObject.

type as array — ["string", "number"] → union anyOf

getType in src/parser/type-mapping.ts now accepts string | string[] | undefined. Array types are mapped element-by-element to TypeScript types and joined as a deduplicated union (e.g. string | number). Helper functions getSchemaTypes() and hasType() in src/parser/schema.ts normalize the type field across both versions.

Nullability via "null" in type array (replaces nullable: true)

isNullableSchema() in src/parser/schema.ts checks both nullable: true (3.0) and "null" in the type array (3.1). stripNullability() removes these markers before parsing to prevent emitting | null twice. All property and persisted-schema nullable detection updated to use these helpers.

const keyword

New output type OpenApiConstSchema and parseConstSchema() function. Literal values are serialized: strings become quoted ('fixed'), nulls become null, objects are JSON.stringify-ed, primitives use String(). The file-serializer now emits const schemas as TypeScript literal types.

prefixItems (tuples)

New output type OpenApiTupleSchema and parseTupleSchema() function. Positional items from prefixItems become a TypeScript tuple [T1, T2, ...]. The items keyword (governing additional elements beyond the tuple) becomes a rest element: [T1, T2, ...T3[]]. Serialized in the file-serializer.

contentEncoding / contentMediaType

Content-encoded strings (e.g. contentEncoding: "base64") are mapped to Blob, consistent with the existing format: binaryBlob mapping. Both keywords are also collected into schema properties for JSDoc emission.

examples array in schemas

parseSchemaProperties now collects the plural examples field. JSDoc generation in src/schema-util.ts renders each array entry as a separate @example tag. When both example (deprecated singular) and examples are present, a warning is logged and example is dropped in favour of examples.

Numeric exclusiveMinimum / exclusiveMaximum

These were previously not collected at all. Now collected with an undefined-guard (not a falsiness check, so 0 is correctly treated as meaningful). In 3.1 these are numeric bounds; the 3.0 boolean form was not relevant to code generation either, but the type is widened to number | boolean to accept both versions.

patternProperties

Pattern-keyed property schemas are merged into the Record<string, V> additional-properties type as a union. If additionalProperties: false but patternProperties exist, only the pattern schemas govern additional keys. Per-pattern type distinctions are lost when patterns have different value types (see remaining gaps).

$ref sibling description

In 3.1, $ref may carry sibling keywords. Previously description on a reference object in property position was forced to undefined. The branch preserves it.


2. Document / Top-Level Structure

paths now optional

An empty paths: {} object is injected before SwaggerParser.parse() so the underlying validator (which still requires the key) accepts paths-less documents. If a document has no paths, an info log is emitted. parseApis already returned an empty array for empty paths — no crash.

webhooks — warning instead of silent drop

warnOnUnsupportedFeatures() in src/parser/document.ts lists webhook names in a logger.warn call. No client code is generated for webhooks (semantically correct — they model inbound requests to the consumer, not outbound calls).

components/pathItems — warning

The same warnOnUnsupportedFeatures() function emits a warning listing path item names. No code generation for them.


3. Tests

30 new tests added across 6 spec files:

File New tests What it covers
src/parser/schema.spec.ts 16 3.1 feature block (type arrays, null, const, tuples, patternProperties, etc.)
src/parser/type-mapping.spec.ts 4 Type arrays / union mapping
src/file-serializer/schema.spec.ts 4 Const / tuple serialization
src/schema-util.spec.ts 1 3.1 property documentation
src/parser/document.spec.ts 4 Nullable persisted schemas, paths-less docs, webhooks/pathItems warnings
src/document-converter.spec.ts 1 3.1 passthrough / version detection

OpenAPI 3.1 Release History

Version Date Notes
3.1.0 RC0 June 2020 Introduced webhooks, jsonSchemaDialect, components/pathItems, license.identifier
3.1.0 RC1 Sept 2020 Refinements
3.1.0 RC2 Nov 2020 Further refinements
3.1.0 final February 2021 Full JSON Schema 2020-12 alignment; nullable removed; type arrays; const; prefixItems; numeric exclusiveMin/Max; $ref siblings; paths optional; responses optional
3.1.1 October 24, 2024 Patch only — clarifications on enum/default (SHOULDMUST), OAuth/bearer docs, Security Considerations section. No breaking changes.
3.1.2 In spec repo Clarifications only. No breaking changes.

OpenAPI no longer follows SemVer — future minor increments may introduce breaking changes.


Coverage Matrix

Fully Covered

Feature Handler
type as array getSchemaTypes / getType with union join
nullable removed; null via type array isNullableSchema / stripNullability
Standalone type: "null" Explicit branch in parseSchema
const keyword parseConstSchema + serializer
prefixItems (tuples) parseTupleSchema with rest element
contentEncoding/contentMediaTypeBlob Schema parsing + property collection
examples array Collected + multi-@example JSDoc
Numeric exclusiveMin/Max Collected with undefined-guard
patternProperties Merged into additionalProperties union
$ref sibling description Preserved in property parsing
paths optional Empty paths: {} injected before validation
webhooks Explicit named warning
components/pathItems Explicit named warning
swagger2openapi bypass for 3.x docs Version string detection in converter
example + examples mutual exclusivity Warning + example dropped

Not a Generator Concern (by Design)

Item Reason
responses optional under Operation parseResponses already handles undefined — no crash
info.version SemVer dropped Generator never validates info.version
info.license.identifier License data not consumed
Mutual TLS security scheme Generator does not produce auth/security code
Server variable enum/default strictness Generator does not validate server variable constraints
jsonSchemaDialect / $schema swagger-parser handles document parsing
$ref sibling summary No TypeScript output for summary on a $ref
3.1.1 / 3.1.2 patch releases Clarification-only; no code impact

Known Remaining Gaps

Gap Impact Notes
Advanced JSON Schema 2020-12 applicators: if/then/else, $defs, unevaluatedProperties, unevaluatedItems, dependentSchemas, dependentRequired, propertyNames, contains/minContains/maxContains, $dynamicRef/$dynamicAnchor, $vocabulary, $anchor Low–Medium Silently ignored; schemas using them degrade toward any or Record<string,any>. Would require a full JSON Schema 2020-12 evaluation layer to close.
patternProperties with distinct per-pattern value types Low All pattern schemas collapsed into a single Record<string, V> union — per-pattern type distinctions are lost when patterns have different value types.
webhooks code generation Design decision No callable client methods emitted; warning only. Semantically correct for an outbound client SDK, but a gap if webhook handler stubs are ever desired.
components/pathItems code generation Low Warning only; path items used as $ref targets for webhooks remain unresolved in the generated client.

Conclusion

The branch is a solid, backward-compatible first implementation of 3.1 support. All breaking changes from OAS 3.0 → 3.1 that are relevant to TypeScript client codegen are addressed. The remaining gaps are either advanced JSON Schema applicator keywords (requiring a full evaluation engine, out of scope) or structural features (webhooks, pathItems) that do not map naturally to an outbound client SDK.

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