@@ -248,31 +248,24 @@ const parseObject = ({
248
248
irSchema . properties = schemaProperties ;
249
249
}
250
250
251
- // --- PATCH: Avoid [key: string]: never for empty objects in allOf ---
252
- // If this object is empty (no properties, no required, no patternProperties, no min/maxProperties)
253
- // and additionalProperties is false, and we are inside an allOf composition,
254
- // then do NOT emit additionalProperties: { type: 'never' }.
255
- // Instead, let the composition enforce the restriction.
256
- const isEmptyObject =
257
- ( ! schema . properties || Object . keys ( schema . properties ) . length === 0 ) &&
258
- ( ! schema . required || schema . required . length === 0 ) &&
259
- schema . minProperties === undefined &&
260
- schema . maxProperties === undefined ;
261
-
262
- // Heuristic: if state has a marker for "inAllOf", skip [key: string]: never for empty objects
263
- const inAllOf = ( state as any ) ?. inAllOf ;
264
-
265
251
if ( schema . additionalProperties === undefined ) {
266
252
if ( ! irSchema . properties ) {
267
253
irSchema . additionalProperties = {
268
254
type : 'unknown' ,
269
255
} ;
270
256
}
271
257
} else if ( typeof schema . additionalProperties === 'boolean' ) {
272
- if ( schema . additionalProperties === false && isEmptyObject && inAllOf ) {
273
- // Do not emit [key: string]: never for empty object in allOf
274
- // Just skip setting additionalProperties
275
- } else {
258
+ // Avoid [key: string]: never for empty objects with additionalProperties: false inside allOf
259
+ // This would override inherited properties from other schemas in the composition
260
+ const isEmptyObjectInAllOf =
261
+ state . inAllOf &&
262
+ schema . additionalProperties === false &&
263
+ ( ! schema . properties || Object . keys ( schema . properties ) . length === 0 ) &&
264
+ ! schema . allOf &&
265
+ ! schema . anyOf &&
266
+ ! schema . oneOf ;
267
+
268
+ if ( ! isEmptyObjectInAllOf ) {
276
269
irSchema . additionalProperties = {
277
270
type : schema . additionalProperties ? 'unknown' : 'never' ,
278
271
} ;
@@ -338,26 +331,20 @@ const parseAllOf = ({
338
331
const compositionSchemas = schema . allOf ;
339
332
340
333
for ( const compositionSchema of compositionSchemas ) {
341
- // Mark that we are inside an allOf for parseObject
342
- // Only pass inAllOf directly to the schema in allOf if it is NOT a $ref.
343
- let irCompositionSchema ;
344
- if (
345
- compositionSchema &&
346
- typeof compositionSchema === 'object' &&
347
- ! ( '$ref' in compositionSchema )
348
- ) {
349
- irCompositionSchema = schemaToIrSchema ( {
350
- context,
351
- schema : compositionSchema ,
352
- state : { ...state , inAllOf : true } ,
353
- } ) ;
354
- } else {
355
- irCompositionSchema = schemaToIrSchema ( {
356
- context,
357
- schema : compositionSchema ,
358
- state,
359
- } ) ;
360
- }
334
+ // Don't propagate inAllOf flag to $ref schemas to avoid issues with reusable components
335
+ const isRef = '$ref' in compositionSchema ;
336
+ const schemaState = isRef
337
+ ? state
338
+ : {
339
+ ...state ,
340
+ inAllOf : true ,
341
+ } ;
342
+
343
+ const irCompositionSchema = schemaToIrSchema ( {
344
+ context,
345
+ schema : compositionSchema ,
346
+ state : schemaState ,
347
+ } ) ;
361
348
362
349
irSchema . accessScopes = mergeSchemaAccessScopes (
363
350
irSchema . accessScopes ,
0 commit comments