validator-fns 3.0.0-next.0 → 3.0.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,9 +10,11 @@ Small asynchronous validation library. Tries to be as small as possible and use
10
10
 
11
11
  - [Install](#install)
12
12
  - [Usage](#usage)
13
+ - [Migrating from 2.x](#migrating-from-2x)
13
14
  - [API Reference](#api-reference)
14
15
  - [Validation result](#validation-result)
15
16
  - [Validation error message](#validation-error-message)
17
+ - [Required and optional values](#required-and-optional-values)
16
18
  - [Validation types](#validation-types)
17
19
  - [Validation tests](#validation-tests)
18
20
  - [Custom validation](#custom-validation)
@@ -30,7 +32,9 @@ yarn add validator-fns
30
32
 
31
33
  ## Usage
32
34
 
33
- This is a fairly exhaustive example of what's possible with `validator-fns`.
35
+ > **Upgrading from 2.x?** Every validator is now required unless you wrap it in `optional()`, and `required()` is gone. See [Migrating from 2.x](#migrating-from-2x).
36
+
37
+ Every type validator rejects a missing value unless it's wrapped in `optional()`. This is a fairly exhaustive example of what's possible with `validator-fns`.
34
38
 
35
39
  <details><summary>example</summary>
36
40
 
@@ -38,6 +42,7 @@ This is a fairly exhaustive example of what's possible with `validator-fns`.
38
42
  import {
39
43
  array,
40
44
  boolean,
45
+ createValidator,
41
46
  date,
42
47
  email,
43
48
  exact,
@@ -50,7 +55,7 @@ import {
50
55
  number,
51
56
  object,
52
57
  oneOf,
53
- required,
58
+ optional,
54
59
  string,
55
60
  url,
56
61
  valid,
@@ -64,7 +69,7 @@ const TEN_DAYS = ONE_DAY * 10;
64
69
  const now = new Date();
65
70
  const tenDaysFromNow = new Date(now.getTime() + TEN_DAYS);
66
71
 
67
- function customValidator(value, field) {
72
+ const customValidator = createValidator(async (value, field) => {
68
73
  if (value === 'hello') {
69
74
  return valid({ value, field });
70
75
  }
@@ -73,24 +78,23 @@ function customValidator(value, field) {
73
78
  value,
74
79
  field,
75
80
  });
76
- }
81
+ });
77
82
 
78
83
  const validate = object({
79
- firstName: string(
80
- { default: '', trim: true },
81
- required('First name is required.'),
82
- ),
84
+ firstName: string({
85
+ trim: true,
86
+ requiredMessage: 'First name is required.',
87
+ }),
83
88
  emailAddress: string(
84
- required('Email address is required.'),
89
+ { requiredMessage: 'Email address is required.' },
85
90
  email('Must be a valid email address.'),
86
91
  ),
87
92
  age: number(
88
- { round: 'floor' },
89
- required('Age is required.'),
93
+ { round: 'floor', requiredMessage: 'Age is required.' },
90
94
  integer('Age must be a whole number.'),
91
95
  min(18, 'Must be at least {min} years old.'),
92
96
  ),
93
- homepage: string(url('Must be a valid URL.', ['http:', 'https:'])),
97
+ homepage: optional(string(url('Must be a valid URL.', ['http:', 'https:']))),
94
98
  fruit: string(
95
99
  { default: 'apple' },
96
100
  oneOf(
@@ -101,7 +105,7 @@ const validate = object({
101
105
  favoriteCarMakers: array(
102
106
  { default: [] },
103
107
  string(
104
- required('Car brand is required.'),
108
+ { requiredMessage: 'Car brand is required.' },
105
109
  oneOf(
106
110
  [
107
111
  'BMW',
@@ -122,16 +126,20 @@ const validate = object({
122
126
  min(2, 'Must pick at least two.'),
123
127
  max(4, 'Must pick at most four.'),
124
128
  ),
125
- startDate: date(
126
- minDate(now, 'Must be on or after today.'),
127
- maxDate(tenDaysFromNow, 'Must be at most ten days from now.'),
129
+ startDate: optional(
130
+ date(
131
+ minDate(now, 'Must be on or after today.'),
132
+ maxDate(tenDaysFromNow, 'Must be at most ten days from now.'),
133
+ ),
128
134
  ),
129
- optIn: boolean(required('Must decide to opt in or out.')),
135
+ optIn: boolean({ requiredMessage: 'Must decide to opt in or out.' }),
130
136
  notRobot: number(
131
- required('Must enter the correct answer.'),
137
+ { requiredMessage: 'Must enter the correct answer.' },
132
138
  exact(42, 'This is the answer.'),
133
139
  ),
134
- postalCode: string(matches(/^[0-9]{5}$/, 'Must be a five-digit number.')),
140
+ postalCode: optional(
141
+ string(matches(/^[0-9]{5}$/, 'Must be a five-digit number.')),
142
+ ),
135
143
  custom: customValidator,
136
144
  });
137
145
 
@@ -161,20 +169,63 @@ if (result.state === 'valid') {
161
169
 
162
170
  </details>
163
171
 
172
+ ## Migrating from 2.x
173
+
174
+ Version 3 makes every type validator required by default. In 2.x, a validator without `required()` accepted `undefined`, `null` and the other missing values; in 3.x, it rejects them with `'Required.'`.
175
+
176
+ 1. **Move each `required(message)` into the config as `requiredMessage`**, merging it into a config object that's already there:
177
+
178
+ ```js
179
+ // 2.x
180
+ string(required('Enter a name.'), min(2, 'Too short.'));
181
+ number({ round: 'floor' }, required('Enter your age.'));
182
+ array(string(), required('Pick some.'));
183
+
184
+ // 3.x
185
+ string({ requiredMessage: 'Enter a name.' }, min(2, 'Too short.'));
186
+ number({ round: 'floor', requiredMessage: 'Enter your age.' });
187
+ array({ requiredMessage: 'Pick some.' }, string());
188
+ ```
189
+
190
+ 2. **Wrap each validator that had no `required()` in `optional()`**, or it now rejects a missing value:
191
+
192
+ ```js
193
+ // 2.x
194
+ string(email('Must be an email.'));
195
+
196
+ // 3.x
197
+ optional(string(email('Must be an email.')));
198
+ ```
199
+
200
+ 3. **Replace `required(message, true)`** (nullable): `optional()` accepts `null`, as well as the other missing values.
201
+ 4. **Check `object()` calls with a second argument**: it's a config object or the first object-level test, as in `object(schema, { requiredMessage }, ...tests)`. A missing object now fails with its `requiredMessage` instead of reporting each field as missing; wrap it in `optional()` to accept one.
202
+ 5. **Replace `standard()`**: remove it around built-in validators, which are Standard Schemas themselves, and change `standard(fn)` to `createValidator(fn)`:
203
+
204
+ ```js
205
+ // 2.x
206
+ standard(object({ email: string() }));
207
+ standard(async (value, field) => valid({ value, field }));
208
+
209
+ // 3.x
210
+ object({ email: string() });
211
+ createValidator(async (value, field) => valid({ value, field }));
212
+ ```
213
+
214
+ 6. **In TypeScript**, a valid result's `value` no longer includes `null` or `undefined` unless the validator is wrapped in `optional()`, and `object()` makes only `optional()` keys optional. `valid()` takes a value of the validator's type, so a custom validator that returns `null` or `undefined` needs them in its type, such as `ValidatorTest<string | undefined>`.
215
+
164
216
  ## API Reference
165
217
 
166
218
  ### Validation result
167
219
 
168
220
  All validation tests yield one of two results: `valid` and `invalid`. Both are objects. In TypeScript the result is `ValidatorResult<T, E>` and a validation test is `ValidatorTest<T, E>`, where `T` is the value type and `E` the `errors` type. Both default to `unknown`.
169
221
 
170
- | property | type | description |
171
- | :------------ | :------ | :------------------------------------------------------------------------- |
172
- | `state` | string | Either `valid` or `invalid`. |
173
- | `field` | string | Either the field name or `undefined`. |
174
- | `value` | `T` | The parsed value. |
175
- | `message` | string | The error message unless `state` is `valid`. |
176
- | `errors` | `E` | Only if `state` is `invalid` and using the `object` or `array` validators. |
177
- | ~~`isValid`~~ | boolean | Deprecated. Use `state` instead. |
222
+ | property | type | description |
223
+ | :-------- | :----- | :------------------------------------------------------------------------- |
224
+ | `state` | string | Either `valid` or `invalid`. |
225
+ | `field` | string | Either the field name or `undefined`. |
226
+ | `value` | `T` | The parsed value. |
227
+ | `message` | string | The error message unless `state` is `valid`. |
228
+ | `errors` | `E` | Only if `state` is `invalid` and using the `object` or `array` validators. |
178
229
 
179
230
  ### Validation error message
180
231
 
@@ -188,22 +239,55 @@ The `message` argument in the validation tests must be a static string, a templa
188
239
 
189
240
  The parsed `value` is always provided. If available, `field` is also provided. Depending on the validator, additional fields may be available.
190
241
 
242
+ ### Required and optional values
243
+
244
+ Every validation type rejects a missing value: `undefined`, `null`, an empty string `''`, `NaN`, or an invalid date. It checks after parsing and `default`, so `string({ trim: true })` treats `' '` as missing, `number()` treats a blank string as missing, and a `default` fills a missing value before the check. The tests only run on present values.
245
+
246
+ The message is `'Required.'` unless the config sets `requiredMessage`, which takes a [validation error message](#validation-error-message):
247
+
248
+ ```js
249
+ await string()('');
250
+ // { state: 'invalid', message: 'Required.', value: '', ... }
251
+
252
+ await number({ requiredMessage: '{field} is required.' })(undefined, 'age');
253
+ // { state: 'invalid', message: 'age is required.', ... }
254
+ ```
255
+
256
+ #### optional(validator)
257
+
258
+ Returns a validator that accepts a missing value. The missing value skips the tests and becomes the result's `value` as parsed, so `optional(number())('')` is valid with `NaN`. Present values go through `validator` as usual. The validator passed in is unchanged.
259
+
260
+ ```js
261
+ const nickname = optional(string(min(2, 'Too short.')));
262
+
263
+ await nickname(undefined); // { state: 'valid', value: undefined, ... }
264
+ await nickname('a'); // { state: 'invalid', message: 'Too short.', ... }
265
+ ```
266
+
267
+ For a custom validator, `optional()` accepts `undefined` and `null` without calling it, and passes every other value to it.
268
+
269
+ In TypeScript, a validator's value type is `T`, and `optional()` adds `null` and `undefined`. In `object()`, a key is optional when its validator's value type includes `undefined`, so `object({ name: string(), age: optional(number()) })` is typed `{ name: string; age?: number | null | undefined }`.
270
+
191
271
  ### Validation types
192
272
 
193
- A **validation type** is expected to parse and prepare the value for the provided validation tests. For example, the `string` validation type ensures the provided value is a string, `null` or `undefined`. It must be a function that takes a value of any type and returns a promise which resolves to a validation result (see above).
273
+ A **validation type** is expected to parse and prepare the value for the provided validation tests. For example, the `string` validation type ensures the provided value is a string, and rejects a missing value unless wrapped in [`optional()`](#optionalvalidator). It must be a function that takes a value of any type and returns a promise which resolves to a validation result (see above).
194
274
 
195
275
  - [array(config?, itemTest, ...tests)](#arrayconfig-itemtest-tests)
196
276
  - [boolean(config?, ...tests)](#booleanconfig-tests)
197
277
  - [date(config?, ...tests)](#dateconfig-tests)
198
278
  - [number(config?, ...tests)](#numberconfig-tests)
199
- - [object(schema)](#objectschema)
279
+ - [object(schema, config?, ...tests)](#objectschema-config-tests)
200
280
  - [string(config?, ...tests)](#stringconfig-tests)
201
281
 
282
+ Every validation type, and every validator `optional()` returns, is also a [Standard Schema][standard-schema], so libraries that accept one can use it directly. See [createValidator(fn)](#createvalidatorfn) for how results map to issues. In TypeScript, their type is `TypeValidator<T, E>`: a `ValidatorTest<T, E>` with a `~standard` property.
283
+
202
284
  #### array(config?, itemTest, ...tests)
203
285
 
204
- Casts value to an array, `null` or `undefined` if using the default date parser. `config` is optional. `itemTest` is the validation type or test to be applied on each value within the array value. All remaining `tests` are applied to the array as a whole.
286
+ Casts value to an array, or keeps `null` or `undefined` if using the default array parser. `config` is optional. `itemTest` is the validation type or test to be applied on each value within the array value. All remaining `tests` are applied to the array as a whole.
205
287
 
206
- Supported validation tests: `max`, `min`, and `required`.
288
+ A valid result's `value` holds each item as `itemTest` returned it, so `array(number())` turns `['1', '2.5']` into `[1, 2.5]`, and `array(string({ trim: true }))` trims each item.
289
+
290
+ Supported validation tests: `max` and `min`.
207
291
 
208
292
  For invalid results, errors are in the `errors` property. It is an array of type:
209
293
 
@@ -215,40 +299,43 @@ Where valid entries are represented as `null` and invalid entries with the error
215
299
 
216
300
  <details><summary>config</summary>
217
301
 
218
- | option | type | description |
219
- | :-------- | :------- | :-------------------------------------------------------------------------------------- |
220
- | `default` | string | Optional. Value used if the parser returns `undefined`, `null`, or an empty array `[]`. |
221
- | `parser` | function | Optional. Used to customize how a value is converted into a string. |
302
+ | option | type | description |
303
+ | :---------------- | :----------------- | :-------------------------------------------------------------------------------------- |
304
+ | `default` | string | Optional. Value used if the parser returns `undefined`, `null`, or an empty array `[]`. |
305
+ | `requiredMessage` | string or function | Optional. Message for a missing value. Defaults to `'Required.'`. |
306
+ | `parser` | function | Optional. Used to customize how a value is converted into a string. |
222
307
 
223
308
  </details>
224
309
 
225
310
  #### boolean(config?, ...tests)
226
311
 
227
- Casts value to a boolean, `null` or `undefined` if using the default boolean parser. `config` is optional.
312
+ Casts value to a boolean, or keeps `null` or `undefined` if using the default boolean parser. `config` is optional.
228
313
 
229
- Supported validation tests: `oneOf` and `required`.
314
+ Supported validation tests: `oneOf`.
230
315
 
231
316
  <details><summary>config</summary>
232
317
 
233
- | option | type | description |
234
- | :-------- | :------- | :------------------------------------------------------------------- |
235
- | `default` | boolean | Optional. Value used if the parser returns `undefined` or `null`. |
236
- | `parser` | function | Optional. Used to customize how a value is converted into a boolean. |
318
+ | option | type | description |
319
+ | :---------------- | :----------------- | :------------------------------------------------------------------- |
320
+ | `default` | boolean | Optional. Value used if the parser returns `undefined` or `null`. |
321
+ | `requiredMessage` | string or function | Optional. Message for a missing value. Defaults to `'Required.'`. |
322
+ | `parser` | function | Optional. Used to customize how a value is converted into a boolean. |
237
323
 
238
324
  </details>
239
325
 
240
326
  #### date(config?, ...tests)
241
327
 
242
- Casts value to a date, `null` or `undefined` if using the default date parser. `config` is optional.
328
+ Casts value to a date, or keeps `null` or `undefined` if using the default date parser. A string that isn't ISO 8601, such as `'tomorrow'`, and input that isn't a `Date`, number, or string, such as `true` or `{}`, give an invalid result with the message `Failed to parse value to date.`. A blank string and an invalid `Date` become an invalid date, which counts as missing. `config` is optional.
243
329
 
244
- Supported validation tests: `maxDate`, `minDate`, `oneOf`, and `required`.
330
+ Supported validation tests: `maxDate`, `minDate`, and `oneOf`.
245
331
 
246
332
  <details><summary>config</summary>
247
333
 
248
- | option | type | description |
249
- | :-------- | :------- | :---------------------------------------------------------------------------------- |
250
- | `default` | date | Optional. Value used if the parser returns `undefined`, `null`, or an invalid date. |
251
- | `parser` | function | Optional. Used to customize how a value is converted into a date. |
334
+ | option | type | description |
335
+ | :---------------- | :----------------- | :---------------------------------------------------------------------------------- |
336
+ | `default` | date | Optional. Value used if the parser returns `undefined`, `null`, or an invalid date. |
337
+ | `requiredMessage` | string or function | Optional. Message for a missing value. Defaults to `'Required.'`. |
338
+ | `parser` | function | Optional. Used to customize how a value is converted into a date. |
252
339
 
253
340
  The default parser only accepts dates, numbers, and a subset of [ISO 8601][iso8601] formatted strings (excludes week formats). If you want to allow other or more complex formats you should use a third-party library such as [date-fns][date-fns].
254
341
 
@@ -256,50 +343,82 @@ The default parser only accepts dates, numbers, and a subset of [ISO 8601][iso86
256
343
 
257
344
  #### number(config?, ...tests)
258
345
 
259
- Casts value to a number, `null` or `undefined` if using the default number parser. `config` is optional.
346
+ Casts value to a number, or keeps `null` or `undefined` if using the default number parser. `config` is optional.
347
+
348
+ The default parser accepts numbers, bigints, dates (as their timestamp), strings that start with a number (read with `parseFloat`, so `'12px'` is `12`), and `Number` or `String` objects holding one. A blank string (`''` or only whitespace) gives `NaN`, which counts as missing and which `default` replaces. Any other input gives an invalid result with the message `Failed to parse value to number.`: strings without a leading number, such as `'abc'`, booleans, symbols, and objects other than the ones above, arrays and functions included.
260
349
 
261
- Supported validation tests: `exact`, `integer`, `max`, `min`, `oneOf`, and `required`.
350
+ Supported validation tests: `exact`, `integer`, `max`, `min`, and `oneOf`.
262
351
 
263
352
  <details><summary>config</summary>
264
353
 
265
- | option | type | description |
266
- | :-------- | :------- | :----------------------------------------------------------------------------------------- |
267
- | `round` | string | Optional. Rounding method to use, one of `nearest`, `ceil`, `floor` |
268
- | `default` | number | Optional. Value used if the parser returns `undefined`, `null` or an invalid number `NaN`. |
269
- | `parser` | function | Optional. Used to customize how a value is converted into a number. |
354
+ | option | type | description |
355
+ | :---------------- | :----------------- | :----------------------------------------------------------------------------------------- |
356
+ | `round` | string | Optional. Rounding method to use, one of `nearest`, `ceil`, `floor` |
357
+ | `default` | number | Optional. Value used if the parser returns `undefined`, `null` or an invalid number `NaN`. |
358
+ | `requiredMessage` | string or function | Optional. Message for a missing value. Defaults to `'Required.'`. |
359
+ | `parser` | function | Optional. Used to customize how a value is converted into a number. |
270
360
 
271
361
  </details>
272
362
 
273
- #### object(schema)
363
+ #### object(schema, config?, ...tests)
274
364
 
275
- The only validation type that does not cast the entered value, meaning it does not use a parser. There's also no default fallback value option here. Instead, the schema is an object where its properties are validation types such as `string`, `array`, `number`, etc. Nested `object` validators are allowed, but not recommended due to their complexity and potential performance hit.
365
+ The only validation type that does not cast the entered value, meaning it does not use a parser. There's also no default fallback value option here. `config` is optional; when the second argument is a function, it's the first of the `tests`. A missing object, `undefined` or `null`, fails with `config.requiredMessage`, or `'Required.'`, without checking its fields. Instead, the schema is an object where its properties are validation types such as `string`, `array`, `number`, etc. Nested `object` validators are allowed, but not recommended due to their complexity and potential performance hit.
276
366
 
277
367
  For invalid results, errors are in the `errors` property. It matches the provided object with the same keys and strings or string records as values that contain the error messages.
278
368
 
279
- Unlike yup, this API does not (yet at least) have a ref option.
369
+ In TypeScript, a field of the valid value is required unless its validator is wrapped in `optional()`, as in `{ name: string; age?: number | null | undefined }`. A missing optional field is still set on the value, as `undefined`.
370
+
371
+ The remaining `tests` are object-level tests. They run in order on the parsed object, only once every property is valid, and the first failure becomes the result. Use [`check`](#checkpath-test-message) to compare fields and put the error on one of them:
372
+
373
+ ```ts
374
+ const signup = object(
375
+ {
376
+ password: string(),
377
+ confirm: string(),
378
+ },
379
+ check('confirm', (value) => value.confirm === value.password, 'Must match.'),
380
+ );
381
+
382
+ await signup({ password: 'secret', confirm: 'other' });
383
+ // { state: 'invalid', message: '', errors: { confirm: 'Must match.' }, ... }
384
+ ```
385
+
386
+ A field's own error takes precedence: object-level tests don't run while any property is invalid, so they always compare valid, parsed values.
387
+
388
+ <details><summary>config</summary>
389
+
390
+ | option | type | description |
391
+ | :---------------- | :----------------- | :----------------------------------------------------------------- |
392
+ | `requiredMessage` | string or function | Optional. Message for a missing object. Defaults to `'Required.'`. |
393
+
394
+ </details>
280
395
 
281
396
  To use this with a library such as [Formik][formik], you can use the resulting `errors` property. It is a key-value structure with the schema property keys and their validation errors if any. Besides that, the object validation results are the same as described above.
282
397
 
283
398
  #### string(config?, ...tests)
284
399
 
285
- Casts value to a string, `null` or `undefined` if using the default string parser. `config` is optional.
400
+ Casts value to a string, or keeps `null` or `undefined` if using the default string parser. `config` is optional.
286
401
 
287
- Supported validation tests: `email`, `exact`, `matches`, `max`, `min`, `oneOf`, `required`, `url`, and `uuid`.
402
+ The default parser accepts strings, numbers, bigints, booleans, dates (as an ISO string), and `String`, `Number`, or `Boolean` objects. Any other object, including arrays and functions, and symbols give an invalid result with the message `Failed to parse value to string.`
403
+
404
+ Supported validation tests: `email`, `exact`, `matches`, `max`, `min`, `oneOf`, `url`, and `uuid`.
288
405
 
289
406
  <details><summary>config</summary>
290
407
 
291
- | option | type | description |
292
- | :-------- | :------- | :--------------------------------------------------------------------------------------- |
293
- | `trim` | boolean | Optional. If true, clears whitespace from the start and end of the string. |
294
- | `default` | string | Optional. Value used if the parser returns `undefined`, `null`, or an empty string `''`. |
295
- | `parser` | function | Optional. Used to customize how a value is converted into a string. |
408
+ | option | type | description |
409
+ | :---------------- | :----------------- | :--------------------------------------------------------------------------------------- |
410
+ | `trim` | boolean | Optional. If true, clears whitespace from the start and end of the string. |
411
+ | `default` | string | Optional. Value used if the parser returns `undefined`, `null`, or an empty string `''`. |
412
+ | `requiredMessage` | string or function | Optional. Message for a missing value. Defaults to `'Required.'`. |
413
+ | `parser` | function | Optional. Used to customize how a value is converted into a string. |
296
414
 
297
415
  </details>
298
416
 
299
417
  ### Validation tests
300
418
 
301
- A **validation test** is a simplified version of a validation type. It accepts a value of a specific type including `null` and `undefined` and then returns a promise that resolves to a validation result. You can use a validation test directly without the validation type, but it's not recommended as you lose the parsing step and you can't apply multiple tests to the same field as easily.
419
+ A **validation test** is a simplified version of a validation type. It accepts a value of a specific type and returns a promise that resolves to a validation result. Validation types only run tests on present values; called directly, the built-in tests pass `null` and `undefined` through. You can use a validation test directly without the validation type, but it's not recommended as you lose the parsing step and you can't apply multiple tests to the same field as easily.
302
420
 
421
+ - [check(path?, test, message)](#checkpath-test-message)
303
422
  - [email(message)](#emailmessage)
304
423
  - [exact(limit, message)](#exactlimit-message)
305
424
  - [integer(message)](#integermessage)
@@ -309,10 +428,23 @@ A **validation test** is a simplified version of a validation type. It accepts a
309
428
  - [min(limit, message, exclusive?)](#minlimit-message-exclusive)
310
429
  - [minDate(limit, message, exclusive?)](#mindatelimit-message-exclusive)
311
430
  - [oneOf(values, message)](#oneofvalues-message)
312
- - [required(message, nullable?)](#requiredmessage-nullable)
313
431
  - [url(message, protocols?)](#urlmessage-protocols)
314
432
  - [uuid(message)](#uuidmessage)
315
433
 
434
+ #### check(path?, test, message)
435
+
436
+ An object-level test for `object`. It fails when `test` returns `false` for the parsed object. With a `path`, the message is the error at that property in the object's `errors`; a list of names reaches into nested objects, such as `['shipping', 'zip']`. Without a `path`, the message is the object's own `message`. The parsed object is provided to the message as `value`.
437
+
438
+ <details><summary>arguments</summary>
439
+
440
+ | name | type | description |
441
+ | :-------- | :----------------- | :---------------------------------------------------------------- |
442
+ | `path` | string or string[] | Optional. The property, or the path into nested objects, to fail. |
443
+ | `test` | function | Gets the parsed object and returns `true` when it is valid. |
444
+ | `message` | string or function | The validation error message. |
445
+
446
+ </details>
447
+
316
448
  #### email(message)
317
449
 
318
450
  Ensures the value follows an email address format. Wraps the `matches` validation test. Works with strings.
@@ -432,31 +564,16 @@ Ensures value is one of the specified values. Works with strings, arrays, boolea
432
564
 
433
565
  </details>
434
566
 
435
- #### required(message, nullable?)
436
-
437
- Ensures value is **not** one of: `undefined`, `null`, `NaN`, an empty string, or an invalid date. Works with all types.
438
-
439
- <details><summary>arguments</summary>
440
-
441
- | name | type | description |
442
- | :--------- | :----------------- | :-------------------------------- |
443
- | `message` | string or function | The validation error message. |
444
- | `nullable` | boolean | Optional. If true, allows `null`. |
445
-
446
- </details>
447
-
448
567
  #### url(message, protocols?)
449
568
 
450
- Ensures value is a valid URL. Works with strings. `protocols` is provided to the message.
451
-
452
- > **Warning:** without `protocols`, any URL that the `URL` constructor parses is valid, including `javascript:` and `data:` URLs, which can run script when used as a link. Pass `['http:', 'https:']` for values you render as links. The default is planned to change to `http:` and `https:` in v3 ([#521](https://github.com/smonn/validator-fns/issues/521)).
569
+ Ensures value is a valid URL with an allowed protocol. Works with strings. `protocols` defaults to `['http:', 'https:']`, so `javascript:` and `data:` URLs, which can run script when used as a link, are invalid. A list replaces the default, so `['mailto:']` allows only `mailto:`. `protocols` is provided to the message.
453
570
 
454
571
  <details><summary>arguments</summary>
455
572
 
456
- | name | type | description |
457
- | :---------- | :----------------- | :------------------------------------------------------- |
458
- | `message` | string or function | The validation error message. |
459
- | `protocols` | array | List of allowed URL protocols, e.g. `https:`, `mailto:`. |
573
+ | name | type | description |
574
+ | :---------- | :----------------- | :--------------------------------------------------------------------------------- |
575
+ | `message` | string or function | The validation error message. |
576
+ | `protocols` | array | Allowed URL protocols, e.g. `https:`, `mailto:`. Defaults to `http:` and `https:`. |
460
577
 
461
578
  </details>
462
579
 
@@ -476,22 +593,51 @@ Ensures the value is a UUID as defined by [RFC 9562](https://www.rfc-editor.org/
476
593
 
477
594
  Custom validation types and validators can be created and used as needed. There are some helpers that, while used internally, are considered part of the public API.
478
595
 
596
+ - [createValidator(fn)](#createvalidatorfn)
479
597
  - [formatMessage(template, params)](#formatmessagetemplate-params)
480
598
  - [createTypeValidatorTest(defaultConfig, applyConfig)](#createtypevalidatortestdefaultconfig-applyconfig)
481
599
  - [valid({ value, field })](#valid-value-field-)
482
600
  - [invalid({ message, value, field, errors, extras })](#invalid-message-value-field-errors-extras-)
483
601
 
602
+ #### createValidator(fn)
603
+
604
+ Makes a custom validator from `fn`, an async function that takes a value and a field name and returns a result made with `valid()` or `invalid()`. The validator gives the same results as `fn`, works with `optional()` and inside `object()` and `array()`, and is a [Standard Schema][standard-schema] like the validation types. `fn` itself is unchanged. A validator that's already a Standard Schema from this library, such as `string()`, is returned as it is. In TypeScript, its type is `TypeValidator<T, E>`, with `T` and `E` inferred from `fn`'s return type.
605
+
606
+ `fn` must return a promise. A synchronous function is a type error.
607
+
608
+ ```ts
609
+ const hello = createValidator(async (value, field) =>
610
+ value === 'hello'
611
+ ? valid({ value, field })
612
+ : invalid({ message: 'Must be "hello".', value, field }),
613
+ );
614
+
615
+ await hello['~standard'].validate('hi');
616
+ // { issues: [{ message: 'Must be "hello".' }] }
617
+
618
+ const schema = object({ email: string(email('Must be an email.')) });
619
+ await schema['~standard'].validate({ email: 'nope' });
620
+ // { issues: [{ message: 'Must be an email.', path: ['email'] }] }
621
+ ```
622
+
623
+ How a validator's results map to Standard Schema results:
624
+
625
+ - `validate` always returns a promise, because every validator here is async. Libraries that only accept synchronous schemas can't use it.
626
+ - A valid result gives `{ value }`, the parsed value. Its type is the validator's value type, which includes `null` and `undefined` only for `optional()` validators.
627
+ - An invalid result gives one issue per error message. Object keys and array indexes in `errors` form each issue's `path`, and a non-empty `message`, such as an array-level error, is an issue with no path. An error with no message gets `'Invalid value.'`.
628
+ - An `object` field that fails both an array-level test and item tests keeps only the array-level message, because `object` stores a field's message in place of its errors, so only that message becomes an issue.
629
+
484
630
  #### formatMessage(template, params)
485
631
 
486
632
  Formats a string for use as an error message. `template` can be a plain string with `{keys}` replaced by the `params` or a function that returns a string and accepts `params` as a parameter.
487
633
 
488
634
  #### createTypeValidatorTest(defaultConfig, applyConfig)
489
635
 
490
- Useful helper for simple validation types such as strings, numbers, etc. `defaultConfig` is the configuration object that the `applyConfig` function will use when parsing the value being validated. At least this should include a `parser` function.
636
+ Useful helper for simple validation types such as strings, numbers, etc. `defaultConfig` is the configuration object that the `applyConfig` function will use when parsing the value being validated. At least this should include a `parser` function. The resulting validator is required by default, takes `requiredMessage` in its config, works with `optional()`, and is a Standard Schema, like the built-in ones. Its return type is a `TypeValidator`, which is still a `ValidatorTest`, so factories typed with `ValidatorFactory` keep working.
491
637
 
492
638
  The validation tests passed to the resulting validator report their errors as strings, as the built-in ones do; a test whose `errors` has another type is a type error.
493
639
 
494
- In TypeScript, pass the value type and the config type as type arguments. TypeScript 5.6 and later infer the config type from `defaultConfig` alone, so without them the validator rejects options that `defaultConfig` doesn't set.
640
+ In TypeScript, the value type and the config type are inferred from `applyConfig`, so the validator accepts options that `defaultConfig` doesn't set. Passing them as type arguments, as in `createTypeValidatorTest<number, MoneyConfig>(…)`, still works.
495
641
 
496
642
  ```ts
497
643
  import {
@@ -515,7 +661,7 @@ function applyMoneyConfig(
515
661
  : amount;
516
662
  }
517
663
 
518
- const money = createTypeValidatorTest<number, MoneyConfig>(
664
+ const money = createTypeValidatorTest(
519
665
  { parser: parseNumber },
520
666
  applyMoneyConfig,
521
667
  );
@@ -526,7 +672,7 @@ const result = await money({ cents: true })('12.5');
526
672
 
527
673
  #### valid({ value, field })
528
674
 
529
- Formats a successful validation result. `value` is the parsed value and `field` is the name of the object schema property.
675
+ Formats a successful validation result. `value` is the parsed value and `field` is the name of the object schema property. In TypeScript, `value` has the validator's value type, so a custom validator that can return `null` or `undefined` needs them in that type.
530
676
 
531
677
  #### invalid({ message, value, field, errors, extras })
532
678
 
@@ -537,12 +683,12 @@ Formats a failed validation result. `message` is the same as the `formatMessage`
537
683
  Supports Node versions in active or maintenance LTS at release time. Dropping one waits for the next major release.
538
684
 
539
685
  - Node.js 22 and later.
686
+ - TypeScript 5.4 and later, for the type declarations.
540
687
  - Chrome and Edge 85+, Firefox 77+, and Safari 13.1+ (iOS 13.4+): the first versions with every feature below, per [MDN's browser compatibility data][bcd] 8.1.6.
541
688
 
542
689
  To support older environments, transpile or polyfill these:
543
690
 
544
691
  - `String.prototype.replaceAll` (ES2021)
545
- - Nullish coalescing (`??`, ES2020)
546
692
  - Optional catch binding (ES2019)
547
693
  - Object spread (`...`, ES2018)
548
694
  - `async`, `await` (ES2017)
@@ -552,6 +698,7 @@ To support older environments, transpile or polyfill these:
552
698
  [npm]: https://www.npmjs.com/package/validator-fns
553
699
  [docs]: #documentation
554
700
  [github]: https://github.com/smonn/validator-fns
701
+ [standard-schema]: https://standardschema.dev
555
702
  [yup]: https://github.com/jquense/yup
556
703
  [bcd]: https://github.com/mdn/browser-compat-data
557
704
  [date-fns]: https://date-fns.org
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e){return Object.prototype.toString.call(e)===`[object Object]`}function t(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function n(e){return!!Reflect.get(Object(e),Symbol.iterator)}const r=/{(\w+)}/g;function i(e,t){return typeof e==`string`?e.replaceAll(r,(e,n)=>String(Reflect.get(t,n))):e(t)}async function a({value:e,field:t}){return{isValid:!0,state:`valid`,value:e,field:t}}async function o({errors:e,field:t,message:n,value:r,extras:a}){return{isValid:!1,state:`invalid`,message:i(n,{...a,value:r,field:t}),value:r,field:t,errors:e}}function s(e){return Array.isArray(e)||e==null?e:n(e)?[...e]:[]}function c(e,t){let n=e.parser(t);return e.default!==void 0&&(n==null||n.length===0)&&(n=e.default),n}async function l(e,t,n){for(let r of e){let e=await r(t,n);if(e.state===`invalid`)return e}}async function u(e,t,n){let r=!0,i=[];if(!t||!e)return{isValid:r,errors:i};for(let[a,o]of t.entries()){let t=await e(o,n?`${n}[${a}]`:`[${a}]`);t.state===`invalid`?(r=!1,i.push(t.message||t.errors)):i.push(null)}return{isValid:r,errors:i}}function d(e,...t){let n=t,r={parser:s};return e!==void 0&&(typeof e==`function`?n=[e,...t]:r={...r,...e}),async(e,t)=>{let i=c(r,e),[s,...d]=n,f=await l(d,i,t),p=await u(s,i,t);return!f&&p.isValid?a({value:i,field:t}):o({message:f?f.message:``,value:e,field:t,errors:p.errors})}}function f(e,t){return(n,...r)=>{let i=e,s=r;return n!==void 0&&(typeof n==`function`?s=[n,...r]:i={...e,...n}),async(e,n)=>{try{let r=t(e,i);for(let e of s){let t=await e(r,n);if(t.state===`invalid`)return t}return await a({value:r,field:n})}catch(t){return o({message:t instanceof Error?t.message:String(t),value:e,field:n})}}}}function p(e,t,n){return async(r,i)=>e(r,i)?a({value:r,field:i}):o({message:t,value:r,field:i,extras:n?n(r):void 0})}function m(e){return e==null||typeof e==`boolean`?e:!!e}function h(e,t){let n=t.parser(e);return t.default!==void 0&&n==null&&(n=t.default),n}const g=f({parser:m},h),_=/* @__PURE__ */ new Date(``),v=/^(\d{4})(?:-([0-2]\d)(?:-([0-3]\d)(?:[ T]([0-2]\d):([0-5]\d)(?::([0-5]\d)(\.\d+)?(Z|[+-][0-2]\d:?[0-5]\d)?)?)?)?)?$/,y=/^([+-])([0-2]\d):?([0-5]\d)$/;function b(e){let t=y.exec(e);if(e===`Z`||!t)return 0;let[,n,r=`0`,i=`0`]=t;return(n===`-`?-1:1)*(Number.parseInt(r,10)*60+Number.parseInt(i,10))}const x=[()=>0,(e=`0`)=>Number.parseInt(e,10),(e=`1`)=>Number.parseInt(e,10)-1,(e=`1`)=>Number.parseInt(e,10),(e=`0`)=>Number.parseInt(e,10),(e=`0`)=>Number.parseInt(e,10),(e=`0`)=>Number.parseInt(e,10),(e=`0`)=>Number.parseFloat(e)*1e3];function S(e){return e==null||e instanceof Date?e:typeof e==`number`?new Date(e):typeof e==`string`?C(e):_}function C(e){let t=v.exec(e);if(t===null)return _;let[,n=0,r=0,i=0,a=0,o=0,s=0,c=0]=x.map((e,n)=>e(t[n])),l=t[8];return l?new Date(Date.UTC(n,r,i,a,o+b(l),s,c)):new Date(n,r,i,a,o,s,c)}function w(e,t){let n=t.parser(e);return t.default!==void 0&&(n==null||Number.isNaN(n.getTime()))&&(n=t.default),n}function T(e,t,n){let r=S(e);return p(e=>r!=null&&(e==null||e instanceof Date&&(n?e>r:e>=r)),t,()=>({min:r,limit:r,exclusive:n}))}function E(e,t,n){let r=S(e);return p(e=>r!=null&&(e==null||e instanceof Date&&(n?e<r:e<=r)),t,()=>({max:r,limit:r,exclusive:n}))}const D=f({parser:S},w);function O(e){return e==null||typeof e==`number`?e:e instanceof Date?e.getTime():typeof e==`string`?Number.parseFloat(e):Number.parseFloat(String(e))}function k(e,t){let n=t.parser(e);if(t.default!==void 0&&(n==null||Number.isNaN(n))&&(n=t.default),t.round&&typeof n==`number`)switch(t.round){case`nearest`:n=Math.round(n);break;case`ceil`:n=Math.ceil(n);break;case`floor`:n=Math.floor(n);break;default:throw Error(`Unknown round type: ${String(t.round)}`)}return n}function A(e){return async(t,n)=>t==null||typeof t==`number`&&Number.isFinite(t)&&Math.floor(t)===t?a({value:t,field:n}):o({message:e,value:t,field:n})}const j=f({parser:O},k);function M(e){if(typeof e!=`object`||!e)throw TypeError("`properties` must be a configuration object");return async(n,r)=>{let i={},s={},c=!0;for(let r in e)if(t(e,r)){let t=e[r],a=Reflect.get(Object(n),r),l=await(typeof t==`function`?t(a,r):o({field:r,message:`No validator set`,value:a}));s[r]=l.value,l.state===`invalid`&&(c=!1,i[r]=l.message||l.errors)}return c?a({value:s,field:r}):o({message:``,value:n,field:r,errors:i})}}function N(e,t){return p(e=>t&&e===null||e!=null&&(typeof e!=`string`||e!==``)&&!(typeof e==`number`&&Number.isNaN(e))&&!(e instanceof Date&&Number.isNaN(e.valueOf())),e)}function P(e,t){let n=e;return p(t=>t==null||n.includes(t)||t instanceof Date&&e.some(e=>e.valueOf()===t.valueOf()),t,()=>({values:e}))}function F(e){return typeof e==`string`||Array.isArray(e)?e.length:e}function I(e,t,n){return p(t=>{let r=F(t);return r==null||t===``||(n?r<e:r<=e)},t,t=>({max:e,limit:e,amount:F(t),exclusive:n}))}function L(e,t,n){return p(t=>{let r=F(t);return r==null||t===``||(n?r>e:r>=e)},t,t=>({min:e,limit:e,amount:F(t),exclusive:n}))}function R(e,t){return p(t=>{let n=F(t);return n==null||t===``||n===e},t,t=>({amount:F(t),limit:e,exact:e}))}const z=/^[\w!#$%&'*+./=?^`{|}~-]+@[\dA-Za-z](?:[\dA-Za-z-]{0,61}[\dA-Za-z])?(?:\.[\dA-Za-z](?:[\dA-Za-z-]{0,61}[\dA-Za-z])?)*$/,B=/^(?:[\da-f]{8}-[\da-f]{4}-[1-8][\da-f]{3}-[89ab][\da-f]{3}-[\da-f]{12}|0{8}-0{4}-0{4}-0{4}-0{12}|f{8}-f{4}-f{4}-f{4}-f{12})$/i;function V(t){if(t==null||typeof t==`string`)return t;if(t instanceof Date)return t.toISOString();if(e(t))throw TypeError(`Failed to parse value to string.`);return String(t)}function H(e,t){let n=t.parser(e);return t.default!==void 0&&(n==null||n===``)&&(n=t.default),t.trim&&typeof n==`string`&&(n=n.trim()),n}function U(e,t){let n=new RegExp(e);return p(e=>(n.lastIndex=0,e==null||e===``||typeof e==`string`&&n.test(e)),t,()=>({pattern:e}))}function W(e){return U(z,e)}function G(e){return U(B,e)}function K(e,t){return p(e=>{try{let n;if(e==null||e===``||typeof e==`string`&&(n=new URL(e)))return!(n&&t&&!t.includes(n.protocol))}catch{}return!1},e,()=>({protocols:t}))}const q=f({parser:V},H);exports.applyArrayConfig=c,exports.applyBooleanConfig=h,exports.applyDateConfig=w,exports.applyNumberConfig=k,exports.applyStringConfig=H,exports.array=d,exports.boolean=g,exports.createTypeValidatorTest=f,exports.createValidatorTest=p,exports.date=D,exports.email=W,exports.exact=R,exports.formatMessage=i,exports.hasOwnProperty=t,exports.integer=A,exports.invalid=o,exports.invalidDate=_,exports.isObject=e,exports.matches=U,exports.max=I,exports.maxDate=E,exports.min=L,exports.minDate=T,exports.number=j,exports.object=M,exports.oneOf=P,exports.parseArray=s,exports.parseBoolean=m,exports.parseDate=S,exports.parseNumber=O,exports.parseString=V,exports.required=N,exports.string=q,exports.url=K,exports.uuid=G,exports.valid=a;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});async function e(e,t,n){for(let r of e){let e=await r(t,n);if(e.state===`invalid`)return e}}function t(e){return e.message||e.errors===void 0?e.message:e.errors}function n(e){return Object.prototype.toString.call(e)===`[object Object]`}function r(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function i(e){return!!Reflect.get(Object(e),Symbol.iterator)}const a=/{(\w+)}/g;function o(e,t){return typeof e==`string`?e.replaceAll(a,(e,n)=>String(Reflect.get(t,n))):e(t)}async function s(e){return c(e)}function c({value:e,field:t}){return{state:`valid`,value:e,field:t}}async function l(e){return u(e)}function u({errors:e,field:t,message:n,value:r,extras:i}){return{state:`invalid`,message:o(n,{...i,value:r,field:t}),value:r,field:t,errors:e}}const d=`Invalid value.`;function f(e,t,n){if(typeof e==`string`)n.push({message:e||d,path:t});else if(Array.isArray(e))for(let[r,i]of e.entries())i!==null&&f(i,[...t,r],n);else if(typeof e==`object`&&e)for(let r of Object.keys(e))f(Reflect.get(e,r),[...t,r],n);else n.push({message:d,path:t})}const p=/* @__PURE__ */ new WeakSet;function m(e){return p.has(e)}function h(e){let t=Object.assign(e,{"~standard":{version:1,vendor:`validator-fns`,validate:async t=>{let n=await e(t);if(n.state===`valid`)return{value:n.value};let r=n.message?[{message:n.message}]:[];return n.errors!==void 0&&f(n.errors,[],r),{issues:r.length>0?r:[{message:d}]}}}});return p.add(t),t}function ee(e){return m(e)?e:h((t,n)=>e(t,n))}const g=Symbol(`optional`);function _(e){return e===``||typeof e==`number`&&Number.isNaN(e)||e instanceof Date&&Number.isNaN(e.getTime())}function v(e,t){let n=e===void 0?`Required.`:e,r=(e,t)=>u({message:n,value:e,field:t}),i=(e,t)=>c({value:e,field:t}),a=(e,n)=>t(e,n,r),o=(e,n)=>t(e,n,i);return Object.assign(h(a),{[g]:h(o)})}function te(e){let t=e[g];return t===void 0?h(async(t,n)=>t==null?c({value:t,field:n}):e(t,n)):t}function y(e){return Array.isArray(e)||e==null?e:i(e)?[...e]:[]}function b(e,t){let n=e.parser(t);return e.default!==void 0&&(n==null||n.length===0)&&(n=e.default),n}async function x(e,n,r){let i=!0,a=[];if(!e)return{isValid:i,errors:a,values:n};let o=[];for(let[s,c]of n.entries()){let n=await e(c,`${r||``}[${s}]`);o.push(n.value),n.state===`invalid`?(i=!1,a.push(t(n))):a.push(null)}return{isValid:i,errors:a,values:o}}function S(t,...n){let r=typeof t==`function`?[t,...n]:n,i={parser:y,...typeof t==`function`?void 0:t};return v(i.requiredMessage,async(t,n,a)=>{let o=b(i,t);if(o==null)return a(o,n);let[c,...u]=r,d=await e(u,o,n),f=await x(c,o,n);return!d&&f.isValid?s({value:f.values,field:n}):l({message:d?d.message:``,value:t,field:n,errors:f.errors})})}const C=/* @__PURE__ */ new WeakMap;function w(e,t){return(n,...r)=>{let i=e,a=r;return n!==void 0&&(typeof n==`function`?a=[n,...r]:i={...e,...n}),v(i.requiredMessage,async(e,n,r)=>{try{let o=t(e,i);if(o==null||_(o))return r(o,n);for(let e of a){let t=C.get(e),r;if(r=t?t(o,n):await e(o,n),r.state===`invalid`)return r}return c({value:o,field:n})}catch(t){return u({message:t instanceof Error?t.message:String(t),value:e,field:n})}})}}function T(e,t,n){let r=(r,i)=>e(r,i)?c({value:r,field:i}):u({message:t,value:r,field:i,extras:n?n(r):void 0}),i=async(e,t)=>r(e,t);return C.set(i,r),i}function E(e){return e==null||typeof e==`boolean`?e:!!e}function D(e,t){let n=t.parser(e);return t.default!==void 0&&n==null&&(n=t.default),n}const O=w({parser:E},D),k=/* @__PURE__ */ new Date(``),A=/^(\d{4})(?:-([0-2]\d)(?:-([0-3]\d)(?:[ T]([0-2]\d):([0-5]\d)(?::([0-5]\d)(\.\d+)?(Z|[+-][0-2]\d:?[0-5]\d)?)?)?)?)?$/,j=/^([+-])([0-2]\d):?([0-5]\d)$/;function M(e){let t=j.exec(e);if(e===`Z`||!t)return 0;let[,n,r,i]=t;return(n===`-`?-1:1)*(Number(r)*60+Number(i))}const ne=[()=>0,e=>Number(e),(e=`1`)=>Number.parseInt(e,10)-1,(e=`1`)=>Number.parseInt(e,10),(e=`0`)=>Number.parseInt(e,10),(e=`0`)=>Number.parseInt(e,10),(e=`0`)=>Number.parseInt(e,10),(e=`0`)=>Number.parseFloat(e)*1e3],N=`Failed to parse value to date.`;function P(e){if(e==null||e instanceof Date)return e;if(typeof e==`number`)return new Date(e);if(typeof e!=`string`)throw TypeError(N);return e.trim()===``?k:re(e)}function re(e){let t=A.exec(e);if(t===null)throw TypeError(N);let[,n=0,r=0,i=0,a=0,o=0,s=0,c=0]=ne.map((e,n)=>e(t[n])),l=t[8];return l?new Date(Date.UTC(n,r,i,a,o+M(l),s,c)):new Date(n,r,i,a,o,s,c)}function F(e,t){let n=t.parser(e);return t.default!==void 0&&(n==null||Number.isNaN(n.getTime()))&&(n=t.default),n}function I(e,t,n){let r=P(e);return T(e=>r!=null&&(e==null||e instanceof Date&&(n?e>r:e>=r)),t,()=>({min:r,limit:r,exclusive:n}))}function L(e,t,n){let r=P(e);return T(e=>r!=null&&(e==null||e instanceof Date&&(n?e<r:e<=r)),t,()=>({max:r,limit:r,exclusive:n}))}const R=w({parser:P},F),z=[e=>String.prototype.valueOf.call(e),e=>Number.prototype.valueOf.call(e),e=>Boolean.prototype.valueOf.call(e)];function B(e){if(typeof e!=`object`||!e)return e;for(let t of z)try{return t(e)}catch{}return e}function V(e){let t=B(e);switch(typeof t){case`string`:case`number`:case`bigint`:case`boolean`:return String(t);default:return}}function H(e){if(e==null||typeof e==`number`)return e;if(e instanceof Date)return e.getTime();let t=V(e),n=t===void 0?NaN:Number.parseFloat(t);if(Number.isNaN(n)&&(t===void 0||t.trim()!==``))throw TypeError(`Failed to parse value to number.`);return n}function U(e,t){let n=t.parser(e);if(t.default!==void 0&&(n==null||Number.isNaN(n))&&(n=t.default),t.round&&typeof n==`number`)switch(t.round){case`nearest`:n=Math.round(n);break;case`ceil`:n=Math.ceil(n);break;case`floor`:n=Math.floor(n);break;default:throw Error(`Unknown round type: ${String(t.round)}`)}return n}function W(e){return T(e=>e==null||typeof e==`number`&&Number.isFinite(e)&&Math.floor(e)===e,e)}const G=w({parser:H},U);function K(...e){let[t,n,r]=e.length===2?[[],...e]:e,i=typeof t==`string`?[t]:t;return async(e,t)=>{let a=e;return n(a)?s({value:a,field:t}):i.length===0?l({message:r,value:a,field:t}):l({message:``,value:a,field:t,errors:i.reduceRight((e,t)=>({[t]:e}),o(r,{value:a,field:t}))})}}function q(e,t,n){Object.defineProperty(e,t,{value:n,enumerable:!0,writable:!0,configurable:!0})}function J(n,i,...a){if(typeof n!=`object`||!n)throw TypeError("`properties` must be a configuration object");let o=typeof i==`function`?[i,...a]:a;return v(typeof i==`object`?i.requiredMessage:void 0,async(i,a,c)=>{if(i==null)return c(i,a);let u=Object(i),d={},f={},p=!0;for(let e in n)if(r(n,e)){let i=n[e],a=r(u,e)?Reflect.get(u,e):void 0,o=await(typeof i==`function`?i(a,e):l({field:e,message:`No validator set`,value:a}));q(f,e,o.value),o.state===`invalid`&&(p=!1,q(d,e,t(o)))}if(!p)return l({message:``,value:i,field:a,errors:d});let m=await e(o,f,a);return m?l({message:m.message,value:i,field:a,errors:m.errors}):s({value:f,field:a})})}function Y(e,t){let n=e;return T(t=>t==null||n.includes(t)||t instanceof Date&&e.some(e=>e.valueOf()===t.valueOf()),t,()=>({values:e}))}function X(e){return typeof e==`string`||Array.isArray(e)?e.length:e}function ie(e,t,n){return T(t=>{let r=X(t);return r==null||t===``||(n?r<e:r<=e)},t,t=>({max:e,limit:e,amount:X(t),exclusive:n}))}function ae(e,t,n){return T(t=>{let r=X(t);return r==null||t===``||(n?r>e:r>=e)},t,t=>({min:e,limit:e,amount:X(t),exclusive:n}))}function oe(e,t){return T(t=>{let n=X(t);return n==null||t===``||n===e},t,t=>({amount:X(t),limit:e,exact:e}))}const se=/^[\w!#$%&'*+./=?^`{|}~-]+@[\dA-Za-z](?:[\dA-Za-z-]{0,61}[\dA-Za-z])?(?:\.[\dA-Za-z](?:[\dA-Za-z-]{0,61}[\dA-Za-z])?)*$/,ce=/^(?:[\da-f]{8}-[\da-f]{4}-[1-8][\da-f]{3}-[89ab][\da-f]{3}-[\da-f]{12}|0{8}-0{4}-0{4}-0{4}-0{12}|f{8}-f{4}-f{4}-f{4}-f{12})$/i;function Z(e){if(e==null||typeof e==`string`)return e;if(e instanceof Date)return e.toISOString();let t=V(e);if(t===void 0)throw TypeError(`Failed to parse value to string.`);return t}function Q(e,t){let n=t.parser(e);return t.default!==void 0&&(n==null||n===``)&&(n=t.default),t.trim&&typeof n==`string`&&(n=n.trim()),n}function $(e,t){let n=new RegExp(e);return T(e=>(n.lastIndex=0,e==null||e===``||typeof e==`string`&&n.test(e)),t,()=>({pattern:e}))}function le(e){return $(se,e)}function ue(e){return $(ce,e)}function de(e,t=[`http:`,`https:`]){return T(e=>{try{let n;if(e==null||e===``||typeof e==`string`&&(n=new URL(e)))return!n||t.includes(n.protocol)}catch{}return!1},e,()=>({protocols:t}))}const fe=w({parser:Z},Q);exports.applyArrayConfig=b,exports.applyBooleanConfig=D,exports.applyDateConfig=F,exports.applyNumberConfig=U,exports.applyStringConfig=Q,exports.array=S,exports.boolean=O,exports.check=K,exports.createTypeValidatorTest=w,exports.createValidator=ee,exports.createValidatorTest=T,exports.date=R,exports.email=le,exports.exact=oe,exports.formatMessage=o,exports.hasOwnProperty=r,exports.integer=W,exports.invalid=l,exports.invalidDate=k,exports.isObject=n,exports.matches=$,exports.max=ie,exports.maxDate=L,exports.min=ae,exports.minDate=I,exports.number=G,exports.object=J,exports.oneOf=Y,exports.optional=te,exports.parseArray=y,exports.parseBoolean=E,exports.parseDate=P,exports.parseNumber=H,exports.parseString=Z,exports.string=fe,exports.url=de,exports.uuid=ue,exports.valid=s;
2
2
  //# sourceMappingURL=index.cjs.map