mirror of
https://github.com/tribufu/proxmox-ve-openapi
synced 2026-05-06 07:07:28 +00:00
195 lines
5.7 KiB
JavaScript
195 lines
5.7 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 === '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))
|