Skip to content

fix: resolve $ref siblings during bundling#2772

Draft
vadyvas wants to merge 6 commits into
mainfrom
fix/bundle-ref-siblings-resolution
Draft

fix: resolve $ref siblings during bundling#2772
vadyvas wants to merge 6 commits into
mainfrom
fix/bundle-ref-siblings-resolution

Conversation

@vadyvas
Copy link
Copy Markdown
Contributor

@vadyvas vadyvas commented Apr 24, 2026

What/Why/How?

Fixed bundling for $ref siblings so sibling properties are resolved reliably, including nested external refs and non-Schema sibling contexts.

  • Updated traversal logic in walk to process sibling properties next to $ref correctly.

Important

Bundling now resolves all sibling properties next to $ref, regardless of whether the node is interpreted as a Reference Object or a Schema Object.

This is important because OpenAPI 3.1 distinguishes these cases in the spec:

“This object cannot be extended with additional properties and any properties added SHALL be ignored.
Note that this restriction on additional properties is a difference between Reference Objects and Schema Objects that contain a $ref keyword.”

Reference

OpenAPI 3.1 — Reference Object

Testing

Screenshots (optional)

paths:
  /sample:
    get:
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Base'
                properties: # <-- should be processed as sibling content during bundle
                  second:
                    $ref: ./reference.yaml#/Second # <-- should be resolved
                additionalProperties:
                  $ref: ./reference.yaml#/Meta # <-- should be resolved
      requestBody:
        $ref: '#/components/requestBodies/SampleBody'
        description:
          $ref: ./reference.yaml#/title # <-- should be resolved (non-Schema sibling context)

Check yourself

  • This PR follows the contributing guide
  • All new/updated code is covered by tests
  • Core code changed? - Tested with other Redocly products (internal contributions only)
  • New package installed? - Tested in different environments (browser/node)
  • Documentation update has been considered

Security

  • The security impact of the change has been considered
  • Code follows company security practices and guidelines

Note

Medium Risk
Touches core walk traversal/ref-resolution logic used by bundling, which could subtly affect how referenced nodes are visited and resolved across specs. Risk is mitigated by added unit and e2e coverage for nested/external $ref sibling cases.

Overview
Fixes bundling so sibling keys next to a $ref are traversed and resolved reliably, including when the parent node is treated as a Reference Object and when sibling values contain nested external refs.

This introduces refHasSibling to precisely detect sibling presence and updates walk to visit sibling properties on $ref nodes based on that check while preserving wrapper fields (e.g., readOnly, description). Adds new unit fixtures/tests and an e2e ref-siblings scenario (bundled and --dereferenced) to lock in the expected output.

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

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 24, 2026

🦋 Changeset detected

Latest commit: 3fee16d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@redocly/openapi-core Patch
@redocly/cli Patch
@redocly/respect-core Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vadyvas vadyvas force-pushed the fix/bundle-ref-siblings-resolution branch from 2f635d9 to 60ef033 Compare April 24, 2026 09:12
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 24, 2026

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 80.69% (🎯 80%) 7197 / 8919
🔵 Statements 80.07% (🎯 79%) 7476 / 9336
🔵 Functions 83.69% (🎯 83%) 1437 / 1717
🔵 Branches 72.37% (🎯 71%) 4888 / 6754
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/core/src/ref-utils.ts 95.12% 97.82% 100% 97.36% 11, 62
packages/core/src/walk.ts 98.18% 97.22% 84.21% 98.69% 186, 201, 422
Generated in workflow #9787 for commit 3fee16d by the Vitest Coverage Report Action

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 24, 2026

CLI Version Mean Time ± Std Dev (s) Relative Performance (Lower is Faster)
cli-latest 2.057s ± 0.020s ▓ 1.00x
cli-next 2.050s ± 0.032s ▓ 1.00x (Fastest)

@vadyvas vadyvas self-assigned this Apr 24, 2026
@vadyvas
Copy link
Copy Markdown
Contributor Author

vadyvas commented Apr 24, 2026

@cursor review

Comment thread tests/e2e/bundle/bundle.test.ts
@vadyvas vadyvas added the snapshot Create experimental release PR label Apr 28, 2026
@github-actions
Copy link
Copy Markdown
Contributor

📦 A new experimental 🧪 version v0.0.0-snapshot.1777378978 of Redocly CLI has been published for testing.

Install with NPM:

npm install @redocly/cli@0.0.0-snapshot.1777378978
# or
npm install @redocly/openapi-core@0.0.0-snapshot.1777378978
# or
npm install @redocly/respect-core@0.0.0-snapshot.1777378978

⚠️ Note: This is a development build and may contain unstable features.

@vadyvas vadyvas force-pushed the fix/bundle-ref-siblings-resolution branch from 81fe95d to 03fdf9a Compare May 4, 2026 18:12
@vadyvas vadyvas marked this pull request as ready for review May 4, 2026 18:20
@vadyvas vadyvas requested review from a team as code owners May 4, 2026 18:20
@vadyvas vadyvas force-pushed the fix/bundle-ref-siblings-resolution branch from 2051968 to b8066fb Compare May 12, 2026 10:11
Comment thread packages/core/src/walk.ts
Comment thread packages/core/src/walk.ts
}

if (isRef(node[propName]) && propType?.name === 'scalar') {
if (!isNamedType(propType)) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

to avoid duplication in the two checks below

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 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 3fee16d. Configure here.

Comment thread packages/core/src/walk.ts
continue;
}

if (!isNamedType(propType) || (propType.name === 'scalar' && !isRef(value))) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sibling walked with propType derived from resolved value

Medium Severity

When a property exists in both the resolved $ref target and as a sibling, value is set to resolvedNode[propName] (line 326) and propType is computed from that resolved value (line 337). But when the sibling check at line 360 fires, node[propName] (the sibling) is walked with this propType. For function-based type resolvers like additionalProperties (returns { type: 'boolean' } for false vs 'Schema' for objects) or items (returns listOf('Schema') for arrays vs 'Schema' for objects), the sibling value can end up walked with the wrong type. This is visible in the E2E snapshot where additionalProperties: {$ref: reference.yaml} is inlined while identical refs at second and third.items are bundled as component references — an inconsistency caused by the sibling being walked as scalar instead of Schema.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3fee16d. Configure here.

@vadyvas vadyvas requested a review from tatomyr May 12, 2026 14:45
@vadyvas vadyvas marked this pull request as draft May 12, 2026 15:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

snapshot Create experimental release PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bundle does not resolve references in $ref siblings

3 participants