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.
Files changed (143) hide show
  1. package/README.md +1 -1
  2. package/constants.js +1 -1
  3. package/core/constants.d.ts +11 -0
  4. package/core/constants.js +11 -0
  5. package/core/context.d.ts +57 -0
  6. package/core/context.js +57 -0
  7. package/core/types.d.ts +40 -0
  8. package/core/utilities.d.ts +42 -2
  9. package/core/utilities.js +21 -1
  10. package/core/validation-error.d.ts +13 -0
  11. package/core/validation-error.js +13 -0
  12. package/core/validator.d.ts +100 -0
  13. package/core/validator.js +6 -0
  14. package/package.json +1 -1
  15. package/rules/format-rules/is-alpha.d.ts +10 -1
  16. package/rules/format-rules/is-alpha.js +10 -1
  17. package/rules/format-rules/is-alphanumeric.d.ts +10 -1
  18. package/rules/format-rules/is-alphanumeric.js +10 -1
  19. package/rules/format-rules/is-ascii.d.ts +10 -1
  20. package/rules/format-rules/is-ascii.js +10 -1
  21. package/rules/format-rules/is-base64.d.ts +20 -1
  22. package/rules/format-rules/is-base64.js +10 -1
  23. package/rules/format-rules/is-btc-address.d.ts +10 -1
  24. package/rules/format-rules/is-btc-address.js +10 -1
  25. package/rules/format-rules/is-credit-card.d.ts +16 -1
  26. package/rules/format-rules/is-credit-card.js +11 -1
  27. package/rules/format-rules/is-decimal.d.ts +12 -2
  28. package/rules/format-rules/is-decimal.js +12 -2
  29. package/rules/format-rules/is-ean.d.ts +11 -1
  30. package/rules/format-rules/is-ean.js +11 -1
  31. package/rules/format-rules/is-email.d.ts +19 -7
  32. package/rules/format-rules/is-email.js +13 -1
  33. package/rules/format-rules/is-eth-address.d.ts +10 -1
  34. package/rules/format-rules/is-eth-address.js +10 -1
  35. package/rules/format-rules/is-fqdn.d.ts +13 -2
  36. package/rules/format-rules/is-fqdn.js +12 -1
  37. package/rules/format-rules/is-hash.d.ts +17 -1
  38. package/rules/format-rules/is-hash.js +16 -1
  39. package/rules/format-rules/is-hex-color.d.ts +13 -1
  40. package/rules/format-rules/is-hex-color.js +13 -1
  41. package/rules/format-rules/is-hex.d.ts +13 -1
  42. package/rules/format-rules/is-hex.js +13 -1
  43. package/rules/format-rules/is-iban.d.ts +33 -2
  44. package/rules/format-rules/is-iban.js +19 -1
  45. package/rules/format-rules/is-ip.d.ts +44 -2
  46. package/rules/format-rules/is-ip.js +42 -2
  47. package/rules/format-rules/is-issn.d.ts +19 -2
  48. package/rules/format-rules/is-issn.js +18 -1
  49. package/rules/format-rules/is-jwt.d.ts +16 -1
  50. package/rules/format-rules/is-jwt.js +16 -1
  51. package/rules/format-rules/is-lowercase.d.ts +13 -1
  52. package/rules/format-rules/is-lowercase.js +13 -1
  53. package/rules/format-rules/is-mac-address.d.ts +19 -2
  54. package/rules/format-rules/is-mac-address.js +16 -1
  55. package/rules/format-rules/is-mobile-phone.d.ts +19 -3
  56. package/rules/format-rules/is-mobile-phone.js +17 -1
  57. package/rules/format-rules/is-object-id.d.ts +20 -1
  58. package/rules/format-rules/is-object-id.js +19 -1
  59. package/rules/format-rules/is-passport-number.d.ts +17 -1
  60. package/rules/format-rules/is-passport-number.js +17 -1
  61. package/rules/format-rules/is-port.d.ts +16 -1
  62. package/rules/format-rules/is-port.js +16 -1
  63. package/rules/format-rules/is-swift.d.ts +15 -1
  64. package/rules/format-rules/is-swift.js +15 -1
  65. package/rules/format-rules/is-time.d.ts +22 -1
  66. package/rules/format-rules/is-time.js +22 -1
  67. package/rules/format-rules/is-uppercase.d.ts +15 -1
  68. package/rules/format-rules/is-uppercase.js +15 -1
  69. package/rules/format-rules/is-url.d.ts +99 -1
  70. package/rules/format-rules/is-url.js +19 -1
  71. package/rules/format-rules/is-uuid.d.ts +23 -1
  72. package/rules/format-rules/is-uuid.js +23 -1
  73. package/rules/format-rules/is-vat-number.d.ts +19 -2
  74. package/rules/format-rules/is-vat-number.js +19 -2
  75. package/rules/format-rules/matches.d.ts +27 -1
  76. package/rules/format-rules/matches.js +23 -1
  77. package/rules/logical-rules/is-defined.d.ts +14 -2
  78. package/rules/logical-rules/is-defined.js +13 -2
  79. package/rules/logical-rules/is-empty.d.ts +40 -2
  80. package/rules/logical-rules/is-empty.js +38 -2
  81. package/rules/logical-rules/is-equal.d.ts +31 -4
  82. package/rules/logical-rules/is-equal.js +29 -4
  83. package/rules/logical-rules/is-gt.d.ts +26 -1
  84. package/rules/logical-rules/is-gt.js +20 -1
  85. package/rules/logical-rules/is-gte.d.ts +25 -1
  86. package/rules/logical-rules/is-gte.js +20 -1
  87. package/rules/logical-rules/is-lt.d.ts +24 -1
  88. package/rules/logical-rules/is-lt.js +19 -1
  89. package/rules/logical-rules/is-lte.d.ts +25 -1
  90. package/rules/logical-rules/is-lte.js +20 -1
  91. package/rules/logical-rules/length.d.ts +38 -2
  92. package/rules/logical-rules/length.js +38 -2
  93. package/rules/logical-rules/range.d.ts +25 -1
  94. package/rules/logical-rules/range.js +23 -1
  95. package/rules/type-rules/is-any.d.ts +12 -1
  96. package/rules/type-rules/is-any.js +12 -1
  97. package/rules/type-rules/is-array.d.ts +23 -2
  98. package/rules/type-rules/is-array.js +23 -2
  99. package/rules/type-rules/is-bigint.d.ts +14 -2
  100. package/rules/type-rules/is-bigint.js +14 -2
  101. package/rules/type-rules/is-boolean.d.ts +17 -2
  102. package/rules/type-rules/is-boolean.js +17 -2
  103. package/rules/type-rules/is-date.d.ts +47 -5
  104. package/rules/type-rules/is-date.js +42 -5
  105. package/rules/type-rules/is-enum.d.ts +23 -1
  106. package/rules/type-rules/is-enum.js +21 -1
  107. package/rules/type-rules/is-instanceof.d.ts +21 -1
  108. package/rules/type-rules/is-instanceof.js +21 -1
  109. package/rules/type-rules/is-integer.d.ts +17 -2
  110. package/rules/type-rules/is-integer.js +17 -2
  111. package/rules/type-rules/is-null.d.ts +51 -4
  112. package/rules/type-rules/is-null.js +51 -4
  113. package/rules/type-rules/is-number.d.ts +17 -2
  114. package/rules/type-rules/is-number.js +17 -2
  115. package/rules/type-rules/is-object.d.ts +45 -7
  116. package/rules/type-rules/is-object.js +40 -7
  117. package/rules/type-rules/is-record.d.ts +21 -2
  118. package/rules/type-rules/is-record.js +21 -2
  119. package/rules/type-rules/is-string.d.ts +16 -2
  120. package/rules/type-rules/is-string.js +16 -2
  121. package/rules/type-rules/is-tuple.d.ts +21 -2
  122. package/rules/type-rules/is-undefined.d.ts +16 -4
  123. package/rules/type-rules/is-undefined.js +16 -4
  124. package/rules/utility-rules/all-of.d.ts +28 -1
  125. package/rules/utility-rules/all-of.js +27 -1
  126. package/rules/utility-rules/exists.d.ts +30 -1
  127. package/rules/utility-rules/exists.js +29 -1
  128. package/rules/utility-rules/fixed.d.ts +19 -1
  129. package/rules/utility-rules/fixed.js +19 -1
  130. package/rules/utility-rules/get-length.d.ts +25 -2
  131. package/rules/utility-rules/get-length.js +25 -2
  132. package/rules/utility-rules/nullable.d.ts +28 -1
  133. package/rules/utility-rules/nullable.js +27 -1
  134. package/rules/utility-rules/one-of.d.ts +52 -3
  135. package/rules/utility-rules/one-of.js +81 -9
  136. package/rules/utility-rules/optional.d.ts +29 -1
  137. package/rules/utility-rules/optional.js +28 -1
  138. package/rules/utility-rules/pipe.d.ts +38 -1
  139. package/rules/utility-rules/pipe.js +30 -1
  140. package/rules/utility-rules/required.d.ts +39 -1
  141. package/rules/utility-rules/required.js +32 -1
  142. package/rules/utility-rules/string-utils.d.ts +99 -5
  143. package/rules/utility-rules/string-utils.js +53 -3
@@ -1,6 +1,32 @@
1
1
  import { validator, } from '../../core/index.js';
2
2
  /**
3
- * Makes the sub-rule nullable (accepts undefined or null)
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 each rule against the input in order and returns the first one that
5
- * passes. An optional discriminator record narrows which rule to try based
6
- * on a distinguishing field of the input.
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 each rule against the input in order and returns the first one that
4
- * passes. An optional discriminator record narrows which rule to try based
5
- * on a distinguishing field of the input.
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
- // Mock fail method to prevent errors
17
- context.fail = () => (passed = false);
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
- * Makes the sub-rule optional
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
- * Makes the sub-rule optional
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 rules so each one's output becomes the next one's input.
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 rules so each one's output becomes the next one's input.
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
- * Check if value is not nullish before calling nested rule
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
- * Check if value is not nullish before calling nested rule
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
- * Applies "String.replace" method
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
- * Applies "String.split" method
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>;