mirror of
https://github.com/matrix-org/matrix-spec
synced 2026-03-26 04:54:10 +01:00
Revert "Create Swagger 2.0 to OpenAPI 3.1 conversion scripts"
This reverts commit 667c39f259.
This commit is contained in:
parent
902e38189f
commit
e2efbfbe5c
|
|
@ -1,83 +0,0 @@
|
|||
"use strict";
|
||||
import fs from 'node:fs/promises';
|
||||
import converter from 'swagger2openapi';
|
||||
import path_utils from 'node:path';
|
||||
import yaml from 'yaml';
|
||||
|
||||
import { applyObjectFixes } from './object-fixes.mjs';
|
||||
|
||||
async function getStartComment(path) {
|
||||
const file = await fs.open(path);
|
||||
|
||||
let start_comment = "";
|
||||
for await (const line of file.readLines()) {
|
||||
if (line.startsWith('#')) {
|
||||
start_comment += line + '\n';
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
await file.close();
|
||||
|
||||
return start_comment
|
||||
}
|
||||
|
||||
async function convertDefinitionsFile(path) {
|
||||
let relative_separator = path.lastIndexOf('/data/api');
|
||||
let short_path = path.slice(relative_separator + 1);
|
||||
console.log("%s", short_path);
|
||||
|
||||
// Save the comments at the start of the file to not lose them.
|
||||
let start_comment = await getStartComment(path);
|
||||
|
||||
// Convert.
|
||||
const options = await converter.convertFile(path, {
|
||||
// Patch fixable errors.
|
||||
patch: true,
|
||||
// Keep $ref siblings.
|
||||
refSiblings: 'preserve',
|
||||
// Don't deduplicate requestBodies.
|
||||
resolveInternal: true,
|
||||
// Write OpenAPI version 3.1.0, even if it's not completely true, it'll
|
||||
// be fixed later.
|
||||
targetVersion: '3.1.0',
|
||||
});
|
||||
|
||||
// Apply fixes on object.
|
||||
const obj = applyObjectFixes(options.openapi);
|
||||
|
||||
// Serialize.
|
||||
const doc = new yaml.Document(obj);
|
||||
const content = yaml.stringify(doc, {
|
||||
// Use "literal" blocks, like the input.
|
||||
blockQuote: "literal"
|
||||
});
|
||||
|
||||
// Save to file.
|
||||
await fs.writeFile(path, start_comment + content);
|
||||
}
|
||||
|
||||
export async function convertDefinitionsDir(path) {
|
||||
console.log("Converting files in %s", path);
|
||||
|
||||
const files = await fs.readdir(path);
|
||||
|
||||
for (const file of files) {
|
||||
if (file.endsWith(".yaml")) {
|
||||
await convertDefinitionsFile(path_utils.join(path, file));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert Swagger 2.0 definitions to OpenAPI 3.0.0.
|
||||
export async function convertDefinitions(path) {
|
||||
// We don't want to try to convert schemas in subdirectories, so we need to
|
||||
// call this separately for every directory inside `data/api`.
|
||||
let api_dir = path_utils.join(path, "api");
|
||||
const files = await fs.readdir(api_dir);
|
||||
|
||||
for (const file of files) {
|
||||
await convertDefinitionsDir(path_utils.join(api_dir, file));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
"use strict";
|
||||
import nopt from 'nopt';
|
||||
|
||||
import { convertDefinitions } from './convert-definitions.mjs';
|
||||
import { applyStringFixes } from './string-fixes.mjs';
|
||||
|
||||
const opts = nopt({
|
||||
"help": Boolean,
|
||||
"data": String
|
||||
}, {
|
||||
"h": "--help",
|
||||
"d": "--data"
|
||||
});
|
||||
|
||||
console.log("params: {}", opts);
|
||||
if (opts.help) {
|
||||
console.log(
|
||||
"Convert the definitions from Swagger 2.0 to OpenAPI 3.0\n" +
|
||||
"Usage:\n" +
|
||||
" node index.mjs -d <data_folder>"
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
if (!opts.data) {
|
||||
console.error("No [d]ata dir specified.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log("Converting Swagger 2.0 definitions to OpenAPI 3.0 in %s...", opts.data);
|
||||
try {
|
||||
await convertDefinitions(opts.data);
|
||||
|
||||
console.log("Applying string fixes...");
|
||||
await applyStringFixes(opts.data);
|
||||
|
||||
console.log(" ✅ Success");
|
||||
} catch (err) {
|
||||
console.error(' ❌ {}', err);
|
||||
process.exit(1);
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
"use strict";
|
||||
import { URL } from 'node:url';
|
||||
|
||||
// Refactor `servers` field to be able to access `basePath` easily.
|
||||
function refactorServers(obj) {
|
||||
if (!obj.servers) {
|
||||
return;
|
||||
}
|
||||
|
||||
let server = {
|
||||
url: "",
|
||||
variables: {
|
||||
protocol: {},
|
||||
hostname: {
|
||||
default: ""
|
||||
},
|
||||
basePath: {
|
||||
default: ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const url = new URL(obj.servers[0].url);
|
||||
|
||||
if (obj.servers.length > 1) {
|
||||
// In our case several URLs always mean both http and https for the same
|
||||
// host.
|
||||
obj.servers.pop()
|
||||
}
|
||||
|
||||
server.url = "{protocol}://{hostname}{basePath}"
|
||||
server.variables.protocol = {
|
||||
enum: ["http", "https"],
|
||||
default: "https",
|
||||
}
|
||||
server.variables.hostname.default = url.host
|
||||
server.variables.basePath.default = url.pathname
|
||||
|
||||
obj.servers[0] = server;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Fixes to apply to a converted schema object.
|
||||
export function applyObjectFixes(obj) {
|
||||
obj = refactorServers(obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
1292
scripts/openapi-convert/package-lock.json
generated
1292
scripts/openapi-convert/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,17 +0,0 @@
|
|||
{
|
||||
"name": "openapi-convert",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"nopt": "^3.0.2",
|
||||
"replace": "^1.2.2",
|
||||
"swagger2openapi": "^7.0.8",
|
||||
"yaml": "^2.1.3"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,165 +0,0 @@
|
|||
"use strict";
|
||||
import fs from 'node:fs/promises';
|
||||
import path_utils from 'node:path';
|
||||
import yaml from 'yaml';
|
||||
|
||||
const DEFAULT_INDENT = 2;
|
||||
|
||||
// Find the first child field with the given indentation in the given content.
|
||||
//
|
||||
// Returns the position at the end of the field's line.
|
||||
function findYamlChildField(content, min_indent, field_name) {
|
||||
const min_indent_string = " ".repeat(min_indent);
|
||||
const field_line = min_indent_string + field_name + ":\n";
|
||||
let line_start_idx = 0;
|
||||
|
||||
while (line_start_idx < content.length) {
|
||||
const content_end = content.slice(line_start_idx);
|
||||
const line_length = content_end.indexOf("\n") + 1;
|
||||
const line_end_idx = line_start_idx + line_length;
|
||||
const line = content_end.slice(0, line_length);
|
||||
|
||||
if (line == field_line) {
|
||||
// This is the child we are looking for.
|
||||
return line_end_idx;
|
||||
}
|
||||
|
||||
if (!line.startsWith(min_indent_string)) {
|
||||
// We changed the parent so we can't find the child anymore.
|
||||
return null;
|
||||
}
|
||||
|
||||
line_start_idx = line_end_idx;
|
||||
}
|
||||
|
||||
// We didn't find the child.
|
||||
return null;
|
||||
}
|
||||
|
||||
// Find the end of the children with the given indentation in the YAML content.
|
||||
//
|
||||
// Returns the position at the end of the last child.
|
||||
function findYamlChildrenEnd(content, min_indent) {
|
||||
const min_indent_string = " ".repeat(min_indent);
|
||||
let line_start_idx = 0;
|
||||
|
||||
while (line_start_idx < content.length) {
|
||||
const content_end = content.slice(line_start_idx);
|
||||
|
||||
if (content_end.startsWith(min_indent_string)) {
|
||||
const line_length = content_end.indexOf("\n") + 1;
|
||||
line_start_idx += line_length;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return line_start_idx;
|
||||
}
|
||||
|
||||
// Convert and replace the YAML in the given content between start and end with JSON.
|
||||
function replaceYamlWithJson(content, start, end, extra_indent) {
|
||||
console.log("Processing example", start, end);
|
||||
const example_yaml = content.slice(start, end);
|
||||
console.log("```" + example_yaml + "```");
|
||||
const example_obj = yaml.parse(example_yaml);
|
||||
const example_json = JSON.stringify(example_obj, null, DEFAULT_INDENT) + "\n";
|
||||
console.log("```" + example_json + "```");
|
||||
|
||||
// Fix the indentation.
|
||||
let json_lines = example_json.split("\n");
|
||||
// The first and last line don't need the extra indent.
|
||||
for (let i = 1; i < json_lines.length - 1; i++) {
|
||||
json_lines[i] = " ".repeat(extra_indent) + json_lines[i];
|
||||
}
|
||||
const indented_example_json = json_lines.join("\n");
|
||||
|
||||
// Put the opening bracket on the same line as the parent field.
|
||||
const replace_start = start - 1;
|
||||
content = content.slice(0, replace_start) + ' ' + indented_example_json + content.slice(end);
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
/// Convert the examples under the given fields in the YAML content to JSON.
|
||||
function convertExamplesToJson(content, parent_field, example_field) {
|
||||
const parent_field_regex_string = "( +)" + parent_field + ":\n";
|
||||
const parent_field_regex = RegExp(parent_field_regex_string, 'g');
|
||||
let match;
|
||||
let examples = [];
|
||||
|
||||
while ((match = parent_field_regex.exec(content)) !== null) {
|
||||
console.log("Found parent field", parent_field, match.index);
|
||||
const indent_capture = match[1];
|
||||
const example_field_line_indent = indent_capture.length + DEFAULT_INDENT;
|
||||
const parent_field_line_end = parent_field_regex.lastIndex;
|
||||
let content_end = content.slice(parent_field_line_end);
|
||||
|
||||
const example_field_line_end = findYamlChildField(content_end, example_field_line_indent, example_field);
|
||||
|
||||
if (example_field_line_end == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const example_start = parent_field_line_end + example_field_line_end;
|
||||
content_end = content.slice(example_start);
|
||||
console.log("Found example at", example_start);
|
||||
const example_line_min_indent = example_field_line_indent + DEFAULT_INDENT;
|
||||
const example_length = findYamlChildrenEnd(content_end, example_line_min_indent);
|
||||
console.log("Example length", example_length);
|
||||
|
||||
if (example_length > 0) {
|
||||
examples.push({
|
||||
start: example_start,
|
||||
end: example_start + example_length,
|
||||
extra_indent: example_field_line_indent,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for (const example of examples.reverse()) {
|
||||
content = replaceYamlWithJson(content, example.start, example.end, example.extra_indent);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
async function applyStringFixesFile(path) {
|
||||
const relative_separator = path.lastIndexOf('/data/api');
|
||||
const short_path = path.slice(relative_separator + 1);
|
||||
console.log("%s", short_path);
|
||||
|
||||
let content = await fs.readFile(path, "utf-8");
|
||||
|
||||
// Fix occurrences of `*xx` status codes to `*XX`.
|
||||
content = content.replaceAll("3xx:", "\"3XX\":");
|
||||
content = content.replaceAll("4xx:", "\"4XX\":");
|
||||
|
||||
// Fix occurrences of `_ref` to `$ref`.
|
||||
content = content.replaceAll("_ref:", "$ref:");
|
||||
|
||||
// Fix occurrences of `x-example` to `example`.
|
||||
content = content.replaceAll("x-example:", "example:");
|
||||
|
||||
// Convert examples back to JSON.
|
||||
// Response examples.
|
||||
content = convertExamplesToJson(content, "response", "value");
|
||||
// Schema examples.
|
||||
content = convertExamplesToJson(content, "schema", "example");
|
||||
|
||||
await fs.writeFile(path, content);
|
||||
}
|
||||
|
||||
// Fixes to apply to the string content of the files.
|
||||
export async function applyStringFixes(path) {
|
||||
const stat = await fs.lstat(path);
|
||||
if (stat.isDirectory()) {
|
||||
const files = await fs.readdir(path);
|
||||
|
||||
for (const file of files) {
|
||||
await applyStringFixes(path_utils.join(path, file))
|
||||
}
|
||||
} else if (stat.isFile()) {
|
||||
await applyStringFixesFile(path);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue