Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/salty-pets-notice.md
Original file line number Diff line number Diff line change
@@ -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.
24 changes: 14 additions & 10 deletions src/schema-parser/base-schema-parsers/discriminator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
},
{},
Expand Down
229 changes: 229 additions & 0 deletions tests/spec/discriminator/__snapshots__/basic.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -236,3 +236,232 @@ type BaseBlockDtoWithEnumTypeMapping<Key, Type> = {
} & 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<Key, Type> = {
"@type": Key;
} & Type;

interface BasePetWithEnum {
pet_type: PetEnum;
}

type BasePetWithEnumPetTypeMapping<Key, Type> = {
pet_type: Key;
} & Type;

interface BasePet {
pet_type: string;
}

type BasePetPetTypeMapping<Key, Type> = {
pet_type: Key;
} & Type;

interface BaseBlockDto {
title: string;
}

type BaseBlockDtoTypeMapping<Key, Type> = {
type: Key;
} & Type;

interface BaseBlockDtoWithEnum {
title: string;
type: BlockDTOEnum;
}

type BaseBlockDtoWithEnumTypeMapping<Key, Type> = {
type: Key;
} & Type;
"
`;
18 changes: 18 additions & 0 deletions tests/spec/discriminator/basic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});
});