Merge pull request #1192 from DEVTomatoCake/feat/improve-schema-openapi-generation
This commit is contained in:
commit
4f19ee19bb
Binary file not shown.
Binary file not shown.
@ -28,15 +28,13 @@ require("missing-native-js-functions");
|
|||||||
const openapiPath = path.join(__dirname, "..", "assets", "openapi.json");
|
const openapiPath = path.join(__dirname, "..", "assets", "openapi.json");
|
||||||
const SchemaPath = path.join(__dirname, "..", "assets", "schemas.json");
|
const SchemaPath = path.join(__dirname, "..", "assets", "schemas.json");
|
||||||
const schemas = JSON.parse(fs.readFileSync(SchemaPath, { encoding: "utf8" }));
|
const schemas = JSON.parse(fs.readFileSync(SchemaPath, { encoding: "utf8" }));
|
||||||
// const specification = JSON.parse(
|
|
||||||
// fs.readFileSync(openapiPath, { encoding: "utf8" }),
|
|
||||||
// );
|
|
||||||
let specification = {
|
let specification = {
|
||||||
openapi: "3.1.0",
|
openapi: "3.1.0",
|
||||||
info: {
|
info: {
|
||||||
title: "Spacebar Server",
|
title: "Spacebar Server",
|
||||||
description:
|
description:
|
||||||
"Spacebar is a free open source selfhostable discord compatible chat, voice and video platform",
|
"Spacebar is a Discord.com server implementation and extension, with the goal of complete feature parity with Discord.com, all while adding some additional goodies, security, privacy, and configuration options.",
|
||||||
license: {
|
license: {
|
||||||
name: "AGPLV3",
|
name: "AGPLV3",
|
||||||
url: "https://www.gnu.org/licenses/agpl-3.0.en.html",
|
url: "https://www.gnu.org/licenses/agpl-3.0.en.html",
|
||||||
@ -68,8 +66,9 @@ let specification = {
|
|||||||
paths: {},
|
paths: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const schemaRegEx = new RegExp(/^[\w.]+$/);
|
||||||
function combineSchemas(schemas) {
|
function combineSchemas(schemas) {
|
||||||
var definitions = {};
|
let definitions = {};
|
||||||
|
|
||||||
for (const name in schemas) {
|
for (const name in schemas) {
|
||||||
definitions = {
|
definitions = {
|
||||||
@ -84,9 +83,8 @@ function combineSchemas(schemas) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const key in definitions) {
|
for (const key in definitions) {
|
||||||
const reg = new RegExp(/^[a-zA-Z0-9.\-_]+$/, "gm");
|
if (!schemaRegEx.test(key)) {
|
||||||
if (!reg.test(key)) {
|
console.error(`Invalid schema name: ${key}`);
|
||||||
console.error(`Invalid schema name: ${key} (${reg.test(key)})`);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
specification.components = specification.components || {};
|
specification.components = specification.components || {};
|
||||||
@ -116,7 +114,7 @@ function getTag(key) {
|
|||||||
return key.match(/\/([\w-]+)/)[1];
|
return key.match(/\/([\w-]+)/)[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
function apiRoutes() {
|
function apiRoutes(missingRoutes) {
|
||||||
const routes = getRouteDescriptions();
|
const routes = getRouteDescriptions();
|
||||||
|
|
||||||
// populate tags
|
// populate tags
|
||||||
@ -157,32 +155,30 @@ function apiRoutes() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}.merge(obj.requestBody);
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (route.responses) {
|
if (route.responses) {
|
||||||
for (const [k, v] of Object.entries(route.responses)) {
|
obj.responses = {};
|
||||||
let schema = {
|
|
||||||
$ref: `#/components/schemas/${v.body}`,
|
|
||||||
};
|
|
||||||
|
|
||||||
obj.responses = {
|
for (const [k, v] of Object.entries(route.responses)) {
|
||||||
[k]: {
|
if (v.body)
|
||||||
...(v.body
|
obj.responses[k] = {
|
||||||
? {
|
description: obj?.responses?.[k]?.description || "",
|
||||||
description:
|
content: {
|
||||||
obj?.responses?.[k]?.description || "",
|
"application/json": {
|
||||||
content: {
|
schema: {
|
||||||
"application/json": {
|
$ref: `#/components/schemas/${v.body}`,
|
||||||
schema: schema,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
: {
|
else
|
||||||
description: "No description available",
|
obj.responses[k] = {
|
||||||
}),
|
description:
|
||||||
},
|
obj?.responses?.[k]?.description ||
|
||||||
}.merge(obj.responses);
|
"No description available",
|
||||||
|
};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
obj.responses = {
|
obj.responses = {
|
||||||
@ -218,6 +214,15 @@ function apiRoutes() {
|
|||||||
|
|
||||||
obj.tags = [...(obj.tags || []), getTag(p)].unique();
|
obj.tags = [...(obj.tags || []), getTag(p)].unique();
|
||||||
|
|
||||||
|
if (missingRoutes.additional.includes(path.replace(/\/$/, ""))) {
|
||||||
|
obj["x-badges"] = [
|
||||||
|
{
|
||||||
|
label: "Spacebar-only",
|
||||||
|
color: "red",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
specification.paths[path] = Object.assign(
|
specification.paths[path] = Object.assign(
|
||||||
specification.paths[path] || {},
|
specification.paths[path] || {},
|
||||||
{
|
{
|
||||||
@ -227,10 +232,21 @@ function apiRoutes() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function main() {
|
async function main() {
|
||||||
console.log("Generating OpenAPI Specification...");
|
console.log("Generating OpenAPI Specification...");
|
||||||
|
|
||||||
|
const routesRes = await fetch(
|
||||||
|
"https://github.com/spacebarchat/missing-routes/raw/main/missing.json",
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Accept: "application/json",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const missingRoutes = await routesRes.json();
|
||||||
|
|
||||||
combineSchemas(schemas);
|
combineSchemas(schemas);
|
||||||
apiRoutes();
|
apiRoutes(missingRoutes);
|
||||||
|
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
openapiPath,
|
openapiPath,
|
||||||
|
|||||||
@ -41,11 +41,16 @@ const Excluded = [
|
|||||||
"EntitySchema",
|
"EntitySchema",
|
||||||
"ServerResponse",
|
"ServerResponse",
|
||||||
"Http2ServerResponse",
|
"Http2ServerResponse",
|
||||||
|
"ExpressResponse",
|
||||||
"global.Express.Response",
|
"global.Express.Response",
|
||||||
|
"global.Response",
|
||||||
"Response",
|
"Response",
|
||||||
"e.Response",
|
"e.Response",
|
||||||
"request.Response",
|
"request.Response",
|
||||||
"supertest.Response",
|
"supertest.Response",
|
||||||
|
"DiagnosticsChannel.Response",
|
||||||
|
"_Response",
|
||||||
|
"ReadableStream<any>",
|
||||||
|
|
||||||
// TODO: Figure out how to exclude schemas from node_modules?
|
// TODO: Figure out how to exclude schemas from node_modules?
|
||||||
"SomeJSONSchema",
|
"SomeJSONSchema",
|
||||||
|
|||||||
Reference in New Issue
Block a user