Skip to content

feat(openapi): expand support for unions/intersection of objects when generating OpenAPI specs#1178

Merged
dinwwwh merged 9 commits intomainfrom
unnoq/issue1162
Nov 9, 2025
Merged

feat(openapi): expand support for unions/intersection of objects when generating OpenAPI specs#1178
dinwwwh merged 9 commits intomainfrom
unnoq/issue1162

Conversation

@dinwwwh
Copy link
Copy Markdown
Member

@dinwwwh dinwwwh commented Nov 6, 2025

Fixes #1162

Summary by CodeRabbit

  • New Features

    • Improved OpenAPI generation: composed-object schemas and discriminated unions are now simplified earlier, producing clearer path/query/header parameters and request/response bodies across routes and methods; GET/query handling improved for optional fields.
  • Tests

    • Expanded test coverage for schema simplification, composed-object scenarios, discriminated unions, reference resolution, merging/deduplication and many edge cases.
  • Chores

    • Exposed a reusable schema-simplification utility for downstream use.

@dinwwwh dinwwwh requested a review from Copilot November 6, 2025 07:46
@dosubot dosubot Bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Nov 6, 2025
@vercel
Copy link
Copy Markdown

vercel Bot commented Nov 6, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
orpc Ready Ready Preview Comment Nov 7, 2025 3:13am

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @unnoq, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly improves the OpenAPI generator's ability to handle advanced schema compositions, specifically unions and intersections of object schemas. By introducing a new simplification utility, the generator can now produce more accurate and user-friendly OpenAPI specifications for complex input types, particularly for parameters in GET requests and dynamic routes. This change ensures that the generated API documentation better reflects the underlying data structures, enhancing clarity and usability for API consumers.

Highlights

  • Enhanced OpenAPI Schema Generation: Expanded support for generating OpenAPI specifications from complex Zod schemas involving unions (anyOf, oneOf) and intersections (allOf) of objects, particularly for request parameters.
  • New Schema Simplification Utility: Introduced a new utility function, simplifyComposedObjectJsonSchemasAndRefs, which flattens and merges properties and required fields from composed object schemas (e.g., anyOf, oneOf, allOf) into a single object schema for better OpenAPI representation.
  • Improved Parameter Handling: The OpenAPI generator now applies this simplification to input schemas for detailed structures, or compact structures with dynamic parameters or GET methods, leading to more accurate and concise parameter definitions in the generated spec.
  • Comprehensive Testing: Added extensive unit tests for the new schema simplification logic, covering various combinations of anyOf, oneOf, allOf, nested compositions, and $ref resolution to ensure robustness.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Nov 6, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds a new exported schema-simplification utility that flattens/merges composed object JSON Schemas (anyOf/oneOf/allOf, resolves $ref when doc provided) and integrates it into the OpenAPIGenerator; generator preprocessing now uses simplified schemas for params, queries, headers, bodies and responses. Tests added (one duplicate test present).

Changes

Cohort / File(s) Summary
Core utility implementation
packages/openapi/src/openapi-utils.ts
New exported simplifyComposedObjectJsonSchemasAndRefs(schema, doc?): resolves $ref when doc provided, flattens nested anyOf/oneOf/allOf for object schemas, merges/dedupes properties, computes per-property required, and returns a consolidated object schema or the original when not applicable. Adds imports used by the new function.
Generator integration
packages/openapi/src/openapi-generator.ts
Imports and applies simplifyComposedObjectJsonSchemasAndRefs; introduces preprocessing of input schemas for detailed output, compact-with-dynamic-params, and GET cases; replaces many resolve-openapi-schema calls with simplified schemas for params, query, headers, body, and responses; adjusts branching to operate on simplified representations.
Utility tests
packages/openapi/src/openapi-utils.test.ts
Adds extensive test suite for simplifyComposedObjectJsonSchemasAndRefs, covering no-ops, flattening, merging, deduping, discriminated unions, nested compositions, and $ref resolution prior to simplification.
Generator tests
packages/openapi/src/openapi-generator.test.ts
Adds a test ("expand support for union/interaction of object schemas in some cases") verifying discriminated-union handling for path params (POST) and query params (GET). The test appears twice (duplicate) in the file.
Minor formatting
packages/openapi/src/schema-utils.test.ts
Reformatted import block to multi-line/trailing-comma style only; no behavioral changes.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Caller
    participant Gen as OpenAPIGenerator
    participant Simplify as Simplifier
    participant Resolver as RefResolver

    Client->>Gen: generate(contract)
    Gen->>Gen: determine inputStructure & method
    alt Preprocess needed (detailed OR compact+dynamic OR GET)
        Gen->>Simplify: simplifyComposedObjectJsonSchemasAndRefs(schema, doc?)
        alt doc provided
            Simplify->>Resolver: resolve $ref(s)
            Resolver-->>Simplify: resolved schema(s)
        end
        Simplify-->>Gen: simplified schema (flattened/merged)
    end
    Gen->>Gen: build path params, query params, headers, body, responses using simplified schemas
    alt GET-specific nuance
        Gen->>Gen: validate/build query params (may use original/unresolved schema in some checks)
    end
    Gen-->>Client: OpenAPI document
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Points needing attention:

  • Correctness of property merging, deduplication, and computed required handling in simplifyComposedObjectJsonSchemasAndRefs.
  • Ref-resolution behavior when a doc is provided and interactions with existing resolver helpers.
  • Branching in openapi-generator.ts where original vs. simplified schemas are chosen (especially GET/query logic).
  • The duplicated test in openapi-generator.test.ts (likely unintended).

Possibly related PRs

  • unnoq/orpc#920 — Modifies GET input handling and schema-resolution logic in OpenAPIGenerator; closely related to GET-specific changes here.
  • unnoq/orpc#208 — Integrates schema utilities into the generator and touches the same generator areas; overlaps with the new simplification utility.
  • unnoq/orpc#490 — Adjusts success-response handling in the generator; related to the generator's response/header changes using simplified schemas.

Suggested labels

size:L

Poem

🐰 I hop through anyOf, oneOf, and all,
I flatten refs so no fragments fall.
Properties gather, required flags align,
Paths and queries now neatly define.
A rabbit cheers the spec — tidy, compact, fine.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: expanding support for unions/intersections of objects in OpenAPI spec generation.
Linked Issues check ✅ Passed The PR implements the core objective from issue #1162 by adding simplifyComposedObjectJsonSchemasAndRefs to handle Zod object schemas without direct .shape from intersections/unions.
Out of Scope Changes check ✅ Passed All changes are scoped to the OpenAPI generator functionality. The test additions, utility functions, and schema handling directly support the objective of fixing union/intersection support.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch unnoq/issue1162

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds a new function simplifyComposedObjectJsonSchemasAndRefs that flattens composed JSON schemas (using anyOf, oneOf, allOf) to make them compatible with OpenAPI parameters extraction in scenarios with path parameters or GET requests. The function merges object schemas from unions and intersections into a single flattened object schema.

Key changes:

  • New simplifyComposedObjectJsonSchemasAndRefs function that recursively flattens composed object schemas
  • Integration into the OpenAPI generator to simplify schemas before parameter extraction
  • Removal of minStructureDepthForRef configuration option
  • Comprehensive test coverage for the new simplification logic

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
packages/openapi/src/schema-utils.test.ts Reformatted imports for better readability
packages/openapi/src/openapi-utils.ts Added new simplifyComposedObjectJsonSchemasAndRefs function and related imports
packages/openapi/src/openapi-utils.test.ts Added comprehensive tests for the new schema simplification function
packages/openapi/src/openapi-generator.ts Integrated schema simplification and removed minStructureDepthForRef option
packages/openapi/src/openapi-generator.test.ts Added integration test for discriminated unions with path parameters

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@codecov
Copy link
Copy Markdown

codecov Bot commented Nov 6, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Nov 6, 2025

More templates

@orpc/ai-sdk

npm i https://pkg.pr.new/@orpc/ai-sdk@1178

@orpc/arktype

npm i https://pkg.pr.new/@orpc/arktype@1178

@orpc/client

npm i https://pkg.pr.new/@orpc/client@1178

@orpc/contract

npm i https://pkg.pr.new/@orpc/contract@1178

@orpc/experimental-durable-iterator

npm i https://pkg.pr.new/@orpc/experimental-durable-iterator@1178

@orpc/hey-api

npm i https://pkg.pr.new/@orpc/hey-api@1178

@orpc/interop

npm i https://pkg.pr.new/@orpc/interop@1178

@orpc/json-schema

npm i https://pkg.pr.new/@orpc/json-schema@1178

@orpc/nest

npm i https://pkg.pr.new/@orpc/nest@1178

@orpc/openapi

npm i https://pkg.pr.new/@orpc/openapi@1178

@orpc/openapi-client

npm i https://pkg.pr.new/@orpc/openapi-client@1178

@orpc/otel

npm i https://pkg.pr.new/@orpc/otel@1178

@orpc/experimental-publisher

npm i https://pkg.pr.new/@orpc/experimental-publisher@1178

@orpc/react

npm i https://pkg.pr.new/@orpc/react@1178

@orpc/react-query

npm i https://pkg.pr.new/@orpc/react-query@1178

@orpc/experimental-react-swr

npm i https://pkg.pr.new/@orpc/experimental-react-swr@1178

@orpc/server

npm i https://pkg.pr.new/@orpc/server@1178

@orpc/shared

npm i https://pkg.pr.new/@orpc/shared@1178

@orpc/solid-query

npm i https://pkg.pr.new/@orpc/solid-query@1178

@orpc/standard-server

npm i https://pkg.pr.new/@orpc/standard-server@1178

@orpc/standard-server-aws-lambda

npm i https://pkg.pr.new/@orpc/standard-server-aws-lambda@1178

@orpc/standard-server-fastify

npm i https://pkg.pr.new/@orpc/standard-server-fastify@1178

@orpc/standard-server-fetch

npm i https://pkg.pr.new/@orpc/standard-server-fetch@1178

@orpc/standard-server-node

npm i https://pkg.pr.new/@orpc/standard-server-node@1178

@orpc/standard-server-peer

npm i https://pkg.pr.new/@orpc/standard-server-peer@1178

@orpc/svelte-query

npm i https://pkg.pr.new/@orpc/svelte-query@1178

@orpc/tanstack-query

npm i https://pkg.pr.new/@orpc/tanstack-query@1178

@orpc/trpc

npm i https://pkg.pr.new/@orpc/trpc@1178

@orpc/valibot

npm i https://pkg.pr.new/@orpc/valibot@1178

@orpc/vue-colada

npm i https://pkg.pr.new/@orpc/vue-colada@1178

@orpc/vue-query

npm i https://pkg.pr.new/@orpc/vue-query@1178

@orpc/zod

npm i https://pkg.pr.new/@orpc/zod@1178

commit: d586491

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a valuable feature to expand support for union and intersection object types in parameters for OpenAPI spec generation. The implementation is mostly solid, introducing a new utility function simplifyComposedObjectJsonSchemasAndRefs to flatten complex schemas, along with comprehensive tests. I've identified a critical bug in how required properties are determined when combining allOf and anyOf schemas, and a potential performance improvement in the same function. My feedback includes a fix for the bug, a new test case to prevent regressions, and a suggestion to refactor for better performance.

Comment thread packages/openapi/src/openapi-utils.ts Outdated
Comment thread packages/openapi/src/openapi-utils.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2ab85b9 and 5e17ca2.

📒 Files selected for processing (5)
  • packages/openapi/src/openapi-generator.test.ts (1 hunks)
  • packages/openapi/src/openapi-generator.ts (3 hunks)
  • packages/openapi/src/openapi-utils.test.ts (2 hunks)
  • packages/openapi/src/openapi-utils.ts (2 hunks)
  • packages/openapi/src/schema-utils.test.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
packages/openapi/src/openapi-utils.test.ts (2)
packages/openapi/src/openapi-utils.ts (1)
  • simplifyComposedObjectJsonSchemasAndRefs (186-316)
packages/openapi/src/openapi-generator.ts (3)
  • doc (190-276)
  • doc (278-412)
  • doc (414-539)
packages/openapi/src/openapi-utils.ts (3)
packages/shared/src/array.ts (1)
  • toArray (1-3)
packages/openapi/src/schema-utils.ts (1)
  • isObjectSchema (15-17)
packages/shared/src/json.ts (1)
  • stringifyJSON (9-12)
packages/openapi/src/openapi-generator.ts (2)
packages/openapi/src/openapi-utils.ts (2)
  • simplifyComposedObjectJsonSchemasAndRefs (186-316)
  • toOpenAPIParameters (103-138)
packages/openapi/src/schema-utils.ts (1)
  • isObjectSchema (15-17)
packages/openapi/src/openapi-generator.test.ts (2)
packages/openapi/src/openapi-generator.ts (1)
  • OpenAPIGenerator (91-602)
packages/zod/src/zod4/converter.ts (3)
  • ZodToJsonSchemaConverter (88-631)
  • schema (116-565)
  • schema (567-589)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: lint
  • GitHub Check: publish-commit
  • GitHub Check: test

Comment thread packages/openapi/src/openapi-utils.ts Outdated
dinwwwh and others added 2 commits November 6, 2025 14:56
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5e17ca2 and 34f11f5.

📒 Files selected for processing (1)
  • packages/openapi/src/openapi-utils.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/openapi/src/openapi-utils.ts (4)
packages/openapi/src/schema.ts (2)
  • JSONSchema (5-5)
  • ObjectSchema (10-10)
packages/shared/src/array.ts (1)
  • toArray (1-3)
packages/openapi/src/schema-utils.ts (1)
  • isObjectSchema (15-17)
packages/shared/src/json.ts (1)
  • stringifyJSON (9-12)

Comment thread packages/openapi/src/openapi-utils.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/openapi/src/openapi-utils.ts (1)

238-255: Critical: Handle required keys that lack property definitions in allOf branches.

When an allOf branch declares a key in its required array but doesn't define it in properties (the property schema may live in a different allOf branch), the current loop skips that key entirely. This causes the simplified schema to drop required flags that are still enforced by the intersection, breaking path parameter detection and other required field validations. JSON Schema explicitly allows required without properties.

Based on learnings

Update this block to first process each branch's required array before iterating properties:

  const mergedInteractionPropertyMap: Map<string, { required: boolean, schemas: JSONSchema[] }> = new Map()
  for (const u of objectIntersectionSchemas) {
+    if (Array.isArray(u.required)) {
+      for (const key of u.required) {
+        let entry = mergedInteractionPropertyMap.get(key)
+        if (!entry) {
+          entry = { required: true, schemas: [] }
+          mergedInteractionPropertyMap.set(key, entry)
+        } else {
+          entry.required = true
+        }
+      }
+    }
+
    if (u.properties) {
      for (const [key, value] of Object.entries(u.properties)) {
        let entry = mergedInteractionPropertyMap.get(key)
        if (!entry) {
          entry = { required: false, schemas: [] }
          mergedInteractionPropertyMap.set(key, entry)
+        } else {
+          entry.schemas.push(value)
        }
-
-        entry.schemas.push(value)
+
+        if (u.required?.includes(key)) {
+          entry.required = true
+        }
      }
    }
  }
-  for (const [key, entry] of mergedInteractionPropertyMap) {
-    if (objectIntersectionSchemas.some(s => s.required?.includes(key))) {
-      entry.required = true
-    }
-  }
🧹 Nitpick comments (2)
packages/openapi/src/openapi-utils.ts (2)

181-193: Verify the warning about looseness is accurate.

The warning states the result is "looser than the original schema," but the actual behavior depends on the composition. For intersections (allOf), the simplified schema might be looser since it may not enforce all constraints from each branch. However, for unions (anyOf/oneOf), marking a property as required only when all union branches require it is actually stricter than the original (where the property could be required in just one branch and still satisfy the schema).

Consider clarifying the warning to explain that:

  • Intersection simplification may lose constraint enforcement
  • Union simplification may over-constrain by requiring properties that only need to be present in one branch

209-225: Consider refactoring to improve performance.

The nested loop with objectUnionSchemas.every(...) at line 222 results in O(schemas × properties × schemas) complexity. For schemas with many properties and union members, this could become inefficient.

Refactor to two separate loops as suggested in the past review: first populate the map with all properties, then determine required status in a second pass. This reduces complexity to O(schemas × properties + unique_properties × schemas).

Apply this refactoring:

  const mergedUnionPropertyMap: Map<string, { required: boolean, schemas: JSONSchema[] }> = new Map()
  for (const u of objectUnionSchemas) {
    if (u.properties) {
      for (const [key, value] of Object.entries(u.properties)) {
        let entry = mergedUnionPropertyMap.get(key)
        if (!entry) {
          entry = { required: false, schemas: [] }
          mergedUnionPropertyMap.set(key, entry)
        }
        entry.schemas.push(value)
      }
    }
  }
+
  for (const [key, entry] of mergedUnionPropertyMap) {
    if (objectUnionSchemas.every(s => s.required?.includes(key))) {
      entry.required = true
    }
  }
-  for (const [key, entry] of mergedUnionPropertyMap) {
-    if (objectUnionSchemas.every(s => s.required?.includes(key))) {
-      entry.required = true
-    }
-  }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 34f11f5 and adce0d4.

📒 Files selected for processing (2)
  • packages/openapi/src/openapi-generator.ts (8 hunks)
  • packages/openapi/src/openapi-utils.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/openapi/src/openapi-utils.ts (5)
packages/openapi/src/schema.ts (2)
  • JSONSchema (5-5)
  • ObjectSchema (10-10)
packages/openapi/src/openapi-generator.ts (3)
  • doc (190-276)
  • doc (278-412)
  • doc (414-541)
packages/shared/src/array.ts (1)
  • toArray (1-3)
packages/openapi/src/schema-utils.ts (1)
  • isObjectSchema (15-17)
packages/shared/src/json.ts (1)
  • stringifyJSON (9-12)
packages/openapi/src/openapi-generator.ts (2)
packages/openapi/src/openapi-utils.ts (4)
  • simplifyComposedObjectJsonSchemasAndRefs (186-317)
  • toOpenAPIParameters (103-138)
  • resolveOpenAPIJsonSchemaRef (171-179)
  • toOpenAPIContent (25-51)
packages/openapi/src/schema-utils.ts (2)
  • isObjectSchema (15-17)
  • applySchemaOptionality (135-146)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: publish-commit
  • GitHub Check: test
  • GitHub Check: lint
🔇 Additional comments (5)
packages/openapi/src/openapi-utils.ts (1)

311-313: LGTM: Required flag logic is correct.

The use of || correctly ensures a property is marked as required if either the union side or the intersection side declares it required. This properly handles cases where allOf enforces a requirement that anyOf/oneOf does not.

packages/openapi/src/openapi-generator.ts (4)

314-316: LGTM: Schema preprocessing logic is correct.

The conditional preprocessing appropriately applies schema simplification when:

  • Input structure is detailed (needs to extract params/query/headers/body)
  • Input structure is compact with dynamic path parameters (needs to extract and validate params)
  • Input structure is compact with GET method (needs to extract query parameters)

This ensures composed schemas (anyOf/oneOf/allOf) are flattened before parameter extraction, which directly addresses the issue described in #1162.


370-372: LGTM: Params schema simplification is correctly applied.

The simplification of the params schema before validation ensures that composed schemas (e.g., FooSchema.and(PlanetIdInputSchema)) are properly flattened so dynamic path parameters can be detected in their required array.


386-403: LGTM: Consistent simplification across parameter sources.

The loop correctly applies simplification to params, query, and headers schemas before validating they are object schemas and converting them to OpenAPI parameters. This ensures all parameter sources benefit from the composition-flattening logic.


473-540: LGTM: Success response handling correctly uses simplified schemas.

The detailed output structure handling properly:

  • Simplifies each union item before processing (line 473)
  • Uses the simplified schema for all property accesses and checks
  • Applies nested simplification to the headers schema (line 516)
  • Correctly references simplifiedItem for required checks (lines 529, 537)

This ensures composed response schemas are properly handled when extracting status, headers, and body.

@dinwwwh dinwwwh changed the title feat(openapi): expand support for unions/intersection of objects in parameters when generating OpenAPI specs feat(openapi): expand support for unions/intersection of objects when generating OpenAPI specs Nov 7, 2025
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2d785de and 3dcc5a5.

📒 Files selected for processing (2)
  • packages/openapi/src/openapi-utils.test.ts (2 hunks)
  • packages/openapi/src/openapi-utils.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/openapi/src/openapi-utils.test.ts (2)
packages/openapi/src/openapi-utils.ts (1)
  • simplifyComposedObjectJsonSchemasAndRefs (186-328)
packages/openapi/src/openapi-generator.ts (3)
  • doc (190-276)
  • doc (278-412)
  • doc (414-541)
packages/openapi/src/openapi-utils.ts (4)
packages/openapi/src/schema.ts (2)
  • JSONSchema (5-5)
  • ObjectSchema (10-10)
packages/shared/src/array.ts (1)
  • toArray (1-3)
packages/openapi/src/schema-utils.ts (1)
  • isObjectSchema (15-17)
packages/shared/src/json.ts (1)
  • stringifyJSON (9-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: lint
  • GitHub Check: publish-commit
  • GitHub Check: test

Comment thread packages/openapi/src/openapi-utils.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/openapi/src/openapi-utils.ts (1)

208-222: Consider optimizing the required-field computation.

The objectUnionSchemas.every(...) call on line 214 executes inside a nested loop for each property, resulting in O(schemas × properties × schemas) time complexity. For schemas with many union branches and properties, this could impact performance.

You could refactor to compute the required status for all properties in a separate pass:

  const mergedUnionPropertyMap: Map<string, { required: boolean, schemas: JSONSchema[] }> = new Map()
  for (const u of objectUnionSchemas) {
    if (u.properties) {
      for (const [key, value] of Object.entries(u.properties)) {
        let entry = mergedUnionPropertyMap.get(key)
        if (!entry) {
-         const required = objectUnionSchemas.every(s => s.required?.includes(key))
-
-         entry = { required, schemas: [] }
+         entry = { required: false, schemas: [] }
          mergedUnionPropertyMap.set(key, entry)
        }
        entry.schemas.push(value)
      }
    }
  }
+
+ for (const [key, entry] of mergedUnionPropertyMap.entries()) {
+   entry.required = objectUnionSchemas.every(s => s.required?.includes(key))
+ }

This changes the complexity to O(schemas × properties + unique_properties × schemas), which is more efficient for complex schemas.

Based on past review comments.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3dcc5a5 and d586491.

📒 Files selected for processing (2)
  • packages/openapi/src/openapi-utils.test.ts (2 hunks)
  • packages/openapi/src/openapi-utils.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/openapi/src/openapi-utils.test.ts (2)
packages/openapi/src/openapi-utils.ts (1)
  • simplifyComposedObjectJsonSchemasAndRefs (186-316)
packages/openapi/src/openapi-generator.ts (3)
  • doc (190-276)
  • doc (278-412)
  • doc (414-541)
packages/openapi/src/openapi-utils.ts (4)
packages/openapi/src/openapi-generator.ts (3)
  • doc (190-276)
  • doc (278-412)
  • doc (414-541)
packages/shared/src/array.ts (1)
  • toArray (1-3)
packages/openapi/src/schema-utils.ts (1)
  • isObjectSchema (15-17)
packages/shared/src/json.ts (1)
  • stringifyJSON (9-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: publish-commit
  • GitHub Check: lint
  • GitHub Check: test
🔇 Additional comments (5)
packages/openapi/src/openapi-utils.ts (5)

186-193: LGTM!

The entry point correctly resolves references when a document is provided and efficiently short-circuits when the schema doesn't need simplification.


224-237: LGTM!

Correctly processes allOf schemas recursively and appropriately treats the base schema as part of the intersection when it's an object alongside composition keywords.


256-263: LGTM!

Clean initialization of the result schema with appropriate early return when no properties are found.


265-276: LGTM!

Straightforward deduplication using JSON stringification for schema equality checks.


278-313: LGTM!

The property schema merging logic correctly combines union and intersection entries, using anyOf for union alternatives and allOf for intersection constraints. The required-field logic on line 310 correctly uses || to mark a property as required if either composition type requires it.

Comment thread packages/openapi/src/openapi-utils.test.ts
Comment thread packages/openapi/src/openapi-utils.ts
@dinwwwh dinwwwh added the lgtm This PR has been approved by a maintainer label Nov 7, 2025
@dinwwwh dinwwwh merged commit 6424b57 into main Nov 9, 2025
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm This PR has been approved by a maintainer size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OpenAPI schema generator doen't handle Zod object without shape on dynamic params

2 participants