@thi.ng/validate 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -2
- package/api.d.ts +1 -1
- package/package.json +2 -2
- package/validators.d.ts +82 -13
- package/validators.js +111 -26
package/README.md
CHANGED
|
@@ -90,13 +90,17 @@ try {
|
|
|
90
90
|
- [`isPositive()`](https://docs.thi.ng/umbrella/validate/functions/isPositive.html)
|
|
91
91
|
- [`isRegExp()`](https://docs.thi.ng/umbrella/validate/functions/isRegExp.html)
|
|
92
92
|
- [`isString()`](https://docs.thi.ng/umbrella/validate/functions/isString.html)
|
|
93
|
+
- [`isTypedArray()`](https://docs.thi.ng/umbrella/validate/functions/isTypedArray.html)
|
|
94
|
+
- [`isU8Array()`](https://docs.thi.ng/umbrella/validate/functions/isU8Array.html)
|
|
93
95
|
- [`isUndefined()`](https://docs.thi.ng/umbrella/validate/functions/isUndefined.html)
|
|
94
96
|
- [`matchesRegexp()`](https://docs.thi.ng/umbrella/validate/functions/matchesRegexp.html)
|
|
95
97
|
|
|
96
98
|
### Combinators
|
|
97
99
|
|
|
98
|
-
- [`
|
|
100
|
+
- [`every()`](https://docs.thi.ng/umbrella/validate/functions/every.html)
|
|
101
|
+
- [`not()`](https://docs.thi.ng/umbrella/validate/functions/not.html)
|
|
99
102
|
- [`optional()`](https://docs.thi.ng/umbrella/validate/functions/optional.html)
|
|
103
|
+
- [`some()`](https://docs.thi.ng/umbrella/validate/functions/some.html)
|
|
100
104
|
|
|
101
105
|
## Status
|
|
102
106
|
|
|
@@ -130,7 +134,7 @@ For Node.js REPL:
|
|
|
130
134
|
const val = await import("@thi.ng/validate");
|
|
131
135
|
```
|
|
132
136
|
|
|
133
|
-
Package sizes (brotli'd, pre-treeshake): ESM:
|
|
137
|
+
Package sizes (brotli'd, pre-treeshake): ESM: 1.19 KB
|
|
134
138
|
|
|
135
139
|
## Dependencies
|
|
136
140
|
|
package/api.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/validate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Functional, composable, fully extensible, predicate-based value validation with customizable error messages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -85,5 +85,5 @@
|
|
|
85
85
|
"status": "alpha",
|
|
86
86
|
"year": 2026
|
|
87
87
|
},
|
|
88
|
-
"gitHead": "
|
|
88
|
+
"gitHead": "7e7cd1f3214bf256630f87efaa1f2f5f53454133"
|
|
89
89
|
}
|
package/validators.d.ts
CHANGED
|
@@ -56,20 +56,54 @@ export declare const ValidationError: {
|
|
|
56
56
|
*/
|
|
57
57
|
export declare const validator: (...validators: Validator[]) => (x: any) => boolean;
|
|
58
58
|
/**
|
|
59
|
-
*
|
|
60
|
-
|
|
59
|
+
* Utility validator which always passes.
|
|
60
|
+
*/
|
|
61
|
+
export declare const ALWAYS: Validator;
|
|
62
|
+
/**
|
|
63
|
+
* Utility validator which always fails.
|
|
64
|
+
*/
|
|
65
|
+
export declare const NEVER: Validator;
|
|
66
|
+
/**
|
|
67
|
+
* Higher order validator. Takes existing validator(s) and returns an augmented
|
|
68
|
+
* version which also allows values to be nullish. If more than one validator is
|
|
69
|
+
* given, they're first combined via {@link every}.
|
|
70
|
+
*
|
|
71
|
+
* @param first
|
|
72
|
+
* @param rest
|
|
73
|
+
*/
|
|
74
|
+
export declare const optional: (first: Validator, ...rest: Validator[]) => Validator;
|
|
75
|
+
/**
|
|
76
|
+
* Higher order validator. Takes existing validator and optional error message.
|
|
77
|
+
* Returns an augmented validator which applies logical negation of the original
|
|
78
|
+
* validator.
|
|
61
79
|
*
|
|
62
80
|
* @param validator
|
|
81
|
+
* @param msg
|
|
63
82
|
*/
|
|
64
|
-
export declare const
|
|
83
|
+
export declare const not: ({ coerce, valid, msg: $msg }: Validator, msg?: Validator["msg"]) => Validator;
|
|
65
84
|
/**
|
|
66
|
-
* Higher order validator. Takes
|
|
67
|
-
* which will apply the validators in given order,
|
|
68
|
-
*
|
|
85
|
+
* Higher order validator. Takes one or more validators and returns a new one
|
|
86
|
+
* which will apply the validators in given order, and return successfully with
|
|
87
|
+
* the first one passed and only fails if **none** of the validators passed.
|
|
69
88
|
*
|
|
70
|
-
* @param
|
|
89
|
+
* @param first
|
|
90
|
+
* @param rest
|
|
71
91
|
*/
|
|
72
|
-
export declare const
|
|
92
|
+
export declare const some: (first: Validator | Validator[], ...rest: (Validator | Validator[])[]) => Validator;
|
|
93
|
+
/**
|
|
94
|
+
* Higher order validator. Takes a number of validators and returns a new one
|
|
95
|
+
* which will apply the validators in given order, and only returns success if
|
|
96
|
+
* **all** of the validators passed.
|
|
97
|
+
*
|
|
98
|
+
* @remarks
|
|
99
|
+
* Essentially the same as {@link validator}, but returns a {@link Validator}
|
|
100
|
+
* object (presumably for further composition) instead of a predicate function
|
|
101
|
+
* to apply directly.
|
|
102
|
+
*
|
|
103
|
+
* @param first
|
|
104
|
+
* @param rest
|
|
105
|
+
*/
|
|
106
|
+
export declare const every: (first: Validator, ...rest: Validator[]) => Validator;
|
|
73
107
|
/**
|
|
74
108
|
* Returns validator to check if value is undefined.
|
|
75
109
|
*
|
|
@@ -82,11 +116,19 @@ export declare const isUndefined: (msg?: Validator["msg"]) => Validator;
|
|
|
82
116
|
* @param msg
|
|
83
117
|
*/
|
|
84
118
|
export declare const isNullish: (msg?: Validator["msg"]) => Validator;
|
|
119
|
+
export declare const isArray: (msg?: Validator["msg"]) => Validator;
|
|
120
|
+
export declare const isArrayOf: (validators: Validator | Validator[], msg?: Validator["msg"]) => Validator;
|
|
85
121
|
export declare const isBoolean: (msg?: Validator["msg"]) => Validator;
|
|
86
122
|
export declare const isNumber: (msg?: Validator["msg"]) => Validator;
|
|
87
123
|
export declare const isString: (msg?: Validator["msg"]) => Validator;
|
|
88
124
|
export declare const isDate: (msg?: Validator["msg"]) => Validator;
|
|
125
|
+
export declare const isFunction: (msg?: Validator["msg"]) => Validator;
|
|
89
126
|
export declare const isRegExp: (msg?: Validator["msg"]) => Validator;
|
|
127
|
+
/**
|
|
128
|
+
* Returns validator which checks that given value is a plain object (not class).
|
|
129
|
+
*
|
|
130
|
+
* @param msg
|
|
131
|
+
*/
|
|
90
132
|
export declare const isObject: (msg?: Validator["msg"]) => Validator;
|
|
91
133
|
/**
|
|
92
134
|
* Returns validator to check if value is a plain object and the values of all
|
|
@@ -96,12 +138,39 @@ export declare const isObject: (msg?: Validator["msg"]) => Validator;
|
|
|
96
138
|
* @param msg
|
|
97
139
|
*/
|
|
98
140
|
export declare const isObjectOf: (validators: Validator | Validator[], msg?: Validator["msg"]) => Validator;
|
|
99
|
-
export declare const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
141
|
+
export declare const isTypedArray: (msg?: Validator["msg"]) => Validator;
|
|
142
|
+
/**
|
|
143
|
+
* Returns validator to check if value is a `Uint8Array`.
|
|
144
|
+
*
|
|
145
|
+
* @param msg
|
|
146
|
+
*/
|
|
147
|
+
export declare const isU8Array: (msg?: Validator["msg"]) => Validator;
|
|
148
|
+
/**
|
|
149
|
+
* Returns validator to ensure given `keys` are present in an object, optionally
|
|
150
|
+
* also checks their values are `nonNullish` (default: false). If `onlyKeys` is
|
|
151
|
+
* true (default: false), the validator also checks that no other keys are
|
|
152
|
+
* defined in the object.
|
|
153
|
+
*
|
|
154
|
+
* @param keys
|
|
155
|
+
* @param nonNullish
|
|
156
|
+
* @param onlyKeys
|
|
157
|
+
* @param msg
|
|
158
|
+
*/
|
|
159
|
+
export declare const hasRequiredKeys: (keys: string[], nonNullish?: boolean, onlyKeys?: boolean, msg?: Validator["msg"]) => Validator;
|
|
160
|
+
/**
|
|
161
|
+
* Takes object of validators to check values of different keys in an object.
|
|
162
|
+
* Returns validator which applies all checks, optionally also ensures no other
|
|
163
|
+
* keys are defined (if `onlyKeys` is true, default: false).
|
|
164
|
+
*
|
|
165
|
+
* @param validators
|
|
166
|
+
* @param onlyKeys
|
|
167
|
+
*/
|
|
168
|
+
export declare const hasKeysOf: (validators: Record<PropertyKey, Validator | Validator[]>, onlyKeys?: boolean) => Validator;
|
|
169
|
+
export declare const hasRequiredPatternKeys: (pattern: RegExp, nonNullish?: boolean, onlyKeys?: boolean, msg?: Validator["msg"]) => Validator;
|
|
170
|
+
export declare const hasPatternKeysOf: (pattern: RegExp, validators: Validator | Validator[], onlyKeys?: boolean) => Validator;
|
|
103
171
|
/**
|
|
104
|
-
* Returns validator to check if value is one of the given options.
|
|
172
|
+
* Returns validator to check if value is one of the given options. Values are
|
|
173
|
+
* checked via `opts.includes(x)`.
|
|
105
174
|
*
|
|
106
175
|
* @param opts
|
|
107
176
|
* @param msg
|
package/validators.js
CHANGED
|
@@ -2,38 +2,55 @@ import { isArray as $isArray } from "@thi.ng/checks/is-array";
|
|
|
2
2
|
import { isArrayOf as $isArrayOf } from "@thi.ng/checks/is-array-of";
|
|
3
3
|
import { isBoolean as $isBoolean } from "@thi.ng/checks/is-boolean";
|
|
4
4
|
import { isDate as $isDate } from "@thi.ng/checks/is-date";
|
|
5
|
-
import { isFunction } from "@thi.ng/checks/is-function";
|
|
5
|
+
import { isFunction as $isFunction } from "@thi.ng/checks/is-function";
|
|
6
6
|
import { isNumber as $isNumber } from "@thi.ng/checks/is-number";
|
|
7
7
|
import { isObjectOf as $isObjectOf } from "@thi.ng/checks/is-object-of";
|
|
8
8
|
import { isPlainObject } from "@thi.ng/checks/is-plain-object";
|
|
9
9
|
import { isRegExp as $isRegExp } from "@thi.ng/checks/is-regexp";
|
|
10
10
|
import { isString as $isString } from "@thi.ng/checks/is-string";
|
|
11
|
+
import { isTypedArray as $isTypedArray } from "@thi.ng/checks/is-typedarray";
|
|
11
12
|
import { defError } from "@thi.ng/errors/deferror";
|
|
12
13
|
const ValidationError = defError(() => `validation error`);
|
|
13
14
|
const validator = (...validators) => (x) => {
|
|
14
15
|
for (let { coerce, valid, msg } of validators) {
|
|
15
16
|
if (coerce) x = coerce(x);
|
|
16
17
|
if (!valid(x)) {
|
|
17
|
-
if (isFunction(msg)) msg = msg(x);
|
|
18
|
+
if ($isFunction(msg)) msg = msg(x);
|
|
18
19
|
throw new ValidationError(msg ?? "failed validation");
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
return true;
|
|
22
23
|
};
|
|
23
|
-
const
|
|
24
|
+
const __asArray = (v) => $isArray(v) ? v : [v];
|
|
25
|
+
const ALWAYS = { valid: () => true };
|
|
26
|
+
const NEVER = { valid: () => false };
|
|
27
|
+
const optional = (first, ...rest) => {
|
|
28
|
+
const { coerce, valid, msg } = rest.length ? every(first, ...rest) : first;
|
|
29
|
+
return {
|
|
30
|
+
coerce,
|
|
31
|
+
valid: (x) => x == null || valid(x),
|
|
32
|
+
msg
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
const not = ({ coerce, valid, msg: $msg }, msg) => ({
|
|
24
36
|
coerce,
|
|
25
|
-
valid: (x) =>
|
|
26
|
-
|
|
37
|
+
valid: (x) => {
|
|
38
|
+
try {
|
|
39
|
+
return !valid(x);
|
|
40
|
+
} catch (e) {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
msg: msg ?? $msg
|
|
27
45
|
});
|
|
28
|
-
const
|
|
29
|
-
const oneOf = (validators) => {
|
|
46
|
+
const some = (first, ...rest) => {
|
|
30
47
|
let lastMsg;
|
|
31
48
|
return {
|
|
32
49
|
valid: (x) => {
|
|
33
50
|
lastMsg = void 0;
|
|
34
|
-
for (let v of
|
|
51
|
+
for (let $v of [first, ...rest]) {
|
|
35
52
|
try {
|
|
36
|
-
return validator(...__asArray(v))(x);
|
|
53
|
+
return validator(...__asArray($v))(x);
|
|
37
54
|
} catch (e) {
|
|
38
55
|
lastMsg = e.origMessage ?? e.message;
|
|
39
56
|
}
|
|
@@ -43,6 +60,9 @@ const oneOf = (validators) => {
|
|
|
43
60
|
msg: () => lastMsg ?? "invalid value"
|
|
44
61
|
};
|
|
45
62
|
};
|
|
63
|
+
const every = (first, ...rest) => ({
|
|
64
|
+
valid: (x) => validator(first, ...rest)(x)
|
|
65
|
+
});
|
|
46
66
|
const isUndefined = (msg) => ({
|
|
47
67
|
valid: (x) => x === void 0,
|
|
48
68
|
msg: msg ?? `expected undefined value`
|
|
@@ -51,6 +71,14 @@ const isNullish = (msg) => ({
|
|
|
51
71
|
valid: (x) => x === null,
|
|
52
72
|
msg: msg ?? `expected nullish value`
|
|
53
73
|
});
|
|
74
|
+
const isArray = (msg) => ({
|
|
75
|
+
valid: $isArray,
|
|
76
|
+
msg: msg ?? `required array value`
|
|
77
|
+
});
|
|
78
|
+
const isArrayOf = (validators, msg) => ({
|
|
79
|
+
valid: $isArrayOf(validator(...__asArray(validators))),
|
|
80
|
+
msg: msg ?? `required array value`
|
|
81
|
+
});
|
|
54
82
|
const isBoolean = (msg) => ({
|
|
55
83
|
valid: $isBoolean,
|
|
56
84
|
msg: msg ?? `required boolean value`
|
|
@@ -67,48 +95,96 @@ const isDate = (msg) => ({
|
|
|
67
95
|
valid: $isDate,
|
|
68
96
|
msg: msg ?? `required date value`
|
|
69
97
|
});
|
|
98
|
+
const isFunction = (msg) => ({
|
|
99
|
+
valid: $isFunction,
|
|
100
|
+
msg: msg ?? `required function value`
|
|
101
|
+
});
|
|
70
102
|
const isRegExp = (msg) => ({
|
|
71
103
|
valid: $isRegExp,
|
|
72
104
|
msg: msg ?? `required regexp value`
|
|
73
105
|
});
|
|
74
106
|
const isObject = (msg) => ({
|
|
75
107
|
valid: isPlainObject,
|
|
76
|
-
msg: msg ?? `required object value`
|
|
108
|
+
msg: msg ?? `required plain object value`
|
|
77
109
|
});
|
|
78
110
|
const isObjectOf = (validators, msg) => ({
|
|
79
111
|
valid: $isObjectOf(validator(...__asArray(validators))),
|
|
80
112
|
msg: msg ?? `required object value`
|
|
81
113
|
});
|
|
82
|
-
const
|
|
83
|
-
valid: $
|
|
84
|
-
msg: msg ?? `required array value`
|
|
114
|
+
const isTypedArray = (msg) => ({
|
|
115
|
+
valid: $isTypedArray,
|
|
116
|
+
msg: msg ?? `required typed array value`
|
|
85
117
|
});
|
|
86
|
-
const
|
|
87
|
-
valid:
|
|
88
|
-
msg: msg ?? `required array value`
|
|
118
|
+
const isU8Array = (msg) => ({
|
|
119
|
+
valid: (x) => x instanceof Uint8Array,
|
|
120
|
+
msg: msg ?? `required byte array value`
|
|
89
121
|
});
|
|
90
|
-
const hasRequiredKeys = (keys, msg) => ({
|
|
122
|
+
const hasRequiredKeys = (keys, nonNullish = false, onlyKeys = false, msg) => ({
|
|
91
123
|
valid: (x) => {
|
|
92
|
-
|
|
93
|
-
return keys.every((k) =>
|
|
124
|
+
if (onlyKeys) __onlyKeys(keys, x);
|
|
125
|
+
return keys.every((k) => k in x && (nonNullish ? x[k] != null : true));
|
|
94
126
|
},
|
|
95
|
-
msg: msg ?? `required keys: ${keys.join(", ")}`
|
|
127
|
+
msg: msg ?? `required keys: ${keys.join(", ")}${nonNullish ? " (values must be non-nullish)" : ""}`
|
|
96
128
|
});
|
|
97
|
-
const hasKeysOf = (validators) => ({
|
|
129
|
+
const hasKeysOf = (validators, onlyKeys = false) => ({
|
|
98
130
|
valid: (x) => {
|
|
99
|
-
if (
|
|
100
|
-
for (let
|
|
131
|
+
if (onlyKeys) __onlyKeys(Object.keys(validators), x);
|
|
132
|
+
for (let k in validators) {
|
|
101
133
|
try {
|
|
102
|
-
validator(...__asArray(
|
|
134
|
+
validator(...__asArray(validators[k]))(x[k]);
|
|
103
135
|
} catch (e) {
|
|
104
136
|
throw new ValidationError(
|
|
105
|
-
(e.origMessage ?? e.message) + ` (key: ${
|
|
137
|
+
(e.origMessage ?? e.message) + ` (key: ${k})`
|
|
106
138
|
);
|
|
107
139
|
}
|
|
108
140
|
}
|
|
109
141
|
return true;
|
|
110
142
|
}
|
|
111
143
|
});
|
|
144
|
+
const hasRequiredPatternKeys = (pattern, nonNullish = false, onlyKeys = false, msg) => ({
|
|
145
|
+
valid: (x) => {
|
|
146
|
+
let found = false;
|
|
147
|
+
for (let k in x) {
|
|
148
|
+
if (pattern.test(k)) {
|
|
149
|
+
if (nonNullish && x[k] == null) return false;
|
|
150
|
+
found = true;
|
|
151
|
+
} else if (onlyKeys) {
|
|
152
|
+
__disallowedKey(k);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return found;
|
|
156
|
+
},
|
|
157
|
+
msg: msg ?? `required pattern keys: ${pattern}${nonNullish ? " (values must be non-nullish)" : ""}`
|
|
158
|
+
});
|
|
159
|
+
const hasPatternKeysOf = (pattern, validators, onlyKeys = false) => {
|
|
160
|
+
const fn = validator(...__asArray(validators));
|
|
161
|
+
return {
|
|
162
|
+
valid: (x) => {
|
|
163
|
+
for (let k in x) {
|
|
164
|
+
if (pattern.test(k)) {
|
|
165
|
+
try {
|
|
166
|
+
fn(x[k]);
|
|
167
|
+
} catch (e) {
|
|
168
|
+
throw new ValidationError(
|
|
169
|
+
(e.origMessage ?? e.message) + ` (key: ${k})`
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
} else if (onlyKeys) {
|
|
173
|
+
__disallowedKey(k);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
};
|
|
180
|
+
const __onlyKeys = (keys, x) => {
|
|
181
|
+
for (let k in x) {
|
|
182
|
+
if (!keys.includes(k)) __disallowedKey(k);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
const __disallowedKey = (key) => {
|
|
186
|
+
throw new ValidationError(`key: ${key} not allowed`);
|
|
187
|
+
};
|
|
112
188
|
const isEnum = (opts, msg) => ({
|
|
113
189
|
valid: (x) => opts.includes(x),
|
|
114
190
|
msg: msg ?? `required value to be one of: ${opts.join(", ")}`
|
|
@@ -154,14 +230,20 @@ const matchesRegexp = (re, msg) => ({
|
|
|
154
230
|
msg: msg ?? `doesn't match pattern`
|
|
155
231
|
});
|
|
156
232
|
export {
|
|
233
|
+
ALWAYS,
|
|
234
|
+
NEVER,
|
|
157
235
|
ValidationError,
|
|
236
|
+
every,
|
|
158
237
|
hasKeysOf,
|
|
238
|
+
hasPatternKeysOf,
|
|
159
239
|
hasRequiredKeys,
|
|
240
|
+
hasRequiredPatternKeys,
|
|
160
241
|
isArray,
|
|
161
242
|
isArrayOf,
|
|
162
243
|
isBoolean,
|
|
163
244
|
isDate,
|
|
164
245
|
isEnum,
|
|
246
|
+
isFunction,
|
|
165
247
|
isInRange,
|
|
166
248
|
isLength,
|
|
167
249
|
isMaxLength,
|
|
@@ -177,9 +259,12 @@ export {
|
|
|
177
259
|
isPositive,
|
|
178
260
|
isRegExp,
|
|
179
261
|
isString,
|
|
262
|
+
isTypedArray,
|
|
263
|
+
isU8Array,
|
|
180
264
|
isUndefined,
|
|
181
265
|
matchesRegexp,
|
|
182
|
-
|
|
266
|
+
not,
|
|
183
267
|
optional,
|
|
268
|
+
some,
|
|
184
269
|
validator
|
|
185
270
|
};
|