@thi.ng/validate 0.2.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/api.d.ts CHANGED
@@ -6,7 +6,7 @@ export interface Validator {
6
6
  coerce?: Fn<any, any>;
7
7
  /**
8
8
  * Validation predicate. If the function returns false, the
9
- * {@link volidator} wrapper will throw an error.
9
+ * {@link validator} wrapper will throw an error.
10
10
  */
11
11
  valid: Predicate<any>;
12
12
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/validate",
3
- "version": "0.2.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": "c0d6e8f2517c5edc745774266f3cbca586b03d5e"
88
+ "gitHead": "7e7cd1f3214bf256630f87efaa1f2f5f53454133"
89
89
  }
package/validators.d.ts CHANGED
@@ -55,6 +55,14 @@ export declare const ValidationError: {
55
55
  * @param validators
56
56
  */
57
57
  export declare const validator: (...validators: Validator[]) => (x: any) => boolean;
58
+ /**
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;
58
66
  /**
59
67
  * Higher order validator. Takes existing validator(s) and returns an augmented
60
68
  * version which also allows values to be nullish. If more than one validator is
@@ -108,11 +116,19 @@ export declare const isUndefined: (msg?: Validator["msg"]) => Validator;
108
116
  * @param msg
109
117
  */
110
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;
111
121
  export declare const isBoolean: (msg?: Validator["msg"]) => Validator;
112
122
  export declare const isNumber: (msg?: Validator["msg"]) => Validator;
113
123
  export declare const isString: (msg?: Validator["msg"]) => Validator;
114
124
  export declare const isDate: (msg?: Validator["msg"]) => Validator;
125
+ export declare const isFunction: (msg?: Validator["msg"]) => Validator;
115
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
+ */
116
132
  export declare const isObject: (msg?: Validator["msg"]) => Validator;
117
133
  /**
118
134
  * Returns validator to check if value is a plain object and the values of all
@@ -122,8 +138,6 @@ export declare const isObject: (msg?: Validator["msg"]) => Validator;
122
138
  * @param msg
123
139
  */
124
140
  export declare const isObjectOf: (validators: Validator | Validator[], msg?: Validator["msg"]) => Validator;
125
- export declare const isArray: (msg?: Validator["msg"]) => Validator;
126
- export declare const isArrayOf: (validators: Validator | Validator[], msg?: Validator["msg"]) => Validator;
127
141
  export declare const isTypedArray: (msg?: Validator["msg"]) => Validator;
128
142
  /**
129
143
  * Returns validator to check if value is a `Uint8Array`.
@@ -152,8 +166,11 @@ export declare const hasRequiredKeys: (keys: string[], nonNullish?: boolean, onl
152
166
  * @param onlyKeys
153
167
  */
154
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;
155
171
  /**
156
- * 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)`.
157
174
  *
158
175
  * @param opts
159
176
  * @param msg
package/validators.js CHANGED
@@ -2,7 +2,7 @@ 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";
@@ -15,13 +15,15 @@ const validator = (...validators) => (x) => {
15
15
  for (let { coerce, valid, msg } of validators) {
16
16
  if (coerce) x = coerce(x);
17
17
  if (!valid(x)) {
18
- if (isFunction(msg)) msg = msg(x);
18
+ if ($isFunction(msg)) msg = msg(x);
19
19
  throw new ValidationError(msg ?? "failed validation");
20
20
  }
21
21
  }
22
22
  return true;
23
23
  };
24
24
  const __asArray = (v) => $isArray(v) ? v : [v];
25
+ const ALWAYS = { valid: () => true };
26
+ const NEVER = { valid: () => false };
25
27
  const optional = (first, ...rest) => {
26
28
  const { coerce, valid, msg } = rest.length ? every(first, ...rest) : first;
27
29
  return {
@@ -69,6 +71,14 @@ const isNullish = (msg) => ({
69
71
  valid: (x) => x === null,
70
72
  msg: msg ?? `expected nullish value`
71
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
+ });
72
82
  const isBoolean = (msg) => ({
73
83
  valid: $isBoolean,
74
84
  msg: msg ?? `required boolean value`
@@ -85,26 +95,22 @@ const isDate = (msg) => ({
85
95
  valid: $isDate,
86
96
  msg: msg ?? `required date value`
87
97
  });
98
+ const isFunction = (msg) => ({
99
+ valid: $isFunction,
100
+ msg: msg ?? `required function value`
101
+ });
88
102
  const isRegExp = (msg) => ({
89
103
  valid: $isRegExp,
90
104
  msg: msg ?? `required regexp value`
91
105
  });
92
106
  const isObject = (msg) => ({
93
107
  valid: isPlainObject,
94
- msg: msg ?? `required object value`
108
+ msg: msg ?? `required plain object value`
95
109
  });
96
110
  const isObjectOf = (validators, msg) => ({
97
111
  valid: $isObjectOf(validator(...__asArray(validators))),
98
112
  msg: msg ?? `required object value`
99
113
  });
100
- const isArray = (msg) => ({
101
- valid: $isArray,
102
- msg: msg ?? `required array value`
103
- });
104
- const isArrayOf = (validators, msg) => ({
105
- valid: $isArrayOf(validator(...__asArray(validators))),
106
- msg: msg ?? `required array value`
107
- });
108
114
  const isTypedArray = (msg) => ({
109
115
  valid: $isTypedArray,
110
116
  msg: msg ?? `required typed array value`
@@ -118,30 +124,67 @@ const hasRequiredKeys = (keys, nonNullish = false, onlyKeys = false, msg) => ({
118
124
  if (onlyKeys) __onlyKeys(keys, x);
119
125
  return keys.every((k) => k in x && (nonNullish ? x[k] != null : true));
120
126
  },
121
- msg: msg ?? `required keys: ${keys.join(", ")}${nonNullish ? " (must be non-nullish)" : ""}`
127
+ msg: msg ?? `required keys: ${keys.join(", ")}${nonNullish ? " (values must be non-nullish)" : ""}`
122
128
  });
123
129
  const hasKeysOf = (validators, onlyKeys = false) => ({
124
130
  valid: (x) => {
125
- if (x == null) return false;
126
131
  if (onlyKeys) __onlyKeys(Object.keys(validators), x);
127
- for (let [key, v] of Object.entries(validators)) {
132
+ for (let k in validators) {
128
133
  try {
129
- validator(...__asArray(v))(x[key]);
134
+ validator(...__asArray(validators[k]))(x[k]);
130
135
  } catch (e) {
131
136
  throw new ValidationError(
132
- (e.origMessage ?? e.message) + ` (key: ${key})`
137
+ (e.origMessage ?? e.message) + ` (key: ${k})`
133
138
  );
134
139
  }
135
140
  }
136
141
  return true;
137
142
  }
138
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
+ };
139
180
  const __onlyKeys = (keys, x) => {
140
181
  for (let k in x) {
141
- if (!keys.includes(k))
142
- throw new ValidationError(`key: ${k} not allowed`);
182
+ if (!keys.includes(k)) __disallowedKey(k);
143
183
  }
144
184
  };
185
+ const __disallowedKey = (key) => {
186
+ throw new ValidationError(`key: ${key} not allowed`);
187
+ };
145
188
  const isEnum = (opts, msg) => ({
146
189
  valid: (x) => opts.includes(x),
147
190
  msg: msg ?? `required value to be one of: ${opts.join(", ")}`
@@ -187,15 +230,20 @@ const matchesRegexp = (re, msg) => ({
187
230
  msg: msg ?? `doesn't match pattern`
188
231
  });
189
232
  export {
233
+ ALWAYS,
234
+ NEVER,
190
235
  ValidationError,
191
236
  every,
192
237
  hasKeysOf,
238
+ hasPatternKeysOf,
193
239
  hasRequiredKeys,
240
+ hasRequiredPatternKeys,
194
241
  isArray,
195
242
  isArrayOf,
196
243
  isBoolean,
197
244
  isDate,
198
245
  isEnum,
246
+ isFunction,
199
247
  isInRange,
200
248
  isLength,
201
249
  isMaxLength,