@@ -334,7 +334,7 @@ fn apply_mount_strategy(path: &str, manifest: &SchemaManifest) -> String {
334334 }
335335}
336336
337- /// Adds prefix to component schema names
337+ /// Adds prefix to component schema names and rewrites $ref strings.
338338pub fn prefix_component_names ( components : & Components , prefix : & str ) -> Components {
339339 if prefix. is_empty ( ) {
340340 return components. clone ( ) ;
@@ -344,7 +344,11 @@ pub fn prefix_component_names(components: &Components, prefix: &str) -> Componen
344344 schemas : components
345345 . schemas
346346 . iter ( )
347- . map ( |( name, schema) | ( format ! ( "{prefix}_{name}" ) , schema. clone ( ) ) )
347+ . map ( |( name, schema) | {
348+ let mut rewritten = schema. clone ( ) ;
349+ rewrite_refs ( & mut rewritten, prefix) ;
350+ ( format ! ( "{prefix}_{name}" ) , rewritten)
351+ } )
348352 . collect ( ) ,
349353 responses : components
350354 . responses
@@ -362,8 +366,97 @@ pub fn prefix_component_names(components: &Components, prefix: &str) -> Componen
362366 . map ( |( name, body) | ( format ! ( "{prefix}_{name}" ) , body. clone ( ) ) )
363367 . collect ( ) ,
364368 headers : HashMap :: new ( ) ,
365- security_schemes : components. security_schemes . clone ( ) , // Don't prefix security schemes
369+ security_schemes : components. security_schemes . clone ( ) ,
370+ }
371+ }
372+
373+ /// Recursively rewrites $ref strings in a JSON value.
374+ /// Transforms "#/components/schemas/Foo" → "#/components/schemas/prefix_Foo".
375+ pub fn rewrite_refs ( value : & mut serde_json:: Value , prefix : & str ) {
376+ match value {
377+ serde_json:: Value :: Object ( map) => {
378+ if let Some ( serde_json:: Value :: String ( ref_str) ) = map. get ( "$ref" ) {
379+ let rewritten = rewrite_ref_string ( ref_str, prefix) ;
380+ map. insert ( "$ref" . to_string ( ) , serde_json:: Value :: String ( rewritten) ) ;
381+ }
382+ for ( key, val) in map. iter_mut ( ) {
383+ if key != "$ref" {
384+ rewrite_refs ( val, prefix) ;
385+ }
386+ }
387+ }
388+ serde_json:: Value :: Array ( arr) => {
389+ for item in arr. iter_mut ( ) {
390+ rewrite_refs ( item, prefix) ;
391+ }
392+ }
393+ _ => { }
394+ }
395+ }
396+
397+ fn rewrite_ref_string ( ref_str : & str , prefix : & str ) -> String {
398+ let component_prefixes = [
399+ "#/components/schemas/" ,
400+ "#/components/responses/" ,
401+ "#/components/parameters/" ,
402+ "#/components/requestBodies/" ,
403+ "#/components/headers/" ,
404+ ] ;
405+
406+ for cp in & component_prefixes {
407+ if let Some ( name) = ref_str. strip_prefix ( cp) {
408+ return format ! ( "{cp}{prefix}_{name}" ) ;
409+ }
410+ }
411+
412+ ref_str. to_string ( )
413+ }
414+
415+ /// Rewrites $ref strings in all operations of a PathItem.
416+ pub fn rewrite_path_item_refs ( item : & mut PathItem , prefix : & str ) {
417+ if prefix. is_empty ( ) {
418+ return ;
366419 }
420+
421+ let rewrite_op = |op : & mut Option < Operation > | {
422+ if let Some ( operation) = op {
423+ // Rewrite refs in responses
424+ if let Some ( ref mut responses) = operation. responses {
425+ for resp in responses. values_mut ( ) {
426+ if let Some ( ref mut content) = resp. content {
427+ for media in content. values_mut ( ) {
428+ if let Some ( ref mut schema) = media. schema {
429+ rewrite_refs ( schema, prefix) ;
430+ }
431+ }
432+ }
433+ }
434+ }
435+ // Rewrite refs in parameters
436+ for param in & mut operation. parameters {
437+ if let Some ( ref mut schema) = param. schema {
438+ rewrite_refs ( schema, prefix) ;
439+ }
440+ }
441+ // Rewrite refs in request body
442+ if let Some ( ref mut rb) = operation. request_body {
443+ for media in rb. content . values_mut ( ) {
444+ if let Some ( ref mut schema) = media. schema {
445+ rewrite_refs ( schema, prefix) ;
446+ }
447+ }
448+ }
449+ }
450+ } ;
451+
452+ rewrite_op ( & mut item. get ) ;
453+ rewrite_op ( & mut item. post ) ;
454+ rewrite_op ( & mut item. put ) ;
455+ rewrite_op ( & mut item. delete ) ;
456+ rewrite_op ( & mut item. patch ) ;
457+ rewrite_op ( & mut item. options ) ;
458+ rewrite_op ( & mut item. head ) ;
459+ rewrite_op ( & mut item. trace ) ;
367460}
368461
369462/// Applies prefixes to operation IDs and tags
@@ -372,6 +465,7 @@ pub fn apply_operation_prefixes(
372465 op_id_prefix : & str ,
373466 tag_prefix : & str ,
374467 service_name : & str ,
468+ collapse_service_tags : bool ,
375469 seen_operation_ids : & mut HashMap < String , String > ,
376470 result : & mut MergeResult ,
377471) -> PathItem {
@@ -399,8 +493,10 @@ pub fn apply_operation_prefixes(
399493 operation. operation_id = Some ( new_id) ;
400494 }
401495
402- // Prefix tags
403- if !tag_prefix. is_empty ( ) {
496+ // Handle tags: collapse all to service name, or prefix individually
497+ if collapse_service_tags {
498+ operation. tags = vec ! [ service_name. to_string( ) ] ;
499+ } else if !tag_prefix. is_empty ( ) {
404500 operation. tags = operation
405501 . tags
406502 . iter ( )
0 commit comments