Skip to content

Commit 2315827

Browse files
committed
Enums can now be required again, as they don't need an explicit default value anymore.
If no default value exists, the first enum value will be used. Fixes #333
1 parent 69168cc commit 2315827

File tree

5 files changed

+97
-30
lines changed

5 files changed

+97
-30
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Fixed
1111

12-
- Array data was set to `undefined` when `dataType: 'json'` was set.
12+
- Enums can now be required again, as they don't need an explicit default value anymore. If no default value exists, the first enum value will be used.
13+
- Empty arrays were set to `undefined` for `dataType: 'json'`.
1314

1415
## [2.0.0] - 2024-02-11
1516

src/lib/jsonSchema/schemaDefaults.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,9 @@ function _defaultValues(schema: JSONSchema, isOptional: boolean, path: string[])
108108
return objectDefaults;
109109
}
110110

111-
// Enums
111+
// Enums, return the first value so it can be a required field
112112
if (schema.enum) {
113-
throw new SchemaError('Enums must have a default value in the schema.', path);
114-
//return schema.enum[0];
113+
return schema.enum[0];
115114
}
116115

117116
// Basic type

src/routes/(v1)/test/+page.server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export const _dataTypeForm = z.object({
3434
date: z.date().optional().default(new Date()),
3535
coercedNumber: z.coerce.number().default(0).optional(),
3636
coercedDate: z.coerce.date().optional(),
37-
nativeEnumInt: z.nativeEnum(Fruits).default(Fruits.Apple),
37+
nativeEnumInt: z.nativeEnum(Fruits),
3838
nativeEnumString: z.nativeEnum({ GRAY: 'GRAY', GREEN: 'GREEN' }).default('GREEN'),
3939
nativeEnumString2: z.nativeEnum(FruitsStr).default(FruitsStr.Banana)
4040
});

src/tests/JSONSchema.test.ts

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ describe('Default values', () => {
123123
});
124124
});
125125

126-
it('should map default values for enums to the first enum value', () => {
126+
it('should use the default value for enums if set', () => {
127127
enum Fruits {
128128
Apple = 2,
129129
Banana = 3
@@ -136,7 +136,6 @@ describe('Default values', () => {
136136

137137
const schema = {
138138
type: 'object',
139-
required: ['nativeEnumInt', 'nativeEnumString', 'nativeEnumString2'],
140139
properties: {
141140
nativeEnumInt: {
142141
type: 'number',
@@ -163,6 +162,43 @@ describe('Default values', () => {
163162
});
164163
});
165164

165+
it('should map default values for enums to the first enum value', () => {
166+
enum Fruits {
167+
Apple = 2,
168+
Banana = 3
169+
}
170+
171+
enum FruitsStr {
172+
Apple = 'Apple',
173+
Banana = 'Banana'
174+
}
175+
176+
const schema = {
177+
type: 'object',
178+
required: ['nativeEnumInt', 'nativeEnumString', 'nativeEnumString2'],
179+
properties: {
180+
nativeEnumInt: {
181+
type: 'number',
182+
enum: Object.keys(Fruits).map(parseInt)
183+
},
184+
nativeEnumString: {
185+
type: 'string',
186+
enum: ['GRAY', 'GREEN']
187+
},
188+
nativeEnumString2: {
189+
type: 'string',
190+
enum: Object.values(FruitsStr)
191+
}
192+
}
193+
} satisfies JSONSchema7;
194+
195+
expect(defaultValues(schema)).toEqual({
196+
nativeEnumInt: 2,
197+
nativeEnumString: 'GRAY',
198+
nativeEnumString2: 'Apple'
199+
});
200+
});
201+
166202
it('should handle native Date through the unix-time format', () => {
167203
const date = new Date();
168204
const schema = {

src/tests/superValidate.test.ts

Lines changed: 54 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,7 @@ import { zod, zodToJSONSchema } from '$lib/adapters/zod.js';
2121
import { z } from 'zod';
2222

2323
import { valibot } from '$lib/adapters/valibot.js';
24-
import {
25-
object,
26-
string,
27-
email,
28-
minLength,
29-
array,
30-
integer,
31-
number,
32-
minValue,
33-
date,
34-
optional,
35-
regex,
36-
transform
37-
} from 'valibot';
24+
import * as v from 'valibot';
3825

3926
//import { ajv } from '$lib/adapters/ajv.js';
4027
//import type { JSONSchema } from '$lib/jsonSchema/index.js';
@@ -204,13 +191,13 @@ describe('Arktype', () => {
204191
/////////////////////////////////////////////////////////////////////
205192

206193
describe('Valibot', () => {
207-
const schema = object({
208-
name: optional(string(), 'Unknown'),
209-
email: string([email()]),
210-
tags: array(string([minLength(2)]), [minLength(3)]),
211-
score: number([integer(), minValue(0)]),
212-
date: optional(date()),
213-
nospace: optional(string([regex(nospacePattern)]))
194+
const schema = v.object({
195+
name: v.optional(v.string(), 'Unknown'),
196+
email: v.string([v.email()]),
197+
tags: v.array(v.string([v.minLength(2)]), [v.minLength(3)]),
198+
score: v.number([v.integer(), v.minValue(0)]),
199+
date: v.optional(v.date()),
200+
nospace: v.optional(v.string([v.regex(nospacePattern)]))
214201
});
215202

216203
describe('Introspection', () => {
@@ -220,6 +207,26 @@ describe('Valibot', () => {
220207
describe('Defaults', () => {
221208
schemaTest(valibot(schema, { defaults }), undefined, 'simple');
222209
});
210+
211+
it('should produce a required enum if no default', () => {
212+
const schema = v.object({
213+
enum: v.picklist(['a', 'b', 'c']),
214+
enumDef: v.optional(v.picklist(['a', 'b', 'c']), 'b')
215+
});
216+
217+
const adapter = valibot(schema);
218+
expect(adapter.jsonSchema.required).toEqual(['enum']);
219+
expect(adapter.defaults).toEqual({
220+
enum: 'a',
221+
enumDef: 'b'
222+
});
223+
224+
// Change defaults
225+
adapter.defaults.enum = '' as 'a';
226+
227+
const a2 = valibot(schema);
228+
expect(a2.defaults.enum).toBe('');
229+
});
223230
});
224231

225232
/////////////////////////////////////////////////////////////////////
@@ -343,6 +350,30 @@ describe('Zod', () => {
343350
num;
344351
});
345352

353+
it('should produce a required enum if no default', () => {
354+
enum Fruits {
355+
Apple = 7,
356+
Banana = 8
357+
}
358+
359+
const schema = z.object({
360+
nativeEnumInt: z.nativeEnum(Fruits),
361+
nativeEnumString: z.nativeEnum({ GRAY: 'GRAY', GREEN: 'GREEN' }).default('GREEN'),
362+
enum: z.enum(['a', 'b', 'c']),
363+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
364+
enumDef: z.enum(['a', 'b', 'c']).default('' as any)
365+
});
366+
367+
const adapter = zod(schema);
368+
expect(adapter.jsonSchema.required).toEqual(['nativeEnumInt', 'enum', 'enumDef']);
369+
expect(adapter.defaults).toEqual({
370+
nativeEnumInt: Fruits.Apple,
371+
nativeEnumString: 'GREEN',
372+
enum: 'a',
373+
enumDef: ''
374+
});
375+
});
376+
346377
schemaTest(zod(schema));
347378
});
348379

@@ -377,8 +408,8 @@ describe('Schema In/Out transformations', () => {
377408
});
378409

379410
it('does not fully work with Valibot', async () => {
380-
const schema = object({
381-
len: transform(string(), (s) => s.length)
411+
const schema = v.object({
412+
len: v.transform(v.string(), (s) => s.length)
382413
});
383414

384415
// @ts-expect-error Using schema Out type as In - Not allowed

0 commit comments

Comments
 (0)