Skip to content

Commit 6573fc9

Browse files
committed
fix(schema-typescript): handle numeric and boolean enum/const values
Previously, enum and const handling in getTypeForProp() only supported string values, passing all values to t.stringLiteral(). This crashed when encountering numeric enums (e.g. dimension: { enum: [2, 3, 4] }) or boolean enums/consts. Changes: - Update JSONSchema type: enum accepts (string | number | boolean)[], const accepts string | number | boolean - Fix getTypeForProp() enum handling: use t.numericLiteral() for numbers, t.booleanLiteral() for booleans, t.stringLiteral() for strings - Fix getTypeForProp() const handling: same type-aware literal creation - Change const check from truthy to !== undefined (handles false/0) - Add tests for numeric, boolean, and mixed enum/const values
1 parent 276d212 commit 6573fc9

4 files changed

Lines changed: 138 additions & 7 deletions

File tree

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
2+
3+
exports[`boolean const value 1`] = `
4+
"export interface AlwaysEnabled {
5+
enabled?: true;
6+
disabled?: false;
7+
}"
8+
`;
9+
10+
exports[`boolean enum values 1`] = `
11+
"export interface ToggleConfig {
12+
enabled?: true | false;
13+
}"
14+
`;
15+
16+
exports[`mixed enum values 1`] = `
17+
"export interface MixedConfig {
18+
status?: "active" | "inactive" | 0 | 1 | true;
19+
}"
20+
`;
21+
22+
exports[`numeric const value 1`] = `
23+
"export interface FixedDimension {
24+
dimension: 3;
25+
label: "3D";
26+
}"
27+
`;
28+
29+
exports[`numeric enum values 1`] = `
30+
"export interface PostGISConfig {
31+
dimension: 2 | 3 | 4;
32+
name?: "point" | "linestring" | "polygon";
33+
}"
34+
`;
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { generateTypeScript } from '../src';
2+
3+
it('numeric enum values', () => {
4+
expect(
5+
generateTypeScript({
6+
title: 'PostGISConfig',
7+
type: 'object',
8+
properties: {
9+
dimension: {
10+
type: 'integer',
11+
enum: [2, 3, 4],
12+
description: 'Coordinate dimensionality',
13+
},
14+
name: {
15+
type: 'string',
16+
enum: ['point', 'linestring', 'polygon'],
17+
},
18+
},
19+
required: ['dimension'],
20+
})
21+
).toMatchSnapshot();
22+
});
23+
24+
it('boolean enum values', () => {
25+
expect(
26+
generateTypeScript({
27+
title: 'ToggleConfig',
28+
type: 'object',
29+
properties: {
30+
enabled: {
31+
enum: [true, false],
32+
},
33+
},
34+
})
35+
).toMatchSnapshot();
36+
});
37+
38+
it('mixed enum values', () => {
39+
expect(
40+
generateTypeScript({
41+
title: 'MixedConfig',
42+
type: 'object',
43+
properties: {
44+
status: {
45+
enum: ['active', 'inactive', 0, 1, true],
46+
},
47+
},
48+
})
49+
).toMatchSnapshot();
50+
});
51+
52+
it('numeric const value', () => {
53+
expect(
54+
generateTypeScript({
55+
title: 'FixedDimension',
56+
type: 'object',
57+
properties: {
58+
dimension: {
59+
const: 3,
60+
},
61+
label: {
62+
const: '3D',
63+
},
64+
},
65+
required: ['dimension', 'label'],
66+
})
67+
).toMatchSnapshot();
68+
});
69+
70+
it('boolean const value', () => {
71+
expect(
72+
generateTypeScript({
73+
title: 'AlwaysEnabled',
74+
type: 'object',
75+
properties: {
76+
enabled: {
77+
const: true,
78+
},
79+
disabled: {
80+
const: false,
81+
},
82+
},
83+
})
84+
).toMatchSnapshot();
85+
});

packages/schema-typescript/src/schema.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -268,14 +268,26 @@ function getTypeForProp(
268268
}
269269

270270
if (prop.enum) {
271-
const enumType = prop.enum.map((enumValue) =>
272-
t.tsLiteralType(t.stringLiteral(enumValue))
273-
);
271+
const enumType = prop.enum.map((enumValue) => {
272+
if (typeof enumValue === 'number') {
273+
return t.tsLiteralType(t.numericLiteral(enumValue));
274+
}
275+
if (typeof enumValue === 'boolean') {
276+
return t.tsLiteralType(t.booleanLiteral(enumValue));
277+
}
278+
return t.tsLiteralType(t.stringLiteral(String(enumValue)));
279+
});
274280
return t.tsUnionType(enumType);
275281
}
276282

277-
if (prop.const) {
278-
return t.tsLiteralType(t.stringLiteral(prop.const));
283+
if (prop.const !== undefined) {
284+
if (typeof prop.const === 'number') {
285+
return t.tsLiteralType(t.numericLiteral(prop.const));
286+
}
287+
if (typeof prop.const === 'boolean') {
288+
return t.tsLiteralType(t.booleanLiteral(prop.const));
289+
}
290+
return t.tsLiteralType(t.stringLiteral(String(prop.const)));
279291
}
280292

281293
if (prop.type) {

packages/schema-typescript/src/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ export interface JSONSchema {
55
properties?: { [key: string]: JSONSchema };
66
required?: string[];
77
type?: string;
8-
const?: string;
9-
enum?: string[];
8+
const?: string | number | boolean;
9+
enum?: (string | number | boolean)[];
1010
items?: JSONSchema;
1111
$defs?: { [key: string]: JSONSchema }; // (JSON Schema Draft 2019-09 and later)
1212
definitions?: { [key: string]: JSONSchema }; // (JSON Schema Draft-04 to Draft-07)

0 commit comments

Comments
 (0)