Skip to content

Commit 15524ca

Browse files
FedeBevFederico Bevione
and
Federico Bevione
authored
Fix wrong generated type when processing enums containing "null" (#492)
* add failing test * fix generated type when processing enums containing "null" Fix issue #482 * remove useless code * avoid double null when enum contains null and is nullable Co-authored-by: Federico Bevione <[email protected]>
1 parent d46d47e commit 15524ca

File tree

7 files changed

+214
-5
lines changed

7 files changed

+214
-5
lines changed

src/transform/schema.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,13 @@ export function transformSchemaObj(node: any): string {
6767
break;
6868
}
6969
case "enum": {
70-
output += tsUnionOf(
71-
(node.enum as string[]).map((item) => (typeof item === "string" ? `'${item.replace(/'/g, "\\'")}'` : item))
72-
);
70+
const items: Array<string | number | boolean> = [];
71+
(node.enum as unknown[]).forEach((item) => {
72+
if (typeof item === "string") items.push(`'${item.replace(/'/g, "\\'")}'`);
73+
else if (typeof item === "number" || typeof item === "boolean") items.push(item);
74+
else if (item === null && !node.nullable) items.push("null");
75+
});
76+
output += tsUnionOf(items);
7377
break;
7478
}
7579
case "object": {

src/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ export function tsPartial(type: string): string {
125125
}
126126

127127
/** Convert [X, Y, Z] into X | Y | Z */
128-
export function tsUnionOf(types: string[]): string {
129-
if (types.length === 1) return types[0]; // don’t add parentheses around one thing
128+
export function tsUnionOf(types: Array<string | number | boolean>): string {
129+
if (types.length === 1) return `${types[0]}`; // don’t add parentheses around one thing
130130
return `(${types.join(") | (")})`;
131131
}
132132

tests/schema.test.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,46 @@ describe("SchemaObject", () => {
103103
).toBe(`{
104104
"string"?: ('Totoro') | ('Sats\\'uki') | ('Mei');
105105
106+
}`);
107+
108+
expect(
109+
transform({
110+
properties: { string: { type: "string", enum: ["Totoro", "Sats'uki", "Mei", null] } }, // note: also tests quotes in enum
111+
type: "object",
112+
})
113+
).toBe(`{
114+
"string"?: ('Totoro') | ('Sats\\'uki') | ('Mei') | (null);
115+
116+
}`);
117+
118+
expect(
119+
transform({
120+
properties: { string: { type: "string", enum: ["Totoro", 2, false, null] } }, // note: also tests quotes in enum
121+
type: "object",
122+
})
123+
).toBe(`{
124+
"string"?: ('Totoro') | (2) | (false) | (null);
125+
126+
}`);
127+
128+
expect(
129+
transform({
130+
properties: { string: { type: "string", enum: ["Totoro", 2, false, null], nullable: true } }, // note: also tests quotes in enum
131+
type: "object",
132+
})
133+
).toBe(`{
134+
"string"?: (('Totoro') | (2) | (false)) | null;
135+
136+
}`);
137+
138+
expect(
139+
transform({
140+
properties: { string: { type: "string", enum: ["Totoro", 2, false], nullable: true } }, // note: also tests quotes in enum
141+
type: "object",
142+
})
143+
).toBe(`{
144+
"string"?: (('Totoro') | (2) | (false)) | null;
145+
106146
}`);
107147
});
108148

tests/v2/expected/null-in-enum.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* This file was auto-generated by openapi-typescript.
3+
* Do not make direct changes to the file.
4+
*/
5+
6+
export interface paths {
7+
"/test": {
8+
post: operations["addTest"];
9+
};
10+
}
11+
12+
export interface definitions {
13+
/** Enum with null and nullable */
14+
MyType: {
15+
myField?: ("foo" | "bar") | null;
16+
};
17+
/** Enum with null */
18+
MyTypeNotNullable: {
19+
myField?: "foo" | "bar" | null;
20+
};
21+
/** Enum with null */
22+
MyTypeNotNullableNotNull: {
23+
myField?: "foo" | "bar";
24+
};
25+
/** Enum with null */
26+
MyTypeMixed: {
27+
myField?: "foo" | 2 | false | null;
28+
};
29+
}
30+
31+
export interface operations {
32+
addTest: {
33+
responses: {
34+
/** OK */
35+
200: unknown;
36+
};
37+
};
38+
}

tests/v2/specs/null-in-enum.yaml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
swagger: 2.0
2+
paths:
3+
/test:
4+
post:
5+
tags:
6+
- "test"
7+
summary: "Just a test path"
8+
description: ""
9+
operationId: "addTest"
10+
consumes:
11+
- "application/json"
12+
- "application/xml"
13+
produces:
14+
- "application/xml"
15+
- "application/json"
16+
responses:
17+
200:
18+
description: "OK"
19+
definitions:
20+
MyType:
21+
description: Enum with null and nullable
22+
type: object
23+
properties:
24+
myField:
25+
type: string
26+
enum: ["foo", "bar", null]
27+
nullable: true
28+
MyTypeNotNullable:
29+
description: Enum with null
30+
type: object
31+
properties:
32+
myField:
33+
type: string
34+
enum: ["foo", "bar", null]
35+
MyTypeNotNullableNotNull:
36+
description: Enum with null
37+
type: object
38+
properties:
39+
myField:
40+
type: string
41+
enum: ["foo", "bar"]
42+
MyTypeMixed:
43+
description: Enum with null
44+
type: object
45+
properties:
46+
myField:
47+
type: string
48+
enum: ["foo", 2, false, null]

tests/v3/expected/null-in-enum.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* This file was auto-generated by openapi-typescript.
3+
* Do not make direct changes to the file.
4+
*/
5+
6+
export interface paths {
7+
"/test": {
8+
get: {
9+
responses: {
10+
/** A list of types. */
11+
200: unknown;
12+
};
13+
};
14+
};
15+
}
16+
17+
export interface components {
18+
schemas: {
19+
/** Enum with null and nullable */
20+
MyType: {
21+
myField?: ("foo" | "bar") | null;
22+
};
23+
/** Enum with null */
24+
MyTypeNotNullable: {
25+
myField?: "foo" | "bar" | null;
26+
};
27+
/** Enum with null */
28+
MyTypeNotNullableNotNull: {
29+
myField?: "foo" | "bar";
30+
};
31+
/** Enum with null */
32+
MyTypeMixed: {
33+
myField?: "foo" | 2 | false | null;
34+
};
35+
};
36+
}
37+
38+
export interface operations {}

tests/v3/specs/null-in-enum.yaml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
openapi: 3.0
2+
paths:
3+
/test:
4+
get:
5+
tags:
6+
- test
7+
summary: "Just a test path"
8+
responses:
9+
200:
10+
description: A list of types.
11+
components:
12+
schemas:
13+
MyType:
14+
description: Enum with null and nullable
15+
type: object
16+
properties:
17+
myField:
18+
type: string
19+
enum: ["foo", "bar", null]
20+
nullable: true
21+
MyTypeNotNullable:
22+
description: Enum with null
23+
type: object
24+
properties:
25+
myField:
26+
type: string
27+
enum: ["foo", "bar", null]
28+
MyTypeNotNullableNotNull:
29+
description: Enum with null
30+
type: object
31+
properties:
32+
myField:
33+
type: string
34+
enum: ["foo", "bar"]
35+
MyTypeMixed:
36+
description: Enum with null
37+
type: object
38+
properties:
39+
myField:
40+
type: string
41+
enum: ["foo", 2, false, null]

0 commit comments

Comments
 (0)