valgen 7.0.0 → 7.0.3
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 +1 -1
- package/constants.js +1 -1
- package/core/constants.d.ts +11 -0
- package/core/constants.js +11 -0
- package/core/context.d.ts +57 -0
- package/core/context.js +57 -0
- package/core/types.d.ts +40 -0
- package/core/utilities.d.ts +42 -2
- package/core/utilities.js +21 -1
- package/core/validation-error.d.ts +13 -0
- package/core/validation-error.js +13 -0
- package/core/validator.d.ts +100 -0
- package/core/validator.js +6 -0
- package/package.json +1 -1
- package/rules/format-rules/is-alpha.d.ts +10 -1
- package/rules/format-rules/is-alpha.js +10 -1
- package/rules/format-rules/is-alphanumeric.d.ts +10 -1
- package/rules/format-rules/is-alphanumeric.js +10 -1
- package/rules/format-rules/is-ascii.d.ts +10 -1
- package/rules/format-rules/is-ascii.js +10 -1
- package/rules/format-rules/is-base64.d.ts +20 -1
- package/rules/format-rules/is-base64.js +10 -1
- package/rules/format-rules/is-btc-address.d.ts +10 -1
- package/rules/format-rules/is-btc-address.js +10 -1
- package/rules/format-rules/is-credit-card.d.ts +16 -1
- package/rules/format-rules/is-credit-card.js +11 -1
- package/rules/format-rules/is-decimal.d.ts +12 -2
- package/rules/format-rules/is-decimal.js +12 -2
- package/rules/format-rules/is-ean.d.ts +11 -1
- package/rules/format-rules/is-ean.js +11 -1
- package/rules/format-rules/is-email.d.ts +19 -7
- package/rules/format-rules/is-email.js +13 -1
- package/rules/format-rules/is-eth-address.d.ts +10 -1
- package/rules/format-rules/is-eth-address.js +10 -1
- package/rules/format-rules/is-fqdn.d.ts +13 -2
- package/rules/format-rules/is-fqdn.js +12 -1
- package/rules/format-rules/is-hash.d.ts +17 -1
- package/rules/format-rules/is-hash.js +16 -1
- package/rules/format-rules/is-hex-color.d.ts +13 -1
- package/rules/format-rules/is-hex-color.js +13 -1
- package/rules/format-rules/is-hex.d.ts +13 -1
- package/rules/format-rules/is-hex.js +13 -1
- package/rules/format-rules/is-iban.d.ts +33 -2
- package/rules/format-rules/is-iban.js +19 -1
- package/rules/format-rules/is-ip.d.ts +44 -2
- package/rules/format-rules/is-ip.js +42 -2
- package/rules/format-rules/is-issn.d.ts +19 -2
- package/rules/format-rules/is-issn.js +18 -1
- package/rules/format-rules/is-jwt.d.ts +16 -1
- package/rules/format-rules/is-jwt.js +16 -1
- package/rules/format-rules/is-lowercase.d.ts +13 -1
- package/rules/format-rules/is-lowercase.js +13 -1
- package/rules/format-rules/is-mac-address.d.ts +19 -2
- package/rules/format-rules/is-mac-address.js +16 -1
- package/rules/format-rules/is-mobile-phone.d.ts +19 -3
- package/rules/format-rules/is-mobile-phone.js +17 -1
- package/rules/format-rules/is-object-id.d.ts +20 -1
- package/rules/format-rules/is-object-id.js +19 -1
- package/rules/format-rules/is-passport-number.d.ts +17 -1
- package/rules/format-rules/is-passport-number.js +17 -1
- package/rules/format-rules/is-port.d.ts +16 -1
- package/rules/format-rules/is-port.js +16 -1
- package/rules/format-rules/is-swift.d.ts +15 -1
- package/rules/format-rules/is-swift.js +15 -1
- package/rules/format-rules/is-time.d.ts +22 -1
- package/rules/format-rules/is-time.js +22 -1
- package/rules/format-rules/is-uppercase.d.ts +15 -1
- package/rules/format-rules/is-uppercase.js +15 -1
- package/rules/format-rules/is-url.d.ts +99 -1
- package/rules/format-rules/is-url.js +19 -1
- package/rules/format-rules/is-uuid.d.ts +23 -1
- package/rules/format-rules/is-uuid.js +23 -1
- package/rules/format-rules/is-vat-number.d.ts +19 -2
- package/rules/format-rules/is-vat-number.js +19 -2
- package/rules/format-rules/matches.d.ts +27 -1
- package/rules/format-rules/matches.js +23 -1
- package/rules/logical-rules/is-defined.d.ts +14 -2
- package/rules/logical-rules/is-defined.js +13 -2
- package/rules/logical-rules/is-empty.d.ts +40 -2
- package/rules/logical-rules/is-empty.js +38 -2
- package/rules/logical-rules/is-equal.d.ts +31 -4
- package/rules/logical-rules/is-equal.js +29 -4
- package/rules/logical-rules/is-gt.d.ts +26 -1
- package/rules/logical-rules/is-gt.js +20 -1
- package/rules/logical-rules/is-gte.d.ts +25 -1
- package/rules/logical-rules/is-gte.js +20 -1
- package/rules/logical-rules/is-lt.d.ts +24 -1
- package/rules/logical-rules/is-lt.js +19 -1
- package/rules/logical-rules/is-lte.d.ts +25 -1
- package/rules/logical-rules/is-lte.js +20 -1
- package/rules/logical-rules/length.d.ts +38 -2
- package/rules/logical-rules/length.js +38 -2
- package/rules/logical-rules/range.d.ts +25 -1
- package/rules/logical-rules/range.js +23 -1
- package/rules/type-rules/is-any.d.ts +12 -1
- package/rules/type-rules/is-any.js +12 -1
- package/rules/type-rules/is-array.d.ts +23 -2
- package/rules/type-rules/is-array.js +23 -2
- package/rules/type-rules/is-bigint.d.ts +14 -2
- package/rules/type-rules/is-bigint.js +14 -2
- package/rules/type-rules/is-boolean.d.ts +17 -2
- package/rules/type-rules/is-boolean.js +17 -2
- package/rules/type-rules/is-date.d.ts +47 -5
- package/rules/type-rules/is-date.js +42 -5
- package/rules/type-rules/is-enum.d.ts +23 -1
- package/rules/type-rules/is-enum.js +21 -1
- package/rules/type-rules/is-instanceof.d.ts +21 -1
- package/rules/type-rules/is-instanceof.js +21 -1
- package/rules/type-rules/is-integer.d.ts +17 -2
- package/rules/type-rules/is-integer.js +17 -2
- package/rules/type-rules/is-null.d.ts +51 -4
- package/rules/type-rules/is-null.js +51 -4
- package/rules/type-rules/is-number.d.ts +17 -2
- package/rules/type-rules/is-number.js +17 -2
- package/rules/type-rules/is-object.d.ts +45 -7
- package/rules/type-rules/is-object.js +40 -7
- package/rules/type-rules/is-record.d.ts +21 -2
- package/rules/type-rules/is-record.js +21 -2
- package/rules/type-rules/is-string.d.ts +16 -2
- package/rules/type-rules/is-string.js +16 -2
- package/rules/type-rules/is-tuple.d.ts +21 -2
- package/rules/type-rules/is-undefined.d.ts +16 -4
- package/rules/type-rules/is-undefined.js +16 -4
- package/rules/utility-rules/all-of.d.ts +28 -1
- package/rules/utility-rules/all-of.js +27 -1
- package/rules/utility-rules/exists.d.ts +30 -1
- package/rules/utility-rules/exists.js +29 -1
- package/rules/utility-rules/fixed.d.ts +19 -1
- package/rules/utility-rules/fixed.js +19 -1
- package/rules/utility-rules/get-length.d.ts +25 -2
- package/rules/utility-rules/get-length.js +25 -2
- package/rules/utility-rules/nullable.d.ts +28 -1
- package/rules/utility-rules/nullable.js +27 -1
- package/rules/utility-rules/one-of.d.ts +52 -3
- package/rules/utility-rules/one-of.js +81 -9
- package/rules/utility-rules/optional.d.ts +29 -1
- package/rules/utility-rules/optional.js +28 -1
- package/rules/utility-rules/pipe.d.ts +38 -1
- package/rules/utility-rules/pipe.js +30 -1
- package/rules/utility-rules/required.d.ts +39 -1
- package/rules/utility-rules/required.js +32 -1
- package/rules/utility-rules/string-utils.d.ts +99 -5
- package/rules/utility-rules/string-utils.js +53 -3
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
import { validator, } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Wraps a rule so that `null` or `undefined` pass through untouched, and
|
|
4
|
+
* anything else is delegated to the nested rule.
|
|
5
|
+
*
|
|
6
|
+
* If `input == null` (i.e. `null` **or** `undefined`), it is returned as-is
|
|
7
|
+
* without ever calling the nested rule - despite the name, `nullable`
|
|
8
|
+
* tolerates both `null` and `undefined`, not just `null`. For any other
|
|
9
|
+
* input, delegates to `nested(input)` and returns/throws exactly what the
|
|
10
|
+
* nested rule does.
|
|
11
|
+
*
|
|
12
|
+
* @typeParam T - The nested validator's output type.
|
|
13
|
+
* @typeParam I - The nested validator's input type.
|
|
14
|
+
* @param nested - The validator to delegate to for non-nullish input.
|
|
15
|
+
* @param options - Shared validation options (`coerce`, `onFail`); `nullable`
|
|
16
|
+
* has no options of its own.
|
|
17
|
+
* @returns A validator that returns `null`/`undefined` unchanged, or the
|
|
18
|
+
* nested rule's result for anything else.
|
|
19
|
+
* @throws Whatever `nested` throws when the input is non-nullish and fails
|
|
20
|
+
* the nested rule.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* import { isString, vg } from 'valgen';
|
|
25
|
+
*
|
|
26
|
+
* vg.nullable(isString)(''); // => ''
|
|
27
|
+
* vg.nullable(isString)(undefined); // => undefined
|
|
28
|
+
* vg.nullable(isString)(null); // => null
|
|
29
|
+
* ```
|
|
4
30
|
* @validator nullable
|
|
5
31
|
*/
|
|
6
32
|
export function nullable(nested, options) {
|
|
@@ -1,13 +1,62 @@
|
|
|
1
1
|
import type { ValidationOptions, Validator } from '../../core/index.js';
|
|
2
2
|
type DiscriminatorRecord = Record<string, Validator>;
|
|
3
3
|
/**
|
|
4
|
-
* Tries
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Tries a list of rules against the input in order and returns the result of
|
|
5
|
+
* the first one that passes.
|
|
6
|
+
*
|
|
7
|
+
* Each entry is either a plain {@link Validator}, or a
|
|
8
|
+
* `[Validator, discriminatorRecord]` tuple. For a plain entry, `oneOf` calls
|
|
9
|
+
* it directly; if it throws or fails, it moves on to the next entry
|
|
10
|
+
* (short-circuits on the first *success*, not the first failure). For a
|
|
11
|
+
* `[validator, discriminator]` tuple, `input` must be an object: `oneOf`
|
|
12
|
+
* first runs each rule in `discriminator` against the matching property of
|
|
13
|
+
* `input` (e.g. `discriminator.kind(input.kind)`); only if every
|
|
14
|
+
* discriminator key passes does it go on to run the tuple's main `validator`
|
|
15
|
+
* against the whole `input`. If any discriminator key fails (or `input`
|
|
16
|
+
* isn't an object), that entry is skipped entirely - the main validator
|
|
17
|
+
* never runs - and `oneOf` moves to the next candidate. This lets you
|
|
18
|
+
* dispatch between differently-shaped objects using a cheap "tag" check
|
|
19
|
+
* (e.g. a `kind` field) instead of trying and catching a full shape
|
|
20
|
+
* validation for each candidate. An unexpected exception thrown by a
|
|
21
|
+
* discriminator or a rule (as opposed to a normal validation failure) is
|
|
22
|
+
* caught and treated the same as a failure.
|
|
23
|
+
*
|
|
24
|
+
* @param rules - The candidates to try, in order: either a plain validator,
|
|
25
|
+
* or a `[validator, discriminator]` tuple.
|
|
26
|
+
* @param options - Shared validation options (`coerce`, `onFail`); `oneOf`
|
|
27
|
+
* has no options of its own.
|
|
28
|
+
* @returns A validator that returns the first candidate's result to pass.
|
|
29
|
+
* @throws {@link ValidationError} reporting the *last* candidate's own
|
|
30
|
+
* failure message directly (a normal validation message, or an unexpected
|
|
31
|
+
* exception's message) when no entry passes - since it can only report a
|
|
32
|
+
* single message anyway, the actual reason is more useful than a vague
|
|
33
|
+
* "didn't match". The generic `Value didn't match one of required rules`
|
|
34
|
+
* message is only used as a fallback when nothing was actually tried (e.g.
|
|
35
|
+
* an empty `rules` array).
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* import { isNull, isNumber, isObject, isString, vg } from 'valgen';
|
|
40
|
+
*
|
|
41
|
+
* // simple form: first rule that passes wins
|
|
42
|
+
* const simple = vg.oneOf([isNull, isNumber]);
|
|
43
|
+
* simple(6); // => 6
|
|
44
|
+
* simple('x'); // throws: "Value must be a number" (the last candidate's own error, reported directly)
|
|
45
|
+
*
|
|
46
|
+
* // discriminated form: pick the object shape based on `kind`
|
|
47
|
+
* const pet = vg.oneOf([
|
|
48
|
+
* isString,
|
|
49
|
+
* [isObject, { kind: vg.isEqual('dog') }],
|
|
50
|
+
* [isObject, { kind: vg.isEqual('cat') }],
|
|
51
|
+
* vg.isEqual(5),
|
|
52
|
+
* ]);
|
|
53
|
+
* pet({ kind: 'cat', name: 'Molly' }); // => { kind: 'cat', name: 'Molly' }
|
|
54
|
+
* ```
|
|
7
55
|
* @validator oneOf
|
|
8
56
|
*/
|
|
9
57
|
export declare function oneOf(rules: (Validator | [Validator, DiscriminatorRecord])[], options?: oneOf.Options): Validator<any, any, import("../../core/types.js").ExecutionOptions>;
|
|
10
58
|
export declare namespace oneOf {
|
|
59
|
+
/** Options accepted by {@link oneOf}. Only the shared {@link ValidationOptions} - no `oneOf`-specific fields. */
|
|
11
60
|
interface Options extends ValidationOptions {
|
|
12
61
|
}
|
|
13
62
|
}
|
|
@@ -1,8 +1,56 @@
|
|
|
1
1
|
import { validator } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
* Tries
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* Tries a list of rules against the input in order and returns the result of
|
|
4
|
+
* the first one that passes.
|
|
5
|
+
*
|
|
6
|
+
* Each entry is either a plain {@link Validator}, or a
|
|
7
|
+
* `[Validator, discriminatorRecord]` tuple. For a plain entry, `oneOf` calls
|
|
8
|
+
* it directly; if it throws or fails, it moves on to the next entry
|
|
9
|
+
* (short-circuits on the first *success*, not the first failure). For a
|
|
10
|
+
* `[validator, discriminator]` tuple, `input` must be an object: `oneOf`
|
|
11
|
+
* first runs each rule in `discriminator` against the matching property of
|
|
12
|
+
* `input` (e.g. `discriminator.kind(input.kind)`); only if every
|
|
13
|
+
* discriminator key passes does it go on to run the tuple's main `validator`
|
|
14
|
+
* against the whole `input`. If any discriminator key fails (or `input`
|
|
15
|
+
* isn't an object), that entry is skipped entirely - the main validator
|
|
16
|
+
* never runs - and `oneOf` moves to the next candidate. This lets you
|
|
17
|
+
* dispatch between differently-shaped objects using a cheap "tag" check
|
|
18
|
+
* (e.g. a `kind` field) instead of trying and catching a full shape
|
|
19
|
+
* validation for each candidate. An unexpected exception thrown by a
|
|
20
|
+
* discriminator or a rule (as opposed to a normal validation failure) is
|
|
21
|
+
* caught and treated the same as a failure.
|
|
22
|
+
*
|
|
23
|
+
* @param rules - The candidates to try, in order: either a plain validator,
|
|
24
|
+
* or a `[validator, discriminator]` tuple.
|
|
25
|
+
* @param options - Shared validation options (`coerce`, `onFail`); `oneOf`
|
|
26
|
+
* has no options of its own.
|
|
27
|
+
* @returns A validator that returns the first candidate's result to pass.
|
|
28
|
+
* @throws {@link ValidationError} reporting the *last* candidate's own
|
|
29
|
+
* failure message directly (a normal validation message, or an unexpected
|
|
30
|
+
* exception's message) when no entry passes - since it can only report a
|
|
31
|
+
* single message anyway, the actual reason is more useful than a vague
|
|
32
|
+
* "didn't match". The generic `Value didn't match one of required rules`
|
|
33
|
+
* message is only used as a fallback when nothing was actually tried (e.g.
|
|
34
|
+
* an empty `rules` array).
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* import { isNull, isNumber, isObject, isString, vg } from 'valgen';
|
|
39
|
+
*
|
|
40
|
+
* // simple form: first rule that passes wins
|
|
41
|
+
* const simple = vg.oneOf([isNull, isNumber]);
|
|
42
|
+
* simple(6); // => 6
|
|
43
|
+
* simple('x'); // throws: "Value must be a number" (the last candidate's own error, reported directly)
|
|
44
|
+
*
|
|
45
|
+
* // discriminated form: pick the object shape based on `kind`
|
|
46
|
+
* const pet = vg.oneOf([
|
|
47
|
+
* isString,
|
|
48
|
+
* [isObject, { kind: vg.isEqual('dog') }],
|
|
49
|
+
* [isObject, { kind: vg.isEqual('cat') }],
|
|
50
|
+
* vg.isEqual(5),
|
|
51
|
+
* ]);
|
|
52
|
+
* pet({ kind: 'cat', name: 'Molly' }); // => { kind: 'cat', name: 'Molly' }
|
|
53
|
+
* ```
|
|
6
54
|
* @validator oneOf
|
|
7
55
|
*/
|
|
8
56
|
export function oneOf(rules, options) {
|
|
@@ -13,8 +61,21 @@ export function oneOf(rules, options) {
|
|
|
13
61
|
let discriminator;
|
|
14
62
|
let v;
|
|
15
63
|
let passed = false;
|
|
16
|
-
//
|
|
17
|
-
|
|
64
|
+
// Every candidate failing is normal control flow here (that's how
|
|
65
|
+
// "try the next one" works), so a candidate's own context.fail must
|
|
66
|
+
// not throw or accumulate into the real error list. But swallowing it
|
|
67
|
+
// completely would hide the *reason* every candidate failed - including
|
|
68
|
+
// a genuine bug in a candidate rule, which would otherwise look
|
|
69
|
+
// identical to "the input just didn't match". So the mock still
|
|
70
|
+
// records the last failure's message, and it's reported directly as
|
|
71
|
+
// the final error (oneOf can only report one message anyway) instead
|
|
72
|
+
// of being discarded in favor of a generic one.
|
|
73
|
+
let lastFailMessage;
|
|
74
|
+
context.fail = (_rule, message) => {
|
|
75
|
+
passed = false;
|
|
76
|
+
lastFailMessage =
|
|
77
|
+
message instanceof Error ? message.message : String(message);
|
|
78
|
+
};
|
|
18
79
|
for (i = 0; i < l; i++) {
|
|
19
80
|
passed = true;
|
|
20
81
|
if (Array.isArray(rules[i])) {
|
|
@@ -39,7 +100,16 @@ export function oneOf(rules, options) {
|
|
|
39
100
|
if (!passed)
|
|
40
101
|
continue;
|
|
41
102
|
}
|
|
42
|
-
catch {
|
|
103
|
+
catch (e) {
|
|
104
|
+
// A discriminator/rule that throws directly (bypassing
|
|
105
|
+
// context.fail entirely, e.g. a plain function rather than one
|
|
106
|
+
// built with validator()) must still count as "this candidate
|
|
107
|
+
// failed" - otherwise `passed` is left at its top-of-loop `true`
|
|
108
|
+
// and, if this is the last candidate, oneOf would silently
|
|
109
|
+
// return an unvalidated value instead of failing.
|
|
110
|
+
passed = false;
|
|
111
|
+
lastFailMessage =
|
|
112
|
+
e?.message != null ? String(e.message) : String(e);
|
|
43
113
|
continue;
|
|
44
114
|
}
|
|
45
115
|
}
|
|
@@ -51,14 +121,16 @@ export function oneOf(rules, options) {
|
|
|
51
121
|
if (passed)
|
|
52
122
|
break;
|
|
53
123
|
}
|
|
54
|
-
catch {
|
|
55
|
-
|
|
124
|
+
catch (e) {
|
|
125
|
+
passed = false;
|
|
126
|
+
lastFailMessage =
|
|
127
|
+
e?.message != null ? String(e.message) : String(e);
|
|
56
128
|
}
|
|
57
129
|
}
|
|
58
130
|
// Restore fail method
|
|
59
131
|
delete context.fail;
|
|
60
132
|
if (passed)
|
|
61
133
|
return v;
|
|
62
|
-
context.fail(_this, `Value didn't match one of required rules`, input);
|
|
134
|
+
context.fail(_this, lastFailMessage || `Value didn't match one of required rules`, input);
|
|
63
135
|
}, options);
|
|
64
136
|
}
|
|
@@ -1,11 +1,39 @@
|
|
|
1
1
|
import type { Maybe } from 'ts-gems';
|
|
2
2
|
import { type ValidationOptions, type Validator } from '../../core/index.js';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Wraps a rule so that `undefined` passes through untouched, and anything
|
|
5
|
+
* else (including `null`) is delegated to the nested rule.
|
|
6
|
+
*
|
|
7
|
+
* If `input === undefined`, it is returned as-is without calling the nested
|
|
8
|
+
* rule. Unlike {@link nullable}, `null` is **not** special-cased - it is
|
|
9
|
+
* passed straight through to the nested rule, so `optional(x)(null)` fails
|
|
10
|
+
* unless `x` itself accepts `null`. For any other input, delegates to
|
|
11
|
+
* `nested(input)` and returns/throws exactly what the nested rule does.
|
|
12
|
+
*
|
|
13
|
+
* @typeParam T - The nested validator's output type.
|
|
14
|
+
* @typeParam I - The nested validator's input type.
|
|
15
|
+
* @param nested - The validator to delegate to for non-`undefined` input.
|
|
16
|
+
* @param options - Shared validation options (`coerce`, `onFail`); `optional`
|
|
17
|
+
* has no options of its own.
|
|
18
|
+
* @returns A validator that returns `undefined` unchanged, or the nested
|
|
19
|
+
* rule's result for anything else.
|
|
20
|
+
* @throws Whatever `nested` throws when the input is not `undefined` and
|
|
21
|
+
* fails the nested rule (including a `null` input, unless `nested` itself
|
|
22
|
+
* accepts `null`).
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { isString, vg } from 'valgen';
|
|
27
|
+
*
|
|
28
|
+
* vg.optional(isString)(''); // => ''
|
|
29
|
+
* vg.optional(isString)(undefined); // => undefined
|
|
30
|
+
* vg.optional(isString)(null); // throws (null is not undefined, and isString rejects null)
|
|
31
|
+
* ```
|
|
5
32
|
* @validator optional
|
|
6
33
|
*/
|
|
7
34
|
export declare function optional<T, I>(nested: Validator<T, I>, options?: optional.Options): Validator<Maybe<T>, Maybe<I>, import("../../core/types.js").ExecutionOptions>;
|
|
8
35
|
export declare namespace optional {
|
|
36
|
+
/** Options accepted by {@link optional}. Only the shared {@link ValidationOptions} - no `optional`-specific fields. */
|
|
9
37
|
interface Options extends ValidationOptions {
|
|
10
38
|
}
|
|
11
39
|
}
|
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
import { validator, } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Wraps a rule so that `undefined` passes through untouched, and anything
|
|
4
|
+
* else (including `null`) is delegated to the nested rule.
|
|
5
|
+
*
|
|
6
|
+
* If `input === undefined`, it is returned as-is without calling the nested
|
|
7
|
+
* rule. Unlike {@link nullable}, `null` is **not** special-cased - it is
|
|
8
|
+
* passed straight through to the nested rule, so `optional(x)(null)` fails
|
|
9
|
+
* unless `x` itself accepts `null`. For any other input, delegates to
|
|
10
|
+
* `nested(input)` and returns/throws exactly what the nested rule does.
|
|
11
|
+
*
|
|
12
|
+
* @typeParam T - The nested validator's output type.
|
|
13
|
+
* @typeParam I - The nested validator's input type.
|
|
14
|
+
* @param nested - The validator to delegate to for non-`undefined` input.
|
|
15
|
+
* @param options - Shared validation options (`coerce`, `onFail`); `optional`
|
|
16
|
+
* has no options of its own.
|
|
17
|
+
* @returns A validator that returns `undefined` unchanged, or the nested
|
|
18
|
+
* rule's result for anything else.
|
|
19
|
+
* @throws Whatever `nested` throws when the input is not `undefined` and
|
|
20
|
+
* fails the nested rule (including a `null` input, unless `nested` itself
|
|
21
|
+
* accepts `null`).
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* import { isString, vg } from 'valgen';
|
|
26
|
+
*
|
|
27
|
+
* vg.optional(isString)(''); // => ''
|
|
28
|
+
* vg.optional(isString)(undefined); // => undefined
|
|
29
|
+
* vg.optional(isString)(null); // throws (null is not undefined, and isString rejects null)
|
|
30
|
+
* ```
|
|
4
31
|
* @validator optional
|
|
5
32
|
*/
|
|
6
33
|
export function optional(nested, options) {
|
|
@@ -1,11 +1,48 @@
|
|
|
1
1
|
import { type ValidationOptions, type Validator } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
* Chains
|
|
3
|
+
* Chains a list of validators so that each one's output becomes the next
|
|
4
|
+
* one's input: `rules[0]`'s output becomes `rules[1]`'s input, and so on.
|
|
5
|
+
*
|
|
6
|
+
* Short-circuits on the first rule that records a failure: as soon as a step
|
|
7
|
+
* adds to the shared context's error list, `pipe` stops immediately and does
|
|
8
|
+
* not run the remaining rules. If every rule succeeds, returns the last
|
|
9
|
+
* rule's output - or, if `options.returnIndex` is given, the output of that
|
|
10
|
+
* specific step (even though later steps still ran for validation purposes).
|
|
11
|
+
*
|
|
12
|
+
* @typeParam T - The output type on success.
|
|
13
|
+
* @param rules - The validators to chain, in order.
|
|
14
|
+
* @param options - Validation options, including {@link pipe.Options.returnIndex}.
|
|
15
|
+
* @returns A validator that feeds the input through each rule in sequence
|
|
16
|
+
* and returns the final (or `returnIndex`-selected) step's output.
|
|
17
|
+
* @throws {@link ValidationError} from whichever rule first records a failure.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { isBoolean, isNumber, isString, vg } from 'valgen';
|
|
22
|
+
*
|
|
23
|
+
* vg.pipe([isString, vg.matches(/^[a-z]+$/)])('abc'); // => 'abc'
|
|
24
|
+
*
|
|
25
|
+
* // each step's output feeds the next: string -> number -> boolean
|
|
26
|
+
* vg.pipe([isString, isNumber, isBoolean])(1, { coerce: true }); // => true
|
|
27
|
+
*
|
|
28
|
+
* // returnIndex pins the result to an earlier step, while later steps still validate
|
|
29
|
+
* vg.pipe([isString, isNumber, vg.isGte(5)], { returnIndex: 1 })('123', {
|
|
30
|
+
* coerce: true,
|
|
31
|
+
* }); // => 123
|
|
32
|
+
* ```
|
|
4
33
|
* @validator pipe
|
|
5
34
|
*/
|
|
6
35
|
export declare function pipe<T>(rules: Validator[], options?: pipe.Options): Validator<T>;
|
|
7
36
|
export declare namespace pipe {
|
|
37
|
+
/** Options accepted by {@link pipe}. */
|
|
8
38
|
interface Options extends ValidationOptions {
|
|
39
|
+
/**
|
|
40
|
+
* Return the intermediate output produced after `rules[returnIndex]`
|
|
41
|
+
* instead of the final step's output. All steps still run (and their
|
|
42
|
+
* results still feed forward into subsequent steps) - this only changes
|
|
43
|
+
* which intermediate value is handed back to the caller.
|
|
44
|
+
* @defaultValue undefined (the last step's output is returned)
|
|
45
|
+
*/
|
|
9
46
|
returnIndex?: number;
|
|
10
47
|
}
|
|
11
48
|
}
|
|
@@ -1,6 +1,35 @@
|
|
|
1
1
|
import { validator, } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
* Chains
|
|
3
|
+
* Chains a list of validators so that each one's output becomes the next
|
|
4
|
+
* one's input: `rules[0]`'s output becomes `rules[1]`'s input, and so on.
|
|
5
|
+
*
|
|
6
|
+
* Short-circuits on the first rule that records a failure: as soon as a step
|
|
7
|
+
* adds to the shared context's error list, `pipe` stops immediately and does
|
|
8
|
+
* not run the remaining rules. If every rule succeeds, returns the last
|
|
9
|
+
* rule's output - or, if `options.returnIndex` is given, the output of that
|
|
10
|
+
* specific step (even though later steps still ran for validation purposes).
|
|
11
|
+
*
|
|
12
|
+
* @typeParam T - The output type on success.
|
|
13
|
+
* @param rules - The validators to chain, in order.
|
|
14
|
+
* @param options - Validation options, including {@link pipe.Options.returnIndex}.
|
|
15
|
+
* @returns A validator that feeds the input through each rule in sequence
|
|
16
|
+
* and returns the final (or `returnIndex`-selected) step's output.
|
|
17
|
+
* @throws {@link ValidationError} from whichever rule first records a failure.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { isBoolean, isNumber, isString, vg } from 'valgen';
|
|
22
|
+
*
|
|
23
|
+
* vg.pipe([isString, vg.matches(/^[a-z]+$/)])('abc'); // => 'abc'
|
|
24
|
+
*
|
|
25
|
+
* // each step's output feeds the next: string -> number -> boolean
|
|
26
|
+
* vg.pipe([isString, isNumber, isBoolean])(1, { coerce: true }); // => true
|
|
27
|
+
*
|
|
28
|
+
* // returnIndex pins the result to an earlier step, while later steps still validate
|
|
29
|
+
* vg.pipe([isString, isNumber, vg.isGte(5)], { returnIndex: 1 })('123', {
|
|
30
|
+
* coerce: true,
|
|
31
|
+
* }); // => 123
|
|
32
|
+
* ```
|
|
4
33
|
* @validator pipe
|
|
5
34
|
*/
|
|
6
35
|
export function pipe(rules, options) {
|
|
@@ -1,10 +1,48 @@
|
|
|
1
1
|
import type { Nullish } from 'ts-gems';
|
|
2
2
|
import { type ValidationOptions, type Validator } from '../../core/index.js';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Wraps a rule so that `null`/`undefined` input fails (or falls back to a
|
|
5
|
+
* default) before being handed to the nested rule.
|
|
6
|
+
*
|
|
7
|
+
* If `input == null` (i.e. `null` or `undefined`) and `options.default` is
|
|
8
|
+
* set, `input` is replaced with `options.default`. If, after that
|
|
9
|
+
* substitution, `input` is still `null`/`undefined` (no default was
|
|
10
|
+
* configured, or the default itself is nullish), it fails with
|
|
11
|
+
* `Value required`. Otherwise, delegates to `nested(input)` - so a
|
|
12
|
+
* configured `default` must itself satisfy the nested rule, or validation
|
|
13
|
+
* still fails (just with the nested rule's own error instead of
|
|
14
|
+
* `Value required`).
|
|
15
|
+
*
|
|
16
|
+
* @typeParam T - The nested validator's output type.
|
|
17
|
+
* @typeParam I - The nested validator's input type.
|
|
18
|
+
* @param nested - The validator to delegate to once the input is non-nullish.
|
|
19
|
+
* @param options - Validation options, including {@link RequiredValidatorOptions.default}.
|
|
20
|
+
* @returns A validator that returns the nested rule's result for a
|
|
21
|
+
* non-nullish (or defaulted) input.
|
|
22
|
+
* @throws {@link ValidationError} with `Value required` when the input is
|
|
23
|
+
* `null`/`undefined` and no usable default is configured; otherwise
|
|
24
|
+
* whatever `nested` throws.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* import { isString, vg } from 'valgen';
|
|
29
|
+
*
|
|
30
|
+
* vg.required(isString)(''); // => ''
|
|
31
|
+
* vg.required(isString)(undefined); // throws: "Value required"
|
|
32
|
+
*
|
|
33
|
+
* // with a default value, substituted (and still validated) when input is nullish
|
|
34
|
+
* vg.required(isString, { default: 'hello world' })(undefined); // => 'hello world'
|
|
35
|
+
* ```
|
|
5
36
|
* @validator required
|
|
6
37
|
*/
|
|
7
38
|
export declare function required<T, I>(nested: Validator<T, I>, options?: RequiredValidatorOptions): Validator<Nullish<T>, I, import("../../core/types.js").ExecutionOptions>;
|
|
39
|
+
/** Options accepted by {@link required}. */
|
|
8
40
|
export interface RequiredValidatorOptions extends ValidationOptions {
|
|
41
|
+
/**
|
|
42
|
+
* Value substituted when `input` is `null` or `undefined`. The substituted
|
|
43
|
+
* default is then still run through the nested rule like any other input -
|
|
44
|
+
* it is not returned raw.
|
|
45
|
+
* @defaultValue undefined
|
|
46
|
+
*/
|
|
9
47
|
default?: any;
|
|
10
48
|
}
|
|
@@ -1,6 +1,37 @@
|
|
|
1
1
|
import { validator, } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Wraps a rule so that `null`/`undefined` input fails (or falls back to a
|
|
4
|
+
* default) before being handed to the nested rule.
|
|
5
|
+
*
|
|
6
|
+
* If `input == null` (i.e. `null` or `undefined`) and `options.default` is
|
|
7
|
+
* set, `input` is replaced with `options.default`. If, after that
|
|
8
|
+
* substitution, `input` is still `null`/`undefined` (no default was
|
|
9
|
+
* configured, or the default itself is nullish), it fails with
|
|
10
|
+
* `Value required`. Otherwise, delegates to `nested(input)` - so a
|
|
11
|
+
* configured `default` must itself satisfy the nested rule, or validation
|
|
12
|
+
* still fails (just with the nested rule's own error instead of
|
|
13
|
+
* `Value required`).
|
|
14
|
+
*
|
|
15
|
+
* @typeParam T - The nested validator's output type.
|
|
16
|
+
* @typeParam I - The nested validator's input type.
|
|
17
|
+
* @param nested - The validator to delegate to once the input is non-nullish.
|
|
18
|
+
* @param options - Validation options, including {@link RequiredValidatorOptions.default}.
|
|
19
|
+
* @returns A validator that returns the nested rule's result for a
|
|
20
|
+
* non-nullish (or defaulted) input.
|
|
21
|
+
* @throws {@link ValidationError} with `Value required` when the input is
|
|
22
|
+
* `null`/`undefined` and no usable default is configured; otherwise
|
|
23
|
+
* whatever `nested` throws.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* import { isString, vg } from 'valgen';
|
|
28
|
+
*
|
|
29
|
+
* vg.required(isString)(''); // => ''
|
|
30
|
+
* vg.required(isString)(undefined); // throws: "Value required"
|
|
31
|
+
*
|
|
32
|
+
* // with a default value, substituted (and still validated) when input is nullish
|
|
33
|
+
* vg.required(isString, { default: 'hello world' })(undefined); // => 'hello world'
|
|
34
|
+
* ```
|
|
4
35
|
* @validator required
|
|
5
36
|
*/
|
|
6
37
|
export function required(nested, options) {
|
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Runs `String(input).replace(searchValue, replacer)`, mirroring
|
|
3
|
+
* `String.prototype.replace`.
|
|
4
|
+
*
|
|
5
|
+
* `null`/`undefined` input is passed through unchanged (the replace is
|
|
6
|
+
* skipped). Any other input is coerced with `String(input)` and then
|
|
7
|
+
* `.replace(searchValue, replacer)` is applied, exactly like the native
|
|
8
|
+
* method - `searchValue` can be a string, a `RegExp` (with or without the
|
|
9
|
+
* global flag), or any object implementing `Symbol.replace`, and the
|
|
10
|
+
* replacer can be a literal string or a substitution callback.
|
|
11
|
+
*
|
|
12
|
+
* @param searchValue - The pattern to search for: a string, `RegExp`, or any
|
|
13
|
+
* object implementing `Symbol.replace`.
|
|
14
|
+
* @param replacer - The replacement: a literal string, or a callback
|
|
15
|
+
* returning the substitution for each match.
|
|
16
|
+
* @returns A validator that returns the replaced string, or the passed-through
|
|
17
|
+
* nullish value.
|
|
18
|
+
* @throws Never fails/throws on its own.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* import { vg } from 'valgen';
|
|
23
|
+
*
|
|
24
|
+
* vg.stringReplace(/-/g, '_')('a-b'); // => 'a_b'
|
|
25
|
+
* vg.stringReplace('-', '_')(null); // => null
|
|
26
|
+
* ```
|
|
3
27
|
* @validator stringReplace
|
|
4
28
|
*/
|
|
5
29
|
export declare function stringReplace(searchValue: string | RegExp, replaceValue: string): any;
|
|
@@ -11,7 +35,27 @@ export declare function stringReplace(searchValue: {
|
|
|
11
35
|
[Symbol.replace](string: string, replacer: (substring: string, ...args: any[]) => string): string;
|
|
12
36
|
}, replacer: (substring: string, ...args: any[]) => string): any;
|
|
13
37
|
/**
|
|
14
|
-
*
|
|
38
|
+
* Runs `String(input).split(separator, limit)`, mirroring
|
|
39
|
+
* `String.prototype.split`.
|
|
40
|
+
*
|
|
41
|
+
* `null`/`undefined` input is passed through unchanged (the split is
|
|
42
|
+
* skipped). Any other input is coerced with `String(input)` and then
|
|
43
|
+
* `.split(separator, limit)` is applied, exactly like the native method.
|
|
44
|
+
*
|
|
45
|
+
* @param separator - The delimiter: a string, `RegExp`, or any object
|
|
46
|
+
* implementing `Symbol.split`.
|
|
47
|
+
* @param limit - Maximum number of substrings to include in the result.
|
|
48
|
+
* @returns A validator that returns the resulting array, or the
|
|
49
|
+
* passed-through nullish value.
|
|
50
|
+
* @throws Never fails/throws on its own.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* import { vg } from 'valgen';
|
|
55
|
+
*
|
|
56
|
+
* vg.stringSplit(',')('a,b'); // => ['a', 'b']
|
|
57
|
+
* vg.stringSplit(',')(null); // => null
|
|
58
|
+
* ```
|
|
15
59
|
* @validator split
|
|
16
60
|
*/
|
|
17
61
|
export declare function stringSplit(separator: string | RegExp, limit?: number): any;
|
|
@@ -19,17 +63,67 @@ export declare function stringSplit(splitter: {
|
|
|
19
63
|
[Symbol.split](string: string, limit?: number): string[];
|
|
20
64
|
}, limit?: number): any;
|
|
21
65
|
/**
|
|
22
|
-
* Removes whitespace from both ends of a string
|
|
66
|
+
* Removes whitespace from both ends of a string, mirroring
|
|
67
|
+
* `String.prototype.trim`.
|
|
68
|
+
*
|
|
69
|
+
* `null`/`undefined` input is passed through unchanged. Any other input is
|
|
70
|
+
* coerced with `String(input)` and then `.trim()` is applied.
|
|
71
|
+
*
|
|
72
|
+
* @returns A validator that returns the trimmed string, or the
|
|
73
|
+
* passed-through nullish value.
|
|
74
|
+
* @throws Never fails/throws on its own.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* import { vg } from 'valgen';
|
|
79
|
+
*
|
|
80
|
+
* vg.trim()(' a '); // => 'a'
|
|
81
|
+
* vg.trim()(null); // => null
|
|
82
|
+
* ```
|
|
23
83
|
* @validator trim
|
|
24
84
|
*/
|
|
25
85
|
export declare function trim(): import("../../core/validator.js").Validator<string, string, import("../../core/types.js").ExecutionOptions>;
|
|
26
86
|
/**
|
|
27
|
-
* Removes whitespace from the end of a string
|
|
87
|
+
* Removes whitespace from the end of a string, mirroring
|
|
88
|
+
* `String.prototype.trimEnd`.
|
|
89
|
+
*
|
|
90
|
+
* `null`/`undefined` input is passed through unchanged. Any other input is
|
|
91
|
+
* coerced with `String(input)` and then `.trimEnd()` is applied (leading
|
|
92
|
+
* whitespace is left untouched).
|
|
93
|
+
*
|
|
94
|
+
* @returns A validator that returns the trimmed string, or the
|
|
95
|
+
* passed-through nullish value.
|
|
96
|
+
* @throws Never fails/throws on its own.
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```ts
|
|
100
|
+
* import { vg } from 'valgen';
|
|
101
|
+
*
|
|
102
|
+
* vg.trimEnd()(' a '); // => ' a'
|
|
103
|
+
* vg.trimEnd()(null); // => null
|
|
104
|
+
* ```
|
|
28
105
|
* @validator trimEnd
|
|
29
106
|
*/
|
|
30
107
|
export declare function trimEnd(): import("../../core/validator.js").Validator<string, string, import("../../core/types.js").ExecutionOptions>;
|
|
31
108
|
/**
|
|
32
|
-
* Removes whitespace from the beginning of a string
|
|
109
|
+
* Removes whitespace from the beginning of a string, mirroring
|
|
110
|
+
* `String.prototype.trimStart`.
|
|
111
|
+
*
|
|
112
|
+
* `null`/`undefined` input is passed through unchanged. Any other input is
|
|
113
|
+
* coerced with `String(input)` and then `.trimStart()` is applied (trailing
|
|
114
|
+
* whitespace is left untouched).
|
|
115
|
+
*
|
|
116
|
+
* @returns A validator that returns the trimmed string, or the
|
|
117
|
+
* passed-through nullish value.
|
|
118
|
+
* @throws Never fails/throws on its own.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* import { vg } from 'valgen';
|
|
123
|
+
*
|
|
124
|
+
* vg.trimStart()(' a '); // => 'a '
|
|
125
|
+
* vg.trimStart()(null); // => null
|
|
126
|
+
* ```
|
|
33
127
|
* @validator trimStart
|
|
34
128
|
*/
|
|
35
129
|
export declare function trimStart(): import("../../core/validator.js").Validator<string, string, import("../../core/types.js").ExecutionOptions>;
|