mirror of
https://github.com/netbirdio/docs.git
synced 2026-04-16 07:26:35 +00:00
* update gitignore * add first version of api generation flow * try to run flow * testing flow * update gen flow * switch flow to macOS * fix * add npm install * test workflow * Update API pages * test workflow with current main * refactor parser * merge examples and schema functions * merge examples and schema functions * merge parameters as well * revert template to single class component * update account * finalizing * update with the newest version of openapi * full flow * update * add docker command * split flow in two jobs * remove testing trigger --------- Co-authored-by: GitHub Actions <no-reply@github.com>
219 lines
7.0 KiB
TypeScript
219 lines
7.0 KiB
TypeScript
import template from './templates/ApiTemplate'
|
|
import { slugify, toArrayWithKey, toTitle, writeToDisk } from './helpers'
|
|
import {OpenAPIV3} from 'openapi-types'
|
|
import * as fs from 'fs'
|
|
import * as ejs from 'ejs'
|
|
|
|
export default async function gen(inputFileName: string, outputDir: string) {
|
|
const specRaw = fs.readFileSync(inputFileName, 'utf8')
|
|
const spec = JSON.parse(specRaw) as any
|
|
|
|
switch (spec.openapi || spec.swagger) {
|
|
case '3.0.0':
|
|
case '3.0.1':
|
|
case '3.0.3':
|
|
await gen_v3(spec, outputDir)
|
|
break
|
|
|
|
default:
|
|
console.log('Unrecognized specification version:', spec.openapi)
|
|
break
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Versioned Generator
|
|
*/
|
|
|
|
// OPENAPI-SPEC-VERSION: 3.0.0
|
|
type v3OperationWithPath = OpenAPIV3.OperationObject & {
|
|
path: string
|
|
}
|
|
export type enrichedOperation = OpenAPIV3.OperationObject & {
|
|
path: string
|
|
fullPath: string
|
|
operationId: string
|
|
}
|
|
|
|
|
|
export type schemaParameter = {
|
|
name: string
|
|
type: string
|
|
description: string
|
|
required: boolean
|
|
minimum?: number
|
|
maximum?: number
|
|
minLength?: number
|
|
maxLength?: number
|
|
enum?: string[]
|
|
}
|
|
|
|
export type component = {
|
|
example: Object
|
|
schema: Object
|
|
parameters: schemaParameter[]
|
|
}
|
|
|
|
async function gen_v3(spec: OpenAPIV3.Document, dest: string) {
|
|
const specLayout = spec.tags || []
|
|
// const operations: enrichedOperation[] = []
|
|
const tagGroups = new Map<string, enrichedOperation[]>()
|
|
const server = spec.servers.pop().url
|
|
Object.entries(spec.paths).forEach(([key, val]) => {
|
|
const fullPath = `${server}${key}`
|
|
|
|
toArrayWithKey(val!, 'operation').forEach((o) => {
|
|
const operation = o as v3OperationWithPath
|
|
const enriched = {
|
|
...operation,
|
|
path: key,
|
|
fullPath,
|
|
operationId: slugify(operation.summary!),
|
|
|
|
responseList: toArrayWithKey(operation.responses!, 'responseCode') || [],
|
|
}
|
|
let tag = operation.tags.pop()
|
|
let tagOperations = tagGroups.get(tag) ?? []
|
|
tagGroups.set(tag, tagOperations.concat(enriched))
|
|
})
|
|
})
|
|
|
|
let components = readComponents(spec.components)
|
|
|
|
tagGroups.forEach((value: enrichedOperation[], key: string) => {
|
|
|
|
const operations = value
|
|
|
|
const sections = specLayout.map((section) => {
|
|
return {
|
|
...section,
|
|
title: toTitle(section.name),
|
|
id: slugify(section.name),
|
|
operations: operations,
|
|
}
|
|
})
|
|
|
|
const content = ejs.render(template, {
|
|
info: spec.info,
|
|
tag: key,
|
|
sections,
|
|
operations,
|
|
components,
|
|
})
|
|
|
|
// Write to disk
|
|
let outputFile = dest + "/" + key.toLowerCase().replace(" ", "-") + ".mdx"
|
|
writeToDisk(outputFile, content)
|
|
// console.log('Saved: ', outputFile)
|
|
})
|
|
}
|
|
|
|
function readComponents(components: OpenAPIV3.ComponentsObject) : Map<string, component> {
|
|
let componentsOutput = new Map<string, component>()
|
|
|
|
for (const [key, value] of Object.entries(components.schemas)) {
|
|
let [schema, example, parameter] = resolveComponents(value, components)
|
|
let component = {
|
|
example: example,
|
|
schema: schema,
|
|
parameters: parameter
|
|
}
|
|
componentsOutput.set(key, component)
|
|
}
|
|
|
|
return componentsOutput
|
|
}
|
|
|
|
function resolveComponents(value: OpenAPIV3.ReferenceObject | OpenAPIV3.ArraySchemaObject | OpenAPIV3.NonArraySchemaObject, components: OpenAPIV3.ComponentsObject) : [Object, Object, schemaParameter[]] {
|
|
if((value as OpenAPIV3.ReferenceObject).$ref) {
|
|
let subcomponentName = (value as OpenAPIV3.ReferenceObject).$ref.split('/').pop()
|
|
let subcomponent = components.schemas[subcomponentName]
|
|
return resolveComponents(subcomponent, components)
|
|
}
|
|
if((value as OpenAPIV3.SchemaObject).properties) {
|
|
return resolveProperties(value as OpenAPIV3.SchemaObject, components)
|
|
}
|
|
if((value as OpenAPIV3.SchemaObject).allOf) {
|
|
return resolveAllOf(value as OpenAPIV3.SchemaObject, components)
|
|
}
|
|
if((value as OpenAPIV3.SchemaObject).type || (value as OpenAPIV3.SchemaObject).example) {
|
|
return [(value as OpenAPIV3.SchemaObject).type, (value as OpenAPIV3.SchemaObject).example, null]
|
|
}
|
|
}
|
|
|
|
function resolveAllOf(object: OpenAPIV3.SchemaObject, components: OpenAPIV3.ComponentsObject) : [Object, Object, schemaParameter[]] {
|
|
let examples = new Map<string, any>()
|
|
let schemas = new Map<string, any>()
|
|
let parameters: schemaParameter[] = []
|
|
for (const [key, value] of Object.entries(object.allOf)) {
|
|
let example;
|
|
let schema;
|
|
let parameter;
|
|
if((value as OpenAPIV3.ReferenceObject).$ref) {
|
|
let subcomponentName = (value as OpenAPIV3.ReferenceObject).$ref.split('/').pop()
|
|
let subcomponent = components.schemas[subcomponentName];
|
|
[schema, example, parameter] = resolveComponents(subcomponent, components)
|
|
}
|
|
if((value as OpenAPIV3.SchemaObject).properties) {
|
|
[schema, example, parameter] = resolveProperties(value as OpenAPIV3.SchemaObject, components)
|
|
}
|
|
if(!(example instanceof Map)) {
|
|
example = new Map(Object.entries(example))
|
|
}
|
|
if(!(schema instanceof Map)) {
|
|
schema = new Map(Object.entries(schema))
|
|
}
|
|
parameters = parameters.concat(parameter)
|
|
examples = mergeMaps(examples, example)
|
|
schemas = mergeMaps(schemas, schema)
|
|
}
|
|
return [Object.fromEntries(schemas), Object.fromEntries(examples), parameters]
|
|
}
|
|
|
|
|
|
function resolveProperties(value: OpenAPIV3.SchemaObject, components: OpenAPIV3.ComponentsObject): [Object, Object, schemaParameter[]] {
|
|
let examples = new Map<string, Object>()
|
|
let schemas = new Map<string, Object>()
|
|
let parameters: schemaParameter[] = []
|
|
for(const [key, property] of Object.entries(value.properties)) {
|
|
let type: string = ""
|
|
if(property["$ref"]) {
|
|
let [schema, example, parameter] = resolveComponents(property, components)
|
|
examples.set(key, example)
|
|
schemas.set(key, schema)
|
|
parameters = parameters.concat(parameter)
|
|
continue
|
|
}
|
|
switch (property["type"]) {
|
|
case "array":
|
|
type = ((property["items"] as OpenAPIV3.SchemaObject).type || (property["items"] as OpenAPIV3.ReferenceObject).$ref.split('/').pop()) + "[]"
|
|
let [schema, example] = resolveComponents(property["items"], components)
|
|
examples.set(key, new Array(example))
|
|
schemas.set(key, new Array(schema))
|
|
break;
|
|
case "object":
|
|
default:
|
|
type = property["type"]
|
|
examples.set(key, property["example"])
|
|
schemas.set(key, property["type"])
|
|
}
|
|
let parameter: schemaParameter = {
|
|
name: key,
|
|
type: type,
|
|
description: property["description"],
|
|
required: value.required?.includes(key) || false,
|
|
minimum: property["minimum"],
|
|
maximum: property["maximum"],
|
|
minLength: property["minLength"],
|
|
maxLength: property["maxLength"],
|
|
enum: property["enum"],
|
|
}
|
|
parameters.push(parameter)
|
|
}
|
|
return [Object.fromEntries(schemas), Object.fromEntries(examples), parameters]
|
|
}
|
|
|
|
function mergeMaps(map1: Map<string, Object>, map2: Map<string, Object>) : Map<string, Object> {
|
|
return new Map([...Array.from(map1.entries()), ...Array.from(map2.entries())]);
|
|
}
|