ivl 0.4.4 → 0.5.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 +303 -2
- package/lib/core.d.ts +136 -50
- package/lib/helpers/index.js +1 -1
- package/lib/helpers/rules.d.ts +162 -12
- package/lib/helpers/schema.d.ts +39 -9
- package/lib/index.js +1 -1
- package/lib/patterns/index.d.ts +1 -0
- package/lib/patterns/index.js +1 -1
- package/lib/patterns/rule-sets.d.ts +19 -0
- package/lib/types.d.ts +86 -12
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Main focus is on speed and flexibility of the validation rules.
|
|
|
4
4
|
|
|
5
5
|
By default `getValueErrors` and `getSchemaErrors` automatically detects and chooses the most performant checking method for your rule set.
|
|
6
6
|
|
|
7
|
-
If
|
|
7
|
+
If you validate against the same rule set or schema repeatedly, compile it once with `compileRules`/`compileSchema` (see [Compiled validators](#compiled-validators)) - that does the sync/async detection up front and is the fastest option.
|
|
8
8
|
|
|
9
9
|
Use synchronous versions of the functions for better performance if you don't need to support asynchronous checks on your inputs.
|
|
10
10
|
|
|
@@ -51,6 +51,80 @@ const inDatabase: RULE<string, [ctx: { db: Database }]> = async (value, ctx) =>
|
|
|
51
51
|
> "may be sync or async", so the return type becomes `string[] | Promise<string[]>`. Prefer
|
|
52
52
|
> `satisfies RULES` / `satisfies SCHEMA`, which validates the shape without losing the inferred types.
|
|
53
53
|
|
|
54
|
+
# Compiled validators
|
|
55
|
+
`compileRules` and `compileSchema` turn a rule set or schema into a reusable validator. They return
|
|
56
|
+
exactly what `getValueErrors`/`getSchemaErrors` would, with the same sync/async type inference, but the
|
|
57
|
+
work those functions repeat on every call - finding the rule keys and checking for async rules - is
|
|
58
|
+
done once up front:
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { compileSchema } from 'ivl';
|
|
62
|
+
import { EMAIL_RULES, STRONG_PASSWORD_RULES } from 'ivl/patterns';
|
|
63
|
+
|
|
64
|
+
// Compile once, at module level
|
|
65
|
+
const validateRegistration = compileSchema({
|
|
66
|
+
email: EMAIL_RULES,
|
|
67
|
+
password: STRONG_PASSWORD_RULES,
|
|
68
|
+
}, { strict: true });
|
|
69
|
+
|
|
70
|
+
// ...then call it per request
|
|
71
|
+
const errors = validateRegistration(body); // { email: string[], password: string[] }
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The rule sets and options are captured when compiling, so changing them afterwards has no effect on an
|
|
75
|
+
existing validator.
|
|
76
|
+
|
|
77
|
+
# Options
|
|
78
|
+
`getSchemaErrors`, `getSchemaErrorsSync`, `getSchemaErrorsAsync` and `compileSchema` take an options object;
|
|
79
|
+
`compileRules` takes `break_early`. Both options are off by default.
|
|
80
|
+
|
|
81
|
+
- **`strict`** - also report keys of the object that the schema doesn't have, each as `['Key not allowed']`.
|
|
82
|
+
- **`break_early`** - report only the first failing rule of each rule set instead of all of them. Rules
|
|
83
|
+
that aren't `async` run first, in order, and stop at the first failure; `async` rules only run if all of
|
|
84
|
+
those passed. So a cheap check that fails skips the expensive ones, like a long regex or a database lookup:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
const validateEmail = compileRules({
|
|
88
|
+
...EMAIL_RULES, // cheap checks first
|
|
89
|
+
"Email already registered": async (i: unknown) => !(await emailExists(i)),
|
|
90
|
+
}, { break_early: true });
|
|
91
|
+
|
|
92
|
+
await validateEmail('not an email'); // ['Must be a valid email address'] - the lookup never ran
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Every field of a schema is still validated with `break_early`; each just reports at most one error. Leave
|
|
96
|
+
it off when you want to show users every problem at once, e.g. all unmet password requirements.
|
|
97
|
+
|
|
98
|
+
# Ready-made rule sets
|
|
99
|
+
`ivl/patterns` exports rule sets for common formats, ready to drop into a schema:
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import { getSchemaErrors } from 'ivl';
|
|
103
|
+
import { EMAIL_RULES, STRONG_PASSWORD_RULES, IPV4_RULES, IPV6_RULES } from 'ivl/patterns';
|
|
104
|
+
|
|
105
|
+
const errors = getSchemaErrors(input, {
|
|
106
|
+
email: EMAIL_RULES,
|
|
107
|
+
password: STRONG_PASSWORD_RULES,
|
|
108
|
+
ip: [IPV4_RULES, IPV6_RULES], // passes if either rule set passes
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Available: `EMAIL_RULES`, `URL_RULES`, `UUID_RULES`, `UUID_V4_RULES`, `IPV4_RULES`, `IPV6_RULES`,
|
|
113
|
+
`MAC_ADDRESS_RULES`, `HEX_COLOR_RULES`, `SLUG_RULES`, `E164_PHONE_RULES`, `SEMVER_RULES`, `BASE64_RULES`,
|
|
114
|
+
`JWT_RULES`, `ISO_8601_DATE_RULES`, `ISO_8601_DATETIME_RULES`, `ISO_8601_TIME_RULES`, `PASSWORD_RULES`
|
|
115
|
+
and `STRONG_PASSWORD_RULES`.
|
|
116
|
+
|
|
117
|
+
All of them are synchronous and frozen. To customise one, spread it into a new object:
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
const COMPANY_EMAIL_RULES = {
|
|
121
|
+
...EMAIL_RULES,
|
|
122
|
+
"Must be a company address": (i: unknown) => typeof i === 'string' && i.endsWith('@example.com'),
|
|
123
|
+
};
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The date rule sets also check the calendar, so `2024-02-30` fails even though it matches the pattern.
|
|
127
|
+
|
|
54
128
|
# Installing
|
|
55
129
|
```typescript
|
|
56
130
|
bun add ivl // bun.js
|
|
@@ -209,4 +283,231 @@ app.put('/register/:invitation_code',
|
|
|
209
283
|
(c)=> c.text("Success"));
|
|
210
284
|
|
|
211
285
|
export default app;
|
|
212
|
-
```
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
<!-- benchmark:start -->
|
|
289
|
+
# Benchmarks
|
|
290
|
+
|
|
291
|
+
Generated by CI on a GitHub-hosted runner, so absolute numbers vary between runs.
|
|
292
|
+
Compare rows within a table rather than across runs. Read the caveats at the end before
|
|
293
|
+
drawing conclusions: the libraries do different amounts of work in some scenarios.
|
|
294
|
+
|
|
295
|
+
## Bun (JavaScriptCore)
|
|
296
|
+
|
|
297
|
+
- **clk**: ~4.30 GHz
|
|
298
|
+
- **cpu**: AMD EPYC 9V45 96-Core Processor
|
|
299
|
+
- **runtime**: bun 1.4.2 (x64-linux)
|
|
300
|
+
|
|
301
|
+
| • ivl execution paths | avg | min | p75 | p99 | max |
|
|
302
|
+
| ------------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
303
|
+
| pure regex helper | ` 13.52 ns/iter` | ` 12.84 ns` | ` 13.64 ns` | ` 16.26 ns` | ` 35.29 ns` |
|
|
304
|
+
| async regex helper | ` 82.30 ns/iter` | ` 73.32 ns` | ` 80.07 ns` | `156.46 ns` | `265.68 ns` |
|
|
305
|
+
| smart regex helper | ` 26.02 ns/iter` | ` 22.43 ns` | ` 24.92 ns` | ` 82.75 ns` | `180.55 ns` |
|
|
306
|
+
| sync regex helper | ` 24.25 ns/iter` | ` 19.55 ns` | ` 23.57 ns` | ` 75.54 ns` | `210.71 ns` |
|
|
307
|
+
|
|
308
|
+
| • single regex rule, report all errors (valid input) | avg | min | p75 | p99 | max |
|
|
309
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
310
|
+
| ivl | ` 34.12 ns/iter` | ` 28.45 ns` | ` 34.15 ns` | ` 90.83 ns` | `133.14 ns` |
|
|
311
|
+
| ivl compiled | ` 38.29 ns/iter` | ` 34.44 ns` | ` 37.92 ns` | ` 95.95 ns` | `122.56 ns` |
|
|
312
|
+
| zod | ` 61.64 ns/iter` | ` 50.50 ns` | ` 54.90 ns` | `197.04 ns` | `418.33 ns` |
|
|
313
|
+
| valibot | ` 36.60 ns/iter` | ` 33.16 ns` | ` 36.12 ns` | ` 69.51 ns` | `129.53 ns` |
|
|
314
|
+
| yup | `705.02 ns/iter` | `618.97 ns` | `732.24 ns` | `846.00 ns` | ` 1.25 µs` |
|
|
315
|
+
|
|
316
|
+
| • single regex rule, report all errors (invalid input) | avg | min | p75 | p99 | max |
|
|
317
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
318
|
+
| ivl | ` 21.34 ns/iter` | ` 18.91 ns` | ` 20.92 ns` | ` 80.84 ns` | `109.01 ns` |
|
|
319
|
+
| ivl compiled | ` 29.84 ns/iter` | ` 26.05 ns` | ` 28.86 ns` | ` 97.03 ns` | `148.36 ns` |
|
|
320
|
+
| zod | ` 1.11 µs/iter` | ` 1.03 µs` | ` 1.11 µs` | ` 1.36 µs` | ` 1.45 µs` |
|
|
321
|
+
| valibot | ` 59.58 ns/iter` | ` 50.78 ns` | ` 57.61 ns` | `127.88 ns` | `184.43 ns` |
|
|
322
|
+
| yup | ` 5.00 µs/iter` | ` 4.78 µs` | ` 5.05 µs` | ` 5.35 µs` | ` 5.42 µs` |
|
|
323
|
+
|
|
324
|
+
| • single regex rule, pass/fail (valid input) | avg | min | p75 | p99 | max |
|
|
325
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
326
|
+
| ivl compiled | ` 26.07 ns/iter` | ` 23.87 ns` | ` 25.92 ns` | ` 40.28 ns` | `113.68 ns` |
|
|
327
|
+
| zod | ` 58.58 ns/iter` | ` 50.32 ns` | ` 56.24 ns` | `133.43 ns` | `150.19 ns` |
|
|
328
|
+
| valibot | ` 31.14 ns/iter` | ` 27.63 ns` | ` 29.65 ns` | ` 90.41 ns` | `151.00 ns` |
|
|
329
|
+
| yup | `722.17 ns/iter` | `639.21 ns` | `770.56 ns` | `816.36 ns` | `901.42 ns` |
|
|
330
|
+
|
|
331
|
+
| • single regex rule, pass/fail (invalid input) | avg | min | p75 | p99 | max |
|
|
332
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
333
|
+
| ivl compiled | ` 16.51 ns/iter` | ` 14.88 ns` | ` 16.05 ns` | ` 28.92 ns` | ` 97.51 ns` |
|
|
334
|
+
| zod | ` 1.05 µs/iter` | `992.50 ns` | ` 1.06 µs` | ` 1.19 µs` | ` 1.21 µs` |
|
|
335
|
+
| valibot | ` 56.66 ns/iter` | ` 46.98 ns` | ` 53.78 ns` | `136.47 ns` | `341.59 ns` |
|
|
336
|
+
| yup | ` 3.40 µs/iter` | ` 3.26 µs` | ` 3.46 µs` | ` 3.59 µs` | ` 3.61 µs` |
|
|
337
|
+
|
|
338
|
+
| • built-in email validator (regexes differ) (valid input) | avg | min | p75 | p99 | max |
|
|
339
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
340
|
+
| ivl | ` 51.80 ns/iter` | ` 47.35 ns` | ` 50.80 ns` | `127.91 ns` | `194.98 ns` |
|
|
341
|
+
| ivl compiled | ` 41.66 ns/iter` | ` 37.96 ns` | ` 41.18 ns` | `103.09 ns` | `136.03 ns` |
|
|
342
|
+
| zod | ` 70.53 ns/iter` | ` 63.73 ns` | ` 69.40 ns` | `141.86 ns` | `294.39 ns` |
|
|
343
|
+
| valibot | ` 43.41 ns/iter` | ` 40.13 ns` | ` 43.64 ns` | ` 72.32 ns` | `143.37 ns` |
|
|
344
|
+
| yup | `832.47 ns/iter` | `751.96 ns` | `880.36 ns` | `961.46 ns` | `981.26 ns` |
|
|
345
|
+
|
|
346
|
+
| • built-in email validator (regexes differ) (invalid input) | avg | min | p75 | p99 | max |
|
|
347
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
348
|
+
| ivl | ` 45.57 ns/iter` | ` 40.58 ns` | ` 44.95 ns` | `124.01 ns` | `155.78 ns` |
|
|
349
|
+
| ivl compiled | ` 36.58 ns/iter` | ` 31.31 ns` | ` 33.96 ns` | `111.54 ns` | `215.61 ns` |
|
|
350
|
+
| zod | ` 1.32 µs/iter` | ` 1.18 µs` | ` 1.29 µs` | ` 2.22 µs` | ` 2.77 µs` |
|
|
351
|
+
| valibot | ` 70.15 ns/iter` | ` 62.03 ns` | ` 68.73 ns` | `137.41 ns` | `170.45 ns` |
|
|
352
|
+
| yup | ` 4.30 µs/iter` | ` 4.04 µs` | ` 4.41 µs` | ` 4.60 µs` | ` 4.65 µs` |
|
|
353
|
+
|
|
354
|
+
| • object schema, report all errors (valid input) | avg | min | p75 | p99 | max |
|
|
355
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
356
|
+
| ivl | `327.50 ns/iter` | `299.90 ns` | `320.39 ns` | `492.24 ns` | `668.48 ns` |
|
|
357
|
+
| ivl compiled | `203.15 ns/iter` | `185.28 ns` | `197.36 ns` | `349.93 ns` | `545.51 ns` |
|
|
358
|
+
| zod | `348.37 ns/iter` | `309.78 ns` | `339.21 ns` | `617.57 ns` | `879.07 ns` |
|
|
359
|
+
| valibot | `321.00 ns/iter` | `306.99 ns` | `322.20 ns` | `425.95 ns` | `498.46 ns` |
|
|
360
|
+
| yup | ` 5.37 µs/iter` | ` 5.17 µs` | ` 5.49 µs` | ` 5.57 µs` | ` 5.62 µs` |
|
|
361
|
+
|
|
362
|
+
| • object schema, report all errors (invalid input) | avg | min | p75 | p99 | max |
|
|
363
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
364
|
+
| ivl | `351.10 ns/iter` | `327.31 ns` | `353.17 ns` | `441.63 ns` | `531.51 ns` |
|
|
365
|
+
| ivl compiled | `198.54 ns/iter` | `184.70 ns` | `195.92 ns` | `283.96 ns` | `316.35 ns` |
|
|
366
|
+
| zod | ` 2.12 µs/iter` | ` 1.87 µs` | ` 2.28 µs` | ` 2.59 µs` | ` 2.60 µs` |
|
|
367
|
+
| valibot | `545.94 ns/iter` | `497.96 ns` | `555.42 ns` | `665.79 ns` | ` 1.13 µs` |
|
|
368
|
+
| yup | ` 17.34 µs/iter` | ` 8.43 µs` | ` 16.94 µs` | ` 47.33 µs` | `636.65 µs` |
|
|
369
|
+
|
|
370
|
+
| • object schema, pass/fail (valid input) | avg | min | p75 | p99 | max |
|
|
371
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
372
|
+
| ivl compiled | `212.72 ns/iter` | `198.92 ns` | `210.15 ns` | `296.15 ns` | `305.23 ns` |
|
|
373
|
+
| zod | `379.33 ns/iter` | `330.83 ns` | `355.65 ns` | `790.78 ns` | `972.48 ns` |
|
|
374
|
+
| valibot | `335.73 ns/iter` | `325.24 ns` | `335.79 ns` | `419.19 ns` | `429.04 ns` |
|
|
375
|
+
| yup | ` 5.53 µs/iter` | ` 5.33 µs` | ` 5.60 µs` | ` 5.83 µs` | ` 5.83 µs` |
|
|
376
|
+
|
|
377
|
+
| • object schema, pass/fail (invalid input) | avg | min | p75 | p99 | max |
|
|
378
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
379
|
+
| ivl compiled | `165.02 ns/iter` | `146.93 ns` | `154.26 ns` | `372.14 ns` | `539.38 ns` |
|
|
380
|
+
| zod | ` 2.05 µs/iter` | ` 1.93 µs` | ` 2.09 µs` | ` 2.36 µs` | ` 2.40 µs` |
|
|
381
|
+
| valibot | `219.92 ns/iter` | `190.17 ns` | `206.55 ns` | `470.12 ns` | `573.75 ns` |
|
|
382
|
+
| yup | ` 6.74 µs/iter` | ` 6.35 µs` | ` 6.82 µs` | ` 7.05 µs` | ` 7.32 µs` |
|
|
383
|
+
|
|
384
|
+
| • object schema with an async rule, report all errors (valid input) | avg | min | p75 | p99 | max |
|
|
385
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
386
|
+
| ivl | ` 1.49 µs/iter` | `991.00 ns` | ` 1.55 µs` | ` 3.67 µs` | `407.89 µs` |
|
|
387
|
+
| ivl compiled | `972.10 ns/iter` | `892.33 ns` | ` 1.01 µs` | ` 1.22 µs` | ` 1.50 µs` |
|
|
388
|
+
| zod | ` 2.04 µs/iter` | ` 1.45 µs` | ` 2.13 µs` | ` 4.55 µs` | `421.99 µs` |
|
|
389
|
+
| valibot | ` 2.06 µs/iter` | ` 1.42 µs` | ` 2.17 µs` | ` 4.55 µs` | `413.39 µs` |
|
|
390
|
+
| yup | ` 6.34 µs/iter` | ` 6.05 µs` | ` 6.48 µs` | ` 6.68 µs` | ` 6.72 µs` |
|
|
391
|
+
|
|
392
|
+
| • object schema with an async rule, report all errors (invalid input) | avg | min | p75 | p99 | max |
|
|
393
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
394
|
+
| ivl | ` 1.15 µs/iter` | ` 1.08 µs` | ` 1.20 µs` | ` 1.25 µs` | ` 1.45 µs` |
|
|
395
|
+
| ivl compiled | `988.52 ns/iter` | `926.70 ns` | ` 1.04 µs` | ` 1.09 µs` | ` 1.09 µs` |
|
|
396
|
+
| zod | ` 3.25 µs/iter` | ` 3.03 µs` | ` 3.34 µs` | ` 3.50 µs` | ` 3.51 µs` |
|
|
397
|
+
| valibot | ` 1.76 µs/iter` | ` 1.60 µs` | ` 1.81 µs` | ` 1.96 µs` | ` 1.99 µs` |
|
|
398
|
+
| yup | ` 12.97 µs/iter` | ` 12.54 µs` | ` 13.12 µs` | ` 13.27 µs` | ` 13.37 µs` |
|
|
399
|
+
|
|
400
|
+
## Node (V8)
|
|
401
|
+
|
|
402
|
+
- **clk**: ~4.25 GHz
|
|
403
|
+
- **cpu**: AMD EPYC 9V45 96-Core Processor
|
|
404
|
+
- **runtime**: node 24.21.0 (x64-linux)
|
|
405
|
+
|
|
406
|
+
| • ivl execution paths | avg | min | p75 | p99 | max |
|
|
407
|
+
| ------------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
408
|
+
| pure regex helper | ` 24.51 ns/iter` | ` 20.15 ns` | ` 23.01 ns` | ` 59.01 ns` | `141.77 ns` |
|
|
409
|
+
| async regex helper | `115.24 ns/iter` | `103.07 ns` | `116.37 ns` | `244.47 ns` | `565.06 ns` |
|
|
410
|
+
| smart regex helper | ` 57.60 ns/iter` | ` 53.07 ns` | ` 56.42 ns` | `113.03 ns` | `173.16 ns` |
|
|
411
|
+
| sync regex helper | ` 37.14 ns/iter` | ` 34.47 ns` | ` 37.31 ns` | ` 54.91 ns` | ` 88.52 ns` |
|
|
412
|
+
|
|
413
|
+
| • single regex rule, report all errors (valid input) | avg | min | p75 | p99 | max |
|
|
414
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
415
|
+
| ivl | ` 62.56 ns/iter` | ` 57.85 ns` | ` 61.46 ns` | `121.22 ns` | `259.12 ns` |
|
|
416
|
+
| ivl compiled | ` 33.48 ns/iter` | ` 30.43 ns` | ` 33.13 ns` | ` 53.45 ns` | `104.86 ns` |
|
|
417
|
+
| zod | ` 83.41 ns/iter` | ` 68.60 ns` | `103.02 ns` | `216.69 ns` | `618.68 ns` |
|
|
418
|
+
| valibot | ` 43.02 ns/iter` | ` 40.24 ns` | ` 43.45 ns` | ` 60.00 ns` | `136.12 ns` |
|
|
419
|
+
| yup | `698.06 ns/iter` | `638.67 ns` | `710.79 ns` | ` 1.00 µs` | ` 1.24 µs` |
|
|
420
|
+
|
|
421
|
+
| • single regex rule, report all errors (invalid input) | avg | min | p75 | p99 | max |
|
|
422
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
423
|
+
| ivl | ` 49.52 ns/iter` | ` 46.45 ns` | ` 49.37 ns` | ` 68.94 ns` | ` 95.38 ns` |
|
|
424
|
+
| ivl compiled | ` 23.19 ns/iter` | ` 21.80 ns` | ` 22.96 ns` | ` 38.54 ns` | `113.55 ns` |
|
|
425
|
+
| zod | ` 1.53 µs/iter` | ` 1.28 µs` | ` 1.36 µs` | ` 3.73 µs` | ` 3.76 µs` |
|
|
426
|
+
| valibot | `184.48 ns/iter` | ` 71.54 ns` | ` 78.01 ns` | ` 4.15 µs` | ` 4.90 µs` |
|
|
427
|
+
| yup | ` 23.65 µs/iter` | ` 22.82 µs` | ` 23.81 µs` | ` 23.96 µs` | ` 25.73 µs` |
|
|
428
|
+
|
|
429
|
+
| • single regex rule, pass/fail (valid input) | avg | min | p75 | p99 | max |
|
|
430
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
431
|
+
| ivl compiled | ` 32.47 ns/iter` | ` 29.39 ns` | ` 33.25 ns` | ` 38.61 ns` | ` 83.76 ns` |
|
|
432
|
+
| zod | ` 72.01 ns/iter` | ` 66.45 ns` | ` 70.41 ns` | `122.20 ns` | `604.70 ns` |
|
|
433
|
+
| valibot | ` 40.36 ns/iter` | ` 38.46 ns` | ` 40.81 ns` | ` 47.20 ns` | `100.89 ns` |
|
|
434
|
+
| yup | `696.18 ns/iter` | `668.23 ns` | `705.27 ns` | `760.27 ns` | `810.10 ns` |
|
|
435
|
+
|
|
436
|
+
| • single regex rule, pass/fail (invalid input) | avg | min | p75 | p99 | max |
|
|
437
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
438
|
+
| ivl compiled | ` 22.68 ns/iter` | ` 21.30 ns` | ` 22.63 ns` | ` 36.02 ns` | `127.04 ns` |
|
|
439
|
+
| zod | ` 1.50 µs/iter` | ` 1.30 µs` | ` 1.33 µs` | ` 3.32 µs` | ` 3.41 µs` |
|
|
440
|
+
| valibot | `188.62 ns/iter` | ` 71.83 ns` | ` 76.80 ns` | ` 4.18 µs` | ` 5.15 µs` |
|
|
441
|
+
| yup | ` 13.65 µs/iter` | ` 13.58 µs` | ` 13.70 µs` | ` 13.70 µs` | ` 13.72 µs` |
|
|
442
|
+
|
|
443
|
+
| • built-in email validator (regexes differ) (valid input) | avg | min | p75 | p99 | max |
|
|
444
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
445
|
+
| ivl | `118.83 ns/iter` | `107.39 ns` | `114.09 ns` | `295.92 ns` | `390.04 ns` |
|
|
446
|
+
| ivl compiled | ` 43.08 ns/iter` | ` 40.58 ns` | ` 43.35 ns` | ` 68.22 ns` | `145.20 ns` |
|
|
447
|
+
| zod | `117.66 ns/iter` | `100.59 ns` | `106.00 ns` | `346.64 ns` | `654.21 ns` |
|
|
448
|
+
| valibot | ` 46.13 ns/iter` | ` 43.45 ns` | ` 46.57 ns` | ` 67.45 ns` | `142.49 ns` |
|
|
449
|
+
| yup | `675.60 ns/iter` | `639.19 ns` | `683.40 ns` | `785.82 ns` | ` 1.21 µs` |
|
|
450
|
+
|
|
451
|
+
| • built-in email validator (regexes differ) (invalid input) | avg | min | p75 | p99 | max |
|
|
452
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
453
|
+
| ivl | `103.16 ns/iter` | ` 97.03 ns` | `104.03 ns` | `132.85 ns` | `181.27 ns` |
|
|
454
|
+
| ivl compiled | ` 34.96 ns/iter` | ` 31.56 ns` | ` 34.17 ns` | ` 73.88 ns` | `179.74 ns` |
|
|
455
|
+
| zod | ` 1.61 µs/iter` | ` 1.37 µs` | ` 1.45 µs` | ` 3.51 µs` | ` 3.71 µs` |
|
|
456
|
+
| valibot | `170.76 ns/iter` | ` 71.09 ns` | ` 76.18 ns` | ` 3.93 µs` | ` 5.23 µs` |
|
|
457
|
+
| yup | ` 22.65 µs/iter` | ` 21.50 µs` | ` 22.21 µs` | ` 24.04 µs` | ` 28.84 µs` |
|
|
458
|
+
|
|
459
|
+
| • object schema, report all errors (valid input) | avg | min | p75 | p99 | max |
|
|
460
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
461
|
+
| ivl | `725.21 ns/iter` | `700.77 ns` | `724.11 ns` | `830.31 ns` | ` 1.17 µs` |
|
|
462
|
+
| ivl compiled | `261.26 ns/iter` | `251.23 ns` | `260.07 ns` | `318.92 ns` | `555.87 ns` |
|
|
463
|
+
| zod | `748.41 ns/iter` | `641.54 ns` | `681.16 ns` | ` 1.57 µs` | ` 1.62 µs` |
|
|
464
|
+
| valibot | `423.50 ns/iter` | `404.05 ns` | `417.93 ns` | `734.86 ns` | `893.94 ns` |
|
|
465
|
+
| yup | ` 4.93 µs/iter` | ` 4.82 µs` | ` 4.93 µs` | ` 5.27 µs` | ` 5.52 µs` |
|
|
466
|
+
|
|
467
|
+
| • object schema, report all errors (invalid input) | avg | min | p75 | p99 | max |
|
|
468
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
469
|
+
| ivl | `695.66 ns/iter` | `681.21 ns` | `694.45 ns` | `751.23 ns` | `918.42 ns` |
|
|
470
|
+
| ivl compiled | `256.14 ns/iter` | `246.15 ns` | `258.42 ns` | `291.06 ns` | `329.57 ns` |
|
|
471
|
+
| zod | ` 3.57 µs/iter` | ` 1.95 µs` | ` 3.13 µs` | ` 8.54 µs` | ` 8.68 ms` |
|
|
472
|
+
| valibot | ` 1.34 µs/iter` | `725.76 ns` | `769.83 ns` | ` 6.39 µs` | ` 6.67 µs` |
|
|
473
|
+
| yup | ` 56.17 µs/iter` | ` 26.44 µs` | ` 72.63 µs` | `132.72 µs` | `363.54 µs` |
|
|
474
|
+
|
|
475
|
+
| • object schema, pass/fail (valid input) | avg | min | p75 | p99 | max |
|
|
476
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
477
|
+
| ivl compiled | `290.00 ns/iter` | `280.18 ns` | `289.45 ns` | `334.74 ns` | `694.99 ns` |
|
|
478
|
+
| zod | `743.37 ns/iter` | `654.72 ns` | `701.12 ns` | ` 1.25 µs` | ` 1.27 µs` |
|
|
479
|
+
| valibot | `402.39 ns/iter` | `391.71 ns` | `402.53 ns` | `444.24 ns` | `753.31 ns` |
|
|
480
|
+
| yup | ` 4.98 µs/iter` | ` 4.90 µs` | ` 5.00 µs` | ` 5.09 µs` | ` 5.24 µs` |
|
|
481
|
+
|
|
482
|
+
| • object schema, pass/fail (invalid input) | avg | min | p75 | p99 | max |
|
|
483
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
484
|
+
| ivl compiled | `220.63 ns/iter` | `212.62 ns` | `219.76 ns` | `252.80 ns` | `478.33 ns` |
|
|
485
|
+
| zod | ` 3.33 µs/iter` | ` 2.62 µs` | ` 4.45 µs` | ` 5.82 µs` | ` 6.13 µs` |
|
|
486
|
+
| valibot | `472.12 ns/iter` | `286.54 ns` | `300.30 ns` | ` 5.70 µs` | ` 5.85 µs` |
|
|
487
|
+
| yup | ` 15.55 µs/iter` | ` 14.94 µs` | ` 15.32 µs` | ` 15.95 µs` | ` 19.16 µs` |
|
|
488
|
+
|
|
489
|
+
| • object schema with an async rule, report all errors (valid input) | avg | min | p75 | p99 | max |
|
|
490
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
491
|
+
| ivl | ` 1.86 µs/iter` | ` 1.37 µs` | ` 1.96 µs` | ` 4.55 µs` | ` 4.88 µs` |
|
|
492
|
+
| ivl compiled | ` 2.08 µs/iter` | ` 1.20 µs` | ` 2.54 µs` | ` 4.50 µs` | ` 4.60 µs` |
|
|
493
|
+
| zod | ` 1.83 µs/iter` | ` 1.71 µs` | ` 1.92 µs` | ` 2.10 µs` | ` 2.22 µs` |
|
|
494
|
+
| valibot | ` 2.36 µs/iter` | ` 1.83 µs` | ` 2.69 µs` | ` 2.92 µs` | ` 3.12 µs` |
|
|
495
|
+
| yup | ` 5.48 µs/iter` | ` 5.35 µs` | ` 5.48 µs` | ` 5.72 µs` | ` 6.15 µs` |
|
|
496
|
+
|
|
497
|
+
| • object schema with an async rule, report all errors (invalid input) | avg | min | p75 | p99 | max |
|
|
498
|
+
| ------------ | ---------------- | ----------- | ----------- | ----------- | ----------- |
|
|
499
|
+
| ivl | ` 1.85 µs/iter` | ` 1.37 µs` | ` 2.28 µs` | ` 3.41 µs` | ` 3.68 µs` |
|
|
500
|
+
| ivl compiled | ` 1.55 µs/iter` | ` 1.14 µs` | ` 2.14 µs` | ` 2.27 µs` | ` 2.53 µs` |
|
|
501
|
+
| zod | ` 4.05 µs/iter` | ` 3.42 µs` | ` 4.66 µs` | ` 4.77 µs` | ` 4.80 µs` |
|
|
502
|
+
| valibot | ` 3.10 µs/iter` | ` 2.04 µs` | ` 3.62 µs` | ` 4.11 µs` | ` 4.99 µs` |
|
|
503
|
+
| yup | ` 40.79 µs/iter` | ` 16.19 µs` | ` 62.34 µs` | ` 84.30 µs` | `705.87 µs` |
|
|
504
|
+
|
|
505
|
+
**Caveats**
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
- Error reports differ in detail: ivl returns the names of the failing rules, zod and valibot build an issue object per failure and copy the parsed value, and yup throws a ValidationError. The "report all errors" results on invalid input largely measure that cost; the "pass/fail" scenarios compare validation alone.
|
|
509
|
+
- After a failed type check, zod and valibot skip the rest of that field, while ivl still runs every rule unless break_early is set.
|
|
510
|
+
- In "pass/fail", valibot (v.is) and yup (isValidSync) stop at the first failure in the whole object; ivl (break_early) still checks every field, stopping within each; zod has no early-exit mode, so it runs safeParse and reads .success.
|
|
511
|
+
- The "built-in email" scenario uses each library's own email regex, so it compares what you get out of the box rather than equal work; ivl's regex is simpler and looser than zod's.
|
|
512
|
+
- Each benchmark cycles through 8 valid or 8 invalid inputs. The async rule resolves immediately, so the async scenario measures promise overhead, not I/O.
|
|
513
|
+
<!-- benchmark:end -->
|
package/lib/core.d.ts
CHANGED
|
@@ -1,16 +1,35 @@
|
|
|
1
|
-
import type { RULES, RULES_SYNC, SCHEMA, SCHEMA_SYNC, SCHEMA_OPTIONS, CHECKABLE_OBJECT, CHECKED_SCHEMA, CHECKED_SCHEMA_SYNC, RULES_KIND, SCHEMA_KIND, MAYBE_ASYNC } from './types';
|
|
2
1
|
/**
|
|
3
|
-
*
|
|
2
|
+
* Core validation functions: run rule sets against single values (`getValueErrors*`), run
|
|
3
|
+
* schemas against objects (`getSchemaErrors*`), and compile either into reusable validators
|
|
4
|
+
* (`compileRules`, `compileSchema`).
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
6
|
+
* Shared semantics:
|
|
7
|
+
* - a rule passes when it returns a truthy value and fails when it returns a falsy value,
|
|
8
|
+
* throws, or (on an async path) rejects - a failing rule never throws out of these functions
|
|
9
|
+
* - errors are the keys of the failing rules, in the rule set's key order
|
|
10
|
+
* - a rule is async only if it is declared with the `async` keyword; the plain `getValueErrors`
|
|
11
|
+
* / `getSchemaErrors` / `compile*` functions use that to pick the sync or async path
|
|
12
|
+
* - any extra `overload` arguments are passed through to every rule after the value
|
|
13
|
+
*
|
|
14
|
+
* @module
|
|
15
|
+
*/
|
|
16
|
+
import type { RULES, RULES_SYNC, SCHEMA, SCHEMA_SYNC, SCHEMA_OPTIONS, RULES_OPTIONS, CHECKABLE_OBJECT, CHECKED_SCHEMA, CHECKED_SCHEMA_SYNC, RULES_KIND, SCHEMA_KIND, MAYBE_ASYNC, ANY_RULES, COMPILED_RULES, COMPILED_SCHEMA } from './types';
|
|
17
|
+
/**
|
|
18
|
+
* Detect whether a value is a function declared with the `async` keyword.
|
|
19
|
+
*
|
|
20
|
+
* Only the declaration is inspected: a plain function that returns a promise is not async
|
|
21
|
+
* by this definition. Works across realms, since it compares the constructor's name.
|
|
22
|
+
*
|
|
23
|
+
* @param {unknown} fn the value to inspect
|
|
24
|
+
* @returns {boolean} `true` if `fn` is an `async` function, otherwise `false`
|
|
7
25
|
*/
|
|
8
26
|
export declare const isAsyncFunction: (fn: unknown) => fn is (...args: never[]) => Promise<unknown>;
|
|
9
27
|
/**
|
|
10
|
-
* Detect
|
|
28
|
+
* Detect whether a rule set, or any rule set in an array of alternatives, contains an
|
|
29
|
+
* `async` rule. This is the check `getValueErrors`/`getSchemaErrors` use to choose a path.
|
|
11
30
|
*
|
|
12
|
-
* @param {RULES|RULES[]} rules a
|
|
13
|
-
* @returns {boolean} true if any
|
|
31
|
+
* @param {RULES|RULES[]} rules a rule set, or an array of alternative rule sets
|
|
32
|
+
* @returns {boolean} `true` if any rule is an `async` function, otherwise `false`
|
|
14
33
|
*/
|
|
15
34
|
export declare const hasAsyncFunction: (rules: {
|
|
16
35
|
[key: string]: unknown;
|
|
@@ -18,69 +37,136 @@ export declare const hasAsyncFunction: (rules: {
|
|
|
18
37
|
[key: string]: unknown;
|
|
19
38
|
}[]) => boolean;
|
|
20
39
|
/**
|
|
21
|
-
*
|
|
40
|
+
* Validate a value against a rule set, always asynchronously.
|
|
22
41
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
42
|
+
* Sync rules run inline and `async` rules run concurrently; a plain rule returning a promise
|
|
43
|
+
* is awaited too. A rule that returns a falsy value, throws or rejects fails. The returned
|
|
44
|
+
* promise never rejects.
|
|
45
|
+
*
|
|
46
|
+
* @template V type of the value being validated
|
|
47
|
+
* @param {V} value the value to validate
|
|
48
|
+
* @param {RULES<V>} rules the rule set; each key is the error reported when its rule fails
|
|
49
|
+
* @param {...unknown} overload extra arguments passed to every rule after the value
|
|
50
|
+
* @returns {Promise<string[]>} the keys of the failing rules, in rule order; empty if all passed
|
|
27
51
|
*/
|
|
28
52
|
export declare const getValueErrorsAsync: <V>(value: V, rules: RULES<V>, ...overload: unknown[]) => Promise<string[]>;
|
|
29
53
|
/**
|
|
30
|
-
*
|
|
54
|
+
* Validate an object against a schema, always asynchronously.
|
|
55
|
+
*
|
|
56
|
+
* Each schema key's rule set is run against `object_to_check[key]` (a missing key is
|
|
57
|
+
* validated as `undefined`). An entry given as an array of alternative rule sets passes if
|
|
58
|
+
* any alternative passes. Fields whose rules are all sync are filled in immediately; only
|
|
59
|
+
* fields with pending promises are awaited, concurrently. The returned promise never rejects.
|
|
31
60
|
*
|
|
32
|
-
* @
|
|
33
|
-
* @param {
|
|
34
|
-
* @param {
|
|
35
|
-
* @param {
|
|
36
|
-
*
|
|
61
|
+
* @template S the schema type, used to infer the result's keys and shapes
|
|
62
|
+
* @param {CHECKABLE_OBJECT} object_to_check the object to validate
|
|
63
|
+
* @param {S} schema maps each key to a rule set, or to an array of alternative rule sets
|
|
64
|
+
* @param {SCHEMA_OPTIONS} [options] `strict: true` also reports keys of the object that the schema doesn't
|
|
65
|
+
* have; `break_early: true` reports only the first failing rule of each rule set
|
|
66
|
+
* @param {...unknown} overload extra arguments passed to every rule after the value
|
|
67
|
+
* @returns {CHECKED_SCHEMA<S>} an object with every schema key, in schema order: `string[]` of
|
|
68
|
+
* failing rule keys for a rule set, or for alternatives `[]` if any passed and otherwise one
|
|
69
|
+
* error list per alternative (`string[][]`). In strict mode, each unknown key follows with
|
|
70
|
+
* `['Key not allowed']`.
|
|
37
71
|
*/
|
|
38
72
|
export declare const getSchemaErrorsAsync: <S extends SCHEMA>(object_to_check: CHECKABLE_OBJECT, schema: S, options?: SCHEMA_OPTIONS, ...overload: unknown[]) => CHECKED_SCHEMA<S>;
|
|
39
73
|
/**
|
|
40
|
-
*
|
|
74
|
+
* Validate a value against a rule set synchronously.
|
|
75
|
+
*
|
|
76
|
+
* A rule that returns a falsy value or throws fails. A rule that returns a promise also
|
|
77
|
+
* fails, because it can't be awaited here - use `getValueErrorsAsync` for those.
|
|
41
78
|
*
|
|
42
|
-
* @
|
|
43
|
-
* @param {
|
|
44
|
-
* @param {
|
|
45
|
-
* @
|
|
79
|
+
* @template V type of the value being validated
|
|
80
|
+
* @param {V} value the value to validate
|
|
81
|
+
* @param {RULES_SYNC<V>} rules the rule set; each key is the error reported when its rule fails
|
|
82
|
+
* @param {...unknown} overload extra arguments passed to every rule after the value
|
|
83
|
+
* @returns {string[]} the keys of the failing rules, in rule order; empty if all passed
|
|
46
84
|
*/
|
|
47
85
|
export declare const getValueErrorsSync: <V>(value: V, rules: RULES_SYNC<V>, ...overload: unknown[]) => string[];
|
|
48
86
|
/**
|
|
49
|
-
*
|
|
87
|
+
* Validate an object against a schema synchronously.
|
|
50
88
|
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
89
|
+
* Each schema key's rule set is run against `object[key]` (a missing key is validated as
|
|
90
|
+
* `undefined`), with the same rule semantics as `getValueErrorsSync`: a rule returning a
|
|
91
|
+
* promise fails. An entry given as an array of alternative rule sets passes if any
|
|
92
|
+
* alternative passes.
|
|
93
|
+
*
|
|
94
|
+
* @template S the schema type, used to infer the result's keys and shapes
|
|
95
|
+
* @param {CHECKABLE_OBJECT} object the object to validate
|
|
96
|
+
* @param {S} schema maps each key to a rule set, or to an array of alternative rule sets
|
|
97
|
+
* @param {SCHEMA_OPTIONS} [options] `strict: true` also reports keys of the object that the schema doesn't
|
|
98
|
+
* have; `break_early: true` reports only the first failing rule of each rule set
|
|
99
|
+
* @param {...unknown} overload extra arguments passed to every rule after the value
|
|
100
|
+
* @returns {CHECKED_SCHEMA_SYNC<S>} an object with every schema key, in schema order: `string[]`
|
|
101
|
+
* of failing rule keys for a rule set, or for alternatives `[]` if any passed and otherwise
|
|
102
|
+
* one error list per alternative (`string[][]`). In strict mode, each unknown key follows
|
|
103
|
+
* with `['Key not allowed']`.
|
|
56
104
|
*/
|
|
57
105
|
export declare const getSchemaErrorsSync: <S extends SCHEMA_SYNC>(object: CHECKABLE_OBJECT, schema: S, options?: SCHEMA_OPTIONS, ...overload: unknown[]) => CHECKED_SCHEMA_SYNC<S>;
|
|
58
106
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
107
|
+
* Validate a value against a rule set, synchronously if no rule is an `async` function and
|
|
108
|
+
* asynchronously otherwise (see `getValueErrorsSync` / `getValueErrorsAsync`).
|
|
61
109
|
*
|
|
62
|
-
* The return type is inferred from the rules: all-sync rules
|
|
63
|
-
*
|
|
64
|
-
*
|
|
110
|
+
* The return type is inferred from the rules: all-sync rules give `string[]`, any `async`
|
|
111
|
+
* rule gives `Promise<string[]>`, and rules typed as returning `boolean | Promise<boolean>`
|
|
112
|
+
* (e.g. annotated as `RULE`) give the union. For a rule set used repeatedly,
|
|
113
|
+
* `compileRules` is faster.
|
|
65
114
|
*
|
|
66
|
-
* @
|
|
67
|
-
* @
|
|
68
|
-
* @param {
|
|
69
|
-
* @
|
|
115
|
+
* @template V type of the value being validated
|
|
116
|
+
* @template R the rule set type, used to infer sync or async
|
|
117
|
+
* @param {V} value the value to validate
|
|
118
|
+
* @param {R} rules the rule set; each key is the error reported when its rule fails
|
|
119
|
+
* @param {...unknown} overload extra arguments passed to every rule after the value
|
|
120
|
+
* @returns {string[]|Promise<string[]>} the keys of the failing rules, in rule order; empty if all passed
|
|
70
121
|
*/
|
|
71
122
|
export declare const getValueErrors: <V, R extends RULES<V>>(value: V, rules: R, ...overload: unknown[]) => MAYBE_ASYNC<RULES_KIND<R>, string[]>;
|
|
72
123
|
/**
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* @
|
|
83
|
-
* @param {
|
|
84
|
-
* @
|
|
124
|
+
* Validate an object against a schema, synchronously if no rule in the schema is an
|
|
125
|
+
* `async` function and asynchronously otherwise (see `getSchemaErrorsSync` /
|
|
126
|
+
* `getSchemaErrorsAsync` for the details and result shape).
|
|
127
|
+
*
|
|
128
|
+
* The return type is inferred from the schema: all-sync rules give the result object
|
|
129
|
+
* directly, any `async` rule gives a `Promise` of it, and rules typed as returning
|
|
130
|
+
* `boolean | Promise<boolean>` (e.g. a schema annotated as `SCHEMA`) give the union. For a
|
|
131
|
+
* schema used repeatedly, `compileSchema` is faster.
|
|
132
|
+
*
|
|
133
|
+
* @template S the schema type, used to infer sync or async and the result's keys and shapes
|
|
134
|
+
* @param {CHECKABLE_OBJECT} object the object to validate
|
|
135
|
+
* @param {S} schema maps each key to a rule set, or to an array of alternative rule sets
|
|
136
|
+
* @param {SCHEMA_OPTIONS} [options] `strict: true` also reports keys of the object that the schema doesn't
|
|
137
|
+
* have; `break_early: true` reports only the first failing rule of each rule set
|
|
138
|
+
* @param {...unknown} overload extra arguments passed to every rule after the value
|
|
139
|
+
* @returns {CHECKED_SCHEMA_SYNC<S>|CHECKED_SCHEMA<S>} the errors per key, or a promise of them
|
|
85
140
|
*/
|
|
86
141
|
export declare const getSchemaErrors: <S extends SCHEMA>(object: CHECKABLE_OBJECT, schema: S, options?: SCHEMA_OPTIONS, ...overload: unknown[]) => MAYBE_ASYNC<SCHEMA_KIND<S>, CHECKED_SCHEMA_SYNC<S>>;
|
|
142
|
+
/**
|
|
143
|
+
* Compile a rule set into a reusable validator that gives the same results as
|
|
144
|
+
* `getValueErrors(value, rules, ...overload)`, but does the key lookup and the sync/async
|
|
145
|
+
* check once here instead of on every call.
|
|
146
|
+
*
|
|
147
|
+
* The rule set is copied, so changes made to `rules` after compiling have no effect on the
|
|
148
|
+
* returned validator.
|
|
149
|
+
*
|
|
150
|
+
* @template R the rule set type; the validator's value parameter and sync/async return type come from it
|
|
151
|
+
* @param {R} rules the rule set; each key is the error reported when its rule fails
|
|
152
|
+
* @param {RULES_OPTIONS} [options] `break_early: true` reports only the first failing rule
|
|
153
|
+
* @returns {COMPILED_RULES<R>} `(value, ...overload) => string[]` if every rule is sync, otherwise
|
|
154
|
+
* an async function returning `Promise<string[]>`
|
|
155
|
+
*/
|
|
156
|
+
export declare const compileRules: <R extends ANY_RULES>(rules: R, options?: RULES_OPTIONS) => COMPILED_RULES<R>;
|
|
157
|
+
/**
|
|
158
|
+
* Compile a schema into a reusable validator that gives the same results as
|
|
159
|
+
* `getSchemaErrors(object, schema, options, ...overload)`, but does the key lookups and the
|
|
160
|
+
* sync/async check once here instead of on every call.
|
|
161
|
+
*
|
|
162
|
+
* The schema, its rule sets and the options are copied, so changes made to them after
|
|
163
|
+
* compiling have no effect on the returned validator.
|
|
164
|
+
*
|
|
165
|
+
* @template S the schema type; the validator's sync/async return type and result shape come from it
|
|
166
|
+
* @param {S} schema maps each key to a rule set, or to an array of alternative rule sets
|
|
167
|
+
* @param {SCHEMA_OPTIONS} [options] `strict: true` also reports keys of the object that the schema doesn't
|
|
168
|
+
* have; `break_early: true` reports only the first failing rule of each rule set
|
|
169
|
+
* @returns {COMPILED_SCHEMA<S>} `(object, ...overload) => errors` if every rule is sync, otherwise
|
|
170
|
+
* an async function returning a promise of them; see `getSchemaErrorsSync` for the result shape
|
|
171
|
+
*/
|
|
172
|
+
export declare const compileSchema: <S extends SCHEMA>(schema: S, options?: SCHEMA_OPTIONS) => COMPILED_SCHEMA<S>;
|
package/lib/helpers/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var u=(n)=>typeof n==="string"||n!==null&&typeof n==="object"&&("length"in n)&&typeof n.length==="number",c=(n)=>(e)=>typeof e===n,l=(n)=>(e)=>typeof e==="string"&&n.test(e),a=(n=1/0)=>(e)=>typeof e==="number"&&e<=n,S=(n=-1/0)=>(e)=>typeof e==="number"&&e>=n,f=(n=1/0)=>(e)=>u(e)&&e.length<=n,C=(n=0)=>(e)=>u(e)&&e.length>=n,y=(n=1/0,e=0)=>(t)=>typeof t==="string"&&t.length>=e&&t.length<=n,k=(n=1/0,e=-1/0)=>(t)=>typeof t==="number"&&t>=e&&t<=n,R=(n)=>(e)=>e===n||Number.isNaN(n)&&Number.isNaN(e),_=(n=[])=>{let e=new Set(n);return(t)=>e.has(t)},w=()=>(n)=>Number.isInteger(n),g=()=>(n)=>Array.isArray(n),L=(n)=>(e)=>e instanceof n,A=(n)=>(e,...t)=>{try{return!n(e,...t)}catch{return!0}},p=(n)=>async(e,...t)=>{try{return!await n(e,...t)}catch{return!0}},O=(n)=>(e,...t)=>{if(!Array.isArray(e))return!1;for(let r=0;r<e.length;r++)if(!n(e[r],...t))return!1;return!0},m=(n)=>async(e,...t)=>{if(!Array.isArray(e))return!1;for(let r=0;r<e.length;r++)if(!await n(e[r],...t))return!1;return!0},U=(n=[])=>async(e,...t)=>(await Promise.all(n.map((r)=>r(e,...t)))).some((r)=>r),N=(n=[])=>(e,...t)=>n.map((r)=>r(e,...t)).some((r)=>r);var E=(n)=>typeof n==="function"&&n.constructor.name==="AsyncFunction";var i=(n,e)=>Object.fromEntries(Object.entries(n).map(([t,r])=>[t,E(r)?async(s,...o)=>e(r,s,o):(s,...o)=>e(r,s,o)])),M=(n)=>i(n,(e,t,r)=>typeof t>"u"?!0:e(t,...r)),P=(n)=>i(n,(e,t,r)=>t===null?!0:e(t,...r)),x=(n,e)=>i(e,(t,r,s)=>t(n(r),...s));export{U as acceptAnyAsync,N as acceptAnySync,P as allowNull,M as allowUndefined,R as equals,m as everyElementAsync,O as everyElementSync,g as isArray,L as isInstanceOf,w as isInteger,_ as isOneOf,c as isType,l as matchesRegex,a as max,f as maxLength,S as min,C as minLength,p as notAsync,A as notSync,k as numberBetween,x as preprocess,y as stringBetween};
|
package/lib/helpers/rules.d.ts
CHANGED
|
@@ -1,39 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule helpers: factories that build common rules, and combinators that modify or combine
|
|
3
|
+
* existing rules. Every factory returns a new rule, so the result can be used directly as a
|
|
4
|
+
* value in a rule set, e.g. `{ "Too long": maxLength(100) }`.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
1
8
|
import type { RULE, RULE_ASYNC, RULE_SYNC } from '../types';
|
|
9
|
+
/** Every string the `typeof` operator can return. */
|
|
2
10
|
export type TYPEOF_RESULT = "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function";
|
|
11
|
+
/**
|
|
12
|
+
* Rule: passes if `typeof value === type`. Note that `typeof null` is `'object'`, so
|
|
13
|
+
* `isType('object')` passes `null`, and `typeof NaN` is `'number'`.
|
|
14
|
+
*
|
|
15
|
+
* @param {TYPEOF_RESULT} type the expected `typeof` result
|
|
16
|
+
* @returns {RULE_SYNC} the rule
|
|
17
|
+
*/
|
|
3
18
|
export declare const isType: (type: TYPEOF_RESULT) => RULE_SYNC;
|
|
19
|
+
/**
|
|
20
|
+
* Rule: passes if the value is a string that `regex` matches. Non-strings fail.
|
|
21
|
+
*
|
|
22
|
+
* The regex is used as given, so one with the `g` or `y` flag is stateful: `test` moves its
|
|
23
|
+
* `lastIndex`, and repeated calls can alternate between passing and failing. Use regexes
|
|
24
|
+
* without those flags.
|
|
25
|
+
*
|
|
26
|
+
* @param {RegExp} regex the pattern to test strings against
|
|
27
|
+
* @returns {RULE_SYNC} the rule
|
|
28
|
+
*/
|
|
4
29
|
export declare const matchesRegex: (regex: RegExp) => RULE_SYNC;
|
|
30
|
+
/**
|
|
31
|
+
* Rule: passes if the value is a number less than or equal to `max_value`. Non-numbers
|
|
32
|
+
* (including bigints) and `NaN` fail.
|
|
33
|
+
*
|
|
34
|
+
* @param {number} [max_value=Infinity] the inclusive upper bound
|
|
35
|
+
* @returns {RULE_SYNC} the rule
|
|
36
|
+
*/
|
|
5
37
|
export declare const max: (max_value?: number) => RULE_SYNC;
|
|
38
|
+
/**
|
|
39
|
+
* Rule: passes if the value is a number greater than or equal to `min_value`. Non-numbers
|
|
40
|
+
* (including bigints) and `NaN` fail.
|
|
41
|
+
*
|
|
42
|
+
* @param {number} [min_value=-Infinity] the inclusive lower bound
|
|
43
|
+
* @returns {RULE_SYNC} the rule
|
|
44
|
+
*/
|
|
6
45
|
export declare const min: (min_value?: number) => RULE_SYNC;
|
|
46
|
+
/**
|
|
47
|
+
* Rule: passes if the value has a numeric `length` (a string, array, or object with a
|
|
48
|
+
* numeric `length`) of at most `max_length`. Values without one fail.
|
|
49
|
+
*
|
|
50
|
+
* @param {number} [max_length=Infinity] the inclusive maximum length
|
|
51
|
+
* @returns {RULE_SYNC} the rule
|
|
52
|
+
*/
|
|
7
53
|
export declare const maxLength: (max_length?: number) => RULE_SYNC;
|
|
54
|
+
/**
|
|
55
|
+
* Rule: passes if the value has a numeric `length` (a string, array, or object with a
|
|
56
|
+
* numeric `length`) of at least `min_length`. Values without one fail, even with the
|
|
57
|
+
* default of `0`.
|
|
58
|
+
*
|
|
59
|
+
* @param {number} [min_length=0] the inclusive minimum length
|
|
60
|
+
* @returns {RULE_SYNC} the rule
|
|
61
|
+
*/
|
|
8
62
|
export declare const minLength: (min_length?: number) => RULE_SYNC;
|
|
63
|
+
/**
|
|
64
|
+
* Rule: passes if the value is a string whose length is between `min` and `max`, inclusive.
|
|
65
|
+
* Note the argument order: the maximum comes first.
|
|
66
|
+
*
|
|
67
|
+
* @param {number} [max=Infinity] the inclusive maximum length
|
|
68
|
+
* @param {number} [min=0] the inclusive minimum length
|
|
69
|
+
* @returns {RULE_SYNC} the rule
|
|
70
|
+
*/
|
|
9
71
|
export declare const stringBetween: (max?: number, min?: number) => RULE_SYNC;
|
|
72
|
+
/**
|
|
73
|
+
* Rule: passes if the value is a number between `min` and `max`, inclusive. Non-numbers
|
|
74
|
+
* and `NaN` fail. Note the argument order: the maximum comes first.
|
|
75
|
+
*
|
|
76
|
+
* @param {number} [max=Infinity] the inclusive upper bound
|
|
77
|
+
* @param {number} [min=-Infinity] the inclusive lower bound
|
|
78
|
+
* @returns {RULE_SYNC} the rule
|
|
79
|
+
*/
|
|
10
80
|
export declare const numberBetween: (max?: number, min?: number) => RULE_SYNC;
|
|
11
|
-
/**
|
|
81
|
+
/**
|
|
82
|
+
* Rule: passes if the value equals `expected` under SameValueZero semantics (`===`, except
|
|
83
|
+
* `NaN` equals `NaN`) - the same comparison `isOneOf` uses. Objects compare by reference.
|
|
84
|
+
*
|
|
85
|
+
* @param {unknown} expected the value to compare against
|
|
86
|
+
* @returns {RULE_SYNC} the rule
|
|
87
|
+
*/
|
|
12
88
|
export declare const equals: (expected: unknown) => RULE_SYNC;
|
|
13
|
-
/**
|
|
89
|
+
/**
|
|
90
|
+
* Rule: passes if the value is one of `allowed_values`, using SameValueZero semantics - the
|
|
91
|
+
* same comparison `equals` uses. The values are copied into a `Set` when the rule is created,
|
|
92
|
+
* so later changes to the array have no effect.
|
|
93
|
+
*
|
|
94
|
+
* @param {unknown[]} [allowed_values=[]] the accepted values; with none, every value fails
|
|
95
|
+
* @returns {RULE_SYNC} the rule
|
|
96
|
+
*/
|
|
14
97
|
export declare const isOneOf: (allowed_values?: unknown[]) => RULE_SYNC;
|
|
98
|
+
/**
|
|
99
|
+
* Rule: passes if the value is a number with no fractional part (`Number.isInteger`).
|
|
100
|
+
* Bigints, numeric strings, `NaN` and `Infinity` fail.
|
|
101
|
+
*
|
|
102
|
+
* @returns {RULE_SYNC} the rule
|
|
103
|
+
*/
|
|
15
104
|
export declare const isInteger: () => RULE_SYNC;
|
|
105
|
+
/**
|
|
106
|
+
* Rule: passes if the value is an array (`Array.isArray`).
|
|
107
|
+
*
|
|
108
|
+
* @returns {RULE_SYNC} the rule
|
|
109
|
+
*/
|
|
16
110
|
export declare const isArray: () => RULE_SYNC;
|
|
111
|
+
/**
|
|
112
|
+
* Rule: passes if `value instanceof constructor`. Like `instanceof`, this checks the
|
|
113
|
+
* prototype chain, so it fails for objects from another realm (e.g. an iframe).
|
|
114
|
+
*
|
|
115
|
+
* @param {Function} constructor the class or constructor function to check against
|
|
116
|
+
* @returns {RULE_SYNC} the rule
|
|
117
|
+
*/
|
|
17
118
|
export declare const isInstanceOf: (constructor: abstract new (...args: never[]) => unknown) => RULE_SYNC;
|
|
18
|
-
/**
|
|
119
|
+
/**
|
|
120
|
+
* Combinator: inverts a synchronous rule. A throwing rule counts as failed, so its negation
|
|
121
|
+
* passes. The rule must be synchronous: a returned promise is truthy, so the negation fails.
|
|
122
|
+
*
|
|
123
|
+
* @template V type of the value being validated
|
|
124
|
+
* @template O tuple type of the overload arguments, passed through to `rule`
|
|
125
|
+
* @param {RULE_SYNC<V, O>} rule the rule to invert
|
|
126
|
+
* @returns {RULE_SYNC<V, O>} the inverted rule
|
|
127
|
+
*/
|
|
19
128
|
export declare const notSync: <V = unknown, O extends unknown[] = unknown[]>(rule: RULE_SYNC<V, O>) => RULE_SYNC<V, O>;
|
|
20
129
|
/**
|
|
21
|
-
*
|
|
22
|
-
* Always async - a single async rule switches the whole rule set onto the
|
|
23
|
-
* path, so prefer `notSync` unless the wrapped rule is genuinely async.
|
|
130
|
+
* Combinator: inverts a sync or async rule. A throwing or rejecting rule counts as failed, so
|
|
131
|
+
* its negation passes. Always async - a single async rule switches the whole rule set onto the
|
|
132
|
+
* async execution path, so prefer `notSync` unless the wrapped rule is genuinely async.
|
|
133
|
+
*
|
|
134
|
+
* @template V type of the value being validated
|
|
135
|
+
* @template O tuple type of the overload arguments, passed through to `rule`
|
|
136
|
+
* @param {RULE<V, O>} rule the rule to invert
|
|
137
|
+
* @returns {RULE_ASYNC<V, O>} the inverted rule
|
|
24
138
|
*/
|
|
25
139
|
export declare const notAsync: <V = unknown, O extends unknown[] = unknown[]>(rule: RULE<V, O>) => RULE_ASYNC<V, O>;
|
|
26
|
-
/**
|
|
140
|
+
/**
|
|
141
|
+
* Combinator: passes if the value is an array and every element (holes included, as
|
|
142
|
+
* `undefined`) passes `rule`. Stops at the first failing element; an empty array passes.
|
|
143
|
+
* A throwing element rule makes the whole rule fail. The rule must be synchronous: a
|
|
144
|
+
* returned promise is truthy, so that element passes.
|
|
145
|
+
*
|
|
146
|
+
* @template E type of the array elements the rule accepts
|
|
147
|
+
* @template O tuple type of the overload arguments, passed through to `rule`
|
|
148
|
+
* @param {RULE_SYNC<E, O>} rule the rule every element must pass
|
|
149
|
+
* @returns {RULE_SYNC<unknown, O>} the array rule
|
|
150
|
+
*/
|
|
27
151
|
export declare const everyElementSync: <E = unknown, O extends unknown[] = unknown[]>(rule: RULE_SYNC<E, O>) => RULE_SYNC<unknown, O>;
|
|
28
152
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
153
|
+
* Combinator: passes if the value is an array and every element (holes included, as
|
|
154
|
+
* `undefined`) passes `rule`, which may be sync or async; an empty array passes. Elements are
|
|
155
|
+
* checked one at a time, stopping at the first failure, so an early invalid element in an
|
|
156
|
+
* attacker-sized array doesn't fan out rule calls for the rest of it. A throwing or rejecting
|
|
157
|
+
* element rule makes the whole rule fail.
|
|
32
158
|
* Always async - a single async rule switches the whole rule set onto the async execution
|
|
33
159
|
* path, so prefer `everyElementSync` unless the element rule is genuinely async.
|
|
160
|
+
*
|
|
161
|
+
* @template E type of the array elements the rule accepts
|
|
162
|
+
* @template O tuple type of the overload arguments, passed through to `rule`
|
|
163
|
+
* @param {RULE<E, O>} rule the rule every element must pass
|
|
164
|
+
* @returns {RULE_ASYNC<unknown, O>} the array rule
|
|
34
165
|
*/
|
|
35
166
|
export declare const everyElementAsync: <E = unknown, O extends unknown[] = unknown[]>(rule: RULE<E, O>) => RULE_ASYNC<unknown, O>;
|
|
36
|
-
/**
|
|
167
|
+
/**
|
|
168
|
+
* Combinator: passes if *any* of the given rules passes. All rules run concurrently and every
|
|
169
|
+
* one is awaited, even after one has passed. If any rule throws or rejects, the combined rule
|
|
170
|
+
* fails, even when another rule passed. With no rules, it fails. Always async.
|
|
171
|
+
*
|
|
172
|
+
* @template V type of the value being validated
|
|
173
|
+
* @template O tuple type of the overload arguments, passed through to every rule
|
|
174
|
+
* @param {RULE<V, O>[]} [rules=[]] the alternatives, sync or async
|
|
175
|
+
* @returns {RULE_ASYNC<V, O>} the combined rule
|
|
176
|
+
*/
|
|
37
177
|
export declare const acceptAnyAsync: <V = unknown, O extends unknown[] = unknown[]>(rules?: RULE<V, O>[]) => RULE_ASYNC<V, O>;
|
|
38
|
-
/**
|
|
178
|
+
/**
|
|
179
|
+
* Combinator: passes if *any* of the given rules passes. Every rule runs, even after one has
|
|
180
|
+
* passed. If any rule throws, the combined rule fails, even when another rule passed. With no
|
|
181
|
+
* rules, it fails. All rules must be synchronous: a returned promise is truthy, so it counts
|
|
182
|
+
* as passing.
|
|
183
|
+
*
|
|
184
|
+
* @template V type of the value being validated
|
|
185
|
+
* @template O tuple type of the overload arguments, passed through to every rule
|
|
186
|
+
* @param {RULE_SYNC<V, O>[]} [rules=[]] the alternatives
|
|
187
|
+
* @returns {RULE_SYNC<V, O>} the combined rule
|
|
188
|
+
*/
|
|
39
189
|
export declare const acceptAnySync: <V = unknown, O extends unknown[] = unknown[]>(rules?: RULE_SYNC<V, O>[]) => RULE_SYNC<V, O>;
|
package/lib/helpers/schema.d.ts
CHANGED
|
@@ -1,29 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule set helpers: wrap every rule in a rule set at once, typically for use as a schema
|
|
3
|
+
* entry, e.g. `{ website: allowUndefined(URL_RULES) }`.
|
|
4
|
+
*
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
1
7
|
import type { RULES } from '../types';
|
|
2
8
|
/**
|
|
3
|
-
* Re-declares each rule so that the
|
|
4
|
-
* original rule's
|
|
5
|
-
* async stays async).
|
|
9
|
+
* Re-declares each rule so that the value parameter of the returned rule is `V` instead of
|
|
10
|
+
* the original rule's, while keeping its overload parameters and its return type (sync stays
|
|
11
|
+
* sync, async stays async).
|
|
12
|
+
*
|
|
13
|
+
* @template R the original rule set
|
|
14
|
+
* @template V the new value type
|
|
6
15
|
*/
|
|
7
16
|
type REWRAPPED<R extends RULES<never>, V> = {
|
|
8
17
|
[K in keyof R]: R[K] extends (value: never, ...overload: infer O) => infer Ret ? (value: V, ...overload: O) => Ret : never;
|
|
9
18
|
};
|
|
10
19
|
/**
|
|
11
|
-
*
|
|
20
|
+
* Wrap every rule in a rule set so that an `undefined` value passes without calling it,
|
|
21
|
+
* making the field optional. Other values are validated as before.
|
|
22
|
+
*
|
|
12
23
|
* Sync rules stay sync and async rules stay async, so `getValueErrors`/`getSchemaErrors`
|
|
13
24
|
* still pick the correct execution path.
|
|
25
|
+
*
|
|
26
|
+
* @template R the rule set type, preserved in the result
|
|
27
|
+
* @param {R} rules the rule set to wrap; it is not modified
|
|
28
|
+
* @returns {R} a new rule set with the same keys
|
|
14
29
|
*/
|
|
15
30
|
export declare const allowUndefined: <R extends RULES>(rules: R) => R;
|
|
16
31
|
/**
|
|
17
|
-
*
|
|
32
|
+
* Wrap every rule in a rule set so that a `null` value passes without calling it. Other
|
|
33
|
+
* values (including `undefined`) are validated as before.
|
|
34
|
+
*
|
|
18
35
|
* Sync rules stay sync and async rules stay async, so `getValueErrors`/`getSchemaErrors`
|
|
19
36
|
* still pick the correct execution path.
|
|
37
|
+
*
|
|
38
|
+
* @template R the rule set type, preserved in the result
|
|
39
|
+
* @param {R} rules the rule set to wrap; it is not modified
|
|
40
|
+
* @returns {R} a new rule set with the same keys
|
|
20
41
|
*/
|
|
21
42
|
export declare const allowNull: <R extends RULES>(rules: R) => R;
|
|
22
43
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
44
|
+
* Wrap every rule in a rule set so that each rule validates `fn(value)` instead of the value,
|
|
45
|
+
* e.g. to trim or parse it first. The original value is not changed.
|
|
46
|
+
*
|
|
47
|
+
* `fn` is called separately for each rule, so it should be cheap and free of side effects.
|
|
48
|
+
* If it throws, every rule it was called for fails. The rules may be typed against the
|
|
49
|
+
* *output* of `fn`; the returned rules accept `unknown`. Sync rules stay sync and async
|
|
50
|
+
* rules stay async.
|
|
51
|
+
*
|
|
52
|
+
* @template V the type `fn` returns
|
|
53
|
+
* @template R the rule set type
|
|
54
|
+
* @param {Function} fn transforms the value before each rule sees it
|
|
55
|
+
* @param {R} rules the rule set to wrap; it is not modified
|
|
56
|
+
* @returns {REWRAPPED<R, unknown>} a new rule set with the same keys, accepting `unknown`
|
|
27
57
|
*/
|
|
28
58
|
export declare const preprocess: <V, R extends RULES<V>>(fn: (value: unknown) => V, rules: R) => REWRAPPED<R, unknown>;
|
|
29
59
|
export {};
|
package/lib/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var A={strict:!1,break_early:!1},w=(n)=>typeof n==="function"&&n.constructor.name==="AsyncFunction",L=(n)=>{let e=Object.keys(n);for(let t=0;t<e.length;t++)if(w(n[e[t]]))return!0;return!1},R=(n)=>{if(Array.isArray(n)){for(let e=0;e<n.length;e++)if(L(n[e]))return!0;return!1}return L(n)},f=(n)=>n!==null&&(typeof n==="object"||typeof n==="function")&&typeof n.then==="function",k=(n,e,t)=>t.length?n(e,...t):n(e),M=(n,e,t,i=Object.keys(e),E=!1)=>{let s=[];for(let l=0;l<i.length;l++){let r=i[l];try{let o=k(e[r],n,t);if(!o||f(o))s.push(r)}catch{s.push(r)}if(E&&s.length)return s}return s},y=(n,e,t,i=Object.keys(e),E=!1)=>{if(E)return N(n,e,t,i);let s=Array(i.length),l,r=(S,u)=>{s[S]=!1,(l??=[]).push(Promise.resolve(u).then((c)=>{s[S]=Boolean(c)},()=>{s[S]=!1}))};for(let S=0;S<i.length;S++){let u=e[i[S]];try{let c=k(u,n,t);if(f(c))r(S,c);else s[S]=Boolean(c)}catch{s[S]=!1}}let o=()=>{let S=[];for(let u=0;u<i.length;u++)if(!s[u])S.push(i[u]);return S};return l?Promise.all(l).then(o):o()},p=(n)=>{Promise.resolve(n).then(void 0,()=>{})},N=(n,e,t,i)=>{let E,s;for(let r=0;r<i.length;r++){let o=e[i[r]];if(w(o)){(E??=[]).push(r);continue}let S;try{S=k(o,n,t)}catch{S=!1}if(f(S))(s??=[]).push([r,S]);else if(!S){if(s)s.forEach(([,u])=>p(u));return[i[r]]}}if(!E&&!s)return[];let l=s??[];if(E)for(let r of E)l.push([r,k(e[i[r]],n,t)]);return Promise.all(l.map(([r,o])=>Promise.resolve(o).then((S)=>S?-1:r,()=>r))).then((r)=>{let o=-1;for(let S of r)if(S!==-1&&(o===-1||S<o))o=S;return o===-1?[]:[i[o]]})},g=(n)=>{for(let e=0;e<n.length;e++)if(!n[e].length)return[];return n},O=(n,e,t)=>{let i=Object.keys(e);for(let E=0;E<i.length;E++){let s=i[E];if(!Object.hasOwn(t,s))n[s]=["Key not allowed"]}},m=async(n,e,...t)=>y(n,e,t),D=async(n,e,t=A,...i)=>{let E={},s=[],l=Object.keys(e);for(let r=0;r<l.length;r++){let o=l[r],S=e[o],u=n[o];if(Array.isArray(S)){let c=S.map((a)=>y(u,a,i,void 0,t.break_early));if(c.some(f))E[o]=[],s.push(Promise.all(c).then((a)=>{E[o]=g(a)}));else E[o]=g(c)}else{let c=y(u,S,i,void 0,t.break_early);if(f(c))E[o]=[],s.push(c.then((a)=>{E[o]=a}));else E[o]=c}}if(t.strict)O(E,n,e);if(s.length)await Promise.all(s);return E},U=(n,e,...t)=>M(n,e,t),d=(n,e,t,i)=>{let E={},s=Object.keys(e);for(let l=0;l<s.length;l++){let r=s[l],o=e[r];if(Array.isArray(o)){let S=Array(o.length);for(let u=0;u<o.length;u++)S[u]=M(n[r],o[u],i,void 0,t.break_early);E[r]=g(S)}else E[r]=M(n[r],o,i,void 0,t.break_early)}if(t.strict)O(E,n,e);return E},Y=(n,e,t=A,...i)=>d(n,e,t,i),I=(n,e,...t)=>L(e)?m(n,e,...t):M(n,e,t),P=(n)=>{let e=Object.keys(n);for(let t=0;t<e.length;t++)if(R(n[e[t]]))return!0;return!1},T=(n,e,t=A,...i)=>P(e)?D(n,e,t,...i):d(n,e,t,i),h=(n,e,t,i)=>{let E=[],{keys:s,fns:l}=e;for(let r=0;r<l.length;r++){try{let o=k(l[r],n,t);if(!o||f(o))E.push(s[r])}catch{E.push(s[r])}if(i&&E.length)return E}return E},H=(n)=>{let e={...n},t=Object.keys(e);return{keys:t,rules:e,fns:t.map((i)=>e[i])}},B=(n,e=A)=>{let t=H(n),i=Boolean(e.break_early);if(L(t.rules))return async(E,...s)=>y(E,t.rules,s,t.keys,i);return(E,...s)=>h(E,t,s,i)},K=(n,e=A)=>{let t=Object.keys(n).map((s)=>{let l=n[s];return Array.isArray(l)?{key:s,set:void 0,alternatives:l.map(H)}:{key:s,set:H(l),alternatives:void 0}}),i=e.strict?{...n}:void 0,E=Boolean(e.break_early);if(!P(n))return(s,...l)=>{let r={};for(let o=0;o<t.length;o++){let{key:S,set:u,alternatives:c}=t[o];if(u)r[S]=h(s[S],u,l,E);else{let a=Array(c.length);for(let C=0;C<c.length;C++)a[C]=h(s[S],c[C],l,E);r[S]=g(a)}}if(i)O(r,s,i);return r};return async(s,...l)=>{let r={},o=[];for(let S=0;S<t.length;S++){let{key:u,set:c,alternatives:a}=t[S];if(c){let C=y(s[u],c.rules,l,c.keys,E);if(f(C))r[u]=[],o.push(C.then((_)=>{r[u]=_}));else r[u]=C}else{let C=a.map((_)=>y(s[u],_.rules,l,_.keys,E));if(C.some(f))r[u]=[],o.push(Promise.all(C).then((_)=>{r[u]=g(_)}));else r[u]=g(C)}}if(i)O(r,s,i);if(o.length)await Promise.all(o);return r}};export{B as compileRules,K as compileSchema,T as getSchemaErrors,D as getSchemaErrorsAsync,Y as getSchemaErrorsSync,I as getValueErrors,m as getValueErrorsAsync,U as getValueErrorsSync,R as hasAsyncFunction,w as isAsyncFunction};
|
package/lib/patterns/index.d.ts
CHANGED
package/lib/patterns/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var _=/^[\w.%+-]+@[\w.-]+\.[a-zA-Z]{1,}$/,z=/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/,S=/^(https?:\/\/)?([^\s$.?#].[^\s]*)\.[a-z]{2,}(\/[^ \t\r\n\v\f]*)?$/i,T=/^(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d(?:\.\d+)?(?:[+-][0-2]\d:[0-5]\d|Z)?)$/,v=/^(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d(?::[0-5]\d(?:\.\d+)?)?)$/,A=/^(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(Z|[+-](?:2[0-3]|[01][0-9]):([0-5][0-9]))?$/,c=/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/,u=(n)=>`[0-9a-f]{8}-[0-9a-f]{4}-${n}[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}`;var N=new RegExp(`^(?:${u("[1-8]")}|0{8}-0{4}-0{4}-0{4}-0{12}|f{8}-f{4}-f{4}-f{4}-f{12})$`,"i"),d=new RegExp(`^${u("4")}$`,"i"),p=new RegExp("^(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)$"),U=new RegExp("^(?:"+["(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}","(?:[0-9a-f]{1,4}:){1,7}:","(?:[0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}","(?:[0-9a-f]{1,4}:){1,5}(?::[0-9a-f]{1,4}){1,2}","(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,3}","(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,4}","(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,5}","[0-9a-f]{1,4}:(?::[0-9a-f]{1,4}){1,6}",":(?:(?::[0-9a-f]{1,4}){1,7}|:)","::(?:ffff(?::0{1,4})?:)?(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)","(?:[0-9a-f]{1,4}:){1,4}:(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)"].join("|")+")$","i"),i=/^[0-9a-f]{2}([:-])(?:[0-9a-f]{2}\1){4}[0-9a-f]{2}$/i,L=/^#([0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i,C=/^[a-z0-9]+(-[a-z0-9]+)*$/,f=/^\+[1-9]\d{1,14}$/,x=/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/,l=/^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$/,O=/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/,I=/[a-z]/,P=/[A-Z]/,y=/\d/,m=/[^\w\s]/;var b=(n)=>typeof n==="string"||n!==null&&typeof n==="object"&&("length"in n)&&typeof n.length==="number",s=(n)=>(e)=>typeof e===n,o=(n)=>(e)=>typeof e==="string"&&n.test(e);var R=(n=1/0)=>(e)=>b(e)&&e.length<=n,w=(n=0)=>(e)=>b(e)&&e.length>=n;var a="Must be a string",t=(n,e)=>Object.freeze({[a]:s("string"),[n]:o(e)}),k=(n,e,E)=>{let r=new Date(0);return r.setUTCFullYear(n,e-1,E),r.getUTCFullYear()===n&&r.getUTCMonth()===e-1&&r.getUTCDate()===E},Y=(n)=>{let[e,E,r]=n.slice(0,10).split("-").map(Number);return k(e,E,r)},V=/([+-])(\d\d):\d\d$/,h=(n)=>{let e=V.exec(n.slice(19))?.[2];return Y(n)&&Number(n.slice(11,13))<24&&(e===void 0||Number(e)<24)},g=254,M=128,B=Object.freeze({[a]:s("string"),[`Must be at most ${g} characters`]:R(g),"Must be a valid email address":o(_)}),j=t("Must be a valid URL",S),F=t("Must be a valid UUID",N),X=t("Must be a valid version 4 UUID",d),J=t("Must be a valid IPv4 address",p),q=t("Must be a valid IPv6 address",U),Q=t("Must be a valid MAC address",i),K=t("Must be a valid hex color",L),nn=t("Must be a valid slug",C),en=t("Must be a valid E.164 phone number",f),tn=t("Must be a valid semantic version",x),on=t("Must be valid base64",l),rn=t("Must be a valid JWT",O),sn=t("Must be a valid ISO 8601 time",A),an=Object.freeze({[a]:s("string"),"Must be a valid ISO 8601 date":(n)=>typeof n==="string"&&c.test(n)&&Y(n)}),En=Object.freeze({[a]:s("string"),"Must be a valid ISO 8601 date and time":(n)=>typeof n==="string"&&T.test(n)&&h(n)}),D=Object.freeze({[a]:s("string"),"Must be at least 8 characters":w(8),[`Must be at most ${M} characters`]:R(M),"Must contain at least one lower case character":o(I),"Must contain at least one upper case character":o(P)}),Rn=Object.freeze({...D,"Must contain at least one digit":o(y),"Must contain at least one symbol":o(m)});export{l as BASE64_PATTERN,on as BASE64_RULES,y as CONTAINS_DIGIT_CHARACTER_PATTERN,I as CONTAINS_LOWERCASE_CHARACTER_PATTERN,m as CONTAINS_SYMBOL_CHARACTER_PATTERN,P as CONTAINS_UPPERCASE_CHARACTER_PATTERN,f as E164_PHONE_PATTERN,en as E164_PHONE_RULES,_ as EMAIL_PATTERN,B as EMAIL_RULES,L as HEX_COLOR_PATTERN,K as HEX_COLOR_RULES,p as IPV4_PATTERN,J as IPV4_RULES,U as IPV6_PATTERN,q as IPV6_RULES,v as ISO_8601_DATETIME_PATTERN,T as ISO_8601_DATETIME_PATTERN_STRICT,En as ISO_8601_DATETIME_RULES,c as ISO_8601_DATE_PATTERN,an as ISO_8601_DATE_RULES,A as ISO_8601_TIME_PATTERN,sn as ISO_8601_TIME_RULES,O as JWT_PATTERN,rn as JWT_RULES,i as MAC_ADDRESS_PATTERN,Q as MAC_ADDRESS_RULES,z as MYSQL_TIMESTAMP_PATTERN,D as PASSWORD_RULES,x as SEMVER_PATTERN,tn as SEMVER_RULES,C as SLUG_PATTERN,nn as SLUG_RULES,Rn as STRONG_PASSWORD_RULES,S as URL_PATTERN,j as URL_RULES,N as UUID_PATTERN,F as UUID_RULES,d as UUID_V4_PATTERN,X as UUID_V4_RULES};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { RULES_SYNC } from '../types';
|
|
2
|
+
export declare const EMAIL_RULES: Readonly<RULES_SYNC>;
|
|
3
|
+
export declare const URL_RULES: Readonly<RULES_SYNC>;
|
|
4
|
+
export declare const UUID_RULES: Readonly<RULES_SYNC>;
|
|
5
|
+
export declare const UUID_V4_RULES: Readonly<RULES_SYNC>;
|
|
6
|
+
export declare const IPV4_RULES: Readonly<RULES_SYNC>;
|
|
7
|
+
export declare const IPV6_RULES: Readonly<RULES_SYNC>;
|
|
8
|
+
export declare const MAC_ADDRESS_RULES: Readonly<RULES_SYNC>;
|
|
9
|
+
export declare const HEX_COLOR_RULES: Readonly<RULES_SYNC>;
|
|
10
|
+
export declare const SLUG_RULES: Readonly<RULES_SYNC>;
|
|
11
|
+
export declare const E164_PHONE_RULES: Readonly<RULES_SYNC>;
|
|
12
|
+
export declare const SEMVER_RULES: Readonly<RULES_SYNC>;
|
|
13
|
+
export declare const BASE64_RULES: Readonly<RULES_SYNC>;
|
|
14
|
+
export declare const JWT_RULES: Readonly<RULES_SYNC>;
|
|
15
|
+
export declare const ISO_8601_TIME_RULES: Readonly<RULES_SYNC>;
|
|
16
|
+
export declare const ISO_8601_DATE_RULES: Readonly<RULES_SYNC>;
|
|
17
|
+
export declare const ISO_8601_DATETIME_RULES: Readonly<RULES_SYNC>;
|
|
18
|
+
export declare const PASSWORD_RULES: Readonly<RULES_SYNC>;
|
|
19
|
+
export declare const STRONG_PASSWORD_RULES: Readonly<RULES_SYNC>;
|
package/lib/types.d.ts
CHANGED
|
@@ -1,48 +1,93 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Types for rules, rule sets, schemas and validation results, plus the type-level machinery
|
|
3
|
+
* that infers whether validation is sync or async from the rules' declared return types.
|
|
4
|
+
*
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* A synchronous validation rule. It passes by returning `true` (any truthy value counts)
|
|
9
|
+
* and fails by returning `false` or throwing.
|
|
3
10
|
*
|
|
4
11
|
* @template V type of the value being validated (defaults to `unknown`)
|
|
5
12
|
* @template O tuple type of any extra "overload" arguments passed through by the caller
|
|
6
13
|
*/
|
|
7
14
|
export type RULE_SYNC<V = unknown, O extends unknown[] = unknown[]> = (value: V, ...overload: O) => boolean;
|
|
8
15
|
/**
|
|
9
|
-
* An asynchronous validation rule.
|
|
16
|
+
* An asynchronous validation rule. It passes by resolving to `true` (any truthy value counts)
|
|
17
|
+
* and fails by resolving to `false` or rejecting.
|
|
10
18
|
*
|
|
11
19
|
* @template V type of the value being validated (defaults to `unknown`)
|
|
12
20
|
* @template O tuple type of any extra "overload" arguments passed through by the caller
|
|
13
21
|
*/
|
|
14
22
|
export type RULE_ASYNC<V = unknown, O extends unknown[] = unknown[]> = (value: V, ...overload: O) => Promise<boolean>;
|
|
15
23
|
/**
|
|
16
|
-
* A validation rule which may be either synchronous or asynchronous.
|
|
24
|
+
* A validation rule which may be either synchronous or asynchronous. Annotating a rule with
|
|
25
|
+
* this type means its sync/async-ness can't be inferred, so results are typed as a union.
|
|
17
26
|
*
|
|
18
27
|
* @template V type of the value being validated (defaults to `unknown`)
|
|
19
28
|
* @template O tuple type of any extra "overload" arguments passed through by the caller
|
|
20
29
|
*/
|
|
21
30
|
export type RULE<V = unknown, O extends unknown[] = unknown[]> = (value: V, ...overload: O) => boolean | Promise<boolean>;
|
|
22
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* A set of synchronous rules. Each key is the error reported when its rule fails, and
|
|
33
|
+
* errors are reported in key order.
|
|
34
|
+
*
|
|
35
|
+
* @template V type of the value being validated (defaults to `unknown`)
|
|
36
|
+
* @template O tuple type of any extra "overload" arguments passed through by the caller
|
|
37
|
+
*/
|
|
23
38
|
export type RULES_SYNC<V = unknown, O extends unknown[] = unknown[]> = {
|
|
24
39
|
[rule_name: string]: RULE_SYNC<V, O>;
|
|
25
40
|
};
|
|
26
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* A set of rules, any of which may be asynchronous. Each key is the error reported when its
|
|
43
|
+
* rule fails, and errors are reported in key order.
|
|
44
|
+
*
|
|
45
|
+
* @template V type of the value being validated (defaults to `unknown`)
|
|
46
|
+
* @template O tuple type of any extra "overload" arguments passed through by the caller
|
|
47
|
+
*/
|
|
27
48
|
export type RULES<V = unknown, O extends unknown[] = unknown[]> = {
|
|
28
49
|
[rule_name: string]: RULE<V, O>;
|
|
29
50
|
};
|
|
30
51
|
/**
|
|
31
|
-
* Maps object
|
|
32
|
-
* (the value passes if it satisfies *any* of the alternatives).
|
|
52
|
+
* A schema whose rules are all synchronous. Maps each object key to a rule set, or to an
|
|
53
|
+
* array of alternative rule sets (the value passes if it satisfies *any* of the alternatives).
|
|
33
54
|
*/
|
|
34
55
|
export type SCHEMA_SYNC = {
|
|
35
56
|
[key: string]: RULES_SYNC | RULES_SYNC[];
|
|
36
57
|
};
|
|
58
|
+
/**
|
|
59
|
+
* A schema whose rules may be asynchronous. Maps each object key to a rule set, or to an
|
|
60
|
+
* array of alternative rule sets (the value passes if it satisfies *any* of the alternatives).
|
|
61
|
+
*/
|
|
37
62
|
export type SCHEMA = {
|
|
38
63
|
[key: string]: RULES | RULES[];
|
|
39
64
|
};
|
|
65
|
+
/** Options for running a rule set. */
|
|
66
|
+
export type RULES_OPTIONS = {
|
|
67
|
+
/**
|
|
68
|
+
* Stop at the first failing rule and report only that error, instead of running every rule
|
|
69
|
+
* and reporting all of them. Defaults to `false`.
|
|
70
|
+
*
|
|
71
|
+
* Sync rules run first, in rule order, stopping at the first failure. `async` rules only run
|
|
72
|
+
* if every sync rule passed; they then run concurrently, and the first failure in rule
|
|
73
|
+
* order is reported. This skips expensive checks (long regexes, database lookups) on input
|
|
74
|
+
* that has already failed a cheap one, so put cheap rules first. It doesn't change valid
|
|
75
|
+
* input, where every rule has to run anyway.
|
|
76
|
+
*/
|
|
77
|
+
break_early?: boolean;
|
|
78
|
+
};
|
|
40
79
|
/**
|
|
41
|
-
*
|
|
42
|
-
|
|
43
|
-
|
|
80
|
+
* Options for validating an object against a schema. `break_early` applies to each field
|
|
81
|
+
* separately: every field is still validated, each reporting at most one error per rule set.
|
|
82
|
+
*/
|
|
83
|
+
export type SCHEMA_OPTIONS = RULES_OPTIONS & {
|
|
84
|
+
/**
|
|
85
|
+
* Report keys of the object that the schema doesn't have, each with the error
|
|
86
|
+
* `['Key not allowed']`. Defaults to `false`, which ignores them.
|
|
87
|
+
*/
|
|
44
88
|
strict?: boolean;
|
|
45
89
|
};
|
|
90
|
+
/** An object that can be validated against a schema: any string-keyed object. */
|
|
46
91
|
export type CHECKABLE_OBJECT = {
|
|
47
92
|
[key: string]: unknown;
|
|
48
93
|
};
|
|
@@ -71,12 +116,41 @@ export type CHECKED_SCHEMA<S extends SCHEMA = SCHEMA> = Promise<CHECKED_SCHEMA_S
|
|
|
71
116
|
* so it can't be determined statically
|
|
72
117
|
*/
|
|
73
118
|
export type RULE_KIND<R> = R extends (...args: never[]) => infer Ret ? [Ret] extends [boolean] ? 'sync' : [Ret] extends [Promise<boolean>] ? 'async' : 'either' : never;
|
|
74
|
-
/** Union of the
|
|
119
|
+
/** Union of the `RULE_KIND`s of every rule in a rule set (or in an array of rule sets). */
|
|
75
120
|
export type RULES_KIND<R> = R extends readonly (infer E)[] ? RULES_KIND<E> : R extends object ? RULE_KIND<R[keyof R]> : never;
|
|
76
|
-
/** Union of the
|
|
121
|
+
/** Union of the `RULE_KIND`s of every rule in a schema. */
|
|
77
122
|
export type SCHEMA_KIND<S> = RULES_KIND<S[keyof S]>;
|
|
78
123
|
/**
|
|
79
124
|
* Wraps a result type according to the kinds found in a rule set / schema:
|
|
80
125
|
* any definitely-async rule => `Promise<X>`; all sync => `X`; otherwise `X | Promise<X>`.
|
|
126
|
+
*
|
|
127
|
+
* @template K union of rule kinds, from `RULES_KIND` or `SCHEMA_KIND`
|
|
128
|
+
* @template X the result type to wrap
|
|
81
129
|
*/
|
|
82
130
|
export type MAYBE_ASYNC<K, X> = 'async' extends K ? Promise<X> : 'either' extends K ? X | Promise<X> : X;
|
|
131
|
+
/**
|
|
132
|
+
* Any rule set, whatever value and overload types its rules accept. Used as the constraint
|
|
133
|
+
* for `compileRules`, so rules with narrowed parameter types can be compiled.
|
|
134
|
+
*/
|
|
135
|
+
export type ANY_RULES = {
|
|
136
|
+
[rule_name: string]: (value: never, ...overload: never[]) => boolean | Promise<boolean>;
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* The value type a rule set accepts: the intersection of what each of its rules accepts,
|
|
140
|
+
* e.g. `string` for a set mixing `(value: unknown)` and `(value: string)` rules.
|
|
141
|
+
*/
|
|
142
|
+
export type RULES_VALUE<R> = R[keyof R] extends (value: infer V, ...overload: never[]) => unknown ? V : unknown;
|
|
143
|
+
/**
|
|
144
|
+
* A validator returned by `compileRules`. Returns the keys of the failing rules, as
|
|
145
|
+
* `string[]` when every rule is sync and `Promise<string[]>` when any is async.
|
|
146
|
+
*
|
|
147
|
+
* @template R the compiled rule set's type
|
|
148
|
+
*/
|
|
149
|
+
export type COMPILED_RULES<R> = (value: RULES_VALUE<R>, ...overload: unknown[]) => MAYBE_ASYNC<RULES_KIND<R>, string[]>;
|
|
150
|
+
/**
|
|
151
|
+
* A validator returned by `compileSchema`. Returns the same result as `getSchemaErrors`,
|
|
152
|
+
* directly when every rule is sync and as a promise when any is async.
|
|
153
|
+
*
|
|
154
|
+
* @template S the compiled schema's type
|
|
155
|
+
*/
|
|
156
|
+
export type COMPILED_SCHEMA<S extends SCHEMA> = (object: CHECKABLE_OBJECT, ...overload: unknown[]) => MAYBE_ASYNC<SCHEMA_KIND<S>, CHECKED_SCHEMA_SYNC<S>>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ivl",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "Oskar Voorel",
|
|
6
6
|
"email": "oskar@voorel.com"
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"@types/bun": "^1.4.0",
|
|
16
16
|
"mitata": "^1.0.34",
|
|
17
|
-
"tsc-alias": "^1.9.2",
|
|
18
17
|
"typescript": "^7.0.2",
|
|
18
|
+
"valibot": "^1.5.0",
|
|
19
19
|
"yup": "^1.7.1",
|
|
20
20
|
"zod": "^4.5.2"
|
|
21
21
|
},
|
|
@@ -49,9 +49,10 @@
|
|
|
49
49
|
],
|
|
50
50
|
"license": "MIT",
|
|
51
51
|
"scripts": {
|
|
52
|
-
"build": "rm -rf ./lib && bun run build.mjs && tsc -p tsconfig.build.json
|
|
52
|
+
"build": "rm -rf ./lib && bun run build.mjs && tsc -p tsconfig.build.json",
|
|
53
53
|
"prepublishOnly": "bun run build",
|
|
54
54
|
"benchmark": "bun run ./benchmark/index.ts",
|
|
55
|
+
"benchmark:node": "bun build ./benchmark/index.ts --target=node --packages=external --outfile=./benchmark/.dist/index.mjs 1>&2 && node ./benchmark/.dist/index.mjs",
|
|
55
56
|
"typecheck": "tsc --noEmit -p tsconfig.test.json",
|
|
56
57
|
"test": "bun test && bun run typecheck",
|
|
57
58
|
"release": "bun run ./scripts/release.ts"
|