-
-
Notifications
You must be signed in to change notification settings - Fork 258
Expand file tree
/
Copy pathjsonschema-to-zod.test.ts
More file actions
131 lines (107 loc) · 4.33 KB
/
jsonschema-to-zod.test.ts
File metadata and controls
131 lines (107 loc) · 4.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import { describe, it, expect } from 'vitest';
import { jsonSchemaToZod } from '../jsonschema-to-zod.ts';
describe('jsonSchemaToZod', () => {
it('converts object properties + required correctly', () => {
const schema = {
type: 'object',
properties: {
a: { type: 'string' },
b: { type: 'integer' },
},
required: ['a'],
};
const zod = jsonSchemaToZod(schema);
expect(zod.safeParse({ a: 'x' }).success).toBe(true);
expect(zod.safeParse({}).success).toBe(false);
expect(zod.safeParse({ a: 'x', b: 1 }).success).toBe(true);
expect(zod.safeParse({ a: 'x', b: 1.5 }).success).toBe(false);
});
it('supports enums (mixed types)', () => {
const schema = {
enum: ['a', 1, true],
description: 'mixed enum',
};
const zod = jsonSchemaToZod(schema);
expect(zod.safeParse('a').success).toBe(true);
expect(zod.safeParse(1).success).toBe(true);
expect(zod.safeParse(true).success).toBe(true);
expect(zod.safeParse('b').success).toBe(false);
});
it('supports arrays with items', () => {
const schema = { type: 'array', items: { type: 'number' } };
const zod = jsonSchemaToZod(schema);
expect(zod.safeParse([1, 2, 3]).success).toBe(true);
expect(zod.safeParse([1, 'x']).success).toBe(false);
});
it('is permissive for unknown constructs', () => {
const schema: unknown = {
type: 'object',
properties: {
x: { oneOf: [{ type: 'string' }, { type: 'number' }] },
},
required: ['x'],
};
const zod = jsonSchemaToZod(schema);
expect(zod.safeParse({ x: 'hello' }).success).toBe(true);
expect(zod.safeParse({ x: 123 }).success).toBe(true);
});
it('does not reject unknown fields on objects (passthrough)', () => {
const schema = {
type: 'object',
properties: {
a: { type: 'string' },
},
required: ['a'],
};
const zod = jsonSchemaToZod(schema);
const parsed = zod.parse({ a: 'x', extra: 1 }) as Record<string, unknown>;
expect(parsed.extra).toBe(1);
});
it('applies default values from JSON Schema', () => {
const schema = {
type: 'object',
properties: {
name: { type: 'string' },
format: { type: 'string', default: 'project-relative' },
},
required: ['name'],
};
const zod = jsonSchemaToZod(schema);
// Default is applied when property is absent
const withDefault = zod.parse({ name: 'test' }) as Record<string, unknown>;
expect(withDefault.format).toBe('project-relative');
// Explicit value overrides the default
const withExplicit = zod.parse({ name: 'test', format: 'absolute' }) as Record<string, unknown>;
expect(withExplicit.format).toBe('absolute');
});
it('applies default values on primitive types', () => {
const stringSchema = { type: 'string', default: 'hello' };
expect(jsonSchemaToZod(stringSchema).parse(undefined)).toBe('hello');
expect(jsonSchemaToZod(stringSchema).parse('world')).toBe('world');
const numberSchema = { type: 'number', default: 42 };
expect(jsonSchemaToZod(numberSchema).parse(undefined)).toBe(42);
const boolSchema = { type: 'boolean', default: true };
expect(jsonSchemaToZod(boolSchema).parse(undefined)).toBe(true);
const intSchema = { type: 'integer', default: 7 };
expect(jsonSchemaToZod(intSchema).parse(undefined)).toBe(7);
});
it('applies default values on enum types', () => {
// String enum with default
const stringEnumSchema = {
enum: ['project-relative', 'absolute'],
default: 'project-relative',
};
expect(jsonSchemaToZod(stringEnumSchema).parse(undefined)).toBe('project-relative');
expect(jsonSchemaToZod(stringEnumSchema).parse('absolute')).toBe('absolute');
// Single-value string enum (literal) with default
const singleEnumSchema = { enum: ['only'], default: 'only' };
expect(jsonSchemaToZod(singleEnumSchema).parse(undefined)).toBe('only');
// Mixed-type enum with default
const mixedEnumSchema = { enum: ['a', 1, true], default: 1 };
expect(jsonSchemaToZod(mixedEnumSchema).parse(undefined)).toBe(1);
expect(jsonSchemaToZod(mixedEnumSchema).parse('a')).toBe('a');
// Single mixed literal with default
const singleMixedSchema = { enum: [42], default: 42 };
expect(jsonSchemaToZod(singleMixedSchema).parse(undefined)).toBe(42);
});
});