From a7a125267be5d1c5e86cd2ee02c69b8613ff9afe Mon Sep 17 00:00:00 2001 From: Vladyslav Makarenko Date: Mon, 19 Oct 2026 16:05:34 +0200 Subject: [PATCH 1/2] fix(realm): ref sibling --- .changeset/ref-sibling-regression.md | 5 +++ src/allOf.js | 3 +- src/traverse.js | 4 ++- test/integration.spec.js | 48 ++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 .changeset/ref-sibling-regression.md diff --git a/.changeset/ref-sibling-regression.md b/.changeset/ref-sibling-regression.md new file mode 100644 index 0000000..f0cee48 --- /dev/null +++ b/.changeset/ref-sibling-regression.md @@ -0,0 +1,5 @@ +--- +"openapi-sampler": patch +--- + +Fixed a regression where a `$ref` inside `allOf` was sampled as `null`, and a `readOnly` or `writeOnly` `$ref` inside `oneOf` or `anyOf` was no longer skipped by `skipReadOnly` or `skipWriteOnly`. diff --git a/src/allOf.js b/src/allOf.js index f7d69da..a4d3d31 100644 --- a/src/allOf.js +++ b/src/allOf.js @@ -7,7 +7,8 @@ export function allOfSample(into, children, options, spec, context) { const subSamples = []; for (let subSchema of children) { - const { type, readOnly, writeOnly, value } = traverse({ type: res.type, ...subSchema }, options, spec, { + const childSchema = subSchema.$ref ? subSchema : { type: res.type, ...subSchema }; + const { type, readOnly, writeOnly, value } = traverse(childSchema, options, spec, { ...context, isAllOfChild: true, }); diff --git a/src/traverse.js b/src/traverse.js index b2632d1..fa4c73b 100644 --- a/src/traverse.js +++ b/src/traverse.js @@ -78,7 +78,9 @@ export function traverse(schema, options, spec, context) { ref = ref.substring(1); } - const { $ref: _, ...siblings } = schema; + const siblings = Object.fromEntries( + Object.entries(schema).filter(([key, value]) => key !== '$ref' && value !== undefined), + ); const referenced = Object.keys(siblings).length && !shouldIgnoreRefSiblings(spec) ? mergeRefSiblings(JsonPointer.get(spec, ref), siblings) : JsonPointer.get(spec, ref); diff --git a/test/integration.spec.js b/test/integration.spec.js index 4ee1a01..4e662a5 100644 --- a/test/integration.spec.js +++ b/test/integration.spec.js @@ -939,6 +939,54 @@ describe('Integration', () => { expect(spec.components.schemas.Num).toEqual({ type: 'number' }); } }); + + it('should apply a null sibling written in the document', () => { + result = sample({ $ref: '#/components/schemas/Num', default: null }, {}, refSiblingsSpec({ openapi: '3.1.0' })); + expect(result).toBeNull(); + }); + + it('should not apply the type that allOf passes to its items to a $ref', () => { + for (const spec of [refSiblingsSpec({ openapi: '3.1.0' }), refSiblingsSpec({})]) { + result = sample({ allOf: [{ $ref: '#/components/schemas/Pet' }] }, {}, spec); + expect(result).toEqual({ name: 'string' }); + + result = sample({ + allOf: [ + { $ref: '#/components/schemas/Pet' }, + { properties: { age: { type: 'integer' } } }, + ] + }, {}, spec); + expect(result).toEqual({ name: 'string', age: 0 }); + } + }); + + it('should keep readOnly and writeOnly of a $ref in oneOf and anyOf', () => { + for (const version of [{ openapi: '3.1.0' }, {}]) { + const spec = { + ...version, + components: { + schemas: { + Id: { type: 'string', readOnly: true }, + Password: { type: 'string', writeOnly: true }, + }, + }, + }; + const schema = { + type: 'object', + properties: { + id: { oneOf: [{ $ref: '#/components/schemas/Id' }] }, + password: { anyOf: [{ $ref: '#/components/schemas/Password' }] }, + name: { type: 'string' }, + }, + }; + + result = sample(schema, { skipReadOnly: true }, spec); + expect(result).toEqual({ password: 'string', name: 'string' }); + + result = sample(schema, { skipWriteOnly: true }, spec); + expect(result).toEqual({ id: 'string', name: 'string' }); + } + }); }); }); From fd96e08d8113ef5b7b8f235be85e9efdcdd7c55c Mon Sep 17 00:00:00 2001 From: Vladyslav Makarenko Date: Mon, 19 Oct 2026 17:45:35 +0300 Subject: [PATCH 2/2] Update .changeset/ref-sibling-regression.md Co-authored-by: Alex Varchuk --- .changeset/ref-sibling-regression.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/ref-sibling-regression.md b/.changeset/ref-sibling-regression.md index f0cee48..1ef5ad6 100644 --- a/.changeset/ref-sibling-regression.md +++ b/.changeset/ref-sibling-regression.md @@ -2,4 +2,4 @@ "openapi-sampler": patch --- -Fixed a regression where a `$ref` inside `allOf` was sampled as `null`, and a `readOnly` or `writeOnly` `$ref` inside `oneOf` or `anyOf` was no longer skipped by `skipReadOnly` or `skipWriteOnly`. +Fixed a regression from 1.7.7: a `$ref` inside `allOf` was sampled as `null`, and `skipReadOnly`/`skipWriteOnly` ignored a `$ref` inside `oneOf` or `anyOf`.