@esmj/schema 0.1.0 → 0.2.0
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 +87 -1
- package/benchmark/benchmark.ts +585 -0
- package/dist/index.d.mts +22 -9
- package/dist/index.d.ts +22 -9
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +14 -8
- package/biome.json +0 -50
package/README.md
CHANGED
|
@@ -18,6 +18,55 @@ npm install @esmj/schema
|
|
|
18
18
|
4. **Lightweight**: None dependencies and a small footprint make it ideal for projects where performance and simplicity are key.
|
|
19
19
|
5. **Customizable**: Offers fine-grained control over validation and error handling.
|
|
20
20
|
|
|
21
|
+
## Comparison with Similar Libraries
|
|
22
|
+
|
|
23
|
+
When choosing a schema validation library, bundle size can be an important factor, especially for frontend applications where minimizing JavaScript size is critical. Here's how `@esmj/schema` compares to other popular libraries:
|
|
24
|
+
|
|
25
|
+
| Library | Bundle Size (minified + gzipped) |
|
|
26
|
+
|------------------|---------------------------------|
|
|
27
|
+
| `@esmj/schema` | ~1 KB |
|
|
28
|
+
| Superstruct | ~3.2 KB |
|
|
29
|
+
| Yup | ~12.2 KB |
|
|
30
|
+
| Zod@3 | ~13 KB |
|
|
31
|
+
| @zod/mini | ~20,5 KB |
|
|
32
|
+
| Joi | ~40,4 KB |
|
|
33
|
+
| Zod@4 | ~40,8 KB |
|
|
34
|
+
|
|
35
|
+
### Performance Comparison
|
|
36
|
+
|
|
37
|
+
#### Schema Creation Performance
|
|
38
|
+
|
|
39
|
+
| Library | 1 Iteration | 1,000 Iterations | 1,000,000 Iterations |
|
|
40
|
+
|-----------------|-------------|------------------|----------------------|
|
|
41
|
+
| `@esmj/schema` | 0.02 ms | 4.93 ms | 399.62 ms |
|
|
42
|
+
| zod@3 | 0.08 ms | 9.68 ms | 8.53 s |
|
|
43
|
+
| @zod/mini | 0.22 ms | 39.77 ms | 34.51 s |
|
|
44
|
+
| Yup | 0.54 ms | 14.03 ms | 12.34 s |
|
|
45
|
+
| Superstruct | 0.13 ms | 1.04 ms | 487.94 ms |
|
|
46
|
+
| Joi | 0.62 ms | 31.60 ms | 23.06 s |
|
|
47
|
+
|
|
48
|
+
#### Parsing Performance
|
|
49
|
+
|
|
50
|
+
| Library | 1 Iteration | 1,000 Iterations | 1,000,000 Iterations |
|
|
51
|
+
|-----------------|-------------|------------------|----------------------|
|
|
52
|
+
| `@esmj/schema` | 0.05 ms | 0.46 ms | 267.93 ms |
|
|
53
|
+
| zod@3 | 0.14 ms | 1.44 ms | 897.89 ms |
|
|
54
|
+
| @zod/mini | 0.23 ms | 0.42 ms | 199.08 ms |
|
|
55
|
+
| Yup | 0.30 ms | 9.49 ms | 8.69 s |
|
|
56
|
+
| Superstruct | 0.08 ms | 4.18 ms | 3.71 s |
|
|
57
|
+
| Joi | 0.33 ms | 3.35 ms | 2.69 s |
|
|
58
|
+
|
|
59
|
+
#### Error Handling Performance
|
|
60
|
+
|
|
61
|
+
| Library | 1 Iteration | 1,000 Iterations | 1,000,000 Iterations |
|
|
62
|
+
|-----------------|-------------|------------------|----------------------|
|
|
63
|
+
| `@esmj/schema` | 0.03 ms | 0.59 ms | 365.32 ms |
|
|
64
|
+
| zod3 | 0.05 ms | 2.09 ms | 1.26 s |
|
|
65
|
+
| @zod/mini | 0.07 ms | 0.99 ms | 545.12 ms |
|
|
66
|
+
| Yup | 0.27 ms | 19.28 ms | 18.87 s |
|
|
67
|
+
| Superstruct | 0.04 ms | 8.62 ms | 6.24 s |
|
|
68
|
+
| Joi | 0.15 ms | 4.13 ms | 2.57 s |
|
|
69
|
+
|
|
21
70
|
## Usage
|
|
22
71
|
|
|
23
72
|
### Basic Usage
|
|
@@ -125,6 +174,26 @@ Creates a schema that accepts any value.
|
|
|
125
174
|
const anySchema = s.any();
|
|
126
175
|
```
|
|
127
176
|
|
|
177
|
+
#### `s.enum(values)`
|
|
178
|
+
|
|
179
|
+
Creates an enum schema that validates against a predefined set of string values.
|
|
180
|
+
|
|
181
|
+
- **`values`**: An array of strings representing the allowed values for the enum. Each value must be a string.
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
const enumSchema = s.enum(['admin', 'user', 'guest']);
|
|
185
|
+
|
|
186
|
+
const validResult = enumSchema.parse('admin');
|
|
187
|
+
console.log(validResult);
|
|
188
|
+
// 'admin'
|
|
189
|
+
|
|
190
|
+
const invalidResult = enumSchema.safeParse('invalidRole');
|
|
191
|
+
console.log(invalidResult.success);
|
|
192
|
+
// false
|
|
193
|
+
console.log(invalidResult.error.message);
|
|
194
|
+
// Error: Invalid enum value. Expected "admin" | "user" | "guest", received "invalidRole".
|
|
195
|
+
```
|
|
196
|
+
|
|
128
197
|
#### `s.preprocess(callback, schema)`
|
|
129
198
|
|
|
130
199
|
Creates a schema that preprocesses the input value using the provided callback before validating it with the given schema.
|
|
@@ -148,9 +217,26 @@ const result = stringSchema.parse('hello');
|
|
|
148
217
|
Safely parses the given value according to the schema, returning a success or error result.
|
|
149
218
|
|
|
150
219
|
```typescript
|
|
151
|
-
const result = stringSchema.safeParse('hello');
|
|
220
|
+
const result = stringSchema.safeParse('hello');
|
|
221
|
+
// { success: true, data: 'hello' }
|
|
222
|
+
|
|
223
|
+
const errorResult = stringSchema.safeParse(123);
|
|
224
|
+
// { success: false, error: { message: 'The value "123" must be type of string but is type of "number".' } }
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Note:** The `error` returned by `safeParse` is not a native `Error` instance. Instead, it is a plain object with the following structure:
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
type ErrorStructure = {
|
|
231
|
+
message: string;
|
|
232
|
+
cause?: {
|
|
233
|
+
key?: string;
|
|
234
|
+
};
|
|
235
|
+
};
|
|
152
236
|
```
|
|
153
237
|
|
|
238
|
+
This allows for easier serialization and debugging but may require additional handling if you expect a native `Error` instance.
|
|
239
|
+
|
|
154
240
|
#### `optional()`
|
|
155
241
|
|
|
156
242
|
Makes the schema optional.
|
|
@@ -0,0 +1,585 @@
|
|
|
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));
|
package/dist/index.d.mts
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
|
+
type ErrorStructure = {
|
|
2
|
+
message: string;
|
|
3
|
+
cause?: {
|
|
4
|
+
key?: string;
|
|
5
|
+
};
|
|
6
|
+
};
|
|
7
|
+
type Valid<Output> = {
|
|
8
|
+
success: true;
|
|
9
|
+
data: Output;
|
|
10
|
+
};
|
|
11
|
+
type Invalid = {
|
|
12
|
+
success: false;
|
|
13
|
+
error: ErrorStructure;
|
|
14
|
+
};
|
|
15
|
+
type InternalParseOutput<Output> = Valid<Output> | Invalid;
|
|
1
16
|
interface SchemaInterface<Input, Output> {
|
|
17
|
+
_parse(value: Input | Partial<Input> | unknown): InternalParseOutput<Output>;
|
|
2
18
|
parse(value: Input | Partial<Input> | unknown): Output;
|
|
3
|
-
safeParse(value: Input | Partial<Input> | unknown):
|
|
4
|
-
success: true;
|
|
5
|
-
data: Output;
|
|
6
|
-
} | {
|
|
7
|
-
success: false;
|
|
8
|
-
error: Error;
|
|
9
|
-
};
|
|
19
|
+
safeParse(value: Input | Partial<Input> | unknown): InternalParseOutput<Output>;
|
|
10
20
|
optional(): SchemaInterface<Input, Partial<Output> | undefined>;
|
|
11
21
|
transform<NewOutput>(callback: (value: Input) => NewOutput): SchemaInterface<Input, NewOutput>;
|
|
12
22
|
nullable(): SchemaInterface<Input, Output | null>;
|
|
@@ -17,6 +27,8 @@ interface SchemaInterface<Input, Output> {
|
|
|
17
27
|
message: string;
|
|
18
28
|
}): SchemaInterface<Input, Output>;
|
|
19
29
|
}
|
|
30
|
+
interface EnumSchemaInterface<T extends string> extends SchemaInterface<string, T> {
|
|
31
|
+
}
|
|
20
32
|
interface StringSchemaInterface extends SchemaInterface<string, string> {
|
|
21
33
|
}
|
|
22
34
|
interface NumberSchemaInterface extends SchemaInterface<number, number> {
|
|
@@ -33,7 +45,7 @@ interface ObjectSchemaInterface<T extends Record<string, SchemaType>> extends Sc
|
|
|
33
45
|
[Property in keyof T]: ReturnType<T[Property]['parse']>;
|
|
34
46
|
}> {
|
|
35
47
|
}
|
|
36
|
-
type SchemaType = StringSchemaInterface | SchemaInterface<string, string> | SchemaInterface<string, string | undefined> | SchemaInterface<string, string | null> | SchemaInterface<string, string | undefined | null> | ObjectSchemaInterface<Record<string, SchemaType>> | SchemaInterface<object, object> | SchemaInterface<object, object | undefined> | SchemaInterface<object, object | null> | SchemaInterface<object, object | undefined | null> | NumberSchemaInterface | SchemaInterface<number, number> | SchemaInterface<number, number | undefined> | SchemaInterface<number, number | null> | SchemaInterface<number, number | undefined | null> | BooleanSchemaInterface | SchemaInterface<boolean, boolean> | SchemaInterface<boolean, boolean | undefined> | SchemaInterface<boolean, boolean | null> | SchemaInterface<boolean, boolean | undefined | null> | DateSchemaInterface | SchemaInterface<Date, Date> | SchemaInterface<Date, Date | undefined> | SchemaInterface<Date, Date | null> | SchemaInterface<Date, Date | undefined | null> | ArraySchemaInterface<StringSchemaInterface | ObjectSchemaInterface<Record<string, SchemaType>> | NumberSchemaInterface | BooleanSchemaInterface
|
|
48
|
+
type SchemaType = StringSchemaInterface | SchemaInterface<string, string> | SchemaInterface<string, string | undefined> | SchemaInterface<string, string | null> | SchemaInterface<string, string | undefined | null> | ObjectSchemaInterface<Record<string, SchemaType>> | SchemaInterface<object, object> | SchemaInterface<object, object | undefined> | SchemaInterface<object, object | null> | SchemaInterface<object, object | undefined | null> | NumberSchemaInterface | SchemaInterface<number, number> | SchemaInterface<number, number | undefined> | SchemaInterface<number, number | null> | SchemaInterface<number, number | undefined | null> | BooleanSchemaInterface | SchemaInterface<boolean, boolean> | SchemaInterface<boolean, boolean | undefined> | SchemaInterface<boolean, boolean | null> | SchemaInterface<boolean, boolean | undefined | null> | DateSchemaInterface | SchemaInterface<Date, Date> | SchemaInterface<Date, Date | undefined> | SchemaInterface<Date, Date | null> | SchemaInterface<Date, Date | undefined | null> | EnumSchemaInterface<string> | ArraySchemaInterface<StringSchemaInterface | ObjectSchemaInterface<Record<string, SchemaType>> | NumberSchemaInterface | BooleanSchemaInterface | DateSchemaInterface | EnumSchemaInterface<string>> | SchemaInterface<Array<unknown>, Array<unknown>> | SchemaInterface<Array<unknown>, Array<unknown> | undefined> | SchemaInterface<Array<unknown>, Array<unknown> | null> | SchemaInterface<Array<unknown>, Array<unknown> | undefined | null>;
|
|
37
49
|
type ExtenderType = (inter: SchemaType, validation: Function, options: {
|
|
38
50
|
message: string;
|
|
39
51
|
type: string;
|
|
@@ -44,6 +56,7 @@ declare const s: {
|
|
|
44
56
|
number(): NumberSchemaInterface;
|
|
45
57
|
boolean(): BooleanSchemaInterface;
|
|
46
58
|
date(): DateSchemaInterface;
|
|
59
|
+
enum(definition: Readonly<Array<string>>): EnumSchemaInterface<(typeof definition)[number]>;
|
|
47
60
|
array<T extends SchemaType>(definition: T): ArraySchemaInterface<T>;
|
|
48
61
|
any(): any;
|
|
49
62
|
preprocess<T extends SchemaType>(callback: Function, schema: T): T;
|
|
@@ -51,4 +64,4 @@ declare const s: {
|
|
|
51
64
|
declare function extend(callback: ExtenderType): void;
|
|
52
65
|
type Infer<T> = T extends SchemaType ? ReturnType<T['parse']> : unknown;
|
|
53
66
|
|
|
54
|
-
export { type ArraySchemaInterface, type BooleanSchemaInterface, type DateSchemaInterface, type ExtenderType, type Infer, type NumberSchemaInterface, type ObjectSchemaInterface, type SchemaInterface, type SchemaType, type StringSchemaInterface, extend, s };
|
|
67
|
+
export { type ArraySchemaInterface, type BooleanSchemaInterface, type DateSchemaInterface, type EnumSchemaInterface, type ExtenderType, type Infer, type NumberSchemaInterface, type ObjectSchemaInterface, type SchemaInterface, type SchemaType, type StringSchemaInterface, extend, s };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
|
+
type ErrorStructure = {
|
|
2
|
+
message: string;
|
|
3
|
+
cause?: {
|
|
4
|
+
key?: string;
|
|
5
|
+
};
|
|
6
|
+
};
|
|
7
|
+
type Valid<Output> = {
|
|
8
|
+
success: true;
|
|
9
|
+
data: Output;
|
|
10
|
+
};
|
|
11
|
+
type Invalid = {
|
|
12
|
+
success: false;
|
|
13
|
+
error: ErrorStructure;
|
|
14
|
+
};
|
|
15
|
+
type InternalParseOutput<Output> = Valid<Output> | Invalid;
|
|
1
16
|
interface SchemaInterface<Input, Output> {
|
|
17
|
+
_parse(value: Input | Partial<Input> | unknown): InternalParseOutput<Output>;
|
|
2
18
|
parse(value: Input | Partial<Input> | unknown): Output;
|
|
3
|
-
safeParse(value: Input | Partial<Input> | unknown):
|
|
4
|
-
success: true;
|
|
5
|
-
data: Output;
|
|
6
|
-
} | {
|
|
7
|
-
success: false;
|
|
8
|
-
error: Error;
|
|
9
|
-
};
|
|
19
|
+
safeParse(value: Input | Partial<Input> | unknown): InternalParseOutput<Output>;
|
|
10
20
|
optional(): SchemaInterface<Input, Partial<Output> | undefined>;
|
|
11
21
|
transform<NewOutput>(callback: (value: Input) => NewOutput): SchemaInterface<Input, NewOutput>;
|
|
12
22
|
nullable(): SchemaInterface<Input, Output | null>;
|
|
@@ -17,6 +27,8 @@ interface SchemaInterface<Input, Output> {
|
|
|
17
27
|
message: string;
|
|
18
28
|
}): SchemaInterface<Input, Output>;
|
|
19
29
|
}
|
|
30
|
+
interface EnumSchemaInterface<T extends string> extends SchemaInterface<string, T> {
|
|
31
|
+
}
|
|
20
32
|
interface StringSchemaInterface extends SchemaInterface<string, string> {
|
|
21
33
|
}
|
|
22
34
|
interface NumberSchemaInterface extends SchemaInterface<number, number> {
|
|
@@ -33,7 +45,7 @@ interface ObjectSchemaInterface<T extends Record<string, SchemaType>> extends Sc
|
|
|
33
45
|
[Property in keyof T]: ReturnType<T[Property]['parse']>;
|
|
34
46
|
}> {
|
|
35
47
|
}
|
|
36
|
-
type SchemaType = StringSchemaInterface | SchemaInterface<string, string> | SchemaInterface<string, string | undefined> | SchemaInterface<string, string | null> | SchemaInterface<string, string | undefined | null> | ObjectSchemaInterface<Record<string, SchemaType>> | SchemaInterface<object, object> | SchemaInterface<object, object | undefined> | SchemaInterface<object, object | null> | SchemaInterface<object, object | undefined | null> | NumberSchemaInterface | SchemaInterface<number, number> | SchemaInterface<number, number | undefined> | SchemaInterface<number, number | null> | SchemaInterface<number, number | undefined | null> | BooleanSchemaInterface | SchemaInterface<boolean, boolean> | SchemaInterface<boolean, boolean | undefined> | SchemaInterface<boolean, boolean | null> | SchemaInterface<boolean, boolean | undefined | null> | DateSchemaInterface | SchemaInterface<Date, Date> | SchemaInterface<Date, Date | undefined> | SchemaInterface<Date, Date | null> | SchemaInterface<Date, Date | undefined | null> | ArraySchemaInterface<StringSchemaInterface | ObjectSchemaInterface<Record<string, SchemaType>> | NumberSchemaInterface | BooleanSchemaInterface
|
|
48
|
+
type SchemaType = StringSchemaInterface | SchemaInterface<string, string> | SchemaInterface<string, string | undefined> | SchemaInterface<string, string | null> | SchemaInterface<string, string | undefined | null> | ObjectSchemaInterface<Record<string, SchemaType>> | SchemaInterface<object, object> | SchemaInterface<object, object | undefined> | SchemaInterface<object, object | null> | SchemaInterface<object, object | undefined | null> | NumberSchemaInterface | SchemaInterface<number, number> | SchemaInterface<number, number | undefined> | SchemaInterface<number, number | null> | SchemaInterface<number, number | undefined | null> | BooleanSchemaInterface | SchemaInterface<boolean, boolean> | SchemaInterface<boolean, boolean | undefined> | SchemaInterface<boolean, boolean | null> | SchemaInterface<boolean, boolean | undefined | null> | DateSchemaInterface | SchemaInterface<Date, Date> | SchemaInterface<Date, Date | undefined> | SchemaInterface<Date, Date | null> | SchemaInterface<Date, Date | undefined | null> | EnumSchemaInterface<string> | ArraySchemaInterface<StringSchemaInterface | ObjectSchemaInterface<Record<string, SchemaType>> | NumberSchemaInterface | BooleanSchemaInterface | DateSchemaInterface | EnumSchemaInterface<string>> | SchemaInterface<Array<unknown>, Array<unknown>> | SchemaInterface<Array<unknown>, Array<unknown> | undefined> | SchemaInterface<Array<unknown>, Array<unknown> | null> | SchemaInterface<Array<unknown>, Array<unknown> | undefined | null>;
|
|
37
49
|
type ExtenderType = (inter: SchemaType, validation: Function, options: {
|
|
38
50
|
message: string;
|
|
39
51
|
type: string;
|
|
@@ -44,6 +56,7 @@ declare const s: {
|
|
|
44
56
|
number(): NumberSchemaInterface;
|
|
45
57
|
boolean(): BooleanSchemaInterface;
|
|
46
58
|
date(): DateSchemaInterface;
|
|
59
|
+
enum(definition: Readonly<Array<string>>): EnumSchemaInterface<(typeof definition)[number]>;
|
|
47
60
|
array<T extends SchemaType>(definition: T): ArraySchemaInterface<T>;
|
|
48
61
|
any(): any;
|
|
49
62
|
preprocess<T extends SchemaType>(callback: Function, schema: T): T;
|
|
@@ -51,4 +64,4 @@ declare const s: {
|
|
|
51
64
|
declare function extend(callback: ExtenderType): void;
|
|
52
65
|
type Infer<T> = T extends SchemaType ? ReturnType<T['parse']> : unknown;
|
|
53
66
|
|
|
54
|
-
export { type ArraySchemaInterface, type BooleanSchemaInterface, type DateSchemaInterface, type ExtenderType, type Infer, type NumberSchemaInterface, type ObjectSchemaInterface, type SchemaInterface, type SchemaType, type StringSchemaInterface, extend, s };
|
|
67
|
+
export { type ArraySchemaInterface, type BooleanSchemaInterface, type DateSchemaInterface, type EnumSchemaInterface, type ExtenderType, type Infer, type NumberSchemaInterface, type ObjectSchemaInterface, type SchemaInterface, type SchemaType, type StringSchemaInterface, extend, s };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
'use strict';var y=
|
|
1
|
+
'use strict';var h=r=>typeof r=="string"||r instanceof String,I=r=>typeof r=="number"||r instanceof Number,l=r=>r===true||r===false,y=r=>r instanceof Date&&!Number.isNaN(r.getTime()),d=r=>Array.isArray(r),S=r=>typeof r=="object"&&r!==null&&!Array.isArray(r),g={object(r){let a=p(S,{type:"object"});return i(a,"_parse",(u,...o)=>{let c=u(...o);if(c.success===false)return c;let n={};for(let t in r){let e=r[t]._parse(c.data[t]);if(e.success)n[t]=e.data;else {e=e;let s=e?.error?.cause?.key?`${t}.${e?.error?.cause?.key}`:t;return e.error.message=`Error parsing key "${s}": ${e.error.message}`,e.error.cause={key:s},e}}return {success:true,data:n}}),a},string(){return p(h,{type:"string"})},number(){return p(I,{type:"number"})},boolean(){return p(l,{type:"boolean"})},date(){return p(y,{type:"date"})},enum(r){let a=n=>r.includes(n),u=n=>`Invalid ${o} value. Expected ${r.map(t=>`"${t}"`).join(" | ")}, received "${n}".`,o="enum";return p(a,{type:o,message:u})},array(r){let a=p(d,{type:"array"});return i(a,"_parse",(u,...o)=>{let c=u(...o);if(c.success===false)return c;let n=[];for(let t=0;t<c.data.length;t++){let e=r._parse(c.data[t]);if(e.success)n.push(e.data);else {e=e;let s=e.error?.cause?.key?`${t}.${e.error.cause.key}`:`${t}`;return e.error.message=`Error parsing index "${t}": ${e.error.message}`,e.error.cause={key:s},e}}return {success:true,data:n}}),a},any(){return p(()=>true)},preprocess(r,a){return i(a,"_parse",(u,o)=>(o=r(o),u(o))),a}};function b(r){return a=>`The value "${a}" must be type of ${r} but is type of "${typeof a}".`}function i(r,a,u){let o=r[a];r[a]=(...c)=>u(o,...c);}function p(r,{type:a="any",message:u}={}){u=u||b(a);let o={message:u,type:a},c={_parse(n){return r(n)?{success:true,data:n}:{success:false,error:{message:u(n)}}},parse(n){let t=c._parse(n);if(!t.success)throw t=t,new Error(t.error.message,{cause:t.error.cause});return t.data},safeParse(n){return c._parse(n)},transform(n){return i(this,"_parse",(t,e)=>{let s=t(e);return s.success&&(s.data=n(s.data)),s}),this},optional(){return i(this,"_parse",(n,t)=>{let e=n(t);return e.success||(e.data=void 0,e.success=true),e}),this},nullable(){return i(this,"_parse",(n,t)=>{let e=n(t);return e.success||(e.data=null,e.success=true),e}),this},nullish(){return i(this,"_parse",(n,t)=>{let e=n(t);return !e.success&&t==null&&(e.success=true,e.data=t),e}),this},default(n){return i(this,"_parse",(t,e)=>(e===void 0&&(e=n,e=typeof n=="function"?n():n),t(e))),this},pipe(n){return i(this,"_parse",(t,e)=>{let s=t(e);return s.success?n._parse(s.data):s}),this},refine(n,{message:t}){return i(this,"_parse",(e,s)=>{let m=e(s);return n(m.data)?m:{success:false,error:{message:t}}}),this}};return f.length>0?f.reduce((n,t)=>t(n,r,o)??n,c):c}var f=[];function T(r){f.push(r);}exports.extend=T;exports.s=g;
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var y=
|
|
1
|
+
var h=r=>typeof r=="string"||r instanceof String,I=r=>typeof r=="number"||r instanceof Number,l=r=>r===true||r===false,y=r=>r instanceof Date&&!Number.isNaN(r.getTime()),d=r=>Array.isArray(r),S=r=>typeof r=="object"&&r!==null&&!Array.isArray(r),g={object(r){let a=p(S,{type:"object"});return i(a,"_parse",(u,...o)=>{let c=u(...o);if(c.success===false)return c;let n={};for(let t in r){let e=r[t]._parse(c.data[t]);if(e.success)n[t]=e.data;else {e=e;let s=e?.error?.cause?.key?`${t}.${e?.error?.cause?.key}`:t;return e.error.message=`Error parsing key "${s}": ${e.error.message}`,e.error.cause={key:s},e}}return {success:true,data:n}}),a},string(){return p(h,{type:"string"})},number(){return p(I,{type:"number"})},boolean(){return p(l,{type:"boolean"})},date(){return p(y,{type:"date"})},enum(r){let a=n=>r.includes(n),u=n=>`Invalid ${o} value. Expected ${r.map(t=>`"${t}"`).join(" | ")}, received "${n}".`,o="enum";return p(a,{type:o,message:u})},array(r){let a=p(d,{type:"array"});return i(a,"_parse",(u,...o)=>{let c=u(...o);if(c.success===false)return c;let n=[];for(let t=0;t<c.data.length;t++){let e=r._parse(c.data[t]);if(e.success)n.push(e.data);else {e=e;let s=e.error?.cause?.key?`${t}.${e.error.cause.key}`:`${t}`;return e.error.message=`Error parsing index "${t}": ${e.error.message}`,e.error.cause={key:s},e}}return {success:true,data:n}}),a},any(){return p(()=>true)},preprocess(r,a){return i(a,"_parse",(u,o)=>(o=r(o),u(o))),a}};function b(r){return a=>`The value "${a}" must be type of ${r} but is type of "${typeof a}".`}function i(r,a,u){let o=r[a];r[a]=(...c)=>u(o,...c);}function p(r,{type:a="any",message:u}={}){u=u||b(a);let o={message:u,type:a},c={_parse(n){return r(n)?{success:true,data:n}:{success:false,error:{message:u(n)}}},parse(n){let t=c._parse(n);if(!t.success)throw t=t,new Error(t.error.message,{cause:t.error.cause});return t.data},safeParse(n){return c._parse(n)},transform(n){return i(this,"_parse",(t,e)=>{let s=t(e);return s.success&&(s.data=n(s.data)),s}),this},optional(){return i(this,"_parse",(n,t)=>{let e=n(t);return e.success||(e.data=void 0,e.success=true),e}),this},nullable(){return i(this,"_parse",(n,t)=>{let e=n(t);return e.success||(e.data=null,e.success=true),e}),this},nullish(){return i(this,"_parse",(n,t)=>{let e=n(t);return !e.success&&t==null&&(e.success=true,e.data=t),e}),this},default(n){return i(this,"_parse",(t,e)=>(e===void 0&&(e=n,e=typeof n=="function"?n():n),t(e))),this},pipe(n){return i(this,"_parse",(t,e)=>{let s=t(e);return s.success?n._parse(s.data):s}),this},refine(n,{message:t}){return i(this,"_parse",(e,s)=>{let m=e(s);return n(m.data)?m:{success:false,error:{message:t}}}),this}};return f.length>0?f.reduce((n,t)=>t(n,r,o)??n,c):c}var f=[];function T(r){f.push(r);}export{T as extend,g as s};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@esmj/schema",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Tiny extendable package for schema validation.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"schema",
|
|
@@ -22,6 +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/index.ts",
|
|
25
26
|
"dev": "node_modules/.bin/tsup --dts --watch --onSuccess 'node ./dist/index.mjs'",
|
|
26
27
|
"test": "node --test --experimental-strip-types",
|
|
27
28
|
"test:watch": "npm run test -- --watch",
|
|
@@ -62,17 +63,22 @@
|
|
|
62
63
|
"homepage": "https://github.com/mjancarik/esmj-schema#readme",
|
|
63
64
|
"devDependencies": {
|
|
64
65
|
"@biomejs/biome": "1.9.4",
|
|
65
|
-
"@commitlint/cli": "^19.
|
|
66
|
-
"@commitlint/config-conventional": "^19.
|
|
67
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
68
|
-
"@typescript-eslint/parser": "^8.
|
|
66
|
+
"@commitlint/cli": "^19.8.1",
|
|
67
|
+
"@commitlint/config-conventional": "^19.8.1",
|
|
68
|
+
"@typescript-eslint/eslint-plugin": "^8.33.0",
|
|
69
|
+
"@typescript-eslint/parser": "^8.33.0",
|
|
70
|
+
"@zod/mini": "^4.0.0-beta.0",
|
|
69
71
|
"commitizen": "^4.3.1",
|
|
70
72
|
"conventional-changelog-cli": "^5.0.0",
|
|
71
73
|
"cz-conventional-changelog": "^3.3.0",
|
|
72
74
|
"git-cz": "^4.9.0",
|
|
73
75
|
"husky": "^9.1.7",
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
76
|
+
"joi": "^17.13.3",
|
|
77
|
+
"lint-staged": "^16.1.0",
|
|
78
|
+
"prettier": "^3.5.3",
|
|
79
|
+
"superstruct": "^2.0.2",
|
|
80
|
+
"tsup": "^8.5.0",
|
|
81
|
+
"yup": "^1.6.1",
|
|
82
|
+
"zod": "^3.25.42"
|
|
77
83
|
}
|
|
78
84
|
}
|
package/biome.json
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"files": {
|
|
3
|
-
"include": ["src/**/*.mjs", "src/**/*.ts", "utils/**/*.mjs"],
|
|
4
|
-
"ignore": [".history/**/*"]
|
|
5
|
-
},
|
|
6
|
-
"formatter": {
|
|
7
|
-
"enabled": true,
|
|
8
|
-
"formatWithErrors": true,
|
|
9
|
-
"indentStyle": "space",
|
|
10
|
-
"indentWidth": 2,
|
|
11
|
-
"lineEnding": "lf",
|
|
12
|
-
"lineWidth": 80,
|
|
13
|
-
"attributePosition": "auto"
|
|
14
|
-
},
|
|
15
|
-
"organizeImports": { "enabled": true },
|
|
16
|
-
"linter": {
|
|
17
|
-
"enabled": true,
|
|
18
|
-
"rules": {
|
|
19
|
-
"recommended": true,
|
|
20
|
-
"complexity": {
|
|
21
|
-
"noForEach": "off",
|
|
22
|
-
"noBannedTypes": "off"
|
|
23
|
-
},
|
|
24
|
-
"style": {
|
|
25
|
-
"noParameterAssign": "off"
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
"javascript": {
|
|
30
|
-
"formatter": {
|
|
31
|
-
"jsxQuoteStyle": "double",
|
|
32
|
-
"quoteProperties": "asNeeded",
|
|
33
|
-
"trailingCommas": "all",
|
|
34
|
-
"semicolons": "always",
|
|
35
|
-
"arrowParentheses": "always",
|
|
36
|
-
"bracketSpacing": true,
|
|
37
|
-
"bracketSameLine": false,
|
|
38
|
-
"quoteStyle": "single",
|
|
39
|
-
"attributePosition": "auto"
|
|
40
|
-
}
|
|
41
|
-
},
|
|
42
|
-
"overrides": [
|
|
43
|
-
{
|
|
44
|
-
"include": ["*.json"],
|
|
45
|
-
"formatter": {
|
|
46
|
-
"indentWidth": 2
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
]
|
|
50
|
-
}
|