given this input:
openapi: 3.0.1
info:
title: test enums
description: test enums
version: "1.00"
components:
schemas:
VideoProcessingStateDto:
type: string
enum:
- IN_PROGRESS
- FAILED
- FINISHED
I wish to generate the following typescript enum
export enum VideoProcessingStateDto {
IN_PROGRESS = 'IN_PROGRESS',
FAILED = 'FAILED',
FINISHED = 'FINISHED',
}
However, openapi-typescript continues to give me a string union as such:
/** @enum {string} */
VideoProcessingStateDto: "IN_PROGRESS" | "FAILED" | "FINISHED";
Is it possible to configure openapi-typescript to generate enums in this case?
Based on a very superficial glance at the source code, I am not seeing any configuration options
Perhaps I am not defining the enum correctly in the input?
Any guidance would be greatly appreciated, thank you!
Ok so I decided to engage with the transform
option on the API, which allows users to reshape the output as needed. In this case, I am replacing the value with the name of an enum, generating a enum from the values in the union, and adding them to a cache.
When it comes time to output the results to the file, I am then appending the enums to the end of the file so that they exist when they are referenced in the schema components.
This is very rough code and you will probably need to modify it to meet you needs but here is all the code.
import openapiTS, { SchemaObject } from 'openapi-typescript';
import * as fs from 'node:fs';
// Utility function to get the name of the schema from the path
function getSchemaName(str: string) {
const arr = str.split('/');
const schemaName = arr[arr.length - 1];
return schemaName;
}
/** trasform the sting union of "IN_PROGRESS" | "FAILED" | "FINISHED"
* to a typescript enum like:
* enum Status {
* IN_PROGRESS = "IN_PROGRESS",
* FAILED = "FAILED",
* FINISHED = "FINISHED"
* }
*/
function unionToEnum(enumValues: string[], enumName: string) {
const enumString = enumValues
.map((value) => `${value} = "${value}"`)
.join(',\n');
const enumType = `enum ${enumName} {
${enumString}
}`;
return enumType;
}
async function generateTypesFromSchema(): Promise<string> {
const localPath = new URL('api.yml', import.meta.url);
const output = await openapiTS(localPath, {
transform: collectAndTransformEnums,
});
if (output) {
return output;
}
return '';
}
const enumCache = new Map();
function collectAndTransformEnums(
schemaObject: SchemaObject,
metadata: any
): string {
if ('enum' in schemaObject) {
const enumName = getSchemaName(metadata.path);
const enumValues = schemaObject.enum as string[];
enumCache.set(getSchemaName(enumName), unionToEnum(enumValues, enumName));
return enumName;
}
return '';
}
/**
* 1. generate the types from the schema
* 2. iterate over the enumCache and add the enums to the types
* 3. write the types to a file
*/
generateTypesFromSchema().then((types) => {
enumCache.forEach((enumType) => {
types += enumType;
});
// write the types to a file
return fs.writeFile('defs/types.ts', types, (err) => {
if (err) {
console.error(err);
return;
}
});
});
Using the script above, given this input:
openapi: 3.0.1
info:
title: Sample Video API
description: Sample Video API
version: '1.0'
paths:
/api/v1/video-process:
get:
tags:
- video
summary: Process a video input
operationId: VideoProcess
responses:
'200':
description: Successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/VideoProcessingStateDto'
components:
schemas:
VideoProcessingStateDto:
type: string
enum:
- IN_PROGRESS
- FAILED
- FINISHED
The output will be:
/**
* This file was auto-generated by openapi-typescript.
* Do not make direct changes to the file.
*/
export interface paths {
'/api/v1/video-process': {
/** Process a video input */
get: operations['VideoProcess'];
};
}
export type webhooks = Record<string, never>;
export interface components {
schemas: {
/** @enum {string} */
VideoProcessingStateDto: VideoProcessingStateDto;
};
responses: never;
parameters: never;
requestBodies: never;
headers: never;
pathItems: never;
}
export type external = Record<string, never>;
export interface operations {
/** Process a video input */
VideoProcess: {
responses: {
/** @description Successful operation */
200: {
content: {
'application/json': components['schemas']['VideoProcessingStateDto'];
};
};
};
};
}
enum VideoProcessingStateDto {
IN_PROGRESS = 'IN_PROGRESS',
FAILED = 'FAILED',
FINISHED = 'FINISHED',
}