Add workflow for api gen and refactor genration script (#60)

* 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>
This commit is contained in:
pascal-fischer
2023-06-05 09:35:54 +02:00
committed by GitHub
parent 33b3153723
commit f33b4df3dd
20 changed files with 481 additions and 5928 deletions

View File

@@ -1,13 +1,12 @@
import template from './templates/ApiTemplate'
import { slugify, toArrayWithKey, toTitle, writeToDisk } from './helpers'
import { OpenAPIV3, OpenAPIV2 } from 'openapi-types'
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
// console.log('spec', spec)
switch (spec.openapi || spec.swagger) {
case '3.0.0':
@@ -79,90 +78,7 @@ async function gen_v3(spec: OpenAPIV3.Document, dest: string) {
})
})
let components = new Map<string, component>();
Object.entries(spec.components?.schemas).forEach(([key, val]) => {
const schema = val as OpenAPIV3.SchemaObject
let outputSchema = new Map<string, any>();
let outputExample = new Map<string, any>();
let parameters : schemaParameter[] = []
if(schema.allOf){
schema.allOf.forEach((item) => {
if((item as OpenAPIV3.ReferenceObject).$ref){
let component = components.get((item as OpenAPIV3.ReferenceObject).$ref.split('/').pop())
let schemaMap = new Map(Object.entries(component.schema))
let exampleMap = new Map(Object.entries(component.example))
schemaMap.forEach((value, key) => {
outputSchema.set(key, value)
})
exampleMap.forEach((value, key) => {
outputExample.set(key, value)
})
parameters = parameters.concat(component.parameters)
}
if((item as OpenAPIV3.SchemaObject).properties){
Object.entries((item as OpenAPIV3.SchemaObject).properties).forEach(([key, val]) => {
let property = val as OpenAPIV3.SchemaObject
let type, exampleValue
if (property.type === "array") {
type = new Array(resolveType(property.items, spec.components?.schemas))
exampleValue = new Array(resolveExampleValue(property.items, spec.components?.schemas))
} else {
type = resolveType(property, spec.components?.schemas)
exampleValue = resolveExampleValue(property, spec.components?.schemas)
}
outputSchema.set(key, type)
outputExample.set(key, exampleValue)
let parameter: schemaParameter = {
name: key,
type: property.type === "array" ? ((property.items as OpenAPIV3.SchemaObject).type || (property.items as OpenAPIV3.ReferenceObject).$ref.split('/').pop()) + "[]" : property.type,
description: property.description,
required: schema.required?.includes(key) || false,
minimum: property.minimum,
maximum: property.maximum,
minLength: property.minLength,
maxLength: property.maxLength,
enum: property.enum
}
parameters.push(parameter)
})
}
})
} else {
Object.entries(schema.properties).forEach(([key, val]) => {
let property = val as OpenAPIV3.SchemaObject
let type, exampleValue
if(property.type === "array"){
type = new Array(resolveType(property.items, spec.components?.schemas))
exampleValue = new Array(resolveExampleValue(property.items, spec.components?.schemas))
} else {
type = resolveType(property, spec.components?.schemas)
exampleValue = resolveExampleValue(property, spec.components?.schemas)
}
outputSchema.set(key, type)
outputExample.set(key, exampleValue)
let parameter : schemaParameter = {
name: key,
type: property.type === "array" ? ((property.items as OpenAPIV3.SchemaObject).type || (property.items as OpenAPIV3.ReferenceObject).$ref.split('/').pop()) + "[]" : property.type,
description: property.description,
required: schema.required?.includes(key) || false,
minimum: property.minimum,
maximum: property.maximum,
minLength: property.minLength,
maxLength: property.maxLength,
enum: property.enum
}
parameters.push(parameter)
})
}
let output : component = {
example: Object.fromEntries(outputExample),
schema: Object.fromEntries(outputSchema),
parameters: parameters
}
components.set(key, output)
})
let components = readComponents(spec.components)
tagGroups.forEach((value: enrichedOperation[], key: string) => {
@@ -192,42 +108,111 @@ async function gen_v3(spec: OpenAPIV3.Document, dest: string) {
})
}
function resolveType(items: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject | OpenAPIV3.NonArraySchemaObjectType, schemas) : any {
if((items as OpenAPIV3.ReferenceObject).$ref){
let ref = (items as OpenAPIV3.ReferenceObject).$ref
let map = new Map<string, any>()
Object.entries(schemas[ref.split('/').pop()].properties).forEach(([key, val]) => {
let property = val as OpenAPIV3.SchemaObject
let type
if(property.type === "array"){
type = new Array(resolveType(property.items, schemas))
} else {
type = resolveType(property, schemas)
}
map.set(key, type)
})
return Object.fromEntries(map)
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 (items as OpenAPIV3.ArraySchemaObject).type
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 resolveExampleValue(items: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject | OpenAPIV3.NonArraySchemaObjectType, schemas) : any {
if((items as OpenAPIV3.ReferenceObject).$ref){
let ref = (items as OpenAPIV3.ReferenceObject).$ref
let map = new Map<string, any>()
Object.entries(schemas[ref.split('/').pop()].properties).forEach(([key, val]) => {
let property = val as OpenAPIV3.SchemaObject
let exampleValue
if(property.type === "array"){
exampleValue = new Array(resolveExampleValue(property.items, schemas))
} else {
exampleValue = resolveExampleValue(property, schemas)
}
map.set(key, exampleValue)
})
return Object.fromEntries(map)
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 (items as OpenAPIV3.ArraySchemaObject).example
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())]);
}