mirror of
https://github.com/spacebarchat/server.git
synced 2024-11-26 04:03:03 +01:00
138 lines
3.6 KiB
JavaScript
138 lines
3.6 KiB
JavaScript
// https://mermade.github.io/openapi-gui/#
|
|
// https://editor.swagger.io/
|
|
const getRouteDescriptions = require("../jest/getRouteDescriptions");
|
|
const path = require("path");
|
|
const fs = require("fs");
|
|
require("missing-native-js-functions");
|
|
|
|
const openapiPath = path.join(__dirname, "..", "assets", "openapi.json");
|
|
const SchemaPath = path.join(__dirname, "..", "assets", "schemas.json");
|
|
const schemas = JSON.parse(fs.readFileSync(SchemaPath, { encoding: "utf8" }));
|
|
const specification = JSON.parse(fs.readFileSync(openapiPath, { encoding: "utf8" }));
|
|
|
|
function combineSchemas(schemas) {
|
|
let definitions = {};
|
|
|
|
for (const name in schemas) {
|
|
definitions = {
|
|
...definitions,
|
|
...schemas[name].definitions,
|
|
[name]: { ...schemas[name], definitions: undefined, $schema: undefined }
|
|
};
|
|
}
|
|
|
|
for (const key in definitions) {
|
|
specification.components.schemas[key] = definitions[key];
|
|
delete definitions[key].additionalProperties;
|
|
delete definitions[key].$schema;
|
|
const definition = definitions[key];
|
|
|
|
if (typeof definition.properties === "object") {
|
|
for (const property of Object.values(definition.properties)) {
|
|
if (Array.isArray(property.type)) {
|
|
if (property.type.includes("null")) {
|
|
property.type = property.type.find((x) => x !== "null");
|
|
property.nullable = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return definitions;
|
|
}
|
|
|
|
function getTag(key) {
|
|
return key.match(/\/([\w-]+)/)[1];
|
|
}
|
|
|
|
function apiRoutes() {
|
|
const routes = getRouteDescriptions();
|
|
|
|
const tags = Array.from(routes.keys()).map((x) => getTag(x));
|
|
specification.tags = [...specification.tags.map((x) => x.name), ...tags].unique().map((x) => ({ name: x }));
|
|
|
|
routes.forEach((route, pathAndMethod) => {
|
|
const [p, method] = pathAndMethod.split("|");
|
|
const path = p.replace(/:(\w+)/g, "{$1}");
|
|
|
|
let obj = specification.paths[path]?.[method] || {};
|
|
if (!obj.description) {
|
|
const permission = route.permission ? `##### Requires the \`\`${route.permission}\`\` permission\n` : "";
|
|
const event = route.test?.event ? `##### Fires a \`\`${route.test?.event}\`\` event\n` : "";
|
|
obj.description = permission + event;
|
|
}
|
|
if (route.body) {
|
|
obj.requestBody = {
|
|
required: true,
|
|
content: {
|
|
"application/json": {
|
|
schema: { $ref: `#/components/schemas/${route.body}` }
|
|
}
|
|
}
|
|
}.merge(obj.requestBody);
|
|
}
|
|
if (!obj.responses) {
|
|
obj.responses = {
|
|
default: {
|
|
description: "not documented"
|
|
}
|
|
};
|
|
}
|
|
if (route.test?.response) {
|
|
const status = route.test.response.status || 200;
|
|
let schema = {
|
|
allOf: [
|
|
{
|
|
$ref: `#/components/schemas/${route.test.response.body}`
|
|
},
|
|
{
|
|
example: route.test.body
|
|
}
|
|
]
|
|
};
|
|
if (!route.test.body) schema = schema.allOf[0];
|
|
|
|
obj.responses = {
|
|
[status]: {
|
|
...(route.test.response.body
|
|
? {
|
|
description: obj.responses[status].description || "",
|
|
content: {
|
|
"application/json": {
|
|
schema: schema
|
|
}
|
|
}
|
|
}
|
|
: {})
|
|
}
|
|
}.merge(obj.responses);
|
|
delete obj.responses.default;
|
|
}
|
|
if (p.includes(":")) {
|
|
obj.parameters = p.match(/:\w+/g)?.map((x) => ({
|
|
name: x.replace(":", ""),
|
|
in: "path",
|
|
required: true,
|
|
schema: { type: "string" },
|
|
description: x.replace(":", "")
|
|
}));
|
|
}
|
|
obj.tags = [...(obj.tags || []), getTag(p)].unique();
|
|
|
|
specification.paths[path] = { ...specification.paths[path], [method]: obj };
|
|
});
|
|
}
|
|
|
|
function main() {
|
|
combineSchemas(schemas);
|
|
apiRoutes();
|
|
|
|
fs.writeFileSync(
|
|
openapiPath,
|
|
JSON.stringify(specification, null, 4).replaceAll("#/definitions", "#/components/schemas").replaceAll("bigint", "number")
|
|
);
|
|
}
|
|
|
|
main();
|