Skip to content

Commit f978609

Browse files
committed
apply prefix name to all 'components' types for consistency
1 parent cfa51c2 commit f978609

2 files changed

Lines changed: 221 additions & 188 deletions

File tree

.github/redocly/schema-name-prefix.plugin.js

Lines changed: 64 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
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(/\/schemas\/([^\/]+)\/([^\/]+)\.yaml$/);
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(/\/(schemas|responses|parameters|examples|requestBodies|headers|securitySchemes|links|callbacks)\/([^\/]+)\/([^\/]+)\.yaml$/);
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

Comments
 (0)