diff --git a/src/configuration.ts b/src/configuration.ts index 8824268fe..ad95ef989 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -53,6 +53,8 @@ export class CodeGenConfig { generateClient = true; /** CLI flag */ generateUnionEnums = false; + /** CLI flag, */ + generateErasableSyntaxEnums = false; /** CLI flag */ addReadonly = false; enumNamesAsValues = false; diff --git a/src/schema-parser/base-schema-parsers/enum.ts b/src/schema-parser/base-schema-parsers/enum.ts index 5f53f6a58..de3917b22 100644 --- a/src/schema-parser/base-schema-parsers/enum.ts +++ b/src/schema-parser/base-schema-parsers/enum.ts @@ -124,9 +124,11 @@ export class EnumSchemaParser extends MonoSchemaParser { schemaType: SCHEMA_TYPES.ENUM, type: SCHEMA_TYPES.ENUM, keyType: keyType, - typeIdentifier: this.config.generateUnionEnums - ? this.config.Ts.Keyword.Type - : this.config.Ts.Keyword.Enum, + typeIdentifier: + this.config.generateUnionEnums || + this.config.generateErasableSyntaxEnums + ? this.config.Ts.Keyword.Type + : this.config.Ts.Keyword.Enum, name: this.typeName, description: this.schemaFormatters.formatDescription( this.schema.description, diff --git a/src/schema-parser/schema-formatters.ts b/src/schema-parser/schema-formatters.ts index ccd57d7de..7a35cd0af 100644 --- a/src/schema-parser/schema-formatters.ts +++ b/src/schema-parser/schema-formatters.ts @@ -27,6 +27,16 @@ export class SchemaFormatters { parsedSchema.content.map(({ value }) => value), ), }; + } else if (this.config.generateErasableSyntaxEnums) { + return { + ...parsedSchema, + $content: parsedSchema.content, + content: this.config.Ts.ObjectWrapper( + parsedSchema.content.map( + ({ key, value }) => `${this.config.Ts.TypeField({ key, value })}`, + ), + ), + }; } return { diff --git a/templates/base/enum-data-contract.ejs b/templates/base/enum-data-contract.ejs index 56107460b..885c8e4d1 100644 --- a/templates/base/enum-data-contract.ejs +++ b/templates/base/enum-data-contract.ejs @@ -5,6 +5,12 @@ const { name, $content } = contract; %> <% if (config.generateUnionEnums) { %> export type <%~ name %> = <%~ _.map($content, ({ value }) => value).join(" | ") %> +<% } else if (config.generateErasableSyntaxEnums) { %> + export const <%~ name %>: { [key: string]: string } = { + <%~ _.map($content, ({key, value}) => `${key}: "${value}"`).join(",\n") %> + } as const; + + export type <%~ name %> = typeof <%~ name %>[keyof typeof <%~ name %>]; <% } else { %> export enum <%~ name %> { <%~ _.map($content, ({ key, value }) => `${key} = ${value}`).join(",\n") %> diff --git a/tests/spec/enumsErasableSyntax/__snapshots__/basic.test.ts.snap b/tests/spec/enumsErasableSyntax/__snapshots__/basic.test.ts.snap new file mode 100644 index 000000000..0e17874c5 --- /dev/null +++ b/tests/spec/enumsErasableSyntax/__snapshots__/basic.test.ts.snap @@ -0,0 +1,112 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`basic > enumsErasableSyntax 1`] = ` +"/* eslint-disable */ +/* tslint:disable */ +// @ts-nocheck +/* + * --------------------------------------------------------------- + * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ## + * ## ## + * ## AUTHOR: acacode ## + * ## SOURCE: https://github.com/acacode/swagger-typescript-api ## + * --------------------------------------------------------------- + */ + +/** @format int32 */ +export type SomeInterestEnum = { + Bla: 6; + Blabla: 2; + Boiler: 1; + Bbabab: 67; + Nowadays: 88; + FAIL: 122; + Vvvvv: 88; + ASdasAS: 0; + ASDsacZX: 213; + Zook: 12378; + EnumMm: 123125; + VCsa: 32452; + Yuuu: 1111; + ASddd: 66666; + ASdsdsa: "ASdsdsa"; + ASDds: "ASDds"; + HSDFDS: "HSDFDS"; +}; + +/** @format int32 */ +export type EnumWithMoreNames = { + Bla: 1; + Blabla: "Blabla"; + Boiler: "Boiler"; +}; + +export type StringCompleteEnums = { + Bla: "foo"; + Blabla: "bar"; + Boiler: "baz"; +}; + +export type StringEnums = { + Bla: "foo"; + Blabla: "bar"; + Boiler: "Boiler"; +}; + +export type SimpleEnumNonNullable = { + Value0: 0; + Value1: 1; + Value2: 2; + Value3: 3; + Value4: 4; + Value5: 5; +}; + +export type XNullableEnum = { + Value0: 0; + Value1: 1; + Value2: 2; + Value3: 3; + Value4: 4; + Value5: 5; +}; + +export type Currency = { + USDollar: "USD"; + Euro: "EUR"; + RussianRuble: "RUB"; +}; + +export interface ObjWithEnum { + "prop-enum-nullable"?: 0 | 1 | 2 | 3 | 4 | 5 | null; + "prop-enum"?: 0 | 1 | 2 | 3 | 4 | 5; +} + +export type OnlyEnumNames = { + Bla: "Bla"; + Blabla: "Blabla"; + Boiler: "Boiler"; +}; + +export type StringOnlyEnumNames = { + Bla: "Bla"; + Blabla: "Blabla"; + Boiler: "Boiler"; +}; + +/** @format int32 */ +export type EmptyEnum = { + Bla: "Bla"; + Blabla: "Blabla"; + Boiler: "Boiler"; +}; + +export interface PostFooPayload { + someTypeId?: 1 | 2 | 3 | 4 | 5; +} + +export interface PostFooParams { + testKek: 1 | 2 | 3 | 4 | 5; +} +" +`; diff --git a/tests/spec/enumsErasableSyntax/basic.test.ts b/tests/spec/enumsErasableSyntax/basic.test.ts new file mode 100644 index 000000000..e352c1a52 --- /dev/null +++ b/tests/spec/enumsErasableSyntax/basic.test.ts @@ -0,0 +1,40 @@ +import * as fs from "node:fs/promises"; +import * as os from "node:os"; +import * as path from "node:path"; + +import { afterAll, beforeAll, describe, expect, test } from "vitest"; + +import { generateApi } from "../../../src/index.js"; + +describe("basic", async () => { + let tmpdir = ""; + + beforeAll(async () => { + tmpdir = await fs.mkdtemp(path.join(os.tmpdir(), "swagger-typescript-api")); + }); + + afterAll(async () => { + await fs.rm(tmpdir, { recursive: true }); + }); + + test("enumsErasableSyntax", async () => { + await generateApi({ + fileName: "schema", + input: path.resolve(import.meta.dirname, "schema.json"), + output: tmpdir, + silent: true, + extractRequestParams: true, + extractRequestBody: true, + extractResponseBody: true, + extractResponseError: true, + generateClient: false, + generateErasableSyntaxEnums: true, + }); + + const content = await fs.readFile(path.join(tmpdir, "schema.ts"), { + encoding: "utf8", + }); + + expect(content).toMatchSnapshot(); + }); +}); diff --git a/tests/spec/enumsErasableSyntax/schema.json b/tests/spec/enumsErasableSyntax/schema.json new file mode 100644 index 000000000..f9d9b4953 --- /dev/null +++ b/tests/spec/enumsErasableSyntax/schema.json @@ -0,0 +1,123 @@ +{ + "swagger": "2.0", + "schemes": ["https"], + "host": "ffff.com", + "basePath": "/", + "info": {}, + "definitions": { + "objWithEnum": { + "type": "object", + "properties": { + "prop-enum-nullable": { + "type": "integer", + "x-nullable": true, + "enum": [0, 1, 2, 3, 4, 5] + }, + "prop-enum": { + "type": "integer", + "enum": [0, 1, 2, 3, 4, 5] + } + } + }, + "currency": { + "type": "string", + "enum": ["USD", "EUR", "RUB"], + "x-enumNames": ["US Dollar", "Euro", "Russian Ruble"] + }, + "x-nullable-enum": { + "type": "integer", + "x-nullable": true, + "enum": [0, 1, 2, 3, 4, 5] + }, + "simple-enum-non-nullable": { + "type": "integer", + "enum": [0, 1, 2, 3, 4, 5] + }, + "OnlyEnumNames": { + "x-enumNames": ["Bla", "Blabla", "Boiler"] + }, + "StringOnlyEnumNames": { + "type": "int32", + "x-enumNames": ["Bla", "Blabla", "Boiler"] + }, + "StringEnums": { + "type": "int32", + "enum": ["foo", "bar"], + "x-enumNames": ["Bla", "Blabla", "Boiler"] + }, + "StringCompleteEnums": { + "type": "int32", + "enum": ["foo", "bar", "baz"], + "x-enumNames": ["Bla", "Blabla", "Boiler"] + }, + "EmptyEnum": { + "format": "int32", + "type": "integer", + "x-enumNames": ["Bla", "Blabla", "Boiler"] + }, + "EnumWithMoreNames": { + "format": "int32", + "type": "integer", + "enum": [1], + "x-enumNames": ["Bla", "Blabla", "Boiler"] + }, + "SomeInterestEnum": { + "format": "int32", + "enum": [ + 6, 2, 1, 67, 88, 122, 88, 0, 213, 12378, 123125, 32452, 1111, 66666 + ], + "type": "integer", + "x-enumNames": [ + "Bla", + "Blabla", + "Boiler", + "Bbabab", + "Nowadays", + "FAIL", + "Vvvvv", + "ASdasAS", + "ASDsacZX", + "Zook", + "EnumMm", + "VCsa", + "Yuuu", + "ASddd", + "ASdsdsa", + "ASDds", + "HSDFDS" + ] + } + }, + "paths": { + "/foo": { + "post": { + "operationId": "postFoo", + "parameters": [ + { + "in": "query", + "name": "testKek", + "required": true, + "type": "integer", + "enum": [1, 2, 3, 4, 5] + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "someTypeId": { + "type": "integer", + "enum": [1, 2, 3, 4, 5] + } + } + } + } + } + }, + "responses": {} + } + } + } +} diff --git a/types/index.ts b/types/index.ts index 42736d932..f4dfd03dc 100644 --- a/types/index.ts +++ b/types/index.ts @@ -682,6 +682,7 @@ export interface GenerateApiConfiguration { generateRouteTypes: boolean; generateClient: boolean; generateUnionEnums: boolean; + generateErasableSyntaxEnums: boolean; swaggerSchema: object; originalSchema: object; componentsMap: Record;