@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.
- package/LICENSE +21 -0
- package/README.md +31 -0
- package/dist/validationComposer/index.d.ts +3 -1
- package/dist/validationComposer/index.js +3 -1
- package/dist/validationComposer/validationComposer.combinators.d.ts +21 -0
- package/dist/validationComposer/validationComposer.combinators.js +78 -0
- package/dist/validationComposer/validationComposer.core.d.ts +10 -24
- package/dist/validationComposer/validationComposer.core.js +2 -139
- package/dist/validationComposer/validationComposer.wrappers.d.ts +38 -0
- package/dist/validationComposer/validationComposer.wrappers.js +96 -0
- package/dist/validationConstraints/collection/index.d.ts +8 -0
- package/dist/validationConstraints/collection/index.js +8 -0
- package/dist/validationConstraints/{validationConstraints.array.d.ts → collection/validationConstraints.array.d.ts} +1 -1
- package/dist/validationConstraints/{validationConstraints.array.js → collection/validationConstraints.array.js} +23 -3
- package/dist/validationConstraints/{validationConstraints.collection.d.ts → collection/validationConstraints.collection.d.ts} +1 -1
- package/dist/validationConstraints/{validationConstraints.collection.js → collection/validationConstraints.collection.js} +1 -1
- package/dist/validationConstraints/index.d.ts +3 -8
- package/dist/validationConstraints/index.js +6 -16
- package/dist/validationConstraints/scalar/index.d.ts +9 -0
- package/dist/validationConstraints/scalar/index.js +9 -0
- package/dist/validationConstraints/scalar/validationConstraints.date.d.ts +13 -0
- package/dist/validationConstraints/scalar/validationConstraints.date.js +45 -0
- package/dist/validationConstraints/{validationConstraints.number.d.ts → scalar/validationConstraints.number.d.ts} +1 -1
- package/dist/validationConstraints/{validationConstraints.number.js → scalar/validationConstraints.number.js} +12 -1
- package/dist/validationConstraints/{validationConstraints.string.d.ts → scalar/validationConstraints.string.d.ts} +18 -3
- package/dist/validationConstraints/{validationConstraints.string.js → scalar/validationConstraints.string.js} +49 -13
- package/dist/validationConstraints/structure/index.d.ts +10 -0
- package/dist/validationConstraints/structure/index.js +10 -0
- package/dist/validationConstraints/{validationConstraints.circular.d.ts → structure/validationConstraints.circular.d.ts} +8 -4
- package/dist/validationConstraints/structure/validationConstraints.circular.js +55 -0
- package/dist/validationConstraints/structure/validationConstraints.depth.d.ts +37 -0
- package/dist/validationConstraints/structure/validationConstraints.depth.js +58 -0
- package/dist/validationConstraints/structure/validationConstraints.size.d.ts +31 -0
- package/dist/validationConstraints/structure/validationConstraints.size.js +101 -0
- package/dist/validationConstraints/structure/validationConstraints.traverse.d.ts +57 -0
- package/dist/validationConstraints/structure/validationConstraints.traverse.js +118 -0
- package/dist/validationConstraints/validationConstraints.base.d.ts +18 -3
- package/dist/validationConstraints/validationConstraints.base.js +50 -25
- package/dist/validationErrors/validationError.base.js +28 -1
- package/dist/validationFactory/validationFactory.core.d.ts +9 -8
- package/dist/validationFactory/validationFactory.core.js +11 -9
- package/dist/validationNormalizer/validationNormalizer.core.js +2 -4
- package/dist/validationNormalizer/validationNormalizer.helpers.d.ts +36 -3
- package/dist/validationNormalizer/validationNormalizer.helpers.js +48 -7
- package/dist/validationParser/index.d.ts +2 -1
- package/dist/validationParser/index.js +2 -1
- package/dist/validationParser/validationParser.collection.d.ts +28 -0
- package/dist/validationParser/validationParser.collection.js +98 -0
- package/dist/validationParser/validationParser.core.d.ts +0 -12
- package/dist/validationParser/validationParser.core.js +0 -71
- package/dist/validationRegistry/validationRegistry.core.d.ts +8 -0
- package/dist/validationRegistry/validationRegistry.core.js +15 -1
- package/dist/validationResult/validationResult.type.d.ts +8 -1
- package/dist/validationResult/validationResult.type.js +20 -5
- package/dist/validationTransformer/index.d.ts +2 -1
- package/dist/validationTransformer/index.js +2 -1
- package/dist/validationTransformer/validationTransformer.core.d.ts +0 -15
- package/dist/validationTransformer/validationTransformer.core.js +5 -56
- package/dist/validationTransformer/validationTransformer.helpers.d.ts +23 -0
- package/dist/validationTransformer/validationTransformer.helpers.js +67 -0
- package/package.json +24 -13
- package/dist/.tsbuildinfo +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/validationComposer/index.d.ts.map +0 -1
- package/dist/validationComposer/index.js.map +0 -1
- package/dist/validationComposer/validationComposer.core.d.ts.map +0 -1
- package/dist/validationComposer/validationComposer.core.js.map +0 -1
- package/dist/validationConstraints/index.d.ts.map +0 -1
- package/dist/validationConstraints/index.js.map +0 -1
- package/dist/validationConstraints/validationConstraints.array.d.ts.map +0 -1
- package/dist/validationConstraints/validationConstraints.array.js.map +0 -1
- package/dist/validationConstraints/validationConstraints.base.d.ts.map +0 -1
- package/dist/validationConstraints/validationConstraints.base.js.map +0 -1
- package/dist/validationConstraints/validationConstraints.circular.d.ts.map +0 -1
- package/dist/validationConstraints/validationConstraints.circular.js +0 -73
- package/dist/validationConstraints/validationConstraints.circular.js.map +0 -1
- package/dist/validationConstraints/validationConstraints.collection.d.ts.map +0 -1
- package/dist/validationConstraints/validationConstraints.collection.js.map +0 -1
- package/dist/validationConstraints/validationConstraints.date.d.ts +0 -14
- package/dist/validationConstraints/validationConstraints.date.d.ts.map +0 -1
- package/dist/validationConstraints/validationConstraints.date.js +0 -30
- package/dist/validationConstraints/validationConstraints.date.js.map +0 -1
- package/dist/validationConstraints/validationConstraints.depth.d.ts +0 -20
- package/dist/validationConstraints/validationConstraints.depth.d.ts.map +0 -1
- package/dist/validationConstraints/validationConstraints.depth.js +0 -70
- package/dist/validationConstraints/validationConstraints.depth.js.map +0 -1
- package/dist/validationConstraints/validationConstraints.number.d.ts.map +0 -1
- package/dist/validationConstraints/validationConstraints.number.js.map +0 -1
- package/dist/validationConstraints/validationConstraints.size.d.ts +0 -20
- package/dist/validationConstraints/validationConstraints.size.d.ts.map +0 -1
- package/dist/validationConstraints/validationConstraints.size.js +0 -82
- package/dist/validationConstraints/validationConstraints.size.js.map +0 -1
- package/dist/validationConstraints/validationConstraints.string.d.ts.map +0 -1
- package/dist/validationConstraints/validationConstraints.string.js.map +0 -1
- package/dist/validationErrors/index.d.ts.map +0 -1
- package/dist/validationErrors/index.js.map +0 -1
- package/dist/validationErrors/validationError.base.d.ts.map +0 -1
- package/dist/validationErrors/validationError.base.js.map +0 -1
- package/dist/validationErrors/validationError.types.d.ts.map +0 -1
- package/dist/validationErrors/validationError.types.js.map +0 -1
- package/dist/validationFactory/index.d.ts.map +0 -1
- package/dist/validationFactory/index.js.map +0 -1
- package/dist/validationFactory/validationFactory.core.d.ts.map +0 -1
- package/dist/validationFactory/validationFactory.core.js.map +0 -1
- package/dist/validationNormalizer/index.d.ts.map +0 -1
- package/dist/validationNormalizer/index.js.map +0 -1
- package/dist/validationNormalizer/validationNormalizer.core.d.ts.map +0 -1
- package/dist/validationNormalizer/validationNormalizer.core.js.map +0 -1
- package/dist/validationNormalizer/validationNormalizer.helpers.d.ts.map +0 -1
- package/dist/validationNormalizer/validationNormalizer.helpers.js.map +0 -1
- package/dist/validationParser/index.d.ts.map +0 -1
- package/dist/validationParser/index.js.map +0 -1
- package/dist/validationParser/validationParser.core.d.ts.map +0 -1
- package/dist/validationParser/validationParser.core.js.map +0 -1
- package/dist/validationRegistry/index.d.ts.map +0 -1
- package/dist/validationRegistry/index.js.map +0 -1
- package/dist/validationRegistry/validationRegistry.core.d.ts.map +0 -1
- package/dist/validationRegistry/validationRegistry.core.js.map +0 -1
- package/dist/validationRegistry/validationRegistry.readonly.d.ts.map +0 -1
- package/dist/validationRegistry/validationRegistry.readonly.js.map +0 -1
- package/dist/validationResult/index.d.ts.map +0 -1
- package/dist/validationResult/index.js.map +0 -1
- package/dist/validationResult/validationResult.type.d.ts.map +0 -1
- package/dist/validationResult/validationResult.type.js.map +0 -1
- package/dist/validationSchema/index.d.ts.map +0 -1
- package/dist/validationSchema/index.js.map +0 -1
- package/dist/validationSchema/validationSchema.core.d.ts.map +0 -1
- package/dist/validationSchema/validationSchema.core.js.map +0 -1
- package/dist/validationTransformer/index.d.ts.map +0 -1
- package/dist/validationTransformer/index.js.map +0 -1
- package/dist/validationTransformer/validationTransformer.core.d.ts.map +0 -1
- package/dist/validationTransformer/validationTransformer.core.js.map +0 -1
|
@@ -21,17 +21,52 @@ export function normalizeUppercase(value) {
|
|
|
21
21
|
export function normalizeUnicode(value) {
|
|
22
22
|
return value.normalize("NFC");
|
|
23
23
|
}
|
|
24
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* Normalizes Unicode text using NFKC, folding compatibility forms.
|
|
26
|
+
*
|
|
27
|
+
* Use this wherever the result identifies something. NFC is canonical only:
|
|
28
|
+
* it leaves ligatures and fullwidth forms distinct from their ASCII
|
|
29
|
+
* spellings, so two visually identical identifiers survive as two values.
|
|
30
|
+
*/
|
|
31
|
+
export function normalizeUnicodeCompatibility(value) {
|
|
32
|
+
return value.normalize("NFKC");
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Case-folds a string for identifier comparison.
|
|
36
|
+
*
|
|
37
|
+
* `toLowerCase` is a locale-sensitive display transform. Folding through
|
|
38
|
+
* upper- then lower-case is the closest stable approximation available
|
|
39
|
+
* without ICU, and is what identifier comparison needs.
|
|
40
|
+
*/
|
|
41
|
+
export function foldCase(value) {
|
|
42
|
+
return value.toUpperCase().toLowerCase();
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Normalizes an email address.
|
|
46
|
+
*
|
|
47
|
+
* Only the domain is lowercased. The local part is case-sensitive per RFC
|
|
48
|
+
* 5321, and folding it can merge two distinct mailboxes.
|
|
49
|
+
*/
|
|
25
50
|
export function normalizeEmail(value) {
|
|
26
|
-
|
|
51
|
+
const trimmed = normalizeUnicodeCompatibility(normalizeWhitespace(value));
|
|
52
|
+
const at = trimmed.lastIndexOf("@");
|
|
53
|
+
if (at === -1)
|
|
54
|
+
return trimmed;
|
|
55
|
+
return `${trimmed.slice(0, at)}@${foldCase(trimmed.slice(at + 1))}`;
|
|
27
56
|
}
|
|
28
57
|
/** Normalizes a URL by removing surrounding whitespace. */
|
|
29
58
|
export function normalizeUrl(value) {
|
|
30
59
|
return normalizeWhitespace(normalizeUnicode(value));
|
|
31
60
|
}
|
|
32
|
-
/**
|
|
61
|
+
/**
|
|
62
|
+
* Normalizes an identifier by trimming, compatibility-folding and case-folding.
|
|
63
|
+
*
|
|
64
|
+
* The output identifies an account or a resource, so it uses NFKC and a case
|
|
65
|
+
* fold rather than NFC and `toLowerCase`: otherwise two spellings that render
|
|
66
|
+
* identically normalize to two different identifiers.
|
|
67
|
+
*/
|
|
33
68
|
export function normalizeIdentifier(value) {
|
|
34
|
-
return
|
|
69
|
+
return foldCase(normalizeWhitespace(normalizeUnicodeCompatibility(value)));
|
|
35
70
|
}
|
|
36
71
|
/** Removes surrounding quotes from a string. */
|
|
37
72
|
export function normalizeQuotes(value) {
|
|
@@ -47,13 +82,19 @@ export function normalizeQuotes(value) {
|
|
|
47
82
|
export function removeBom(value) {
|
|
48
83
|
return value.replace(/^\uFEFF/u, "");
|
|
49
84
|
}
|
|
50
|
-
/**
|
|
85
|
+
/**
|
|
86
|
+
* Normalizes an array by applying a normalizer to every item.
|
|
87
|
+
*
|
|
88
|
+
* The normalizer is invoked with the value only. Passing it straight to `map`
|
|
89
|
+
* would also hand it the index and the array, which silently overrides the
|
|
90
|
+
* optional second parameter of functions like `parseInt`.
|
|
91
|
+
*/
|
|
51
92
|
export function normalizeArray(values, normalizer) {
|
|
52
|
-
return values.map(normalizer);
|
|
93
|
+
return values.map((value) => normalizer(value));
|
|
53
94
|
}
|
|
54
95
|
/** Normalizes an array asynchronously. */
|
|
55
96
|
export async function normalizeArrayAsync(values, normalizer) {
|
|
56
|
-
return Promise.all(values.map(normalizer));
|
|
97
|
+
return Promise.all(values.map((value) => normalizer(value)));
|
|
57
98
|
}
|
|
58
99
|
/** Composes multiple normalizers into one. */
|
|
59
100
|
export function composeNormalizers(...normalizers) {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @zudojs/validation/validationParser
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Reusable parsers built from validation schemas.
|
|
5
5
|
*/
|
|
6
6
|
export * from "./validationParser.core.js";
|
|
7
|
+
export * from "./validationParser.collection.js";
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @zudojs/validation/validationParser
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Reusable parsers built from validation schemas.
|
|
5
5
|
*/
|
|
6
6
|
export * from "./validationParser.core.js";
|
|
7
|
+
export * from "./validationParser.collection.js";
|
|
7
8
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @zudojs/validation — Parsing collections of values.
|
|
3
|
+
*
|
|
4
|
+
* @module validationParser/validationParser.collection
|
|
5
|
+
*/
|
|
6
|
+
import type { ParseOptions, ValidationSchema } from "../validationSchema/validationSchema.core.js";
|
|
7
|
+
import type { ValidationResult } from "../validationResult/validationResult.type.js";
|
|
8
|
+
/** Parses multiple values using the same schema. Succeeds only when every value is valid. */
|
|
9
|
+
export declare function parseMany<T>(schema: ValidationSchema<T>, values: readonly unknown[]): ValidationResult<readonly T[]>;
|
|
10
|
+
/** Parses multiple values asynchronously. */
|
|
11
|
+
export declare function parseManyAsync<T>(schema: ValidationSchema<T>, values: readonly unknown[]): Promise<ValidationResult<readonly T[]>>;
|
|
12
|
+
/**
|
|
13
|
+
* Parses a record of values using a schema.
|
|
14
|
+
*
|
|
15
|
+
* Results accumulate into a null-prototype object and are installed with
|
|
16
|
+
* `defineProperty`. A plain literal would route a `__proto__` key — which
|
|
17
|
+
* `JSON.parse` produces as a real own property — through the prototype setter,
|
|
18
|
+
* so the returned "validated" object would silently inherit attacker-supplied
|
|
19
|
+
* fields that `Object.keys` does not show.
|
|
20
|
+
*/
|
|
21
|
+
export declare function parseRecord<T>(schema: ValidationSchema<T>, values: Readonly<Record<string, unknown>>): ValidationResult<Readonly<Record<string, T>>>;
|
|
22
|
+
/** Parses an optional value. Undefined is accepted and returned as undefined. */
|
|
23
|
+
export declare function parseOptional<T>(schema: ValidationSchema<T>, value: unknown, options?: ParseOptions): ValidationResult<T | undefined>;
|
|
24
|
+
/** Parses a nullable value. Null is accepted and returned as null. */
|
|
25
|
+
export declare function parseNullable<T>(schema: ValidationSchema<T>, value: unknown, options?: ParseOptions): ValidationResult<T | null>;
|
|
26
|
+
/** Parses an optional nullable value. */
|
|
27
|
+
export declare function parseOptionalNullable<T>(schema: ValidationSchema<T>, value: unknown, options?: ParseOptions): ValidationResult<T | null | undefined>;
|
|
28
|
+
//# sourceMappingURL=validationParser.collection.d.ts.map
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @zudojs/validation — Parsing collections of values.
|
|
3
|
+
*
|
|
4
|
+
* @module validationParser/validationParser.collection
|
|
5
|
+
*/
|
|
6
|
+
import { validate, validateAsync, } from "../validationSchema/validationSchema.core.js";
|
|
7
|
+
import { failure, success } from "../validationResult/validationResult.type.js";
|
|
8
|
+
/** Property names that would mutate a prototype instead of adding a key. */
|
|
9
|
+
const FORBIDDEN_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
10
|
+
/** Parses multiple values using the same schema. Succeeds only when every value is valid. */
|
|
11
|
+
export function parseMany(schema, values) {
|
|
12
|
+
const parsed = [];
|
|
13
|
+
const issues = [];
|
|
14
|
+
for (let index = 0; index < values.length; index++) {
|
|
15
|
+
const result = validate(schema, values[index], { pathPrefix: [index] });
|
|
16
|
+
if (result.success) {
|
|
17
|
+
parsed.push(result.data);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
issues.push(...result.issues);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return issues.length > 0 ? failure(issues) : success(parsed);
|
|
24
|
+
}
|
|
25
|
+
/** Parses multiple values asynchronously. */
|
|
26
|
+
export async function parseManyAsync(schema, values) {
|
|
27
|
+
const parsed = [];
|
|
28
|
+
const issues = [];
|
|
29
|
+
for (let index = 0; index < values.length; index++) {
|
|
30
|
+
const result = await validateAsync(schema, values[index], {
|
|
31
|
+
pathPrefix: [index],
|
|
32
|
+
});
|
|
33
|
+
if (result.success) {
|
|
34
|
+
parsed.push(result.data);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
issues.push(...result.issues);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return issues.length > 0 ? failure(issues) : success(parsed);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Parses a record of values using a schema.
|
|
44
|
+
*
|
|
45
|
+
* Results accumulate into a null-prototype object and are installed with
|
|
46
|
+
* `defineProperty`. A plain literal would route a `__proto__` key — which
|
|
47
|
+
* `JSON.parse` produces as a real own property — through the prototype setter,
|
|
48
|
+
* so the returned "validated" object would silently inherit attacker-supplied
|
|
49
|
+
* fields that `Object.keys` does not show.
|
|
50
|
+
*/
|
|
51
|
+
export function parseRecord(schema, values) {
|
|
52
|
+
const parsed = Object.create(null);
|
|
53
|
+
const issues = [];
|
|
54
|
+
for (const [key, value] of Object.entries(values)) {
|
|
55
|
+
if (FORBIDDEN_KEYS.has(key)) {
|
|
56
|
+
issues.push({
|
|
57
|
+
path: [key],
|
|
58
|
+
code: "forbidden_key",
|
|
59
|
+
message: `Key "${key}" is not allowed.`,
|
|
60
|
+
});
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const result = validate(schema, value, { pathPrefix: [key] });
|
|
64
|
+
if (result.success) {
|
|
65
|
+
Object.defineProperty(parsed, key, {
|
|
66
|
+
value: result.data,
|
|
67
|
+
enumerable: true,
|
|
68
|
+
writable: false,
|
|
69
|
+
configurable: false,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
issues.push(...result.issues);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return issues.length > 0
|
|
77
|
+
? failure(issues)
|
|
78
|
+
: { success: true, data: Object.freeze(parsed), issues: [] };
|
|
79
|
+
}
|
|
80
|
+
/** Parses an optional value. Undefined is accepted and returned as undefined. */
|
|
81
|
+
export function parseOptional(schema, value, options = {}) {
|
|
82
|
+
if (value === undefined)
|
|
83
|
+
return success(undefined);
|
|
84
|
+
return validate(schema, value, options);
|
|
85
|
+
}
|
|
86
|
+
/** Parses a nullable value. Null is accepted and returned as null. */
|
|
87
|
+
export function parseNullable(schema, value, options = {}) {
|
|
88
|
+
if (value === null)
|
|
89
|
+
return success(null);
|
|
90
|
+
return validate(schema, value, options);
|
|
91
|
+
}
|
|
92
|
+
/** Parses an optional nullable value. */
|
|
93
|
+
export function parseOptionalNullable(schema, value, options = {}) {
|
|
94
|
+
if (value === undefined || value === null)
|
|
95
|
+
return success(value);
|
|
96
|
+
return validate(schema, value, options);
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=validationParser.collection.js.map
|
|
@@ -27,16 +27,4 @@ export declare function createAsyncValidationParser<T>(schema: ValidationSchema<
|
|
|
27
27
|
export declare function parseOr<T>(schema: ValidationSchema<T>, value: unknown, fallback: T): T;
|
|
28
28
|
/** Parses a value and returns a fallback produced by a function when validation fails. */
|
|
29
29
|
export declare function parseOrElse<T>(schema: ValidationSchema<T>, value: unknown, fallback: (error: SchemaValidationError) => T): T;
|
|
30
|
-
/** Parses multiple values using the same schema. Succeeds only when every value is valid. */
|
|
31
|
-
export declare function parseMany<T>(schema: ValidationSchema<T>, values: readonly unknown[]): ValidationResult<readonly T[]>;
|
|
32
|
-
/** Parses multiple values asynchronously. */
|
|
33
|
-
export declare function parseManyAsync<T>(schema: ValidationSchema<T>, values: readonly unknown[]): Promise<ValidationResult<readonly T[]>>;
|
|
34
|
-
/** Parses a record of values using a schema. */
|
|
35
|
-
export declare function parseRecord<T>(schema: ValidationSchema<T>, values: Readonly<Record<string, unknown>>): ValidationResult<Readonly<Record<string, T>>>;
|
|
36
|
-
/** Parses an optional value. Undefined is accepted and returned as undefined. */
|
|
37
|
-
export declare function parseOptional<T>(schema: ValidationSchema<T>, value: unknown): ValidationResult<T | undefined>;
|
|
38
|
-
/** Parses a nullable value. Null is accepted and returned as null. */
|
|
39
|
-
export declare function parseNullable<T>(schema: ValidationSchema<T>, value: unknown): ValidationResult<T | null>;
|
|
40
|
-
/** Parses an optional nullable value. */
|
|
41
|
-
export declare function parseOptionalNullable<T>(schema: ValidationSchema<T>, value: unknown): ValidationResult<T | null | undefined>;
|
|
42
30
|
//# sourceMappingURL=validationParser.core.d.ts.map
|
|
@@ -44,75 +44,4 @@ export function parseOrElse(schema, value, fallback) {
|
|
|
44
44
|
return result.data;
|
|
45
45
|
return fallback(new SchemaValidationError("Schema validation failed.", result.issues));
|
|
46
46
|
}
|
|
47
|
-
/** Parses multiple values using the same schema. Succeeds only when every value is valid. */
|
|
48
|
-
export function parseMany(schema, values) {
|
|
49
|
-
const parsed = [];
|
|
50
|
-
const issues = [];
|
|
51
|
-
for (let index = 0; index < values.length; index++) {
|
|
52
|
-
const result = validate(schema, values[index], { pathPrefix: [index] });
|
|
53
|
-
if (result.success) {
|
|
54
|
-
parsed.push(result.data);
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
issues.push(...result.issues);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return issues.length > 0
|
|
61
|
-
? { success: false, data: undefined, issues }
|
|
62
|
-
: { success: true, data: parsed, issues: [] };
|
|
63
|
-
}
|
|
64
|
-
/** Parses multiple values asynchronously. */
|
|
65
|
-
export async function parseManyAsync(schema, values) {
|
|
66
|
-
const parsed = [];
|
|
67
|
-
const issues = [];
|
|
68
|
-
for (let index = 0; index < values.length; index++) {
|
|
69
|
-
const result = await validateAsync(schema, values[index], {
|
|
70
|
-
pathPrefix: [index],
|
|
71
|
-
});
|
|
72
|
-
if (result.success) {
|
|
73
|
-
parsed.push(result.data);
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
issues.push(...result.issues);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return issues.length > 0
|
|
80
|
-
? { success: false, data: undefined, issues }
|
|
81
|
-
: { success: true, data: parsed, issues: [] };
|
|
82
|
-
}
|
|
83
|
-
/** Parses a record of values using a schema. */
|
|
84
|
-
export function parseRecord(schema, values) {
|
|
85
|
-
const parsed = {};
|
|
86
|
-
const issues = [];
|
|
87
|
-
for (const [key, value] of Object.entries(values)) {
|
|
88
|
-
const result = validate(schema, value, { pathPrefix: [key] });
|
|
89
|
-
if (result.success) {
|
|
90
|
-
parsed[key] = result.data;
|
|
91
|
-
}
|
|
92
|
-
else {
|
|
93
|
-
issues.push(...result.issues);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return issues.length > 0
|
|
97
|
-
? { success: false, data: undefined, issues }
|
|
98
|
-
: { success: true, data: Object.freeze(parsed), issues: [] };
|
|
99
|
-
}
|
|
100
|
-
/** Parses an optional value. Undefined is accepted and returned as undefined. */
|
|
101
|
-
export function parseOptional(schema, value) {
|
|
102
|
-
if (value === undefined)
|
|
103
|
-
return { success: true, data: undefined, issues: [] };
|
|
104
|
-
return validate(schema, value);
|
|
105
|
-
}
|
|
106
|
-
/** Parses a nullable value. Null is accepted and returned as null. */
|
|
107
|
-
export function parseNullable(schema, value) {
|
|
108
|
-
if (value === null)
|
|
109
|
-
return { success: true, data: null, issues: [] };
|
|
110
|
-
return validate(schema, value);
|
|
111
|
-
}
|
|
112
|
-
/** Parses an optional nullable value. */
|
|
113
|
-
export function parseOptionalNullable(schema, value) {
|
|
114
|
-
if (value === undefined || value === null)
|
|
115
|
-
return { success: true, data: value, issues: [] };
|
|
116
|
-
return validate(schema, value);
|
|
117
|
-
}
|
|
118
47
|
//# sourceMappingURL=validationParser.core.js.map
|
|
@@ -33,6 +33,14 @@ export declare class ValidationRegistry {
|
|
|
33
33
|
entries(): readonly ValidationRule[];
|
|
34
34
|
get size(): number;
|
|
35
35
|
clear(): void;
|
|
36
|
+
/**
|
|
37
|
+
* Validate a value against a registered rule.
|
|
38
|
+
*
|
|
39
|
+
* Constraints receive whatever the caller passed, which at a trust boundary
|
|
40
|
+
* is arbitrary JSON. `checkConstraints` guards and catches internally, so a
|
|
41
|
+
* wrong-typed value reports as a validation failure rather than escaping as
|
|
42
|
+
* a `TypeError` and turning a 400 into a 500.
|
|
43
|
+
*/
|
|
36
44
|
validate<T>(name: string, value: unknown): ValidationResult<T>;
|
|
37
45
|
clone(): ValidationRegistry;
|
|
38
46
|
extend(source: ValidationRegistry, options?: ValidationRuleOptions): this;
|
|
@@ -18,7 +18,13 @@ export class ValidationRegistry {
|
|
|
18
18
|
if (!rule.schema && (!rule.constraints || rule.constraints.length === 0)) {
|
|
19
19
|
throw new TypeError(`Validation rule "${name}" must define a schema or at least one constraint.`);
|
|
20
20
|
}
|
|
21
|
-
this.rules.set(name, Object.freeze({
|
|
21
|
+
this.rules.set(name, Object.freeze({
|
|
22
|
+
...rule,
|
|
23
|
+
name,
|
|
24
|
+
...(rule.constraints
|
|
25
|
+
? { constraints: Object.freeze([...rule.constraints]) }
|
|
26
|
+
: {}),
|
|
27
|
+
}));
|
|
22
28
|
return this;
|
|
23
29
|
}
|
|
24
30
|
registerSchema(name, schema, options = {}) {
|
|
@@ -54,6 +60,14 @@ export class ValidationRegistry {
|
|
|
54
60
|
clear() {
|
|
55
61
|
this.rules.clear();
|
|
56
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Validate a value against a registered rule.
|
|
65
|
+
*
|
|
66
|
+
* Constraints receive whatever the caller passed, which at a trust boundary
|
|
67
|
+
* is arbitrary JSON. `checkConstraints` guards and catches internally, so a
|
|
68
|
+
* wrong-typed value reports as a validation failure rather than escaping as
|
|
69
|
+
* a `TypeError` and turning a 400 into a 500.
|
|
70
|
+
*/
|
|
57
71
|
validate(name, value) {
|
|
58
72
|
const rule = this.require(name);
|
|
59
73
|
if (rule.schema)
|
|
@@ -12,7 +12,14 @@ export interface ValidationIssue {
|
|
|
12
12
|
}
|
|
13
13
|
/** Formats validation issues into a human-readable string. */
|
|
14
14
|
export declare function formatIssues(issues: readonly ValidationIssue[]): string;
|
|
15
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Groups validation issues by their first path segment.
|
|
17
|
+
*
|
|
18
|
+
* Built on a null-prototype object and probed with `Object.hasOwn`. Using `in`
|
|
19
|
+
* against a plain literal reported `constructor`, `toString` and `valueOf` as
|
|
20
|
+
* already present, so a field with one of those names produced no entry and
|
|
21
|
+
* the user saw a rejected form with nothing marked.
|
|
22
|
+
*/
|
|
16
23
|
export declare function toFieldErrors(issues: readonly ValidationIssue[]): Readonly<Record<string, string>>;
|
|
17
24
|
/** A successful validation result. */
|
|
18
25
|
export interface ValidationSuccess<T> {
|
|
@@ -8,15 +8,30 @@ export function formatIssues(issues) {
|
|
|
8
8
|
return "";
|
|
9
9
|
return issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
|
|
10
10
|
}
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Groups validation issues by their first path segment.
|
|
13
|
+
*
|
|
14
|
+
* Built on a null-prototype object and probed with `Object.hasOwn`. Using `in`
|
|
15
|
+
* against a plain literal reported `constructor`, `toString` and `valueOf` as
|
|
16
|
+
* already present, so a field with one of those names produced no entry and
|
|
17
|
+
* the user saw a rejected form with nothing marked.
|
|
18
|
+
*/
|
|
12
19
|
export function toFieldErrors(issues) {
|
|
13
|
-
const result =
|
|
20
|
+
const result = Object.create(null);
|
|
14
21
|
for (const issue of issues) {
|
|
15
22
|
const field = issue.path[0];
|
|
16
|
-
if (typeof field
|
|
17
|
-
|
|
23
|
+
if (typeof field !== "string")
|
|
24
|
+
continue;
|
|
25
|
+
if (Object.hasOwn(result, field))
|
|
26
|
+
continue;
|
|
27
|
+
Object.defineProperty(result, field, {
|
|
28
|
+
value: issue.message,
|
|
29
|
+
enumerable: true,
|
|
30
|
+
writable: false,
|
|
31
|
+
configurable: false,
|
|
32
|
+
});
|
|
18
33
|
}
|
|
19
|
-
return result;
|
|
34
|
+
return Object.freeze(result);
|
|
20
35
|
}
|
|
21
36
|
/** Creates a successful validation result. */
|
|
22
37
|
export function success(data) {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @zudojs/validation/validationTransformer
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Transformation of validated values.
|
|
5
5
|
*/
|
|
6
6
|
export * from "./validationTransformer.core.js";
|
|
7
|
+
export * from "./validationTransformer.helpers.js";
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @zudojs/validation/validationTransformer
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Transformation of validated values.
|
|
5
5
|
*/
|
|
6
6
|
export * from "./validationTransformer.core.js";
|
|
7
|
+
export * from "./validationTransformer.helpers.js";
|
|
7
8
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ValidationSchema } from "../validationSchema/validationSchema.core.js";
|
|
2
1
|
import type { ValidationResult } from "../validationResult/validationResult.type.js";
|
|
3
2
|
/** A synchronous transformation function. */
|
|
4
3
|
export type ValidationTransform<T, U> = (value: T) => U;
|
|
@@ -27,18 +26,4 @@ export interface AsyncValidationTransformer<T, U> {
|
|
|
27
26
|
export declare function createValidationTransformer<T, U>(transform: ValidationTransform<T, U>, options?: TransformerOptions): ValidationTransformer<T, U>;
|
|
28
27
|
/** Creates an asynchronous transformer. */
|
|
29
28
|
export declare function createAsyncValidationTransformer<T, U>(transform: AsyncValidationTransform<T, U>, options?: TransformerOptions): AsyncValidationTransformer<T, U>;
|
|
30
|
-
/** Validates input and then transforms it. */
|
|
31
|
-
export declare function validateAndTransform<T, U>(schema: ValidationSchema<T>, value: unknown, transform: ValidationTransform<T, U>, options?: TransformerOptions): ValidationResult<U>;
|
|
32
|
-
/** Validates input and then transforms it asynchronously. */
|
|
33
|
-
export declare function validateAndTransformAsync<T, U>(schema: ValidationSchema<T>, value: unknown, transform: AsyncValidationTransform<T, U>, options?: TransformerOptions): Promise<ValidationResult<U>>;
|
|
34
|
-
/** Creates a transformation pipeline. */
|
|
35
|
-
export declare function composeTransforms<T, U, V>(first: ValidationTransform<T, U>, second: ValidationTransform<U, V>): ValidationTransform<T, V>;
|
|
36
|
-
/** Creates a transformation pipeline from multiple functions. */
|
|
37
|
-
export declare function composeManyTransforms<T>(...transforms: readonly ValidationTransform<T, T>[]): ValidationTransform<T, T>;
|
|
38
|
-
/** Applies a transformation to every item in an array. */
|
|
39
|
-
export declare function transformArray<T, U>(values: readonly T[], transform: ValidationTransform<T, U>): U[];
|
|
40
|
-
/** Applies an asynchronous transformation to every item in an array. */
|
|
41
|
-
export declare function transformArrayAsync<T, U>(values: readonly T[], transform: AsyncValidationTransform<T, U>): Promise<U[]>;
|
|
42
|
-
/** Creates a schema that transforms the validated value. */
|
|
43
|
-
export declare function withTransformer<T, U>(schema: ValidationSchema<T>, transform: ValidationTransform<T, U>): ValidationSchema<U>;
|
|
44
29
|
//# sourceMappingURL=validationTransformer.core.d.ts.map
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import { validate, validateAsync, } from "../validationSchema/validationSchema.core.js";
|
|
2
1
|
import { failure, success } from "../validationResult/validationResult.type.js";
|
|
3
2
|
import { ConstraintValidationError } from "../validationErrors/validationError.types.js";
|
|
4
|
-
function transformFailure(options
|
|
3
|
+
function transformFailure(options) {
|
|
5
4
|
return failure([
|
|
6
5
|
{
|
|
7
6
|
path: [],
|
|
8
7
|
code: "transform_failed",
|
|
9
8
|
message: options.transformErrorMessage ?? "Validation transformation failed.",
|
|
10
|
-
received: error instanceof Error ? error.message : error,
|
|
11
9
|
},
|
|
12
10
|
]);
|
|
13
11
|
}
|
|
@@ -28,8 +26,8 @@ export function createValidationTransformer(transform, options = {}) {
|
|
|
28
26
|
try {
|
|
29
27
|
return success(transform(value));
|
|
30
28
|
}
|
|
31
|
-
catch
|
|
32
|
-
return transformFailure(options
|
|
29
|
+
catch {
|
|
30
|
+
return transformFailure(options);
|
|
33
31
|
}
|
|
34
32
|
},
|
|
35
33
|
validateAndTransform(value) {
|
|
@@ -54,8 +52,8 @@ export function createAsyncValidationTransformer(transform, options = {}) {
|
|
|
54
52
|
try {
|
|
55
53
|
return success(await transform(value));
|
|
56
54
|
}
|
|
57
|
-
catch
|
|
58
|
-
return transformFailure(options
|
|
55
|
+
catch {
|
|
56
|
+
return transformFailure(options);
|
|
59
57
|
}
|
|
60
58
|
},
|
|
61
59
|
async validateAndTransform(value) {
|
|
@@ -63,53 +61,4 @@ export function createAsyncValidationTransformer(transform, options = {}) {
|
|
|
63
61
|
},
|
|
64
62
|
});
|
|
65
63
|
}
|
|
66
|
-
/** Validates input and then transforms it. */
|
|
67
|
-
export function validateAndTransform(schema, value, transform, options = {}) {
|
|
68
|
-
const validation = validate(schema, value);
|
|
69
|
-
if (!validation.success)
|
|
70
|
-
return validation;
|
|
71
|
-
try {
|
|
72
|
-
return success(transform(validation.data));
|
|
73
|
-
}
|
|
74
|
-
catch (error) {
|
|
75
|
-
return transformFailure(options, error);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
/** Validates input and then transforms it asynchronously. */
|
|
79
|
-
export async function validateAndTransformAsync(schema, value, transform, options = {}) {
|
|
80
|
-
const validation = await validateAsync(schema, value);
|
|
81
|
-
if (!validation.success)
|
|
82
|
-
return validation;
|
|
83
|
-
try {
|
|
84
|
-
return success(await transform(validation.data));
|
|
85
|
-
}
|
|
86
|
-
catch (error) {
|
|
87
|
-
return transformFailure(options, error);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
/** Creates a transformation pipeline. */
|
|
91
|
-
export function composeTransforms(first, second) {
|
|
92
|
-
return (value) => second(first(value));
|
|
93
|
-
}
|
|
94
|
-
/** Creates a transformation pipeline from multiple functions. */
|
|
95
|
-
export function composeManyTransforms(...transforms) {
|
|
96
|
-
return (value) => {
|
|
97
|
-
let current = value;
|
|
98
|
-
for (const transform of transforms)
|
|
99
|
-
current = transform(current);
|
|
100
|
-
return current;
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
/** Applies a transformation to every item in an array. */
|
|
104
|
-
export function transformArray(values, transform) {
|
|
105
|
-
return values.map(transform);
|
|
106
|
-
}
|
|
107
|
-
/** Applies an asynchronous transformation to every item in an array. */
|
|
108
|
-
export async function transformArrayAsync(values, transform) {
|
|
109
|
-
return Promise.all(values.map(transform));
|
|
110
|
-
}
|
|
111
|
-
/** Creates a schema that transforms the validated value. */
|
|
112
|
-
export function withTransformer(schema, transform) {
|
|
113
|
-
return schema.transform(transform);
|
|
114
|
-
}
|
|
115
64
|
//# sourceMappingURL=validationTransformer.core.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @zudojs/validation — Transformation helpers and pipelines.
|
|
3
|
+
*
|
|
4
|
+
* @module validationTransformer/validationTransformer.helpers
|
|
5
|
+
*/
|
|
6
|
+
import type { ValidationSchema } from "../validationSchema/validationSchema.core.js";
|
|
7
|
+
import type { ValidationResult } from "../validationResult/validationResult.type.js";
|
|
8
|
+
import type { AsyncValidationTransform, TransformerOptions, ValidationTransform } from "./validationTransformer.core.js";
|
|
9
|
+
/** Validates input and then transforms it. */
|
|
10
|
+
export declare function validateAndTransform<T, U>(schema: ValidationSchema<T>, value: unknown, transform: ValidationTransform<T, U>, options?: TransformerOptions): ValidationResult<U>;
|
|
11
|
+
/** Validates input and then transforms it asynchronously. */
|
|
12
|
+
export declare function validateAndTransformAsync<T, U>(schema: ValidationSchema<T>, value: unknown, transform: AsyncValidationTransform<T, U>, options?: TransformerOptions): Promise<ValidationResult<U>>;
|
|
13
|
+
/** Creates a transformation pipeline. */
|
|
14
|
+
export declare function composeTransforms<T, U, V>(first: ValidationTransform<T, U>, second: ValidationTransform<U, V>): ValidationTransform<T, V>;
|
|
15
|
+
/** Creates a transformation pipeline from multiple functions. */
|
|
16
|
+
export declare function composeManyTransforms<T>(...transforms: readonly ValidationTransform<T, T>[]): ValidationTransform<T, T>;
|
|
17
|
+
/** Applies a transformation to every item in an array. */
|
|
18
|
+
export declare function transformArray<T, U>(values: readonly T[], transform: ValidationTransform<T, U>): U[];
|
|
19
|
+
/** Applies an asynchronous transformation to every item in an array. */
|
|
20
|
+
export declare function transformArrayAsync<T, U>(values: readonly T[], transform: AsyncValidationTransform<T, U>): Promise<U[]>;
|
|
21
|
+
/** Creates a schema that transforms the validated value. */
|
|
22
|
+
export declare function withTransformer<T, U>(schema: ValidationSchema<T>, transform: ValidationTransform<T, U>): ValidationSchema<U>;
|
|
23
|
+
//# sourceMappingURL=validationTransformer.helpers.d.ts.map
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @zudojs/validation — Transformation helpers and pipelines.
|
|
3
|
+
*
|
|
4
|
+
* @module validationTransformer/validationTransformer.helpers
|
|
5
|
+
*/
|
|
6
|
+
import { validate, validateAsync, } from "../validationSchema/validationSchema.core.js";
|
|
7
|
+
import { failure, success } from "../validationResult/validationResult.type.js";
|
|
8
|
+
/** Builds the failure reported when a transformation throws. */
|
|
9
|
+
function transformFailure(options) {
|
|
10
|
+
return failure([
|
|
11
|
+
{
|
|
12
|
+
path: [],
|
|
13
|
+
code: "transform_failed",
|
|
14
|
+
message: options.transformErrorMessage ?? "Validation transformation failed.",
|
|
15
|
+
},
|
|
16
|
+
]);
|
|
17
|
+
}
|
|
18
|
+
/** Validates input and then transforms it. */
|
|
19
|
+
export function validateAndTransform(schema, value, transform, options = {}) {
|
|
20
|
+
const validation = validate(schema, value);
|
|
21
|
+
if (!validation.success)
|
|
22
|
+
return validation;
|
|
23
|
+
try {
|
|
24
|
+
return success(transform(validation.data));
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
return transformFailure(options);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Validates input and then transforms it asynchronously. */
|
|
31
|
+
export async function validateAndTransformAsync(schema, value, transform, options = {}) {
|
|
32
|
+
const validation = await validateAsync(schema, value);
|
|
33
|
+
if (!validation.success)
|
|
34
|
+
return validation;
|
|
35
|
+
try {
|
|
36
|
+
return success(await transform(validation.data));
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
return transformFailure(options);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** Creates a transformation pipeline. */
|
|
43
|
+
export function composeTransforms(first, second) {
|
|
44
|
+
return (value) => second(first(value));
|
|
45
|
+
}
|
|
46
|
+
/** Creates a transformation pipeline from multiple functions. */
|
|
47
|
+
export function composeManyTransforms(...transforms) {
|
|
48
|
+
return (value) => {
|
|
49
|
+
let current = value;
|
|
50
|
+
for (const transform of transforms)
|
|
51
|
+
current = transform(current);
|
|
52
|
+
return current;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** Applies a transformation to every item in an array. */
|
|
56
|
+
export function transformArray(values, transform) {
|
|
57
|
+
return values.map((value) => transform(value));
|
|
58
|
+
}
|
|
59
|
+
/** Applies an asynchronous transformation to every item in an array. */
|
|
60
|
+
export async function transformArrayAsync(values, transform) {
|
|
61
|
+
return Promise.all(values.map((value) => transform(value)));
|
|
62
|
+
}
|
|
63
|
+
/** Creates a schema that transforms the validated value. */
|
|
64
|
+
export function withTransformer(schema, transform) {
|
|
65
|
+
return schema.transform(transform);
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=validationTransformer.helpers.js.map
|