@@ -163,6 +163,9 @@ impl RefResolver {
163163 // Clean up any remaining unresolved references
164164 self . clean_unresolved_refs ( & mut value) ?;
165165
166+ // Deduplicate response types to prevent progenitor 0.11.0 assertion failures
167+ self . deduplicate_response_types ( & mut value) ?;
168+
166169 Ok ( value)
167170 }
168171
@@ -622,6 +625,131 @@ properties:
622625 }
623626 Ok ( ( ) )
624627 }
628+
629+ fn deduplicate_response_types ( & self , value : & mut Value ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
630+ println ! ( "Deduplicating response types to prevent progenitor assertion failures..." ) ;
631+ let mut operations_modified = 0 ;
632+ let mut total_responses_removed = 0 ;
633+
634+ if let Some ( obj) = value. as_mapping_mut ( ) {
635+ if let Some ( paths) = obj. get_mut ( & Value :: String ( "paths" . to_string ( ) ) ) {
636+ if let Some ( paths_map) = paths. as_mapping_mut ( ) {
637+ for ( path_key, path_value) in paths_map. iter_mut ( ) {
638+ if let Some ( path_obj) = path_value. as_mapping_mut ( ) {
639+ // Check each HTTP method in this path
640+ for ( method_key, method_value) in path_obj. iter_mut ( ) {
641+ if let Some ( method_str) = method_key. as_str ( ) {
642+ // Skip non-HTTP method keys like "parameters"
643+ if ![ "get" , "post" , "put" , "patch" , "delete" , "head" , "options" , "trace" ] . contains ( & method_str) {
644+ continue ;
645+ }
646+
647+ if let Some ( operation) = method_value. as_mapping_mut ( ) {
648+ // Get operation_id before mutable borrow
649+ let operation_id = operation
650+ . get ( & Value :: String ( "operationId" . to_string ( ) ) )
651+ . and_then ( |v| v. as_str ( ) )
652+ . unwrap_or ( "unknown" )
653+ . to_string ( ) ;
654+
655+ if let Some ( responses) = operation. get_mut ( & Value :: String ( "responses" . to_string ( ) ) ) {
656+ if let Some ( responses_map) = responses. as_mapping_mut ( ) {
657+
658+ let original_count = responses_map. len ( ) ;
659+ let mut success_responses = Vec :: new ( ) ;
660+ let mut other_responses = Vec :: new ( ) ;
661+
662+ // Separate success (2xx) responses from others
663+ for ( status_key, response_value) in responses_map. iter ( ) {
664+ if let Some ( status_str) = status_key. as_str ( ) {
665+ if status_str. starts_with ( '2' ) && status_str. len ( ) == 3 {
666+ success_responses. push ( ( status_key. clone ( ) , response_value. clone ( ) ) ) ;
667+ } else {
668+ other_responses. push ( ( status_key. clone ( ) , response_value. clone ( ) ) ) ;
669+ }
670+ } else {
671+ other_responses. push ( ( status_key. clone ( ) , response_value. clone ( ) ) ) ;
672+ }
673+ }
674+
675+ // Use a more aggressive approach: if there are multiple success responses,
676+ // or if there's any response complexity, simplify to just one response
677+ if success_responses. len ( ) > 1 || original_count > 2 {
678+ println ! ( "Operation '{}' ({} {}) has {} responses ({}), simplifying to prevent assertion failure" ,
679+ operation_id, method_str. to_uppercase( ) ,
680+ path_key. as_str( ) . unwrap_or( "unknown" ) ,
681+ success_responses. len( ) ,
682+ original_count) ;
683+
684+ responses_map. clear ( ) ;
685+
686+ // Keep only one response: prefer first success, then first error, then default
687+ if let Some ( ( first_status, first_response) ) = success_responses. into_iter ( ) . next ( ) {
688+ // Also simplify the response content to avoid multiple content types
689+ let mut simplified_response = first_response;
690+ if let Some ( response_obj) = simplified_response. as_mapping_mut ( ) {
691+ if let Some ( content) = response_obj. get_mut ( & Value :: String ( "content" . to_string ( ) ) ) {
692+ if let Some ( content_map) = content. as_mapping_mut ( ) {
693+ // Keep only the first content type to avoid multiple response types
694+ if content_map. len ( ) > 1 {
695+ let first_content_type = content_map. keys ( ) . next ( ) . cloned ( ) ;
696+ if let Some ( first_key) = first_content_type {
697+ let first_value = content_map. get ( & first_key) . cloned ( ) ;
698+ content_map. clear ( ) ;
699+ if let Some ( value) = first_value {
700+ content_map. insert ( first_key, value) ;
701+ }
702+ }
703+ }
704+ }
705+ }
706+ }
707+ responses_map. insert ( first_status, simplified_response) ;
708+ } else if let Some ( ( first_status, first_response) ) = other_responses. iter ( )
709+ . find ( |( status_key, _) | {
710+ if let Some ( status_str) = status_key. as_str ( ) {
711+ status_str != "default"
712+ } else {
713+ true
714+ }
715+ } )
716+ . map ( |( k, v) | ( k. clone ( ) , v. clone ( ) ) ) {
717+ responses_map. insert ( first_status, first_response) ;
718+ } else if let Some ( ( default_status, default_response) ) = other_responses. iter ( )
719+ . find ( |( status_key, _) | {
720+ if let Some ( status_str) = status_key. as_str ( ) {
721+ status_str == "default"
722+ } else {
723+ false
724+ }
725+ } )
726+ . map ( |( k, v) | ( k. clone ( ) , v. clone ( ) ) ) {
727+ responses_map. insert ( default_status, default_response) ;
728+ }
729+
730+ operations_modified += 1 ;
731+ total_responses_removed += original_count - responses_map. len ( ) ;
732+ }
733+ }
734+ }
735+ }
736+ }
737+ }
738+ }
739+ }
740+ }
741+ }
742+ }
743+
744+ if operations_modified > 0 {
745+ println ! ( "Modified {} operations, removed {} duplicate responses" ,
746+ operations_modified, total_responses_removed) ;
747+ } else {
748+ println ! ( "No operations with multiple response types found" ) ;
749+ }
750+
751+ Ok ( ( ) )
752+ }
625753}
626754
627755fn generate_client_code ( spec : & Value ) -> Result < String , Box < dyn std:: error:: Error > > {
0 commit comments