@zudojs/validation 0.1.0 → 1.0.1

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 (133) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +31 -0
  3. package/dist/validationComposer/index.d.ts +3 -1
  4. package/dist/validationComposer/index.js +3 -1
  5. package/dist/validationComposer/validationComposer.combinators.d.ts +21 -0
  6. package/dist/validationComposer/validationComposer.combinators.js +78 -0
  7. package/dist/validationComposer/validationComposer.core.d.ts +10 -24
  8. package/dist/validationComposer/validationComposer.core.js +2 -139
  9. package/dist/validationComposer/validationComposer.wrappers.d.ts +38 -0
  10. package/dist/validationComposer/validationComposer.wrappers.js +96 -0
  11. package/dist/validationConstraints/collection/index.d.ts +8 -0
  12. package/dist/validationConstraints/collection/index.js +8 -0
  13. package/dist/validationConstraints/{validationConstraints.array.d.ts → collection/validationConstraints.array.d.ts} +1 -1
  14. package/dist/validationConstraints/{validationConstraints.array.js → collection/validationConstraints.array.js} +23 -3
  15. package/dist/validationConstraints/{validationConstraints.collection.d.ts → collection/validationConstraints.collection.d.ts} +1 -1
  16. package/dist/validationConstraints/{validationConstraints.collection.js → collection/validationConstraints.collection.js} +1 -1
  17. package/dist/validationConstraints/index.d.ts +3 -8
  18. package/dist/validationConstraints/index.js +6 -16
  19. package/dist/validationConstraints/scalar/index.d.ts +9 -0
  20. package/dist/validationConstraints/scalar/index.js +9 -0
  21. package/dist/validationConstraints/scalar/validationConstraints.date.d.ts +13 -0
  22. package/dist/validationConstraints/scalar/validationConstraints.date.js +45 -0
  23. package/dist/validationConstraints/{validationConstraints.number.d.ts → scalar/validationConstraints.number.d.ts} +1 -1
  24. package/dist/validationConstraints/{validationConstraints.number.js → scalar/validationConstraints.number.js} +12 -1
  25. package/dist/validationConstraints/{validationConstraints.string.d.ts → scalar/validationConstraints.string.d.ts} +18 -3
  26. package/dist/validationConstraints/{validationConstraints.string.js → scalar/validationConstraints.string.js} +49 -13
  27. package/dist/validationConstraints/structure/index.d.ts +10 -0
  28. package/dist/validationConstraints/structure/index.js +10 -0
  29. package/dist/validationConstraints/{validationConstraints.circular.d.ts → structure/validationConstraints.circular.d.ts} +8 -4
  30. package/dist/validationConstraints/structure/validationConstraints.circular.js +55 -0
  31. package/dist/validationConstraints/structure/validationConstraints.depth.d.ts +37 -0
  32. package/dist/validationConstraints/structure/validationConstraints.depth.js +58 -0
  33. package/dist/validationConstraints/structure/validationConstraints.size.d.ts +31 -0
  34. package/dist/validationConstraints/structure/validationConstraints.size.js +101 -0
  35. package/dist/validationConstraints/structure/validationConstraints.traverse.d.ts +57 -0
  36. package/dist/validationConstraints/structure/validationConstraints.traverse.js +118 -0
  37. package/dist/validationConstraints/validationConstraints.base.d.ts +18 -3
  38. package/dist/validationConstraints/validationConstraints.base.js +50 -25
  39. package/dist/validationErrors/validationError.base.js +28 -1
  40. package/dist/validationFactory/validationFactory.core.d.ts +9 -8
  41. package/dist/validationFactory/validationFactory.core.js +11 -9
  42. package/dist/validationNormalizer/validationNormalizer.core.js +2 -4
  43. package/dist/validationNormalizer/validationNormalizer.helpers.d.ts +36 -3
  44. package/dist/validationNormalizer/validationNormalizer.helpers.js +48 -7
  45. package/dist/validationParser/index.d.ts +2 -1
  46. package/dist/validationParser/index.js +2 -1
  47. package/dist/validationParser/validationParser.collection.d.ts +28 -0
  48. package/dist/validationParser/validationParser.collection.js +98 -0
  49. package/dist/validationParser/validationParser.core.d.ts +0 -12
  50. package/dist/validationParser/validationParser.core.js +0 -71
  51. package/dist/validationRegistry/validationRegistry.core.d.ts +8 -0
  52. package/dist/validationRegistry/validationRegistry.core.js +15 -1
  53. package/dist/validationResult/validationResult.type.d.ts +8 -1
  54. package/dist/validationResult/validationResult.type.js +20 -5
  55. package/dist/validationTransformer/index.d.ts +2 -1
  56. package/dist/validationTransformer/index.js +2 -1
  57. package/dist/validationTransformer/validationTransformer.core.d.ts +0 -15
  58. package/dist/validationTransformer/validationTransformer.core.js +5 -56
  59. package/dist/validationTransformer/validationTransformer.helpers.d.ts +23 -0
  60. package/dist/validationTransformer/validationTransformer.helpers.js +67 -0
  61. package/package.json +24 -13
  62. package/dist/.tsbuildinfo +0 -1
  63. package/dist/index.d.ts.map +0 -1
  64. package/dist/index.js.map +0 -1
  65. package/dist/validationComposer/index.d.ts.map +0 -1
  66. package/dist/validationComposer/index.js.map +0 -1
  67. package/dist/validationComposer/validationComposer.core.d.ts.map +0 -1
  68. package/dist/validationComposer/validationComposer.core.js.map +0 -1
  69. package/dist/validationConstraints/index.d.ts.map +0 -1
  70. package/dist/validationConstraints/index.js.map +0 -1
  71. package/dist/validationConstraints/validationConstraints.array.d.ts.map +0 -1
  72. package/dist/validationConstraints/validationConstraints.array.js.map +0 -1
  73. package/dist/validationConstraints/validationConstraints.base.d.ts.map +0 -1
  74. package/dist/validationConstraints/validationConstraints.base.js.map +0 -1
  75. package/dist/validationConstraints/validationConstraints.circular.d.ts.map +0 -1
  76. package/dist/validationConstraints/validationConstraints.circular.js +0 -73
  77. package/dist/validationConstraints/validationConstraints.circular.js.map +0 -1
  78. package/dist/validationConstraints/validationConstraints.collection.d.ts.map +0 -1
  79. package/dist/validationConstraints/validationConstraints.collection.js.map +0 -1
  80. package/dist/validationConstraints/validationConstraints.date.d.ts +0 -14
  81. package/dist/validationConstraints/validationConstraints.date.d.ts.map +0 -1
  82. package/dist/validationConstraints/validationConstraints.date.js +0 -30
  83. package/dist/validationConstraints/validationConstraints.date.js.map +0 -1
  84. package/dist/validationConstraints/validationConstraints.depth.d.ts +0 -20
  85. package/dist/validationConstraints/validationConstraints.depth.d.ts.map +0 -1
  86. package/dist/validationConstraints/validationConstraints.depth.js +0 -70
  87. package/dist/validationConstraints/validationConstraints.depth.js.map +0 -1
  88. package/dist/validationConstraints/validationConstraints.number.d.ts.map +0 -1
  89. package/dist/validationConstraints/validationConstraints.number.js.map +0 -1
  90. package/dist/validationConstraints/validationConstraints.size.d.ts +0 -20
  91. package/dist/validationConstraints/validationConstraints.size.d.ts.map +0 -1
  92. package/dist/validationConstraints/validationConstraints.size.js +0 -82
  93. package/dist/validationConstraints/validationConstraints.size.js.map +0 -1
  94. package/dist/validationConstraints/validationConstraints.string.d.ts.map +0 -1
  95. package/dist/validationConstraints/validationConstraints.string.js.map +0 -1
  96. package/dist/validationErrors/index.d.ts.map +0 -1
  97. package/dist/validationErrors/index.js.map +0 -1
  98. package/dist/validationErrors/validationError.base.d.ts.map +0 -1
  99. package/dist/validationErrors/validationError.base.js.map +0 -1
  100. package/dist/validationErrors/validationError.types.d.ts.map +0 -1
  101. package/dist/validationErrors/validationError.types.js.map +0 -1
  102. package/dist/validationFactory/index.d.ts.map +0 -1
  103. package/dist/validationFactory/index.js.map +0 -1
  104. package/dist/validationFactory/validationFactory.core.d.ts.map +0 -1
  105. package/dist/validationFactory/validationFactory.core.js.map +0 -1
  106. package/dist/validationNormalizer/index.d.ts.map +0 -1
  107. package/dist/validationNormalizer/index.js.map +0 -1
  108. package/dist/validationNormalizer/validationNormalizer.core.d.ts.map +0 -1
  109. package/dist/validationNormalizer/validationNormalizer.core.js.map +0 -1
  110. package/dist/validationNormalizer/validationNormalizer.helpers.d.ts.map +0 -1
  111. package/dist/validationNormalizer/validationNormalizer.helpers.js.map +0 -1
  112. package/dist/validationParser/index.d.ts.map +0 -1
  113. package/dist/validationParser/index.js.map +0 -1
  114. package/dist/validationParser/validationParser.core.d.ts.map +0 -1
  115. package/dist/validationParser/validationParser.core.js.map +0 -1
  116. package/dist/validationRegistry/index.d.ts.map +0 -1
  117. package/dist/validationRegistry/index.js.map +0 -1
  118. package/dist/validationRegistry/validationRegistry.core.d.ts.map +0 -1
  119. package/dist/validationRegistry/validationRegistry.core.js.map +0 -1
  120. package/dist/validationRegistry/validationRegistry.readonly.d.ts.map +0 -1
  121. package/dist/validationRegistry/validationRegistry.readonly.js.map +0 -1
  122. package/dist/validationResult/index.d.ts.map +0 -1
  123. package/dist/validationResult/index.js.map +0 -1
  124. package/dist/validationResult/validationResult.type.d.ts.map +0 -1
  125. package/dist/validationResult/validationResult.type.js.map +0 -1
  126. package/dist/validationSchema/index.d.ts.map +0 -1
  127. package/dist/validationSchema/index.js.map +0 -1
  128. package/dist/validationSchema/validationSchema.core.d.ts.map +0 -1
  129. package/dist/validationSchema/validationSchema.core.js.map +0 -1
  130. package/dist/validationTransformer/index.d.ts.map +0 -1
  131. package/dist/validationTransformer/index.js.map +0 -1
  132. package/dist/validationTransformer/validationTransformer.core.d.ts.map +0 -1
  133. package/dist/validationTransformer/validationTransformer.core.js.map +0 -1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Zudojs Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -24,6 +24,37 @@ if (!result.success) {
24
24
  }
25
25
  ```
26
26
 
27
+ Structural guards for untrusted payloads:
28
+
29
+ ```typescript
30
+ import {
31
+ assertDepthWithinLimit,
32
+ assertSizeWithinLimit,
33
+ assertNoCircularReference,
34
+ } from "@zudojs/validation";
35
+
36
+ // Each aborts as soon as its bound is passed, so the cost is bounded by the
37
+ // limit rather than by the size of the input.
38
+ assertDepthWithinLimit(body, 32);
39
+ assertSizeWithinLimit(body, 1_000_000);
40
+ assertNoCircularReference(body);
41
+ ```
42
+
43
+ ## Safety Notes
44
+
45
+ - Constraint failures do **not** carry the rejected value. `ValidationError` is
46
+ exposed with a 400, so echoing it would return rejected passwords and tokens
47
+ to the caller and write them to any log that serializes the error.
48
+ - `parseRecord` and `toFieldErrors` build on null-prototype objects, so a
49
+ `__proto__` key cannot hijack a validated result.
50
+ - `matches()` strips `g` and `y` from the pattern, which otherwise make
51
+ `test()` stateful and flip the answer on alternate calls.
52
+ - Constraints carry an optional type guard, so wrong-typed input at a trust
53
+ boundary reports as a validation failure rather than a `TypeError`.
54
+ - The depth and size guards count a shared subtree once per occurrence, the way
55
+ a serializer expands it, and walk iteratively so deeply nested input cannot
56
+ exhaust the stack inside the check.
57
+
27
58
  ## Features
28
59
 
29
60
  - Zod schema integration
@@ -1,7 +1,9 @@
1
1
  /**
2
2
  * @zudojs/validation/validationComposer
3
3
  *
4
- * Schema composition and merging utilities.
4
+ * Composition of validation steps into reusable pipelines.
5
5
  */
6
6
  export * from "./validationComposer.core.js";
7
+ export * from "./validationComposer.combinators.js";
8
+ export * from "./validationComposer.wrappers.js";
7
9
  //# sourceMappingURL=index.d.ts.map
@@ -1,7 +1,9 @@
1
1
  /**
2
2
  * @zudojs/validation/validationComposer
3
3
  *
4
- * Schema composition and merging utilities.
4
+ * Composition of validation steps into reusable pipelines.
5
5
  */
6
6
  export * from "./validationComposer.core.js";
7
+ export * from "./validationComposer.combinators.js";
8
+ export * from "./validationComposer.wrappers.js";
7
9
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @zudojs/validation — Validation step combinators.
3
+ *
4
+ * @module validationComposer/validationComposer.combinators
5
+ */
6
+ import type { ValidationStep } from "./validationComposer.core.js";
7
+ /** Combines validators using logical AND semantics. Every validator must succeed. */
8
+ export declare function all<T>(...validators: readonly ValidationStep<T>[]): ValidationStep<T>;
9
+ /** Combines validators using logical OR semantics. Succeeds when at least one validator succeeds. */
10
+ export declare function any<T>(...validators: readonly ValidationStep<T>[]): ValidationStep<T>;
11
+ /**
12
+ * Runs validators sequentially and returns the first successful result.
13
+ *
14
+ * Unlike {@link any}, only the *last* failure is reported when none succeed:
15
+ * a caller asking for the first match wants to know why the final fallback
16
+ * did not apply, not to read every alternative's complaint.
17
+ */
18
+ export declare function first<T>(...validators: readonly ValidationStep<T>[]): ValidationStep<T>;
19
+ /** Negates a validation step. */
20
+ export declare function negate<T>(validator: ValidationStep<T>): ValidationStep<T>;
21
+ //# sourceMappingURL=validationComposer.combinators.d.ts.map
@@ -0,0 +1,78 @@
1
+ /**
2
+ * @zudojs/validation — Validation step combinators.
3
+ *
4
+ * @module validationComposer/validationComposer.combinators
5
+ */
6
+ import { failure, success } from "../validationResult/validationResult.type.js";
7
+ /** The issue reported when no alternative accepted the value. */
8
+ function noValidatorSucceeded() {
9
+ return {
10
+ path: [],
11
+ code: "no_validator_succeeded",
12
+ message: "No validation rule accepted the value.",
13
+ };
14
+ }
15
+ /** Combines validators using logical AND semantics. Every validator must succeed. */
16
+ export function all(...validators) {
17
+ return (value) => {
18
+ const issues = [];
19
+ for (const validator of validators) {
20
+ const result = validator(value);
21
+ if (!result.success)
22
+ issues.push(...result.issues);
23
+ }
24
+ return issues.length > 0 ? failure(issues) : success(value);
25
+ };
26
+ }
27
+ /** Combines validators using logical OR semantics. Succeeds when at least one validator succeeds. */
28
+ export function any(...validators) {
29
+ return (value) => {
30
+ const issues = [];
31
+ for (const validator of validators) {
32
+ const result = validator(value);
33
+ if (result.success)
34
+ return result;
35
+ issues.push(...result.issues);
36
+ }
37
+ // Never echo the rejected value: issues flow into a 400 response and
38
+ // into logs, so `received` would hand back the password or token that
39
+ // was just refused.
40
+ return failure(issues.length > 0 ? issues : [noValidatorSucceeded()]);
41
+ };
42
+ }
43
+ /**
44
+ * Runs validators sequentially and returns the first successful result.
45
+ *
46
+ * Unlike {@link any}, only the *last* failure is reported when none succeed:
47
+ * a caller asking for the first match wants to know why the final fallback
48
+ * did not apply, not to read every alternative's complaint.
49
+ */
50
+ export function first(...validators) {
51
+ return (value) => {
52
+ let lastIssues = [];
53
+ for (const validator of validators) {
54
+ const result = validator(value);
55
+ if (result.success)
56
+ return result;
57
+ lastIssues = result.issues;
58
+ }
59
+ return failure(lastIssues.length > 0 ? lastIssues : [noValidatorSucceeded()]);
60
+ };
61
+ }
62
+ /** Negates a validation step. */
63
+ export function negate(validator) {
64
+ return (value) => {
65
+ const result = validator(value);
66
+ if (result.success) {
67
+ return failure([
68
+ {
69
+ path: [],
70
+ code: "negated_validation_failed",
71
+ message: "Value must not satisfy the supplied validation rule.",
72
+ },
73
+ ]);
74
+ }
75
+ return success(value);
76
+ };
77
+ }
78
+ //# sourceMappingURL=validationComposer.combinators.js.map
@@ -6,11 +6,21 @@ export type ValidationStep<T> = (value: T) => ValidationResult<T>;
6
6
  /** Options for composing validation operations. */
7
7
  export interface ValidationComposerOptions {
8
8
  readonly name?: string;
9
+ /**
10
+ * Stop after the first failing step. Defaults to true.
11
+ *
12
+ * Steps in a pipeline normally build on each other: a later step validating
13
+ * the shape an earlier coercion was supposed to produce will see the raw
14
+ * value instead if the pipeline runs on. Set to false only for pipelines of
15
+ * independent checks, where collecting every issue is the point.
16
+ */
9
17
  readonly stopOnFirstError?: boolean;
10
18
  }
11
19
  /** Reusable composed validator. */
12
20
  export interface ValidationComposer<T> {
13
21
  readonly name: string;
22
+ /** Whether the pipeline halts at the first failing step. */
23
+ readonly stopOnFirstError: boolean;
14
24
  validate(value: T): ValidationResult<T>;
15
25
  assert(value: T): T;
16
26
  }
@@ -24,28 +34,4 @@ export declare function schemaStep<T>(schema: ValidationSchema<T>): ValidationSt
24
34
  export declare function constraintStep<T>(constraint: ValidationConstraint<T>): ValidationStep<T>;
25
35
  /** Creates a validation step from multiple constraints. */
26
36
  export declare function constraintsStep<T>(constraints: readonly ValidationConstraint<T>[]): ValidationStep<T>;
27
- /** Combines validators using logical AND semantics. Every validator must succeed. */
28
- export declare function all<T>(...validators: readonly ValidationStep<T>[]): ValidationStep<T>;
29
- /** Combines validators using logical OR semantics. Succeeds when at least one validator succeeds. */
30
- export declare function any<T>(...validators: readonly ValidationStep<T>[]): ValidationStep<T>;
31
- /** Runs validators sequentially and returns the first successful result. */
32
- export declare function first<T>(...validators: readonly ValidationStep<T>[]): ValidationStep<T>;
33
- /** Negates a validation step. */
34
- export declare function negate<T>(validator: ValidationStep<T>): ValidationStep<T>;
35
- /** Makes a validation step optional. Undefined values bypass the validator. */
36
- export declare function optional<T>(validator: ValidationStep<T>): ValidationStep<T | undefined>;
37
- /** Makes a validation step nullable. Null values bypass the validator. */
38
- export declare function nullable<T>(validator: ValidationStep<T>): ValidationStep<T | null>;
39
- /** Makes a validation step optional and nullable. */
40
- export declare function optionalNullable<T>(validator: ValidationStep<T>): ValidationStep<T | null | undefined>;
41
- /** Adds a custom validation step to an existing pipeline. */
42
- export declare function append<T>(composer: ValidationComposer<T>, step: ValidationStep<T>, options?: ValidationComposerOptions): ValidationComposer<T>;
43
- /** Creates a pipeline that validates a value and returns the original value. */
44
- export declare function tap<T>(validator: ValidationStep<T>): ValidationStep<T>;
45
- /** Creates a validation step that only runs when a predicate matches. */
46
- export declare function when<T>(predicate: (value: T) => boolean, validator: ValidationStep<T>): ValidationStep<T>;
47
- /** Creates a validation step that runs only when a predicate does not match. */
48
- export declare function unless<T>(predicate: (value: T) => boolean, validator: ValidationStep<T>): ValidationStep<T>;
49
- /** Applies a mapping operation after successful validation. */
50
- export declare function mapValidated<T, U>(validator: ValidationStep<T>, mapper: (value: T) => U): ValidationStep<T>;
51
37
  //# sourceMappingURL=validationComposer.core.d.ts.map
@@ -5,9 +5,10 @@ import { ConstraintValidationError } from "../validationErrors/validationError.t
5
5
  /** Creates a reusable validator from validation steps. */
6
6
  export function createValidationComposer(steps, options = {}) {
7
7
  const name = options.name ?? "ValidationComposer";
8
- const stopOnFirstError = options.stopOnFirstError ?? false;
8
+ const stopOnFirstError = options.stopOnFirstError ?? true;
9
9
  return Object.freeze({
10
10
  name,
11
+ stopOnFirstError,
11
12
  validate(value) {
12
13
  let current = value;
13
14
  const issues = [];
@@ -50,142 +51,4 @@ export function constraintStep(constraint) {
50
51
  export function constraintsStep(constraints) {
51
52
  return (value) => checkConstraints(constraints, value);
52
53
  }
53
- /** Combines validators using logical AND semantics. Every validator must succeed. */
54
- export function all(...validators) {
55
- return (value) => {
56
- const issues = [];
57
- for (const validator of validators) {
58
- const result = validator(value);
59
- if (!result.success)
60
- issues.push(...result.issues);
61
- }
62
- return issues.length > 0 ? failure(issues) : success(value);
63
- };
64
- }
65
- /** Combines validators using logical OR semantics. Succeeds when at least one validator succeeds. */
66
- export function any(...validators) {
67
- return (value) => {
68
- const issues = [];
69
- for (const validator of validators) {
70
- const result = validator(value);
71
- if (result.success)
72
- return result;
73
- issues.push(...result.issues);
74
- }
75
- return failure(issues.length > 0
76
- ? issues
77
- : [
78
- {
79
- path: [],
80
- code: "no_validator_succeeded",
81
- message: "No validation rule accepted the value.",
82
- received: value,
83
- },
84
- ]);
85
- };
86
- }
87
- /** Runs validators sequentially and returns the first successful result. */
88
- export function first(...validators) {
89
- return (value) => {
90
- let issues = [];
91
- for (const validator of validators) {
92
- const result = validator(value);
93
- if (result.success)
94
- return result;
95
- issues = [...issues, ...result.issues];
96
- }
97
- return failure(issues.length > 0
98
- ? issues
99
- : [
100
- {
101
- path: [],
102
- code: "no_validator_succeeded",
103
- message: "No validation rule accepted the value.",
104
- received: value,
105
- },
106
- ]);
107
- };
108
- }
109
- /** Negates a validation step. */
110
- export function negate(validator) {
111
- return (value) => {
112
- const result = validator(value);
113
- if (result.success)
114
- return failure([
115
- {
116
- path: [],
117
- code: "negated_validation_failed",
118
- message: "Value must not satisfy the supplied validation rule.",
119
- received: value,
120
- },
121
- ]);
122
- return success(value);
123
- };
124
- }
125
- /** Makes a validation step optional. Undefined values bypass the validator. */
126
- export function optional(validator) {
127
- return (value) => {
128
- if (value === undefined)
129
- return success(undefined);
130
- return validator(value);
131
- };
132
- }
133
- /** Makes a validation step nullable. Null values bypass the validator. */
134
- export function nullable(validator) {
135
- return (value) => {
136
- if (value === null)
137
- return success(null);
138
- return validator(value);
139
- };
140
- }
141
- /** Makes a validation step optional and nullable. */
142
- export function optionalNullable(validator) {
143
- return (value) => {
144
- if (value === null || value === undefined)
145
- return success(value);
146
- return validator(value);
147
- };
148
- }
149
- /** Adds a custom validation step to an existing pipeline. */
150
- export function append(composer, step, options = {}) {
151
- return createValidationComposer([composer.validate, step], {
152
- ...options,
153
- name: options.name ?? composer.name,
154
- });
155
- }
156
- /** Creates a pipeline that validates a value and returns the original value. */
157
- export function tap(validator) {
158
- return (value) => {
159
- const result = validator(value);
160
- if (!result.success)
161
- return result;
162
- return success(value);
163
- };
164
- }
165
- /** Creates a validation step that only runs when a predicate matches. */
166
- export function when(predicate, validator) {
167
- return (value) => {
168
- if (!predicate(value))
169
- return success(value);
170
- return validator(value);
171
- };
172
- }
173
- /** Creates a validation step that runs only when a predicate does not match. */
174
- export function unless(predicate, validator) {
175
- return (value) => {
176
- if (predicate(value))
177
- return success(value);
178
- return validator(value);
179
- };
180
- }
181
- /** Applies a mapping operation after successful validation. */
182
- export function mapValidated(validator, mapper) {
183
- return (value) => {
184
- const result = validator(value);
185
- if (!result.success)
186
- return result;
187
- mapper(result.data);
188
- return success(result.data);
189
- };
190
- }
191
54
  //# sourceMappingURL=validationComposer.core.js.map
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @zudojs/validation — Wrappers that adapt a validation step.
3
+ *
4
+ * Optionality, conditionality and post-validation mapping, kept apart from the
5
+ * combinators that fold several steps into one.
6
+ *
7
+ * @module validationComposer/validationComposer.wrappers
8
+ */
9
+ import type { ValidationResult } from "../validationResult/validationResult.type.js";
10
+ import type { ValidationComposer, ValidationComposerOptions, ValidationStep } from "./validationComposer.core.js";
11
+ /** Makes a validation step optional. Undefined values bypass the validator. */
12
+ export declare function optional<T>(validator: ValidationStep<T>): ValidationStep<T | undefined>;
13
+ /** Makes a validation step nullable. Null values bypass the validator. */
14
+ export declare function nullable<T>(validator: ValidationStep<T>): ValidationStep<T | null>;
15
+ /** Makes a validation step optional and nullable. */
16
+ export declare function optionalNullable<T>(validator: ValidationStep<T>): ValidationStep<T | null | undefined>;
17
+ /** Adds a custom validation step to an existing pipeline. */
18
+ export declare function append<T>(composer: ValidationComposer<T>, step: ValidationStep<T>, options?: ValidationComposerOptions): ValidationComposer<T>;
19
+ /** Creates a pipeline that validates a value and returns the original value. */
20
+ export declare function tap<T>(validator: ValidationStep<T>): ValidationStep<T>;
21
+ /** Creates a validation step that only runs when a predicate matches. */
22
+ export declare function when<T>(predicate: (value: T) => boolean, validator: ValidationStep<T>): ValidationStep<T>;
23
+ /** Creates a validation step that runs only when a predicate does not match. */
24
+ export declare function unless<T>(predicate: (value: T) => boolean, validator: ValidationStep<T>): ValidationStep<T>;
25
+ /**
26
+ * Applies a mapping operation after successful validation.
27
+ *
28
+ * @returns A step producing the mapped value.
29
+ */
30
+ export declare function mapValidated<T, U>(validator: ValidationStep<T>, mapper: (value: T) => U): (value: T) => ValidationResult<U>;
31
+ /**
32
+ * Applies a side effect after successful validation, keeping the value.
33
+ *
34
+ * The counterpart to {@link mapValidated} for callers that want to observe a
35
+ * validated value without changing it.
36
+ */
37
+ export declare function tapValidated<T>(validator: ValidationStep<T>, observe: (value: T) => void): ValidationStep<T>;
38
+ //# sourceMappingURL=validationComposer.wrappers.d.ts.map
@@ -0,0 +1,96 @@
1
+ /**
2
+ * @zudojs/validation — Wrappers that adapt a validation step.
3
+ *
4
+ * Optionality, conditionality and post-validation mapping, kept apart from the
5
+ * combinators that fold several steps into one.
6
+ *
7
+ * @module validationComposer/validationComposer.wrappers
8
+ */
9
+ import { success } from "../validationResult/validationResult.type.js";
10
+ import { createValidationComposer } from "./validationComposer.core.js";
11
+ /** Makes a validation step optional. Undefined values bypass the validator. */
12
+ export function optional(validator) {
13
+ return (value) => {
14
+ if (value === undefined)
15
+ return success(undefined);
16
+ return validator(value);
17
+ };
18
+ }
19
+ /** Makes a validation step nullable. Null values bypass the validator. */
20
+ export function nullable(validator) {
21
+ return (value) => {
22
+ if (value === null)
23
+ return success(null);
24
+ return validator(value);
25
+ };
26
+ }
27
+ /** Makes a validation step optional and nullable. */
28
+ export function optionalNullable(validator) {
29
+ return (value) => {
30
+ if (value === null || value === undefined)
31
+ return success(value);
32
+ return validator(value);
33
+ };
34
+ }
35
+ /** Adds a custom validation step to an existing pipeline. */
36
+ export function append(composer, step, options = {}) {
37
+ return createValidationComposer([(value) => composer.validate(value), step], {
38
+ ...options,
39
+ name: options.name ?? composer.name,
40
+ stopOnFirstError: options.stopOnFirstError ?? composer.stopOnFirstError,
41
+ });
42
+ }
43
+ /** Creates a pipeline that validates a value and returns the original value. */
44
+ export function tap(validator) {
45
+ return (value) => {
46
+ const result = validator(value);
47
+ if (!result.success)
48
+ return result;
49
+ return success(value);
50
+ };
51
+ }
52
+ /** Creates a validation step that only runs when a predicate matches. */
53
+ export function when(predicate, validator) {
54
+ return (value) => {
55
+ if (!predicate(value))
56
+ return success(value);
57
+ return validator(value);
58
+ };
59
+ }
60
+ /** Creates a validation step that runs only when a predicate does not match. */
61
+ export function unless(predicate, validator) {
62
+ return (value) => {
63
+ if (predicate(value))
64
+ return success(value);
65
+ return validator(value);
66
+ };
67
+ }
68
+ /**
69
+ * Applies a mapping operation after successful validation.
70
+ *
71
+ * @returns A step producing the mapped value.
72
+ */
73
+ export function mapValidated(validator, mapper) {
74
+ return (value) => {
75
+ const result = validator(value);
76
+ if (!result.success)
77
+ return result;
78
+ return success(mapper(result.data));
79
+ };
80
+ }
81
+ /**
82
+ * Applies a side effect after successful validation, keeping the value.
83
+ *
84
+ * The counterpart to {@link mapValidated} for callers that want to observe a
85
+ * validated value without changing it.
86
+ */
87
+ export function tapValidated(validator, observe) {
88
+ return (value) => {
89
+ const result = validator(value);
90
+ if (!result.success)
91
+ return result;
92
+ observe(result.data);
93
+ return success(result.data);
94
+ };
95
+ }
96
+ //# sourceMappingURL=validationComposer.wrappers.js.map
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @zudojs/validation — Collection constraints.
3
+ *
4
+ * @module validationConstraints/collection
5
+ */
6
+ export * from "./validationConstraints.array.js";
7
+ export * from "./validationConstraints.collection.js";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @zudojs/validation — Collection constraints.
3
+ *
4
+ * @module validationConstraints/collection
5
+ */
6
+ export * from "./validationConstraints.array.js";
7
+ export * from "./validationConstraints.collection.js";
8
+ //# sourceMappingURL=index.js.map
@@ -1,4 +1,4 @@
1
- import type { ValidationConstraint } from "./validationConstraints.base.js";
1
+ import type { ValidationConstraint } from "../validationConstraints.base.js";
2
2
  /**
3
3
  * Requires an array to contain at least a given number of items.
4
4
  */
@@ -1,4 +1,19 @@
1
- import { createConstraint, assertNonNegativeInteger, } from "./validationConstraints.base.js";
1
+ import { createConstraint, assertNonNegativeInteger, } from "../validationConstraints.base.js";
2
+ /** Narrows an unknown value to a readonly array. */
3
+ function isArrayOf(value) {
4
+ return Array.isArray(value);
5
+ }
6
+ /** Runs an item constraint without letting a type mismatch escape. */
7
+ function itemHolds(constraint, value) {
8
+ if (constraint.guard && !constraint.guard(value))
9
+ return false;
10
+ try {
11
+ return constraint.validate(value);
12
+ }
13
+ catch {
14
+ return false;
15
+ }
16
+ }
2
17
  /**
3
18
  * Requires an array to contain at least a given number of items.
4
19
  */
@@ -8,6 +23,7 @@ export function minItems(minimum) {
8
23
  name: `min_items_${minimum}`,
9
24
  code: "min_items",
10
25
  message: `Value must contain at least ${minimum} items.`,
26
+ guard: isArrayOf,
11
27
  });
12
28
  }
13
29
  /**
@@ -19,6 +35,7 @@ export function maxItems(maximum) {
19
35
  name: `max_items_${maximum}`,
20
36
  code: "max_items",
21
37
  message: `Value must contain at most ${maximum} items.`,
38
+ guard: isArrayOf,
22
39
  });
23
40
  }
24
41
  /**
@@ -30,26 +47,29 @@ export function exactItems(length) {
30
47
  name: `exact_items_${length}`,
31
48
  code: "exact_items",
32
49
  message: `Value must contain exactly ${length} items.`,
50
+ guard: isArrayOf,
33
51
  });
34
52
  }
35
53
  /**
36
54
  * Requires every array item to satisfy a constraint.
37
55
  */
38
56
  export function everyItem(constraint) {
39
- return createConstraint((values) => values.every((value) => constraint.validate(value)), {
57
+ return createConstraint((values) => values.every((value) => itemHolds(constraint, value)), {
40
58
  name: `every_${constraint.name}`,
41
59
  code: "item_constraint_failed",
42
60
  message: constraint.message,
61
+ guard: isArrayOf,
43
62
  });
44
63
  }
45
64
  /**
46
65
  * Requires at least one array item to satisfy a constraint.
47
66
  */
48
67
  export function someItem(constraint) {
49
- return createConstraint((values) => values.some((value) => constraint.validate(value)), {
68
+ return createConstraint((values) => values.some((value) => itemHolds(constraint, value)), {
50
69
  name: `some_${constraint.name}`,
51
70
  code: "some_item_constraint_failed",
52
71
  message: `At least one item must satisfy ${constraint.name}.`,
72
+ guard: isArrayOf,
53
73
  });
54
74
  }
55
75
  //# sourceMappingURL=validationConstraints.array.js.map
@@ -1,4 +1,4 @@
1
- import type { ValidationConstraint } from "./validationConstraints.base.js";
1
+ import type { ValidationConstraint } from "../validationConstraints.base.js";
2
2
  /**
3
3
  * Requires a value to belong to a provided collection.
4
4
  */
@@ -1,4 +1,4 @@
1
- import { createConstraint, not } from "./validationConstraints.base.js";
1
+ import { createConstraint, not } from "../validationConstraints.base.js";
2
2
  /**
3
3
  * Requires a value to belong to a provided collection.
4
4
  */
@@ -5,12 +5,7 @@
5
5
  */
6
6
  export { createConstraint, checkConstraint, checkConstraints, combineConstraints, not, required, assertNonNegativeInteger, } from "./validationConstraints.base.js";
7
7
  export type { ValidationConstraint, ConstraintOptions, } from "./validationConstraints.base.js";
8
- export { nonEmptyString, minLength, maxLength, lengthBetween, matches, email, uuid, httpUrl, ascii, digits, letters, slug, } from "./validationConstraints.string.js";
9
- export { min, max, between, finiteNumber, integer, positive, nonNegative, even, odd, } from "./validationConstraints.number.js";
10
- export { oneOf, noneOf } from "./validationConstraints.collection.js";
11
- export { isoDate, futureDate, pastDate } from "./validationConstraints.date.js";
12
- export { minItems, maxItems, exactItems, everyItem, someItem, } from "./validationConstraints.array.js";
13
- export { assertNoCircularReference, hasCircularReference, } from "./validationConstraints.circular.js";
14
- export { getSerializationDepth, assertDepthWithinLimit, } from "./validationConstraints.depth.js";
15
- export { estimateSerializedSize, assertSizeWithinLimit, } from "./validationConstraints.size.js";
8
+ export * from "./scalar/index.js";
9
+ export * from "./collection/index.js";
10
+ export * from "./structure/index.js";
16
11
  //# sourceMappingURL=index.d.ts.map