@esmj/schema 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -7
- package/package.json +3 -2
- package/benchmark/benchmark.ts +0 -585
package/README.md
CHANGED
|
@@ -24,48 +24,54 @@ When choosing a schema validation library, bundle size can be an important facto
|
|
|
24
24
|
|
|
25
25
|
| Library | Bundle Size (minified + gzipped) |
|
|
26
26
|
|------------------|---------------------------------|
|
|
27
|
-
| `@esmj/schema` |
|
|
27
|
+
| `@esmj/schema` | `~1 KB` |
|
|
28
28
|
| Superstruct | ~3.2 KB |
|
|
29
29
|
| Yup | ~12.2 KB |
|
|
30
30
|
| Zod@3 | ~13 KB |
|
|
31
31
|
| @zod/mini | ~20,5 KB |
|
|
32
32
|
| Joi | ~40,4 KB |
|
|
33
33
|
| Zod@4 | ~40,8 KB |
|
|
34
|
+
| Arktype | ~41,8 KB |
|
|
34
35
|
|
|
35
36
|
### Performance Comparison
|
|
36
37
|
|
|
37
38
|
#### Schema Creation Performance
|
|
38
39
|
|
|
39
|
-
| Library | 1
|
|
40
|
+
| Library | 1 Schema | 1,000 Schema | 1,000,000 Schema |
|
|
40
41
|
|-----------------|-------------|------------------|----------------------|
|
|
41
|
-
| `@esmj/schema` | 0.02 ms
|
|
42
|
+
| `@esmj/schema` | `0.02 ms` | 4.93 ms | `1.13 s` |
|
|
42
43
|
| zod@3 | 0.08 ms | 9.68 ms | 8.53 s |
|
|
43
44
|
| @zod/mini | 0.22 ms | 39.77 ms | 34.51 s |
|
|
44
45
|
| Yup | 0.54 ms | 14.03 ms | 12.34 s |
|
|
45
|
-
| Superstruct | 0.13 ms |
|
|
46
|
+
| Superstruct | 0.13 ms | `3.67 ms` | 1.74 s |
|
|
46
47
|
| Joi | 0.62 ms | 31.60 ms | 23.06 s |
|
|
48
|
+
| ArkType | 0.37 ms | 54.60 ms | Infinity |
|
|
47
49
|
|
|
48
50
|
#### Parsing Performance
|
|
49
51
|
|
|
50
52
|
| Library | 1 Iteration | 1,000 Iterations | 1,000,000 Iterations |
|
|
51
53
|
|-----------------|-------------|------------------|----------------------|
|
|
52
|
-
| `@esmj/schema` | 0.05 ms
|
|
54
|
+
| `@esmj/schema` | `0.05 ms` | 0.46 ms | 267.93 ms |
|
|
53
55
|
| zod@3 | 0.14 ms | 1.44 ms | 897.89 ms |
|
|
54
|
-
| @zod/mini | 0.23 ms | 0.42 ms
|
|
56
|
+
| @zod/mini | 0.23 ms | `0.42 ms` | `199.08 ms` |
|
|
55
57
|
| Yup | 0.30 ms | 9.49 ms | 8.69 s |
|
|
56
58
|
| Superstruct | 0.08 ms | 4.18 ms | 3.71 s |
|
|
57
59
|
| Joi | 0.33 ms | 3.35 ms | 2.69 s |
|
|
60
|
+
| ArkType | 0.08 ms | 0.70 ms | 576,80 ms |
|
|
58
61
|
|
|
59
62
|
#### Error Handling Performance
|
|
60
63
|
|
|
61
64
|
| Library | 1 Iteration | 1,000 Iterations | 1,000,000 Iterations |
|
|
62
65
|
|-----------------|-------------|------------------|----------------------|
|
|
63
|
-
| `@esmj/schema` | 0.03 ms
|
|
66
|
+
| `@esmj/schema` | `0.03 ms` | `0.59 ms` | `365.32 ms` |
|
|
64
67
|
| zod3 | 0.05 ms | 2.09 ms | 1.26 s |
|
|
65
68
|
| @zod/mini | 0.07 ms | 0.99 ms | 545.12 ms |
|
|
66
69
|
| Yup | 0.27 ms | 19.28 ms | 18.87 s |
|
|
67
70
|
| Superstruct | 0.04 ms | 8.62 ms | 6.24 s |
|
|
68
71
|
| Joi | 0.15 ms | 4.13 ms | 2.57 s |
|
|
72
|
+
| ArkType | 0.07 ms | 3.78 ms | 2.87 s |
|
|
73
|
+
|
|
74
|
+
**Note:** During the performance tests, `@zod/mini` was observed to consume 200% CPU, while other libraries used only 100% CPU. This may affect the interpretation of the results, especially in multi-threaded environments.
|
|
69
75
|
|
|
70
76
|
## Usage
|
|
71
77
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@esmj/schema",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Tiny extendable package for schema validation.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"schema",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"scripts": {
|
|
23
23
|
"lint": "biome check --no-errors-on-unmatched",
|
|
24
24
|
"lint:fix": "npm run lint -- --fix --unsafe",
|
|
25
|
-
"benchmark": "node benchmark/
|
|
25
|
+
"benchmark": "node benchmark/benchmark.ts",
|
|
26
26
|
"dev": "node_modules/.bin/tsup --dts --watch --onSuccess 'node ./dist/index.mjs'",
|
|
27
27
|
"test": "node --test --experimental-strip-types",
|
|
28
28
|
"test:watch": "npm run test -- --watch",
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
"@typescript-eslint/eslint-plugin": "^8.33.0",
|
|
69
69
|
"@typescript-eslint/parser": "^8.33.0",
|
|
70
70
|
"@zod/mini": "^4.0.0-beta.0",
|
|
71
|
+
"arktype": "^2.1.20",
|
|
71
72
|
"commitizen": "^4.3.1",
|
|
72
73
|
"conventional-changelog-cli": "^5.0.0",
|
|
73
74
|
"cz-conventional-changelog": "^3.3.0",
|
package/benchmark/benchmark.ts
DELETED
|
@@ -1,585 +0,0 @@
|
|
|
1
|
-
import { performance } from 'node:perf_hooks';
|
|
2
|
-
import { z as zodMini } from '@zod/mini'; // Import Zod Mini
|
|
3
|
-
import Joi from 'joi'; // Import Joi
|
|
4
|
-
import superStruct from 'superstruct'; // Import Superstruct
|
|
5
|
-
import * as yup from 'yup'; // Import Yup
|
|
6
|
-
import { z } from 'zod'; // Import Zod
|
|
7
|
-
import { s } from '../src/index.ts'; // Import @esmj/schema
|
|
8
|
-
|
|
9
|
-
function formatTime(time: number) {
|
|
10
|
-
// Convert time to milliseconds
|
|
11
|
-
if (time < 1000) {
|
|
12
|
-
return `${time.toFixed(2)} ms`;
|
|
13
|
-
}
|
|
14
|
-
// Convert to seconds
|
|
15
|
-
const seconds = time / 1000;
|
|
16
|
-
return `${seconds.toFixed(2)} s`;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function benchmark(label: string, fn: () => void) {
|
|
20
|
-
const REPEAT = 10;
|
|
21
|
-
let sum = 0;
|
|
22
|
-
let min = Number.POSITIVE_INFINITY;
|
|
23
|
-
let max = Number.NEGATIVE_INFINITY;
|
|
24
|
-
for (let i = 0; i < REPEAT; i++) {
|
|
25
|
-
const start = performance.now();
|
|
26
|
-
fn();
|
|
27
|
-
const end = performance.now();
|
|
28
|
-
|
|
29
|
-
const time = end - start;
|
|
30
|
-
|
|
31
|
-
min = Math.min(min, time);
|
|
32
|
-
max = Math.max(max, time);
|
|
33
|
-
sum += time;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const average = sum / REPEAT;
|
|
37
|
-
|
|
38
|
-
console.log(
|
|
39
|
-
`${label} took an average of ${formatTime(average)} over ${REPEAT} iterations. Min: ${formatTime(min)}, Max: ${formatTime(max)}`,
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
return formatTime(average);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function scenarioParseSchema(testData) {
|
|
46
|
-
// Define a schema using @esmj/schema
|
|
47
|
-
const esmjSchema = s.object({
|
|
48
|
-
username: s.string(),
|
|
49
|
-
password: s.string(),
|
|
50
|
-
age: s.number().optional(),
|
|
51
|
-
address: s.object({
|
|
52
|
-
street: s.string().nullish(),
|
|
53
|
-
city: s.string().nullable(),
|
|
54
|
-
date: s.date().optional(), // Optional date field
|
|
55
|
-
}),
|
|
56
|
-
tags: s.array(s.string()),
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
// Define a schema using Zod
|
|
60
|
-
const zodSchema = z.object({
|
|
61
|
-
username: z.string(),
|
|
62
|
-
password: z.string(),
|
|
63
|
-
age: z.number().optional(),
|
|
64
|
-
address: z.object({
|
|
65
|
-
street: z.string().nullish(),
|
|
66
|
-
city: z.string().nullable(),
|
|
67
|
-
date: z.date().optional(), // Optional date field
|
|
68
|
-
}),
|
|
69
|
-
tags: z.array(z.string()),
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
// Define a schema using Zod Mini
|
|
73
|
-
const zodMiniSchema = zodMini.object({
|
|
74
|
-
username: zodMini.string(),
|
|
75
|
-
password: zodMini.string(),
|
|
76
|
-
age: zodMini.optional(zodMini.number()),
|
|
77
|
-
address: zodMini.object({
|
|
78
|
-
street: zodMini.nullish(zodMini.string()),
|
|
79
|
-
city: zodMini.nullable(zodMini.string()),
|
|
80
|
-
date: zodMini.optional(zodMini.date()), // Optional date field
|
|
81
|
-
}),
|
|
82
|
-
tags: zodMini.array(zodMini.string()),
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
// Define a schema using Yup
|
|
86
|
-
const yupSchema = yup.object({
|
|
87
|
-
username: yup.string().required(),
|
|
88
|
-
password: yup.string().required(),
|
|
89
|
-
age: yup.number().optional(),
|
|
90
|
-
address: yup.object({
|
|
91
|
-
street: yup.string().nullable(),
|
|
92
|
-
city: yup.string().nullable(),
|
|
93
|
-
date: yup.date().optional(), // Optional date field
|
|
94
|
-
}),
|
|
95
|
-
tags: yup.array().of(yup.string().required()).required(),
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
// Define a schema using Superstruct
|
|
99
|
-
const superStructSchema = superStruct.object({
|
|
100
|
-
username: superStruct.string(),
|
|
101
|
-
password: superStruct.string(),
|
|
102
|
-
age: superStruct.number(),
|
|
103
|
-
address: superStruct.object({
|
|
104
|
-
street: superStruct.optional(superStruct.string()),
|
|
105
|
-
city: superStruct.optional(superStruct.string()),
|
|
106
|
-
date: superStruct.optional(superStruct.date()), // Optional date field
|
|
107
|
-
}),
|
|
108
|
-
tags: superStruct.array(superStruct.string()),
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
// Define a schema using Joi
|
|
112
|
-
const joiSchema = Joi.object({
|
|
113
|
-
username: Joi.string().required(),
|
|
114
|
-
password: Joi.string().required(),
|
|
115
|
-
age: Joi.number().required(),
|
|
116
|
-
address: Joi.object({
|
|
117
|
-
street: Joi.string().optional(), // Allow null for street
|
|
118
|
-
city: Joi.string().optional(),
|
|
119
|
-
date: Joi.date().optional(), // Optional date field
|
|
120
|
-
}),
|
|
121
|
-
tags: Joi.array().items(Joi.string().required()).required(),
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
const result = {} as Record<string, object>;
|
|
125
|
-
|
|
126
|
-
const esmjSchemaResult = {};
|
|
127
|
-
esmjSchemaResult['1'] = benchmark('@esmj/schema 1', () => {
|
|
128
|
-
for (let i = 0; i < 1; i++) {
|
|
129
|
-
esmjSchema.safeParse(testData);
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
esmjSchemaResult['1_000'] = benchmark('@esmj/schema 1_000', () => {
|
|
134
|
-
for (let i = 0; i < 1_000; i++) {
|
|
135
|
-
esmjSchema.safeParse(testData);
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
esmjSchemaResult['1_000_000'] = benchmark('@esmj/schema 1_000_000', () => {
|
|
140
|
-
for (let i = 0; i < 1_000_000; i++) {
|
|
141
|
-
esmjSchema.safeParse(testData);
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
result.esmjSchema = esmjSchemaResult;
|
|
145
|
-
|
|
146
|
-
const zod = {};
|
|
147
|
-
zod['1'] = benchmark('zod 1', () => {
|
|
148
|
-
for (let i = 0; i < 1; i++) {
|
|
149
|
-
zodSchema.safeParse(testData);
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
zod['1_000'] = benchmark('zod 1_000', () => {
|
|
154
|
-
for (let i = 0; i < 1_000; i++) {
|
|
155
|
-
zodSchema.safeParse(testData);
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
zod['1_000_000'] = benchmark('zod 1_000_000', () => {
|
|
160
|
-
for (let i = 0; i < 1_000_000; i++) {
|
|
161
|
-
zodSchema.safeParse(testData);
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
result.zod = zod;
|
|
165
|
-
|
|
166
|
-
const zodMiniResult = {};
|
|
167
|
-
zodMiniResult['1'] = benchmark('@zod/mini 1', () => {
|
|
168
|
-
for (let i = 0; i < 1; i++) {
|
|
169
|
-
zodMiniSchema.safeParse(testData);
|
|
170
|
-
}
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
zodMiniResult['1_000'] = benchmark('@zod/mini 1_000', () => {
|
|
174
|
-
for (let i = 0; i < 1_000; i++) {
|
|
175
|
-
zodMiniSchema.safeParse(testData);
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
zodMiniResult['1_000_000'] = benchmark('@zod/mini 1_000_000', () => {
|
|
180
|
-
for (let i = 0; i < 1_000_000; i++) {
|
|
181
|
-
zodMiniSchema.safeParse(testData);
|
|
182
|
-
}
|
|
183
|
-
});
|
|
184
|
-
result.zodMini = zodMiniResult;
|
|
185
|
-
|
|
186
|
-
const yupResult = {};
|
|
187
|
-
yupResult['1'] = benchmark('yup 1', () => {
|
|
188
|
-
for (let i = 0; i < 1; i++) {
|
|
189
|
-
yupSchema.isValidSync(testData);
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
yupResult['1_000'] = benchmark('yup 1_000', () => {
|
|
194
|
-
for (let i = 0; i < 1_000; i++) {
|
|
195
|
-
yupSchema.isValidSync(testData);
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
yupResult['1_000_000'] = benchmark('yup 1_000_000', () => {
|
|
200
|
-
for (let i = 0; i < 1_000_000; i++) {
|
|
201
|
-
yupSchema.isValidSync(testData);
|
|
202
|
-
}
|
|
203
|
-
});
|
|
204
|
-
result.yup = yupResult;
|
|
205
|
-
|
|
206
|
-
const superStructResult = {};
|
|
207
|
-
superStructResult['1'] = benchmark('superStruct 1', () => {
|
|
208
|
-
for (let i = 0; i < 1; i++) {
|
|
209
|
-
superStruct.is(testData, superStructSchema);
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
superStructResult['1_000'] = benchmark('superStruct 1_000', () => {
|
|
214
|
-
for (let i = 0; i < 1_000; i++) {
|
|
215
|
-
superStruct.is(testData, superStructSchema);
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
superStructResult['1_000_000'] = benchmark('superStruct 1_000_000', () => {
|
|
220
|
-
for (let i = 0; i < 1_000_000; i++) {
|
|
221
|
-
superStruct.is(testData, superStructSchema);
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
result.superStruct = superStructResult;
|
|
225
|
-
|
|
226
|
-
const joiResult = {};
|
|
227
|
-
joiResult['1'] = benchmark('joi 1', () => {
|
|
228
|
-
for (let i = 0; i < 1; i++) {
|
|
229
|
-
try {
|
|
230
|
-
joiSchema.validate(testData);
|
|
231
|
-
} catch (e) {}
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
joiResult['1_000'] = benchmark('joi 1_000', () => {
|
|
236
|
-
for (let i = 0; i < 1_000; i++) {
|
|
237
|
-
try {
|
|
238
|
-
joiSchema.validate(testData);
|
|
239
|
-
} catch (e) {}
|
|
240
|
-
}
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
joiResult['1_000_000'] = benchmark('joi 1_000_000', () => {
|
|
244
|
-
for (let i = 0; i < 1_000_000; i++) {
|
|
245
|
-
try {
|
|
246
|
-
joiSchema.validate(testData);
|
|
247
|
-
} catch (e) {}
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
result.joi = joiResult;
|
|
251
|
-
|
|
252
|
-
return result;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
function scenarioCreatingSchema() {
|
|
256
|
-
const result = {} as Record<string, object>;
|
|
257
|
-
const esmjSchemaResult = {};
|
|
258
|
-
esmjSchemaResult['1'] = benchmark('@esmj/schema 1', () => {
|
|
259
|
-
for (let i = 0; i < 1; i++) {
|
|
260
|
-
const esmjSchema = s.object({
|
|
261
|
-
username: s.string(),
|
|
262
|
-
password: s.string(),
|
|
263
|
-
age: s.number().optional(),
|
|
264
|
-
address: s.object({
|
|
265
|
-
street: s.string().nullish(),
|
|
266
|
-
city: s.string().nullable(),
|
|
267
|
-
date: s.date().optional(), // Optional date field
|
|
268
|
-
}),
|
|
269
|
-
tags: s.array(s.string()),
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
esmjSchemaResult['1_000'] = benchmark('@esmj/schema 1_000', () => {
|
|
275
|
-
for (let i = 0; i < 1_000; i++) {
|
|
276
|
-
const esmjSchema = s.object({
|
|
277
|
-
username: s.string(),
|
|
278
|
-
password: s.string(),
|
|
279
|
-
age: s.number().optional(),
|
|
280
|
-
address: s.object({
|
|
281
|
-
street: s.string().nullish(),
|
|
282
|
-
city: s.string().nullable(),
|
|
283
|
-
date: s.date().optional(), // Optional date field
|
|
284
|
-
}),
|
|
285
|
-
tags: s.array(s.string()),
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
esmjSchemaResult['1_000_000'] = benchmark('@esmj/schema 1_000_000', () => {
|
|
291
|
-
for (let i = 0; i < 1_000_000; i++) {
|
|
292
|
-
const esmjSchema = s.object({
|
|
293
|
-
username: s.string(),
|
|
294
|
-
password: s.string(),
|
|
295
|
-
age: s.number().optional(),
|
|
296
|
-
address: s.object({
|
|
297
|
-
street: s.string().nullish(),
|
|
298
|
-
city: s.string().nullable(),
|
|
299
|
-
date: s.date().optional(), // Optional date field
|
|
300
|
-
}),
|
|
301
|
-
tags: s.array(s.string()),
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
});
|
|
305
|
-
result.esmjSchema = esmjSchemaResult;
|
|
306
|
-
|
|
307
|
-
const zod = {};
|
|
308
|
-
zod['1'] = benchmark('zod 1', () => {
|
|
309
|
-
for (let i = 0; i < 1; i++) {
|
|
310
|
-
const zodSchema = z.object({
|
|
311
|
-
username: z.string(),
|
|
312
|
-
password: z.string(),
|
|
313
|
-
age: z.number().optional(),
|
|
314
|
-
address: z.object({
|
|
315
|
-
street: z.string().nullish(),
|
|
316
|
-
city: z.string().nullable(),
|
|
317
|
-
date: z.date().optional(), // Optional date field
|
|
318
|
-
}),
|
|
319
|
-
tags: z.array(z.string()),
|
|
320
|
-
});
|
|
321
|
-
}
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
zod['1_000'] = benchmark('zod 1_000', () => {
|
|
325
|
-
for (let i = 0; i < 1_000; i++) {
|
|
326
|
-
const zodSchema = z.object({
|
|
327
|
-
username: z.string(),
|
|
328
|
-
password: z.string(),
|
|
329
|
-
age: z.number().optional(),
|
|
330
|
-
address: z.object({
|
|
331
|
-
street: z.string().nullish(),
|
|
332
|
-
city: z.string().nullable(),
|
|
333
|
-
date: z.date().optional(), // Optional date field
|
|
334
|
-
}),
|
|
335
|
-
tags: z.array(z.string()),
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
zod['1_000_000'] = benchmark('zod 1_000_000', () => {
|
|
341
|
-
for (let i = 0; i < 1_000_000; i++) {
|
|
342
|
-
const zodSchema = z.object({
|
|
343
|
-
username: z.string(),
|
|
344
|
-
password: z.string(),
|
|
345
|
-
age: z.number().optional(),
|
|
346
|
-
address: z.object({
|
|
347
|
-
street: z.string().nullish(),
|
|
348
|
-
city: z.string().nullable(),
|
|
349
|
-
date: z.date().optional(), // Optional date field
|
|
350
|
-
}),
|
|
351
|
-
tags: z.array(z.string()),
|
|
352
|
-
});
|
|
353
|
-
}
|
|
354
|
-
});
|
|
355
|
-
result.zod = zod;
|
|
356
|
-
|
|
357
|
-
const zodMiniResult = {};
|
|
358
|
-
zodMiniResult['1'] = benchmark('@zod/mini 1', () => {
|
|
359
|
-
for (let i = 0; i < 1; i++) {
|
|
360
|
-
const zodMiniSchema = zodMini.object({
|
|
361
|
-
username: zodMini.string(),
|
|
362
|
-
password: zodMini.string(),
|
|
363
|
-
age: zodMini.optional(zodMini.number()),
|
|
364
|
-
address: zodMini.object({
|
|
365
|
-
street: zodMini.nullish(zodMini.string()),
|
|
366
|
-
city: zodMini.nullable(zodMini.string()),
|
|
367
|
-
date: zodMini.optional(zodMini.date()), // Optional date field
|
|
368
|
-
}),
|
|
369
|
-
tags: zodMini.array(zodMini.string()),
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
});
|
|
373
|
-
|
|
374
|
-
zodMiniResult['1_000'] = benchmark('@zod/mini 1_000', () => {
|
|
375
|
-
for (let i = 0; i < 1_000; i++) {
|
|
376
|
-
const zodMiniSchema = zodMini.object({
|
|
377
|
-
username: zodMini.string(),
|
|
378
|
-
password: zodMini.string(),
|
|
379
|
-
age: zodMini.optional(zodMini.number()),
|
|
380
|
-
address: zodMini.object({
|
|
381
|
-
street: zodMini.nullish(zodMini.string()),
|
|
382
|
-
city: zodMini.nullable(zodMini.string()),
|
|
383
|
-
date: zodMini.optional(zodMini.date()), // Optional date field
|
|
384
|
-
}),
|
|
385
|
-
tags: zodMini.array(zodMini.string()),
|
|
386
|
-
});
|
|
387
|
-
}
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
zodMiniResult['1_000_000'] = benchmark('@zod/mini 1_000_000', () => {
|
|
391
|
-
for (let i = 0; i < 1_000_000; i++) {
|
|
392
|
-
const zodMiniSchema = zodMini.object({
|
|
393
|
-
username: zodMini.string(),
|
|
394
|
-
password: zodMini.string(),
|
|
395
|
-
age: zodMini.optional(zodMini.number()),
|
|
396
|
-
address: zodMini.object({
|
|
397
|
-
street: zodMini.nullish(zodMini.string()),
|
|
398
|
-
city: zodMini.nullable(zodMini.string()),
|
|
399
|
-
date: zodMini.optional(zodMini.date()), // Optional date field
|
|
400
|
-
}),
|
|
401
|
-
tags: zodMini.array(zodMini.string()),
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
});
|
|
405
|
-
result.zodMini = zodMiniResult;
|
|
406
|
-
|
|
407
|
-
const yupResult = {};
|
|
408
|
-
yupResult['1'] = benchmark('yup 1', () => {
|
|
409
|
-
for (let i = 0; i < 1; i++) {
|
|
410
|
-
const yupSchema = yup.object({
|
|
411
|
-
username: yup.string().required(),
|
|
412
|
-
password: yup.string().required(),
|
|
413
|
-
age: yup.number().optional(),
|
|
414
|
-
address: yup.object({
|
|
415
|
-
street: yup.string().nullable(),
|
|
416
|
-
city: yup.string().nullable(),
|
|
417
|
-
date: yup.date().optional(), // Optional date field
|
|
418
|
-
}),
|
|
419
|
-
tags: yup.array().of(yup.string().required()).required(),
|
|
420
|
-
});
|
|
421
|
-
}
|
|
422
|
-
});
|
|
423
|
-
|
|
424
|
-
yupResult['1_000'] = benchmark('yup 1_000', () => {
|
|
425
|
-
for (let i = 0; i < 1_000; i++) {
|
|
426
|
-
const yupSchema = yup.object({
|
|
427
|
-
username: yup.string().required(),
|
|
428
|
-
password: yup.string().required(),
|
|
429
|
-
age: yup.number().optional(),
|
|
430
|
-
address: yup.object({
|
|
431
|
-
street: yup.string().nullable(),
|
|
432
|
-
city: yup.string().nullable(),
|
|
433
|
-
date: yup.date().optional(), // Optional date field
|
|
434
|
-
}),
|
|
435
|
-
tags: yup.array().of(yup.string().required()).required(),
|
|
436
|
-
});
|
|
437
|
-
}
|
|
438
|
-
});
|
|
439
|
-
|
|
440
|
-
yupResult['1_000_000'] = benchmark('yup 1_000_000', () => {
|
|
441
|
-
for (let i = 0; i < 1_000_000; i++) {
|
|
442
|
-
const yupSchema = yup.object({
|
|
443
|
-
username: yup.string().required(),
|
|
444
|
-
password: yup.string().required(),
|
|
445
|
-
age: yup.number().optional(),
|
|
446
|
-
address: yup.object({
|
|
447
|
-
street: yup.string().nullable(),
|
|
448
|
-
city: yup.string().nullable(),
|
|
449
|
-
date: yup.date().optional(), // Optional date field
|
|
450
|
-
}),
|
|
451
|
-
tags: yup.array().of(yup.string().required()).required(),
|
|
452
|
-
});
|
|
453
|
-
}
|
|
454
|
-
});
|
|
455
|
-
result.yup = yupResult;
|
|
456
|
-
|
|
457
|
-
const superStructResult = {};
|
|
458
|
-
superStructResult['1'] = benchmark('superStruct 1', () => {
|
|
459
|
-
for (let i = 0; i < 1; i++) {
|
|
460
|
-
const superStructSchema = superStruct.object({
|
|
461
|
-
username: superStruct.string(),
|
|
462
|
-
password: superStruct.string(),
|
|
463
|
-
age: superStruct.number(),
|
|
464
|
-
address: superStruct.object({
|
|
465
|
-
street: superStruct.optional(superStruct.string()),
|
|
466
|
-
city: superStruct.optional(superStruct.string()),
|
|
467
|
-
date: superStruct.optional(superStruct.date()), // Optional date field
|
|
468
|
-
}),
|
|
469
|
-
tags: superStruct.array(superStruct.string()),
|
|
470
|
-
});
|
|
471
|
-
}
|
|
472
|
-
});
|
|
473
|
-
|
|
474
|
-
superStructResult['1_000'] = benchmark('superStruct 1_000', () => {
|
|
475
|
-
for (let i = 0; i < 1_000; i++) {
|
|
476
|
-
const superStructSchema = superStruct.object({
|
|
477
|
-
username: superStruct.string(),
|
|
478
|
-
password: superStruct.string(),
|
|
479
|
-
age: superStruct.number(),
|
|
480
|
-
address: superStruct.object({
|
|
481
|
-
street: superStruct.optional(superStruct.string()),
|
|
482
|
-
city: superStruct.optional(superStruct.string()),
|
|
483
|
-
date: superStruct.optional(superStruct.date()), // Optional date field
|
|
484
|
-
}),
|
|
485
|
-
tags: superStruct.array(superStruct.string()),
|
|
486
|
-
});
|
|
487
|
-
}
|
|
488
|
-
});
|
|
489
|
-
|
|
490
|
-
superStructResult['1_000_000'] = benchmark('superStruct 1_000_000', () => {
|
|
491
|
-
for (let i = 0; i < 1_000_000; i++) {
|
|
492
|
-
const superStructSchema = superStruct.object({
|
|
493
|
-
username: superStruct.string(),
|
|
494
|
-
password: superStruct.string(),
|
|
495
|
-
age: superStruct.number(),
|
|
496
|
-
address: superStruct.object({
|
|
497
|
-
street: superStruct.optional(superStruct.string()),
|
|
498
|
-
city: superStruct.optional(superStruct.string()),
|
|
499
|
-
date: superStruct.optional(superStruct.date()), // Optional date field
|
|
500
|
-
}),
|
|
501
|
-
tags: superStruct.array(superStruct.string()),
|
|
502
|
-
});
|
|
503
|
-
}
|
|
504
|
-
});
|
|
505
|
-
result.superStruct = superStructResult;
|
|
506
|
-
|
|
507
|
-
const joiResult = {};
|
|
508
|
-
joiResult['1'] = benchmark('joi 1', () => {
|
|
509
|
-
for (let i = 0; i < 1; i++) {
|
|
510
|
-
const joiSchema = Joi.object({
|
|
511
|
-
username: Joi.string().required(),
|
|
512
|
-
password: Joi.string().required(),
|
|
513
|
-
age: Joi.number().required(),
|
|
514
|
-
address: Joi.object({
|
|
515
|
-
street: Joi.string().optional(), // Allow null for street
|
|
516
|
-
city: Joi.string().optional(),
|
|
517
|
-
date: Joi.date().optional(), // Optional date field
|
|
518
|
-
}),
|
|
519
|
-
tags: Joi.array().items(Joi.string().required()).required(),
|
|
520
|
-
});
|
|
521
|
-
}
|
|
522
|
-
});
|
|
523
|
-
|
|
524
|
-
joiResult['1_000'] = benchmark('joi 1_000', () => {
|
|
525
|
-
for (let i = 0; i < 1_000; i++) {
|
|
526
|
-
const joiSchema = Joi.object({
|
|
527
|
-
username: Joi.string().required(),
|
|
528
|
-
password: Joi.string().required(),
|
|
529
|
-
age: Joi.number().required(),
|
|
530
|
-
address: Joi.object({
|
|
531
|
-
street: Joi.string().optional(), // Allow null for street
|
|
532
|
-
city: Joi.string().optional(),
|
|
533
|
-
date: Joi.date().optional(), // Optional date field
|
|
534
|
-
}),
|
|
535
|
-
tags: Joi.array().items(Joi.string().required()).required(),
|
|
536
|
-
});
|
|
537
|
-
}
|
|
538
|
-
});
|
|
539
|
-
|
|
540
|
-
joiResult['1_000_000'] = benchmark('joi 1_000_000', () => {
|
|
541
|
-
for (let i = 0; i < 1_000_000; i++) {
|
|
542
|
-
const joiSchema = Joi.object({
|
|
543
|
-
username: Joi.string().required(),
|
|
544
|
-
password: Joi.string().required(),
|
|
545
|
-
age: Joi.number().required(),
|
|
546
|
-
address: Joi.object({
|
|
547
|
-
street: Joi.string().optional(), // Allow null for street
|
|
548
|
-
city: Joi.string().optional(),
|
|
549
|
-
date: Joi.date().optional(), // Optional date field
|
|
550
|
-
}),
|
|
551
|
-
tags: Joi.array().items(Joi.string().required()).required(),
|
|
552
|
-
});
|
|
553
|
-
}
|
|
554
|
-
});
|
|
555
|
-
result.joi = joiResult;
|
|
556
|
-
|
|
557
|
-
return result;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
const testDataGood = {
|
|
561
|
-
username: 'john_doe',
|
|
562
|
-
password: 'securepassword',
|
|
563
|
-
age: 30,
|
|
564
|
-
address: {
|
|
565
|
-
street: '123 Main St',
|
|
566
|
-
city: 'New York',
|
|
567
|
-
date: new Date(),
|
|
568
|
-
},
|
|
569
|
-
tags: ['developer', 'typescript'],
|
|
570
|
-
};
|
|
571
|
-
|
|
572
|
-
const testDataBad = {
|
|
573
|
-
username: 'john_doe',
|
|
574
|
-
password: 'securepassword',
|
|
575
|
-
age: 30,
|
|
576
|
-
address: {
|
|
577
|
-
street: '123 Main St',
|
|
578
|
-
city: 'New York',
|
|
579
|
-
date: new Date(),
|
|
580
|
-
},
|
|
581
|
-
};
|
|
582
|
-
|
|
583
|
-
console.table(scenarioCreatingSchema());
|
|
584
|
-
console.table(scenarioParseSchema(testDataGood));
|
|
585
|
-
console.table(scenarioParseSchema(testDataBad));
|