Skip to content

fix(cli): fix join dropping non-string x-* path extension properties#2949

Open
nonchan7720 wants to merge 10 commits into
Redocly:mainfrom
nonchan7720:fix_issue_1574
Open

fix(cli): fix join dropping non-string x-* path extension properties#2949
nonchan7720 wants to merge 10 commits into
Redocly:mainfrom
nonchan7720:fix_issue_1574

Conversation

@nonchan7720

@nonchan7720 nonchan7720 commented Jul 13, 2026

Copy link
Copy Markdown

What/Why/How?

Fixes join silently dropping non-string x-* extension properties defined directly under a path item (e.g.
paths./pets/{petId}.x-foo: true).

collectPaths only merged path-level extensions when their value was a string, via collectPathStringFields. Non-string values
(booleans, objects, arrays, numbers) were never copied into the joined document.

collectPathExtension now handles every non-string x-* field on a path item: it copies the value into the joined path the first
time it's seen, and logs a warning instead of silently overwriting when two source documents provide different values for the same
field.

Reference

Fixes #1574

Testing

Added a path extensions test group to join.test.ts with fixtures in documents.ts covering:

  • merging a non-string x-* path extension when both source documents agree on the value
  • logging a warning when the values conflict

Verified against the pre-fix implementation that both new tests fail without this change.

Screenshots (optional)

N/A — CLI behavior change only.

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) — N/A, packages/cli only
  • New package installed? - Tested in different environments (browser/node) — N/A
  • Documentation update has been considered — no doc change needed, this restores documented merge behavior
  • Changeset added — still missing, run npx changeset before merging (@redocly/cli, patch)

Security

  • The security impact of the change has been considered — object merge over already-parsed/trusted document data, no new external
    input surface
  • Code follows company security practices and guidelines

Note

Low Risk
Scoped CLI join merge logic with tests; no auth, security, or new external input surfaces.

Overview
Fixes join silently omitting path-item x-* extensions when values are not strings (objects, booleans, arrays, etc.).

collect-paths now routes every x-* field on a path item through the same merge path as string fields (e.g. summary), instead of only copying fields whose value is a string. Conflicts between APIs are detected with dequal instead of !==, so object extensions warn when values differ and are kept when they match.

Adds path extensions tests and fixtures for matching x-metadata, conflicting values, and differing object shapes, plus a patch changeset for @redocly/cli.

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

@changeset-bot

changeset-bot Bot commented Jul 13, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b593d94

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

This PR includes changesets to release 3 packages
Name Type
@redocly/cli Patch
@redocly/openapi-core 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

@nonchan7720 nonchan7720 changed the title fix: join extension property fix: Fix join dropping non-string x-* path extension properties. Jul 13, 2026
Clarified the fix for join extension property to specify that it addresses non-string x-* path extension properties.
@nonchan7720
nonchan7720 marked this pull request as ready for review July 13, 2026 17:16
@nonchan7720
nonchan7720 requested review from a team as code owners July 13, 2026 17:16
@nonchan7720 nonchan7720 changed the title fix: Fix join dropping non-string x-* path extension properties. fix(cli): Fix join dropping non-string x-* path extension properties. Jul 13, 2026
@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Performance Benchmark (Lower is Faster)

CLI Version Bundle Lint Check Config
cli-latest ▓ 1.01x ± 0.02 ▓ 1.00x ± 0 ▓ 1.00x (Fastest)
cli-next ▓ 1.00x (Fastest) ▓ 1.00x (Fastest) ▓ 1.01x ± 0.01

@nonchan7720 nonchan7720 changed the title fix(cli): Fix join dropping non-string x-* path extension properties. fix(cli): fix join dropping non-string x-* path extension properties. Jul 14, 2026
@nonchan7720 nonchan7720 changed the title fix(cli): fix join dropping non-string x-* path extension properties. fix(cli): fix join dropping non-string x-* path extension properties Jul 14, 2026
.mockImplementationOnce(() =>
Promise.resolve({
source: { absoluteRef: 'ref-b' },
parsed: anotherPathWithDifferentObjectExtension,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What if the object had different keys though? Like a.yaml has owner and b.yaml has team?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

A warning log is being output.
I think we'll just have to handle this the same way we do other standard items.

If this part overlaps, it means the paths also overlap.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@nonchan7720 Please add a test for this case { owner: 'team-a' } and { team: 'x' }.

@kanoru3101 kanoru3101 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the contribution. Checked it out locally — works as expected, non-string x-* path extensions now merge the same way as regular path-level fields (first one wins, warning on conflict).

Left a few comments.

Comment thread packages/cli/src/__tests__/commands/join.test.ts
Comment thread packages/cli/src/commands/join/utils/collect-paths.ts Outdated
.mockImplementationOnce(() =>
Promise.resolve({
source: { absoluteRef: 'ref-b' },
parsed: anotherPathWithDifferentObjectExtension,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@nonchan7720 Please add a test for this case { owner: 'team-a' } and { team: 'x' }.

Comment thread .changeset/dull-adults-punch.md Outdated
Co-authored-by: Viktor Sydor <31951646+kanoru3101@users.noreply.github.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

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 using default effort 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.

Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 310638c. Configure here.

Comment thread packages/cli/src/commands/join/utils/collect-paths.ts Outdated

@RomanHotsiy RomanHotsiy left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, left one simplification comment

if (typeof pathItem[field] === 'string') {
if (
typeof pathItem[field] === 'string' ||
(field.startsWith('x-') && typeof pathItem[field] !== 'string')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
(field.startsWith('x-') && typeof pathItem[field] !== 'string')
(field.startsWith('x-'))

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

fixed.
5b7a1cc

@kanoru3101 kanoru3101 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

Comment thread .changeset/dull-adults-punch.md Outdated
Co-authored-by: Viktor Sydor <31951646+kanoru3101@users.noreply.github.com>
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.

"join" remove extension properties under path property

4 participants