11/**
2- * Redocly plugin to preserve schema name prefixes based on directory structure.
2+ * Redocly plugin to preserve component name prefixes based on directory structure.
33 * Workaround for: https://github.com/Redocly/redocly-cli/issues/661
44 *
5- * When bundling, Redocly auto-renames conflicting schemas (e.g., link.yaml -> link-2).
6- * This plugin modifies the bundled output to use directory-based prefixes for schema names.
5+ * When bundling, Redocly auto-renames conflicting components (e.g., link.yaml -> link-2).
6+ * This plugin modifies the bundled output to use directory-based prefixes for ALL component types
7+ * (schemas, responses, parameters, examples, requestBodies, headers, securitySchemes, links, callbacks).
78 */
89
9- // Store mapping of schema objects to their source information
10- const schemaSourceMap = new WeakMap ( ) ;
10+ // Store mapping of component objects to their source information
11+ const componentSourceMap = new WeakMap ( ) ;
1112
12- const PreserveSchemaNamePrefixes = ( ) => {
13+ const PreserveComponentNamePrefixes = ( ) => {
1314 return {
1415 any : {
1516 enter ( node , ctx ) {
16- // Track all nodes from schema files
17+ // Track all nodes from component files
1718 if ( ! node || typeof node !== 'object' ) {
1819 return ;
1920 }
@@ -30,14 +31,19 @@ const PreserveSchemaNamePrefixes = () => {
3031 return ;
3132 }
3233
33- // Extract: .../schemas/{directory}/{filename}.yaml
34- const match = filePath . match ( / \/ s c h e m a s \/ ( [ ^ \/ ] + ) \/ ( [ ^ \/ ] + ) \. y a m l $ / ) ;
34+ // Extract directory and filename from various component paths:
35+ // - schemas/{directory}/{filename}.yaml
36+ // - responses/{directory}/{filename}.yaml
37+ // - parameters/{directory}/{filename}.yaml
38+ // etc.
39+ const match = filePath . match ( / \/ ( s c h e m a s | r e s p o n s e s | p a r a m e t e r s | e x a m p l e s | r e q u e s t B o d i e s | h e a d e r s | s e c u r i t y S c h e m e s | l i n k s | c a l l b a c k s ) \/ ( [ ^ \/ ] + ) \/ ( [ ^ \/ ] + ) \. y a m l $ / ) ;
3540 if ( match ) {
36- const [ , directory , filename ] = match ;
41+ const [ , componentType , directory , filename ] = match ;
3742
38- if ( directory && directory !== 'schemas' ) {
43+ if ( directory && directory !== componentType ) {
3944 // Store the source info for this node
40- schemaSourceMap . set ( node , {
45+ componentSourceMap . set ( node , {
46+ componentType,
4147 directory,
4248 filename,
4349 prefixedName : `${ directory } -${ filename } `
@@ -48,32 +54,57 @@ const PreserveSchemaNamePrefixes = () => {
4854 } ,
4955 Root : {
5056 leave ( root ) {
51- // Post-process: rename component schemas after bundling
52- if ( ! root . components || ! root . components . schemas ) {
57+ // Post-process: rename all component types after bundling
58+ if ( ! root . components ) {
5359 return ;
5460 }
5561
56- const schemas = root . components . schemas ;
62+ // List of all possible component types in OpenAPI 3.x
63+ const componentTypes = [
64+ 'schemas' ,
65+ 'responses' ,
66+ 'parameters' ,
67+ 'examples' ,
68+ 'requestBodies' ,
69+ 'headers' ,
70+ 'securitySchemes' ,
71+ 'links' ,
72+ 'callbacks'
73+ ] ;
74+
5775 const renameMap = new Map ( ) ;
5876
59- // Identify schemas that should be renamed
60- for ( const [ schemaName , schemaContent ] of Object . entries ( schemas ) ) {
61- const sourceInfo = schemaSourceMap . get ( schemaContent ) ;
77+ // Process each component type
78+ for ( const componentType of componentTypes ) {
79+ const components = root . components [ componentType ] ;
80+ if ( ! components ) {
81+ continue ;
82+ }
6283
63- if ( sourceInfo && sourceInfo . prefixedName ) {
64- // Only rename if the name differs
65- if ( schemaName !== sourceInfo . prefixedName ) {
66- renameMap . set ( schemaName , sourceInfo . prefixedName ) ;
84+ // Identify components that should be renamed
85+ for ( const [ componentName , componentContent ] of Object . entries ( components ) ) {
86+ const sourceInfo = componentSourceMap . get ( componentContent ) ;
87+
88+ if ( sourceInfo && sourceInfo . prefixedName ) {
89+ // Only rename if the name differs
90+ if ( componentName !== sourceInfo . prefixedName ) {
91+ const key = `${ componentType } /${ componentName } ` ;
92+ renameMap . set ( key , {
93+ componentType,
94+ oldName : componentName ,
95+ newName : sourceInfo . prefixedName
96+ } ) ;
97+ }
6798 }
6899 }
69100 }
70101
71102 // Apply renames
72- for ( const [ oldName , newName ] of renameMap . entries ( ) ) {
73- // Move the schema to new name
74- if ( schemas [ oldName ] ) {
75- schemas [ newName ] = schemas [ oldName ] ;
76- delete schemas [ oldName ] ;
103+ for ( const [ key , { componentType , oldName, newName } ] of renameMap . entries ( ) ) {
104+ const components = root . components [ componentType ] ;
105+ if ( components && components [ oldName ] ) {
106+ components [ newName ] = components [ oldName ] ;
107+ delete components [ oldName ] ;
77108 }
78109 }
79110
@@ -84,9 +115,9 @@ const PreserveSchemaNamePrefixes = () => {
84115 }
85116
86117 if ( obj . $ref && typeof obj . $ref === 'string' ) {
87- for ( const [ oldName , newName ] of renameMap . entries ( ) ) {
88- const oldRef = `#/components/schemas /${ oldName } ` ;
89- const newRef = `#/components/schemas /${ newName } ` ;
118+ for ( const [ key , { componentType , oldName, newName } ] of renameMap . entries ( ) ) {
119+ const oldRef = `#/components/${ componentType } /${ oldName } ` ;
120+ const newRef = `#/components/${ componentType } /${ newName } ` ;
90121 if ( obj . $ref === oldRef ) {
91122 obj . $ref = newRef ;
92123 }
@@ -111,9 +142,11 @@ module.exports = {
111142 id : 'schema-prefix' ,
112143 decorators : {
113144 oas3 : {
114- 'preserve-schema-name-prefixes' : PreserveSchemaNamePrefixes ,
145+ 'preserve-schema-name-prefixes' : PreserveComponentNamePrefixes ,
115146 }
116147 }
117148} ;
118149
119150
151+
152+
0 commit comments