Skip to content

Commit bdba684

Browse files
committed
feat(enum-values): support record type enums
1 parent 5b397de commit bdba684

File tree

2 files changed

+64
-3
lines changed

2 files changed

+64
-3
lines changed

packages/openapi-typescript/src/transform/schema-object.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ import type { ReferenceObject, SchemaObject, TransformNodeOptions } from "../typ
3434
export default function transformSchemaObject(
3535
schemaObject: SchemaObject | ReferenceObject,
3636
options: TransformNodeOptions,
37+
fromAdditionalProperties = false,
3738
): ts.TypeNode {
38-
const type = transformSchemaObjectWithComposition(schemaObject, options);
39+
const type = transformSchemaObjectWithComposition(schemaObject, options, fromAdditionalProperties);
3940
if (typeof options.ctx.postTransform === "function") {
4041
const postTransformResult = options.ctx.postTransform(type, options);
4142
if (postTransformResult) {
@@ -51,6 +52,7 @@ export default function transformSchemaObject(
5152
export function transformSchemaObjectWithComposition(
5253
schemaObject: SchemaObject | ReferenceObject,
5354
options: TransformNodeOptions,
55+
fromAdditionalProperties = false,
5456
): ts.TypeNode {
5557
/**
5658
* Unexpected types & edge cases
@@ -145,7 +147,13 @@ export function transformSchemaObjectWithComposition(
145147

146148
const enumValuesArray = tsArrayLiteralExpression(
147149
enumValuesVariableName,
148-
oapiRef(options.path ?? "", undefined, true),
150+
// If fromAdditionalProperties is true we are dealing with a record type and we should append [string] to the generated type
151+
fromAdditionalProperties
152+
? ts.factory.createIndexedAccessTypeNode(
153+
oapiRef(options.path ?? "", undefined, true),
154+
ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("string")),
155+
)
156+
: oapiRef(options.path ?? "", undefined, true),
149157
schemaObject.enum as (string | number)[],
150158
{
151159
export: true,
@@ -578,7 +586,7 @@ function transformSchemaObjectCore(schemaObject: SchemaObject, options: Transfor
578586
typeof schemaObject.patternProperties === "object" && Object.keys(schemaObject.patternProperties).length;
579587
const stringIndexTypes = [];
580588
if (hasExplicitAdditionalProperties) {
581-
stringIndexTypes.push(transformSchemaObject(schemaObject.additionalProperties as SchemaObject, options));
589+
stringIndexTypes.push(transformSchemaObject(schemaObject.additionalProperties as SchemaObject, options, true));
582590
}
583591
if (hasImplicitAdditionalProperties || (!schemaObject.additionalProperties && options.ctx.additionalProperties)) {
584592
stringIndexTypes.push(UNKNOWN);

packages/openapi-typescript/test/node-api.test.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,59 @@ type ReadonlyArray<T> = [
998998
export const pathsUrlGetParametersQueryStatusValues: ReadonlyArray<FlattenedDeepRequired<paths>["/url"]["get"]["parameters"]["query"]["status"]> = ["active", "inactive"];
999999
export const statusValues: ReadonlyArray<FlattenedDeepRequired<components>["schemas"]["Status"]> = ["active", "inactive"];
10001000
export const errorCodeValues: ReadonlyArray<FlattenedDeepRequired<components>["schemas"]["ErrorCode"]> = [100, 101, 102, 103, 104, 105];
1001+
export type operations = Record<string, never>;`,
1002+
options: { enumValues: true },
1003+
},
1004+
],
1005+
[
1006+
"options > enumValues with record types",
1007+
{
1008+
given: {
1009+
openapi: "3.1",
1010+
info: { title: "Test", version: "1.0" },
1011+
components: {
1012+
schemas: {
1013+
ComplexEditKeyDto: {
1014+
type: "object",
1015+
properties: {
1016+
states: {
1017+
type: "object",
1018+
additionalProperties: {
1019+
type: "string",
1020+
enum: ["TRANSLATED", "REVIEWED"],
1021+
},
1022+
},
1023+
},
1024+
},
1025+
},
1026+
},
1027+
},
1028+
want: `export type paths = Record<string, never>;
1029+
export type webhooks = Record<string, never>;
1030+
export interface components {
1031+
schemas: {
1032+
ComplexEditKeyDto: {
1033+
states?: {
1034+
[key: string]: "TRANSLATED" | "REVIEWED";
1035+
};
1036+
};
1037+
};
1038+
responses: never;
1039+
parameters: never;
1040+
requestBodies: never;
1041+
headers: never;
1042+
pathItems: never;
1043+
}
1044+
export type $defs = Record<string, never>;
1045+
type FlattenedDeepRequired<T> = {
1046+
[K in keyof T]-?: FlattenedDeepRequired<T[K] extends unknown[] | undefined | null ? Extract<T[K], unknown[]>[number] : T[K]>;
1047+
};
1048+
type ReadonlyArray<T> = [
1049+
Exclude<T, undefined>
1050+
] extends [
1051+
unknown[]
1052+
] ? Readonly<Exclude<T, undefined>> : Readonly<Exclude<T, undefined>[]>;
1053+
export const complexEditKeyDtoStatesValues: ReadonlyArray<FlattenedDeepRequired<components>["schemas"]["ComplexEditKeyDto"]["states"][string]> = ["TRANSLATED", "REVIEWED"];
10011054
export type operations = Record<string, never>;`,
10021055
options: { enumValues: true },
10031056
},

0 commit comments

Comments
 (0)