@@ -382,7 +382,7 @@ export function OpenAPISchemaPresentation(props: {
382382 < div id = { id } className = "openapi-schema-presentation" >
383383 < OpenAPISchemaName
384384 schema = { schema }
385- type = { getSchemaTitle ( schema ) }
385+ type = { getSchemaTitle ( schema , { ignoreAlternatives : ! propertyName } ) }
386386 propertyName = { propertyName }
387387 isDiscriminatorProperty = { isDiscriminatorProperty }
388388 required = { required }
@@ -688,34 +688,90 @@ function flattenAlternatives(
688688) : OpenAPIV3 . SchemaObject [ ] {
689689 // Get the parent schema's required fields from the most recent ancestor
690690 const latestAncestor = Array . from ( ancestors ) . pop ( ) ;
691+ const result : OpenAPIV3 . SchemaObject [ ] = [ ] ;
691692
692- return schemasOrRefs . reduce < OpenAPIV3 . SchemaObject [ ] > ( ( acc , schemaOrRef ) => {
693+ for ( const schemaOrRef of schemasOrRefs ) {
693694 if ( checkIsReference ( schemaOrRef ) ) {
694- return acc ;
695+ continue ;
695696 }
696697
697- if ( schemaOrRef [ alternativeType ] && ! ancestors . has ( schemaOrRef ) ) {
698- const alternatives = getSchemaAlternatives ( schemaOrRef , ancestors ) ;
699- if ( alternatives ?. schemas ) {
700- acc . push (
701- ...alternatives . schemas . map ( ( schema ) => ( {
702- ...schema ,
703- required : mergeRequiredFields ( schema , latestAncestor ) ,
704- } ) )
705- ) ;
698+ const flattened = flattenSchema ( schemaOrRef , alternativeType , ancestors , latestAncestor ) ;
699+
700+ if ( flattened ) {
701+ result . push ( ...flattened ) ;
702+ }
703+ }
704+
705+ return result ;
706+ }
707+
708+ /**
709+ * Flatten a schema that is an alternative of another schema.
710+ */
711+ function flattenSchema (
712+ schema : OpenAPIV3 . SchemaObject ,
713+ alternativeType : AlternativeType ,
714+ ancestors : Set < OpenAPIV3 . SchemaObject > ,
715+ latestAncestor : OpenAPIV3 . SchemaObject | undefined
716+ ) : OpenAPIV3 . SchemaObject [ ] {
717+ if ( schema [ alternativeType ] && ! ancestors . has ( schema ) ) {
718+ const alternatives = getSchemaAlternatives ( schema , ancestors ) ;
719+ if ( alternatives ?. schemas ) {
720+ return alternatives . schemas . map ( ( s ) => {
721+ const required = mergeRequiredFields ( s , latestAncestor ) ;
722+ return {
723+ ...s ,
724+ ...( required ? { required } : { } ) ,
725+ } ;
726+ } ) ;
727+ }
728+
729+ const required = mergeRequiredFields ( schema , latestAncestor ) ;
730+ return [ { ...schema , ...( required ? { required } : { } ) } ] ;
731+ }
732+
733+ // if a schema has allOf that can be safely merged, merge it
734+ if (
735+ ( alternativeType === 'oneOf' || alternativeType === 'anyOf' ) &&
736+ schema . allOf &&
737+ Array . isArray ( schema . allOf ) &&
738+ ! ancestors . has ( schema )
739+ ) {
740+ const allOfSchemas = schema . allOf . filter (
741+ ( s ) : s is OpenAPIV3 . SchemaObject => ! checkIsReference ( s )
742+ ) ;
743+
744+ if ( allOfSchemas . length > 0 ) {
745+ const merged = mergeAlternatives ( 'allOf' , allOfSchemas ) ;
746+ if ( merged && merged . length > 0 ) {
747+ // Only merge if all schemas were successfully merged into one (safe to merge)
748+ if ( merged . length === 1 ) {
749+ return merged . map ( ( s ) => {
750+ const required = mergeRequiredFields ( s , latestAncestor ) ;
751+ const result : OpenAPIV3 . SchemaObject = {
752+ ...s ,
753+ ...( required ? { required } : { } ) ,
754+ } ;
755+
756+ if ( schema . title && ! s . title ) {
757+ result . title = schema . title ;
758+ }
759+
760+ return result ;
761+ } ) ;
762+ }
706763 }
707- return acc ;
708764 }
765+ }
709766
710- // For direct schemas, handle required fields
711- const schema = {
712- ...schemaOrRef ,
713- required : mergeRequiredFields ( schemaOrRef , latestAncestor ) ,
714- } ;
767+ const required = mergeRequiredFields ( schema , latestAncestor ) ;
715768
716- acc . push ( schema ) ;
717- return acc ;
718- } , [ ] ) ;
769+ return [
770+ {
771+ ...schema ,
772+ ...( required ? { required } : { } ) ,
773+ } ,
774+ ] ;
719775}
720776
721777/**
0 commit comments