diff --git a/.changeset/salty-pets-notice.md b/.changeset/salty-pets-notice.md new file mode 100644 index 00000000..0b599e3f --- /dev/null +++ b/.changeset/salty-pets-notice.md @@ -0,0 +1,10 @@ +--- +"swagger-typescript-api": patch +--- + +Ensure discriminator mappings use union enum literals. + +Resolve discriminator mapping generation to use literal values when +`generateUnionEnums` is enabled to avoid emitting enum member references. +Add regression coverage that snapshots the discriminator output with +union enums. diff --git a/src/schema-parser/base-schema-parsers/discriminator.ts b/src/schema-parser/base-schema-parsers/discriminator.ts index 4fce9b17..c79e5b49 100644 --- a/src/schema-parser/base-schema-parsers/discriminator.ts +++ b/src/schema-parser/base-schema-parsers/discriminator.ts @@ -177,18 +177,22 @@ export class DiscriminatorSchemaParser extends MonoSchemaParser { ); } - if ( - mappingPropertySchema?.rawTypeData?.$parsed?.type === SCHEMA_TYPES.ENUM - ) { + const parsedEnum = mappingPropertySchema?.rawTypeData?.$parsed; + if (parsedEnum?.type === SCHEMA_TYPES.ENUM) { mappingPropertySchemaEnumKeysMap = lodash.reduce( - mappingPropertySchema.rawTypeData.$parsed.enum, + parsedEnum.enum, (acc, key, index) => { - const enumKey = - mappingPropertySchema.rawTypeData.$parsed.content[index].key; - acc[key] = ts.EnumUsageKey( - mappingPropertySchema.rawTypeData.$parsed.typeName, - enumKey, - ); + const enumContent = parsedEnum.content?.[index]; + if (this.config.generateUnionEnums) { + const literalValue = + enumContent?.value ?? + (key !== undefined ? ts.StringValue(key) : undefined); + if (literalValue !== undefined) { + acc[key] = literalValue; + } + } else if (parsedEnum.typeName && enumContent?.key) { + acc[key] = ts.EnumUsageKey(parsedEnum.typeName, enumContent.key); + } return acc; }, {}, diff --git a/tests/spec/discriminator/__snapshots__/basic.test.ts.snap b/tests/spec/discriminator/__snapshots__/basic.test.ts.snap index ceeccad5..def7b89e 100644 --- a/tests/spec/discriminator/__snapshots__/basic.test.ts.snap +++ b/tests/spec/discriminator/__snapshots__/basic.test.ts.snap @@ -236,3 +236,232 @@ type BaseBlockDtoWithEnumTypeMapping = { } & Type; " `; + +exports[`basic > discriminator with union enums 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 ## + * --------------------------------------------------------------- + */ + +export type PetEnum = "dog" | "lizard" | "cat"; + +export type BlockDTOEnum = "csv" | "file" | "kek"; + +/** kek pek */ +export type Variant = + | ({ + type: "update"; + } & VariantUpdate) + | ({ + type: "undo"; + } & VariantUndo) + | ({ + type: "rollback"; + } & VariantRollback) + | ({ + type: "scale"; + } & VariantScale) + | ({ + type: "resources"; + } & VariantResources) + | ({ + type: "firewall"; + } & VariantFirewall) + | ({ + type: "gateway"; + } & VariantGateway); + +export type InvalidDiscriminatorPropertyName = + BaseInvalidDiscriminatorPropertyName & + ( + | BaseInvalidDiscriminatorPropertyNameTypeMapping<"num", number> + | BaseInvalidDiscriminatorPropertyNameTypeMapping<"str", string> + ); + +export type PetWithEnum = BasePetWithEnum & + ( + | BasePetWithEnumPetTypeMapping<"dog", DogWithEnum> + | BasePetWithEnumPetTypeMapping<"cat", CatWithEnum> + | BasePetWithEnumPetTypeMapping<"lizard", LizardWithEnum> + ); + +export type PetOnlyDiscriminator = + | ({ + pet_type: "dog"; + } & Dog) + | ({ + pet_type: "cat"; + } & Cat) + | ({ + pet_type: "lizard"; + } & Lizard); + +export type Pet = BasePet & + ( + | BasePetPetTypeMapping<"dog", Dog> + | BasePetPetTypeMapping<"cat", Cat> + | BasePetPetTypeMapping<"lizard", Lizard> + ); + +export type BlockDTO = BaseBlockDto & + ( + | BaseBlockDtoTypeMapping<"csv", CsvBlockDTO> + | BaseBlockDtoTypeMapping<"file", FileBlockDTO> + ); + +export type BlockDTOWithEnum = BaseBlockDtoWithEnum & + ( + | BaseBlockDtoWithEnumTypeMapping<"csv", CsvBlockWithEnumDTO> + | BaseBlockDtoWithEnumTypeMapping<"file", FileBlockWithEnumDTO> + ); + +export type SimpleDiscriminator = SimpleObject | ComplexObject; + +export interface SimpleObject { + objectType: string; +} + +export interface ComplexObject { + objectType: string; +} + +export type CsvBlockWithEnumDTO = BaseBlockDtoWithEnum & { + type: "csv"; + text: string; +}; + +export type FileBlockWithEnumDTO = BaseBlockDtoWithEnum & { + type: "file"; + fileId: string; +}; + +export type CsvBlockDTO = BaseBlockDto & { + /** @default "csv" */ + type: "csv"; + text: string; +}; + +export type FileBlockDTO = BaseBlockDto & { + /** @default "file" */ + type: "file"; + fileId: string; +}; + +export type Cat = BasePet & { + name?: string; +}; + +export type Dog = BasePet & { + bark?: string; +}; + +export type Lizard = BasePet & { + lovesRocks?: boolean; +}; + +export type CatWithEnum = BasePetWithEnum & { + name?: string; +}; + +export type DogWithEnum = BasePetWithEnum & { + bark?: string; +}; + +export type LizardWithEnum = BasePetWithEnum & { + lovesRocks?: boolean; +}; + +/** Proposal to change firewall rules for deployment. */ +export interface VariantFirewall { + /** asdasdasdasdasdsad added to deployment. If not set, no rules are added. */ + rules_added?: string[]; + /** asdasdasdasdasdsad removed from deployment. If not set, no rules were removed. */ + rules_removed?: string[]; +} + +/** asdasdasdasdasd */ +export interface VariantScale { + /** + * asdasdasdasdasdsad + * @example 3 + */ + replicas: number; +} + +/** asdasdasdasdasd */ +export interface VariantResources { + resources: string; +} + +/** asdasdasdasdasd */ +export interface VariantGateway { + /** asdasdasdasdasdsad */ + port?: string; + /** asdasdasdasdasdsad */ + name?: string; + /** asdasdasdasdasdsad */ + domain?: string; +} + +/** Pasdasdasdasdasd. */ +export type VariantUpdate = object; + +/** asdasdasdasdasd */ +export interface VariantRollback { + /** + * asdasdasdasdasdsad + * @example 42 + */ + revision_id: number; +} + +/** asdasdasdasdasdn */ +export type VariantUndo = object; + +type BaseInvalidDiscriminatorPropertyName = object; + +type BaseInvalidDiscriminatorPropertyNameTypeMapping = { + "@type": Key; +} & Type; + +interface BasePetWithEnum { + pet_type: PetEnum; +} + +type BasePetWithEnumPetTypeMapping = { + pet_type: Key; +} & Type; + +interface BasePet { + pet_type: string; +} + +type BasePetPetTypeMapping = { + pet_type: Key; +} & Type; + +interface BaseBlockDto { + title: string; +} + +type BaseBlockDtoTypeMapping = { + type: Key; +} & Type; + +interface BaseBlockDtoWithEnum { + title: string; + type: BlockDTOEnum; +} + +type BaseBlockDtoWithEnumTypeMapping = { + type: Key; +} & Type; +" +`; diff --git a/tests/spec/discriminator/basic.test.ts b/tests/spec/discriminator/basic.test.ts index a1a248d6..d347e040 100644 --- a/tests/spec/discriminator/basic.test.ts +++ b/tests/spec/discriminator/basic.test.ts @@ -31,4 +31,22 @@ describe("basic", async () => { expect(content).toMatchSnapshot(); }); + + test("discriminator with union enums", async () => { + await generateApi({ + fileName: "schema", + input: path.resolve(import.meta.dirname, "schema.json"), + output: tmpdir, + silent: true, + addReadonly: true, + generateClient: false, + generateUnionEnums: true, + }); + + const content = await fs.readFile(path.join(tmpdir, "schema.ts"), { + encoding: "utf8", + }); + + expect(content).toMatchSnapshot(); + }); });