mirror of
https://github.com/tribufu/proxmox-ve-openapi
synced 2026-05-06 07:07:28 +00:00
236 lines
6.6 KiB
JavaScript
236 lines
6.6 KiB
JavaScript
const pveapi = require("./source");
|
|
const yaml = require("js-yaml");
|
|
|
|
const paths = {};
|
|
const models = {};
|
|
const responses = {};
|
|
const tags = [];
|
|
|
|
const capitalizeFirst = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
|
|
|
function generateOpId(method, path) {
|
|
let operation = path
|
|
.split("/")
|
|
.map(capitalizeFirst)
|
|
.join("")
|
|
.replace(/[\-\_]/g, "");
|
|
|
|
operation = operation.replace(/\{[a-z]*\}/g, "Single");
|
|
|
|
const prefix = (() => {
|
|
switch (method) {
|
|
case "post":
|
|
return "create";
|
|
case "put":
|
|
return "update";
|
|
case "patch":
|
|
return "update";
|
|
default:
|
|
return method;
|
|
}
|
|
})();
|
|
|
|
return prefix + operation;
|
|
}
|
|
|
|
const mapping = require("./mapping");
|
|
|
|
function filterSchema(p) {
|
|
const schema = {
|
|
type: p.type,
|
|
};
|
|
if (p.items) schema.items = filterSchema(p.items);
|
|
if (p.properties) {
|
|
schema.properties = {};
|
|
Object.keys(p.properties).forEach(
|
|
(name) =>
|
|
(schema.properties[name] = filterSchema(p.properties[name]))
|
|
);
|
|
}
|
|
return schema;
|
|
}
|
|
|
|
function buildResponseSchema(source) {
|
|
const schema = {
|
|
type: source.type || "string",
|
|
description: source.description || "",
|
|
};
|
|
if (schema.type === "boolean") schema.type = "integer";
|
|
if (schema.type === "integer") schema.type = "int64";
|
|
if (schema.type === "null") schema.type = "string";
|
|
if (source.type === "array" && source.items)
|
|
schema.items = buildResponseSchema(source.items);
|
|
if (source.type === "object" && source.properties) {
|
|
schema.properties = {};
|
|
Object.keys(source.properties || {}).forEach((k) => {
|
|
if (k.endsWith("[n]")) {
|
|
const nk = k.substr(0, k.length - 3);
|
|
for (let i = 0; i < 30; i++) {
|
|
schema.properties[nk + i] = buildResponseSchema(
|
|
source.properties[k]
|
|
);
|
|
}
|
|
} else {
|
|
schema.properties[k] = buildResponseSchema(
|
|
source.properties[k]
|
|
);
|
|
}
|
|
});
|
|
}
|
|
return schema;
|
|
}
|
|
|
|
function parseInfo(path, method, info) {
|
|
let id = generateOpId(method, path);
|
|
id = mapping[id] || id;
|
|
const sourceProperties =
|
|
info.parameters && info.parameters.properties
|
|
? Object.keys(info.parameters.properties).map((k) => ({
|
|
name: k,
|
|
...info.parameters.properties[k],
|
|
}))
|
|
: [];
|
|
|
|
const properties = [];
|
|
|
|
sourceProperties.forEach((p) => {
|
|
if (p.name.endsWith("[n]")) {
|
|
const nk = p.name.substr(0, p.name.length - 3);
|
|
for (let i = 0; i < 30; i++) {
|
|
properties.push({
|
|
...JSON.parse(JSON.stringify(p)),
|
|
name: nk + i,
|
|
});
|
|
}
|
|
} else {
|
|
properties.push(p);
|
|
}
|
|
});
|
|
|
|
const requestName = capitalizeFirst(id) + "Request";
|
|
const responseName = capitalizeFirst(id) + "Response";
|
|
|
|
paths[path][method] = {
|
|
operationId: id,
|
|
summary: id,
|
|
description: info.description || id,
|
|
tags: [path.substr(1).split("/")[0]],
|
|
parameters: properties
|
|
.filter((p) => path.includes("{" + p.name + "}"))
|
|
.map((p) => ({
|
|
name: p.name,
|
|
in: "path",
|
|
required: true,
|
|
description: p.name,
|
|
schema: { type: p.type },
|
|
})),
|
|
responses: {
|
|
200: {
|
|
$ref: "#/components/responses/" + responseName,
|
|
},
|
|
},
|
|
};
|
|
|
|
paths[path][method].tags.forEach((t) => {
|
|
if (!tags.includes(t)) tags.push(t);
|
|
});
|
|
|
|
responses[responseName] = {
|
|
description: responseName,
|
|
content: {
|
|
"application/json": {
|
|
schema: {
|
|
type: "object",
|
|
properties: {
|
|
errors: {
|
|
type: "array",
|
|
items: {
|
|
type: "string",
|
|
},
|
|
},
|
|
data: buildResponseSchema(info.returns),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
if (method === "post" || method === "put") {
|
|
models[requestName] = {
|
|
title: requestName,
|
|
type: "object",
|
|
properties: {},
|
|
required: [],
|
|
};
|
|
properties
|
|
.filter((p) => !path.includes("{" + p.name + "}"))
|
|
.forEach((p) => {
|
|
models[requestName].properties[p.name] = filterSchema(p);
|
|
if (p.optional !== 1) {
|
|
models[requestName].required.push(p.name);
|
|
}
|
|
});
|
|
if (models[requestName].required.length < 1)
|
|
delete models[requestName].required;
|
|
paths[path][method].requestBody = {
|
|
content: {
|
|
"application/json": {
|
|
schema: {
|
|
$ref: "#/components/schemas/" + requestName,
|
|
},
|
|
},
|
|
},
|
|
};
|
|
} else {
|
|
properties
|
|
.filter((p) => !path.includes("{" + p.name + "}"))
|
|
.map((p) => ({
|
|
name: p.name,
|
|
in: "query",
|
|
required: p.optional !== 1,
|
|
description: p.name,
|
|
schema: { type: p.type },
|
|
}));
|
|
}
|
|
}
|
|
|
|
function parsePath(source) {
|
|
if (source.info && Object.keys(source.info).length > 0) {
|
|
paths[source.path] = {};
|
|
Object.keys(source.info).forEach((method) =>
|
|
parseInfo(source.path, method.toLowerCase(), source.info[method])
|
|
);
|
|
}
|
|
if (source.children) source.children.forEach(parsePath);
|
|
}
|
|
|
|
pveapi.forEach(parsePath);
|
|
|
|
const spec = {
|
|
openapi: "3.0.0",
|
|
info: {
|
|
title: "ProxMox VE API",
|
|
version: "2.0",
|
|
description: "ProxMox VE API",
|
|
contact: {
|
|
name: "LUMASERV Support Team",
|
|
email: "support@lumaserv.com",
|
|
},
|
|
},
|
|
servers: [
|
|
{
|
|
description: "local",
|
|
url: "https://cluster.local:8006/api2/json",
|
|
},
|
|
],
|
|
tags: tags.map((t) => ({ name: t })),
|
|
paths: paths,
|
|
components: {
|
|
schemas: models,
|
|
responses: responses,
|
|
},
|
|
};
|
|
|
|
const fs = require("fs");
|
|
|
|
fs.writeFileSync("../reference/spec.v2.yaml", yaml.safeDump(spec));
|