Skip to content

Wrap $ref with sibling properties in allOf during OpenAPI spec bundling#179

Open
kbatuigas wants to merge 2 commits intomainfrom
kb/bundle-openapi-allof-ref-siblings
Open

Wrap $ref with sibling properties in allOf during OpenAPI spec bundling#179
kbatuigas wants to merge 2 commits intomainfrom
kb/bundle-openapi-allof-ref-siblings

Conversation

@kbatuigas
Copy link
Copy Markdown

@kbatuigas kbatuigas commented Mar 27, 2026

Related: redpanda-data/api-docs#60

In OpenAPI 3.0, properties placed alongside $ref (like description and readOnly) are silently ignored. This causes our rendered API docs on Bump.sh to show the referenced schema's description instead of the more specific inline description.

This PR adds a post-processing step to bundle-openapi that wraps $ref nodes having sibling properties in allOf:

# Before                          # After
passwordSetAt:                    passwordSetAt:
  $ref: "...Timestamp"              allOf:
  description: "The timestamp…"        - $ref: "...Timestamp"
  readOnly: true                    description: "The timestamp…"
                                    readOnly: true

This is the standard workaround for OpenAPI 3.0 and has been confirmed as the correct approach by Bump.sh's developer team. The transformation is done during bundling and no changes are needed to source specs.

kbatuigas and others added 2 commits March 18, 2026 20:38
Renderers like Bump.sh ignore sibling properties (description, readOnly,
title) next to $ref and instead display the generic schema description.
Add a wrapRefSiblings() post-processing step that transforms
{ $ref, description, ... } into { allOf: [{ $ref }], description, ... },
which is valid OpenAPI 3.1 and the standard pattern used by
protoc-gen-openapiv2.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@netlify
Copy link
Copy Markdown

netlify bot commented Mar 27, 2026

Deploy Preview for docs-extensions-and-macros ready!

Name Link
🔨 Latest commit 76616c1
🔍 Latest deploy log https://app.netlify.com/projects/docs-extensions-and-macros/deploys/69c5d5a14076a40008c59240
😎 Deploy Preview https://deploy-preview-179--docs-extensions-and-macros.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 27, 2026

📝 Walkthrough

Walkthrough

The changes introduce a new wrapRefSiblings utility function to the OpenAPI bundler that transforms schema objects containing a $ref property alongside sibling keywords. When such objects are encountered during a recursive tree walk, the function replaces the $ref with an allOf wrapper containing the reference, while preserving all sibling properties. The function is integrated into the post-processing pipeline and is accompanied by comprehensive test coverage including edge cases for nested structures and existing allOf patterns.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: wrapping $ref with sibling properties in allOf during OpenAPI bundling.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description check ✅ Passed The pull request description clearly explains the problem, solution, and rationale related to the changeset modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch kb/bundle-openapi-allof-ref-siblings

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

Copy link
Copy Markdown
Contributor

@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.

🧹 Nitpick comments (2)
__tests__/tools/bundle-openapi.test.js (1)

551-554: Misleading comment—this schema is not a "lone $ref".

The google.protobuf.Timestamp schema is defined as {type: object, description: ...}, which has no $ref at all. The comment "Lone $ref should NOT be wrapped" doesn't match what's being tested. Consider clarifying:

📝 Suggested comment fix
-        // Lone $ref should NOT be wrapped
+        // Regular schema definitions (no $ref) should remain unchanged
         const timestamp = result.components.schemas['google.protobuf.Timestamp'];
         expect(timestamp['$ref']).toBeUndefined();
         expect(timestamp.allOf).toBeUndefined();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@__tests__/tools/bundle-openapi.test.js` around lines 551 - 554, The test
comment is misleading: the schema under
result.components.schemas['google.protobuf.Timestamp'] is not a "lone $ref" but
an explicit object (type: object, description: ...); update the comment above
the assertions for the timestamp variable to accurately describe that this
schema has no $ref and should not contain allOf (e.g., "Schema defined inline
should not contain $ref or allOf"), keeping the assertions on timestamp['$ref']
and timestamp.allOf as-is; reference the timestamp variable and
result.components.schemas['google.protobuf.Timestamp'] when editing the comment.
tools/bundle-openapi.js (1)

251-262: JSDoc incorrectly states "OpenAPI 3.1 renderers"—this behavior applies to OpenAPI 3.0.

The comment says "OpenAPI 3.1 renderers (e.g. Bump.sh) ignore sibling properties next to $ref", but this is backwards. OpenAPI 3.1 (aligned with JSON Schema) actually does support sibling properties alongside $ref. The issue exists in OpenAPI 3.0, where siblings next to $ref are ignored per spec. The PR description correctly identifies this as an OpenAPI 3.0 issue.

📝 Suggested docstring fix
 /**
  * Wrap $ref siblings into allOf to preserve field-level descriptions.
  *
- * OpenAPI 3.1 renderers (e.g. Bump.sh) ignore sibling properties next to $ref
- * and instead display the generic description from the referenced schema.
+ * In OpenAPI 3.0, sibling properties next to $ref are ignored per spec.
+ * Some renderers (e.g. Bump.sh) follow this behavior, displaying the generic
+ * description from the referenced schema instead of field-level overrides.
  * This function transforms { $ref, description, ... } into
  * { allOf: [{ $ref }], description, ... } so renderers pick up field-level
  * descriptions correctly.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/bundle-openapi.js` around lines 251 - 262, Update the JSDoc above the
function that wraps $ref siblings into allOf to correctly state that the
behavior applies to OpenAPI 3.0 (not 3.1); change the phrase "OpenAPI 3.1
renderers (e.g. Bump.sh) ignore sibling properties next to $ref" to reference
OpenAPI 3.0 and optionally add a brief note that OpenAPI 3.1 aligns with JSON
Schema and allows siblings, so the transform targets 3.0 renderers that ignore
them. Keep the rest of the description about the transformation ({ $ref,
description, ... } → { allOf: [{ $ref }], description, ... }) unchanged and
preserve parameter/return tags.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@__tests__/tools/bundle-openapi.test.js`:
- Around line 551-554: The test comment is misleading: the schema under
result.components.schemas['google.protobuf.Timestamp'] is not a "lone $ref" but
an explicit object (type: object, description: ...); update the comment above
the assertions for the timestamp variable to accurately describe that this
schema has no $ref and should not contain allOf (e.g., "Schema defined inline
should not contain $ref or allOf"), keeping the assertions on timestamp['$ref']
and timestamp.allOf as-is; reference the timestamp variable and
result.components.schemas['google.protobuf.Timestamp'] when editing the comment.

In `@tools/bundle-openapi.js`:
- Around line 251-262: Update the JSDoc above the function that wraps $ref
siblings into allOf to correctly state that the behavior applies to OpenAPI 3.0
(not 3.1); change the phrase "OpenAPI 3.1 renderers (e.g. Bump.sh) ignore
sibling properties next to $ref" to reference OpenAPI 3.0 and optionally add a
brief note that OpenAPI 3.1 aligns with JSON Schema and allows siblings, so the
transform targets 3.0 renderers that ignore them. Keep the rest of the
description about the transformation ({ $ref, description, ... } → { allOf: [{
$ref }], description, ... }) unchanged and preserve parameter/return tags.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f824e03a-49d3-4e97-9ed4-03cbfbaa2a31

📥 Commits

Reviewing files that changed from the base of the PR and between 8484c74 and 76616c1.

📒 Files selected for processing (3)
  • .gitignore
  • __tests__/tools/bundle-openapi.test.js
  • tools/bundle-openapi.js

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