The vscode-openapi-viewer extension is a valuable tool for developers and architects working with OpenAPI specifications, as it provides a convenient and interactive way to preview, test, and debug APIs within Visual Studio Code.
This whould be apreciated. I have a javascript code that does just that, and I will include it here. Maybe it is possibel to add it to this tool somewhere:
`// REPLACEREFS
// Explanation:
// Function Definition:
// replaceRefs(json) is the main function that takes the JSON object and replaces all $ref references with their corresponding content.
// getRefContent(ref, root) is a helper function that takes a $ref string and the root of the JSON structure. It returns the content at the path specified by the $ref.
//
// Get Reference Content:
// If the $ref starts with #, it is treated as an internal reference, and the function proceeds to traverse the path within the JSON structure.
// If the $ref does not start with #, it is treated as a file path. The function checks the file extension:
// For yaml and yml extensions, it reads and parses the file using yaml.load.
// For json extensions, it reads and parses the file using JSON.parse.
// If the file extension is unsupported, an error is logged.
// The parsed content of the file is then processed with replaceRefs.
// Logging statements print each step of the path traversal and file loading process.
//
// Recursive Traversal:
// If the current object (obj) is an array, it iterates over each element and calls recurse on it, passing the array as the parent and the index as the key.
// If the current object (obj) is a plain object, it iterates over its keys.
// If the key is $ref, it retrieves the new content from the JSON structure or external file using the getRefContent function.
// The retrieved new content replaces the entire object entry (parent[key]), and a deep copy of the new content is created to avoid reference issues.
// The function then recursively scans the new content for further $ref replacements.
// If the key is not $ref, it recursively calls recurse on the value of the key, passing the current object as the parent and the current key.
//
function replaceRefs(json) {
function getRefContent(ref, root) {
if (ref.startsWith("#")) {
// Internal reference
const path = ref.replace(/^#\/?/, "").split("/");
if (verbose) console.log(Resolving $ref: ${ref});
let acc = root;
for (const part of path) {
if (acc && acc[part] !== undefined) {
//console.log(Accessing: ${part} ->, acc[part]);
acc = acc[part];
} else {
if (warn || verbose)
console.warn(
Path not found: ${part}, possibly forward referenced
);
return undefined;
}
}
return acc;
} else {
// External file reference
try {
const fileExtension = ref.split(".").pop();
let fileContent;
}
function recurse(obj, parent, key) {
if (typeof obj === "object" && obj !== null) {
if (Array.isArray(obj)) {
obj.forEach((item, index) => recurse(item, obj, index));
} else {
for (let k in obj) {
if (obj.hasOwnProperty(k)) {
if (k === "$ref") {
const newContent = getRefContent(obj[k], json);
if (newContent !== undefined) {
parent[key] = JSON.parse(JSON.stringify(newContent)); // Deep copy to avoid reference issues
recurse(parent[key], parent, key); // Recurse into the new content
return; // Return early since the current object has been replaced
}
} else {
recurse(obj[k], obj, k);
}
}
}
}
}
}
recurse(json, null, null);
return json;
}
`
It should be called with the json structure of your openapi document in the following manner:
// Read the input file if (fileExtension === ".yaml" || fileExtension === ".yml") { json = yaml.load(contents); } else if (fileExtension === ".json") { json = JSON.parse(contents); } else { console.error(Unsupported input file extension: ${fileExtension}`);
process.exit(1);
}
// Process the JSON content
json = replaceRefs(json); // pass 1: Resolve file includes and non forward references
json = replaceRefs(json); // pass 2: Resolve forward references
if (verbose) console.log(JSON.parse(JSON.stringify(json)));
`
The 2 pass structure copes with forward references.
It seems that the tool is not following $ref: "".
This whould be apreciated. I have a javascript code that does just that, and I will include it here. Maybe it is possibel to add it to this tool somewhere: `// REPLACEREFS // Explanation: // Function Definition:
// replaceRefs(json) is the main function that takes the JSON object and replaces all $ref references with their corresponding content. // getRefContent(ref, root) is a helper function that takes a $ref string and the root of the JSON structure. It returns the content at the path specified by the $ref. // // Get Reference Content: // If the $ref starts with #, it is treated as an internal reference, and the function proceeds to traverse the path within the JSON structure. // If the $ref does not start with #, it is treated as a file path. The function checks the file extension: // For yaml and yml extensions, it reads and parses the file using yaml.load. // For json extensions, it reads and parses the file using JSON.parse. // If the file extension is unsupported, an error is logged. // The parsed content of the file is then processed with replaceRefs. // Logging statements print each step of the path traversal and file loading process. // // Recursive Traversal: // If the current object (obj) is an array, it iterates over each element and calls recurse on it, passing the array as the parent and the index as the key. // If the current object (obj) is a plain object, it iterates over its keys. // If the key is $ref, it retrieves the new content from the JSON structure or external file using the getRefContent function. // The retrieved new content replaces the entire object entry (parent[key]), and a deep copy of the new content is created to avoid reference issues. // The function then recursively scans the new content for further $ref replacements. // If the key is not $ref, it recursively calls recurse on the value of the key, passing the current object as the parent and the current key. // function replaceRefs(json) { function getRefContent(ref, root) { if (ref.startsWith("#")) { // Internal reference const path = ref.replace(/^#\/?/, "").split("/"); if (verbose) console.log(
Resolving $ref: ${ref}
); let acc = root; for (const part of path) { if (acc && acc[part] !== undefined) { //console.log(Accessing: ${part} ->
, acc[part]); acc = acc[part]; } else { if (warn || verbose) console.warn(Path not found: ${part}, possibly forward referenced
); return undefined; } } return acc; } else { // External file reference try { const fileExtension = ref.split(".").pop(); let fileContent;} function recurse(obj, parent, key) { if (typeof obj === "object" && obj !== null) { if (Array.isArray(obj)) { obj.forEach((item, index) => recurse(item, obj, index)); } else { for (let k in obj) { if (obj.hasOwnProperty(k)) { if (k === "$ref") { const newContent = getRefContent(obj[k], json); if (newContent !== undefined) { parent[key] = JSON.parse(JSON.stringify(newContent)); // Deep copy to avoid reference issues recurse(parent[key], parent, key); // Recurse into the new content return; // Return early since the current object has been replaced } } else { recurse(obj[k], obj, k); } } } } } }
recurse(json, null, null); return json; } `
It should be called with the json structure of your openapi document in the following manner:
// Read the input file if (fileExtension === ".yaml" || fileExtension === ".yml") { json = yaml.load(contents); } else if (fileExtension === ".json") { json = JSON.parse(contents); } else { console.error(
Unsupported input file extension: ${fileExtension}`); process.exit(1); }`
The 2 pass structure copes with forward references.
The source code (in a txt doc): gendoc - Copy.txt