fix(cli): fix join dropping non-string x-* path extension properties#2949
fix(cli): fix join dropping non-string x-* path extension properties#2949nonchan7720 wants to merge 10 commits into
Conversation
🦋 Changeset detectedLatest commit: b593d94 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
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 |
Clarified the fix for join extension property to specify that it addresses non-string x-* path extension properties.
Performance Benchmark (Lower is Faster)
|
| .mockImplementationOnce(() => | ||
| Promise.resolve({ | ||
| source: { absoluteRef: 'ref-b' }, | ||
| parsed: anotherPathWithDifferentObjectExtension, |
There was a problem hiding this comment.
What if the object had different keys though? Like a.yaml has owner and b.yaml has team?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
@nonchan7720 Please add a test for this case { owner: 'team-a' } and { team: 'x' }.
kanoru3101
left a comment
There was a problem hiding this comment.
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.
| .mockImplementationOnce(() => | ||
| Promise.resolve({ | ||
| source: { absoluteRef: 'ref-b' }, | ||
| parsed: anotherPathWithDifferentObjectExtension, |
There was a problem hiding this comment.
@nonchan7720 Please add a test for this case { owner: 'team-a' } and { team: 'x' }.
Co-authored-by: Viktor Sydor <31951646+kanoru3101@users.noreply.github.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ 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.
RomanHotsiy
left a comment
There was a problem hiding this comment.
LGTM, left one simplification comment
| if (typeof pathItem[field] === 'string') { | ||
| if ( | ||
| typeof pathItem[field] === 'string' || | ||
| (field.startsWith('x-') && typeof pathItem[field] !== 'string') |
There was a problem hiding this comment.
| (field.startsWith('x-') && typeof pathItem[field] !== 'string') | |
| (field.startsWith('x-')) |
Co-authored-by: Viktor Sydor <31951646+kanoru3101@users.noreply.github.com>

What/Why/How?
Fixes
joinsilently dropping non-stringx-*extension properties defined directly under a path item (e.g.paths./pets/{petId}.x-foo: true).collectPathsonly merged path-level extensions when their value was a string, viacollectPathStringFields. Non-string values(booleans, objects, arrays, numbers) were never copied into the joined document.
collectPathExtensionnow handles every non-stringx-*field on a path item: it copies the value into the joined path the firsttime 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 extensionstest group tojoin.test.tswith fixtures indocuments.tscovering:x-*path extension when both source documents agree on the valueVerified against the pre-fix implementation that both new tests fail without this change.
Screenshots (optional)
N/A — CLI behavior change only.
Check yourself
guide
packages/clionlynpx changesetbefore merging (@redocly/cli, patch)Security
input surface
Note
Low Risk
Scoped CLI join merge logic with tests; no auth, security, or new external input surfaces.
Overview
Fixes
joinsilently omitting path-itemx-*extensions when values are not strings (objects, booleans, arrays, etc.).collect-pathsnow routes everyx-*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 withdequalinstead of!==, so object extensions warn when values differ and are kept when they match.Adds
path extensionstests and fixtures for matchingx-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.