valgen 6.2.2 → 7.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/README.md +102 -15
- package/constants.js +1 -1
- package/core/context.js +15 -4
- package/core/utilities.js +4 -4
- package/index.js +5 -3
- package/package.json +1 -1
- package/rules/format-rules/is-alpha.js +1 -1
- package/rules/format-rules/is-alphanumeric.js +1 -1
- package/rules/format-rules/is-base64.js +1 -1
- package/rules/format-rules/is-email.js +3 -2
- package/rules/format-rules/is-iban.d.ts +2 -1
- package/rules/format-rules/is-iban.js +2 -2
- package/rules/format-rules/is-mobile-phone.d.ts +1 -1
- package/rules/format-rules/is-mobile-phone.js +2 -2
- package/rules/format-rules/is-passport-number.js +1 -1
- package/rules/format-rules/is-swift.js +1 -1
- package/rules/format-rules/is-time.js +1 -1
- package/rules/format-rules/matches.d.ts +2 -2
- package/rules/format-rules/matches.js +3 -2
- package/rules/logical-rules/is-defined.d.ts +2 -1
- package/rules/logical-rules/is-defined.js +2 -1
- package/rules/logical-rules/is-equal.d.ts +4 -2
- package/rules/logical-rules/is-equal.js +4 -2
- package/rules/logical-rules/is-gt.d.ts +2 -2
- package/rules/logical-rules/is-gt.js +2 -2
- package/rules/logical-rules/is-gte.d.ts +1 -1
- package/rules/logical-rules/is-gte.js +1 -1
- package/rules/logical-rules/is-lt.d.ts +1 -1
- package/rules/logical-rules/is-lt.js +2 -2
- package/rules/logical-rules/is-lte.d.ts +1 -1
- package/rules/logical-rules/is-lte.js +2 -2
- package/rules/type-rules/is-array.js +9 -7
- package/rules/type-rules/is-bigint.d.ts +2 -2
- package/rules/type-rules/is-bigint.js +9 -5
- package/rules/type-rules/is-boolean.js +2 -2
- package/rules/type-rules/is-date.d.ts +3 -2
- package/rules/type-rules/is-date.js +22 -15
- package/rules/type-rules/is-instanceof.d.ts +1 -1
- package/rules/type-rules/is-instanceof.js +1 -1
- package/rules/type-rules/is-integer.js +6 -3
- package/rules/type-rules/is-number.js +6 -3
- package/rules/type-rules/is-object.d.ts +7 -2
- package/rules/type-rules/is-object.js +27 -10
- package/rules/type-rules/is-record.js +10 -6
- package/rules/type-rules/is-string.d.ts +1 -1
- package/rules/type-rules/is-string.js +1 -1
- package/rules/type-rules/is-tuple.js +9 -9
- package/rules/type-rules/is-undefined.d.ts +4 -1
- package/rules/type-rules/is-undefined.js +4 -1
- package/rules/utility-rules/all-of.js +3 -2
- package/rules/utility-rules/exists.js +2 -1
- package/rules/utility-rules/fixed.d.ts +2 -2
- package/rules/utility-rules/fixed.js +2 -2
- package/rules/utility-rules/get-length.d.ts +2 -1
- package/rules/utility-rules/get-length.js +2 -1
- package/rules/utility-rules/nullable.d.ts +2 -2
- package/rules/utility-rules/nullable.js +3 -3
- package/rules/utility-rules/one-of.d.ts +4 -1
- package/rules/utility-rules/one-of.js +43 -11
- package/rules/utility-rules/optional.js +1 -1
- package/rules/utility-rules/pipe.d.ts +1 -1
- package/rules/utility-rules/pipe.js +8 -2
- package/rules/utility-rules/required.js +1 -1
- package/factories.d.ts +0 -1
- package/factories.js +0 -1
- package/helpers/object.utils.d.ts +0 -2
- package/helpers/object.utils.js +0 -14
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type ValidationOptions } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
* Validates if value is a "Date" instance
|
|
4
|
-
*
|
|
3
|
+
* Validates if value is a "Date" instance. If the `coerce` option is `true`,
|
|
4
|
+
* also accepts an ISO 8601 formatted date string or a numeric timestamp and
|
|
5
|
+
* converts it to a Date instance.
|
|
5
6
|
* @validator isDate
|
|
6
7
|
*/
|
|
7
8
|
export declare function isDate(options?: isDate.Options): import("../../core/validator.js").Validator<Date, string | number | Date, import("../../core/types.js").ExecutionOptions>;
|
|
@@ -2,8 +2,9 @@ import * as datefns from 'date-fns';
|
|
|
2
2
|
import {} from 'ts-gems';
|
|
3
3
|
import { validator, } from '../../core/index.js';
|
|
4
4
|
/**
|
|
5
|
-
* Validates if value is a "Date" instance
|
|
6
|
-
*
|
|
5
|
+
* Validates if value is a "Date" instance. If the `coerce` option is `true`,
|
|
6
|
+
* also accepts an ISO 8601 formatted date string or a numeric timestamp and
|
|
7
|
+
* converts it to a Date instance.
|
|
7
8
|
* @validator isDate
|
|
8
9
|
*/
|
|
9
10
|
export function isDate(options) {
|
|
@@ -73,6 +74,8 @@ function coerceDateString(input, options = {}) {
|
|
|
73
74
|
let detectedPrecision;
|
|
74
75
|
if (input instanceof Date || typeof input === 'number') {
|
|
75
76
|
const d = typeof input === 'number' ? new Date(input) : input;
|
|
77
|
+
if (!datefns.isValid(d))
|
|
78
|
+
return;
|
|
76
79
|
dateParts = [
|
|
77
80
|
String(d.getFullYear()).padStart(4, '0'),
|
|
78
81
|
String(d.getMonth() + 1).padStart(2, '0'),
|
|
@@ -88,12 +91,10 @@ function coerceDateString(input, options = {}) {
|
|
|
88
91
|
dateParts.push('');
|
|
89
92
|
if (precisionIndex >= 8) {
|
|
90
93
|
const tzOffset = d.getTimezoneOffset();
|
|
91
|
-
const tz = tzOffset > 0
|
|
92
|
-
|
|
93
|
-
:
|
|
94
|
-
|
|
95
|
-
':' +
|
|
96
|
-
String(Math.abs(tzOffset) % 60).padStart(2, '0');
|
|
94
|
+
const tz = (tzOffset > 0 ? '-' : '+') +
|
|
95
|
+
String(Math.floor(Math.abs(tzOffset) / 60)).padStart(2, '0') +
|
|
96
|
+
':' +
|
|
97
|
+
String(Math.abs(tzOffset) % 60).padStart(2, '0');
|
|
97
98
|
dateParts.push(tz);
|
|
98
99
|
}
|
|
99
100
|
}
|
|
@@ -151,7 +152,7 @@ const PRECISION_INDEX = {
|
|
|
151
152
|
month: 2,
|
|
152
153
|
mo: 2,
|
|
153
154
|
day: 3,
|
|
154
|
-
d:
|
|
155
|
+
d: 3,
|
|
155
156
|
hours: 4,
|
|
156
157
|
hr: 4,
|
|
157
158
|
minutes: 5,
|
|
@@ -166,29 +167,35 @@ const PRECISION_INDEX_KEYS = Object.keys(PRECISION_INDEX);
|
|
|
166
167
|
const PRECISION_INDEX_VALUES = Object.values(PRECISION_INDEX);
|
|
167
168
|
function setPrecision(d, precision) {
|
|
168
169
|
switch (precision) {
|
|
169
|
-
case 'year':
|
|
170
|
+
case 'year':
|
|
171
|
+
case 'yr': {
|
|
170
172
|
d.setMonth(0, 1);
|
|
171
173
|
d.setHours(0, 0, 0, 0);
|
|
172
174
|
break;
|
|
173
175
|
}
|
|
174
|
-
case 'month':
|
|
176
|
+
case 'month':
|
|
177
|
+
case 'mo': {
|
|
175
178
|
d.setDate(1);
|
|
176
179
|
d.setHours(0, 0, 0, 0);
|
|
177
180
|
break;
|
|
178
181
|
}
|
|
179
|
-
case 'day':
|
|
182
|
+
case 'day':
|
|
183
|
+
case 'd': {
|
|
180
184
|
d.setHours(0, 0, 0, 0);
|
|
181
185
|
break;
|
|
182
186
|
}
|
|
183
|
-
case 'hours':
|
|
187
|
+
case 'hours':
|
|
188
|
+
case 'hr': {
|
|
184
189
|
d.setMinutes(0, 0, 0);
|
|
185
190
|
break;
|
|
186
191
|
}
|
|
187
|
-
case 'minutes':
|
|
192
|
+
case 'minutes':
|
|
193
|
+
case 'min': {
|
|
188
194
|
d.setSeconds(0, 0);
|
|
189
195
|
break;
|
|
190
196
|
}
|
|
191
|
-
case 'seconds':
|
|
197
|
+
case 'seconds':
|
|
198
|
+
case 'sec': {
|
|
192
199
|
d.setMilliseconds(0);
|
|
193
200
|
break;
|
|
194
201
|
}
|
|
@@ -2,7 +2,7 @@ import type { Type } from 'ts-gems';
|
|
|
2
2
|
import { type ValidationOptions } from '../../core/index.js';
|
|
3
3
|
/**
|
|
4
4
|
* Validates if the value instance of given class or classes
|
|
5
|
-
* @validator
|
|
5
|
+
* @validator isInstanceOf
|
|
6
6
|
*/
|
|
7
7
|
export declare function isInstanceOf<T extends object>(clazz: Type<T>, options?: isInstanceOf.Options): import("../../core/validator.js").Validator<T, unknown, import("../../core/types.js").ExecutionOptions>;
|
|
8
8
|
export declare namespace isInstanceOf {
|
|
@@ -2,7 +2,7 @@ import { isPlainObject } from '@jsopen/objects';
|
|
|
2
2
|
import { validator, } from '../../core/index.js';
|
|
3
3
|
/**
|
|
4
4
|
* Validates if the value instance of given class or classes
|
|
5
|
-
* @validator
|
|
5
|
+
* @validator isInstanceOf
|
|
6
6
|
*/
|
|
7
7
|
export function isInstanceOf(clazz, options) {
|
|
8
8
|
return validator(isInstanceOf.name, (input, context, _this) => {
|
|
@@ -12,9 +12,12 @@ export function isInteger(options) {
|
|
|
12
12
|
if (typeof input === 'string')
|
|
13
13
|
output = parseFloat(input);
|
|
14
14
|
else if (typeof input === 'bigint') {
|
|
15
|
-
|
|
16
|
-
if (input
|
|
17
|
-
|
|
15
|
+
const n = Number(input);
|
|
16
|
+
if (input !== BigInt(n)) {
|
|
17
|
+
context.fail(_this, `Value must be a valid integer value`, input);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
output = n;
|
|
18
21
|
}
|
|
19
22
|
}
|
|
20
23
|
if (typeof output === 'number' &&
|
|
@@ -12,9 +12,12 @@ export function isNumber(options) {
|
|
|
12
12
|
if (typeof input === 'string')
|
|
13
13
|
output = parseFloat(input);
|
|
14
14
|
else if (typeof input === 'bigint') {
|
|
15
|
-
|
|
16
|
-
if (input
|
|
17
|
-
|
|
15
|
+
const n = Number(input);
|
|
16
|
+
if (input !== BigInt(n)) {
|
|
17
|
+
context.fail(_this, `Value must be a number`, input);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
output = n;
|
|
18
21
|
}
|
|
19
22
|
}
|
|
20
23
|
if (typeof output === 'number' && !isNaN(output))
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { type Type, type ValidationOptions, type Validator as Validator_ } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
* Validates the object according to schema
|
|
4
|
-
*
|
|
3
|
+
* Validates the object according to schema. Converts properties according to
|
|
4
|
+
* schema rules if the coerce option is set to 'true'. Supports
|
|
5
|
+
* `additionalFields` (allow/strip/reject/validate unknown properties -
|
|
6
|
+
* defaults to allowing them when no schema is given, and rejecting them
|
|
7
|
+
* otherwise), `caseInSensitive` (match property names ignoring case), and
|
|
8
|
+
* `detectCircular` (guard against circular references when the schema
|
|
9
|
+
* validates itself, e.g. via `forwardRef`).
|
|
5
10
|
* @validator isObject
|
|
6
11
|
*/
|
|
7
12
|
export declare function isObject<T extends object = object, I = object | string>(schema?: isObject.Schema, options?: isObject.Options<T>): isObject.Validator<T, I>;
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { postValidation, preValidation } from '../../constants.js';
|
|
2
2
|
import { isValidator, validator, } from '../../core/index.js';
|
|
3
3
|
/**
|
|
4
|
-
* Validates the object according to schema
|
|
5
|
-
*
|
|
4
|
+
* Validates the object according to schema. Converts properties according to
|
|
5
|
+
* schema rules if the coerce option is set to 'true'. Supports
|
|
6
|
+
* `additionalFields` (allow/strip/reject/validate unknown properties -
|
|
7
|
+
* defaults to allowing them when no schema is given, and rejecting them
|
|
8
|
+
* otherwise), `caseInSensitive` (match property names ignoring case), and
|
|
9
|
+
* `detectCircular` (guard against circular references when the schema
|
|
10
|
+
* validates itself, e.g. via `forwardRef`).
|
|
6
11
|
* @validator isObject
|
|
7
12
|
*/
|
|
8
13
|
export function isObject(schema, options) {
|
|
@@ -66,6 +71,14 @@ export function isObject(schema, options) {
|
|
|
66
71
|
context.root = context.root || ctorName || '';
|
|
67
72
|
const location = context.location || '';
|
|
68
73
|
const processedSchemaKeys = {};
|
|
74
|
+
// Reused across every property instead of allocated per-property.
|
|
75
|
+
// `scope`/`context` never change between properties, so they're set
|
|
76
|
+
// once; `location`/`property` are reassigned every iteration, and
|
|
77
|
+
// `label` is reassigned-or-deleted every iteration (see below) so no
|
|
78
|
+
// field can leak from a previous property into the next one.
|
|
79
|
+
const subCtx = context.extend();
|
|
80
|
+
subCtx.scope = output;
|
|
81
|
+
subCtx.context = ctorName;
|
|
69
82
|
// Iterate object keys and perform rules
|
|
70
83
|
for (i = 0; i < l; i++) {
|
|
71
84
|
inputKey = keys[i];
|
|
@@ -78,21 +91,25 @@ export function isObject(schema, options) {
|
|
|
78
91
|
if (processedSchemaKeys[schemaKey])
|
|
79
92
|
continue;
|
|
80
93
|
processedSchemaKeys[schemaKey] = true;
|
|
81
|
-
const subCtx = context.extend();
|
|
82
|
-
subCtx.scope = output;
|
|
83
|
-
subCtx.context = ctorName;
|
|
84
94
|
subCtx.location = location + (location ? '.' : '') + schemaKey;
|
|
85
95
|
subCtx.property = schemaKey;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
96
|
+
const propLabel = propertyOptions[schemaKey]?.label;
|
|
97
|
+
// Assign (not just skip) when there's no per-property label, so a
|
|
98
|
+
// label left over from a previous property can't leak in - but
|
|
99
|
+
// `delete` rather than `= undefined`, so the lookup still falls
|
|
100
|
+
// through to an inherited label from the parent context, exactly
|
|
101
|
+
// like the original per-iteration `context.extend()` did.
|
|
102
|
+
if (propLabel)
|
|
103
|
+
subCtx.label = propLabel;
|
|
104
|
+
else
|
|
105
|
+
delete subCtx.label;
|
|
106
|
+
v = _propRule(v, undefined, subCtx);
|
|
90
107
|
}
|
|
91
108
|
else if (v !== undefined) {
|
|
92
109
|
if (!additionalFields)
|
|
93
110
|
continue;
|
|
94
111
|
if (additionalFields === 'error') {
|
|
95
|
-
context.fail(
|
|
112
|
+
context.fail(_this, `${ctorName || 'Object'} has no field '${inputKey}' and does not accept additional fields`, v);
|
|
96
113
|
}
|
|
97
114
|
}
|
|
98
115
|
if (v !== undefined) {
|
|
@@ -19,19 +19,23 @@ export function isRecord(keyRule, valueRule, options) {
|
|
|
19
19
|
let k;
|
|
20
20
|
let v;
|
|
21
21
|
const out = {};
|
|
22
|
+
// Set directly on the (already reused) context instead of passed as
|
|
23
|
+
// a fresh {onFail} options object on every call - `k` is read at call
|
|
24
|
+
// time (synchronously, before it's reassigned below), so a single
|
|
25
|
+
// closure works for the whole loop. This also lets both calls below
|
|
26
|
+
// pass `undefined` for options, which the validator wrapper needs in
|
|
27
|
+
// order to skip a needless context.extend() when the key/value rule
|
|
28
|
+
// has no options of its own.
|
|
29
|
+
keyContext.onFail = (issue) => `${k} is not a valid key. ` + issue.message;
|
|
22
30
|
for (i = 0; i < l; i++) {
|
|
23
31
|
k = keys[i];
|
|
24
32
|
v = input[k];
|
|
25
33
|
// Validate key
|
|
26
|
-
k = keyRule(k,
|
|
27
|
-
onFail(issue) {
|
|
28
|
-
return `${k} is not a valid key. ` + issue.message;
|
|
29
|
-
},
|
|
30
|
-
}, keyContext);
|
|
34
|
+
k = keyRule(k, undefined, keyContext);
|
|
31
35
|
// Validate value
|
|
32
36
|
valueContext.property = k;
|
|
33
37
|
valueContext.location = location + (location ? '.' : '') + k;
|
|
34
|
-
v = valueRule(v, valueContext);
|
|
38
|
+
v = valueRule(v, undefined, valueContext);
|
|
35
39
|
out[k] = v;
|
|
36
40
|
}
|
|
37
41
|
return context.errors.length ? undefined : out;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ValidationOptions } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Validates if the value is a string.
|
|
4
|
-
* Converts input value to string if the
|
|
4
|
+
* Converts input value to string if the coerce option is set to 'true'.
|
|
5
5
|
* @validator isString
|
|
6
6
|
*/
|
|
7
7
|
export declare function isString(options?: isString.Options): import("../../core/validator.js").Validator<string, unknown, import("../../core/types.js").ExecutionOptions>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { validator, } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Validates if the value is a string.
|
|
4
|
-
* Converts input value to string if the
|
|
4
|
+
* Converts input value to string if the coerce option is set to 'true'.
|
|
5
5
|
* @validator isString
|
|
6
6
|
*/
|
|
7
7
|
export function isString(options) {
|
|
@@ -5,29 +5,29 @@ export function isTuple(items, options) {
|
|
|
5
5
|
let output = input;
|
|
6
6
|
if (output != null && coerce && !Array.isArray(output))
|
|
7
7
|
output = [output];
|
|
8
|
-
if (!Array.isArray(
|
|
8
|
+
if (!Array.isArray(output)) {
|
|
9
9
|
context.fail(_this, `Value must be a tuple`, input);
|
|
10
10
|
return;
|
|
11
11
|
}
|
|
12
|
+
const nl = items.length;
|
|
13
|
+
if (output.length !== nl) {
|
|
14
|
+
context.fail(_this, `Value must be a tuple of length ${nl}`, input);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
12
17
|
const location = context.location || '';
|
|
13
18
|
let itemRule;
|
|
14
19
|
let i;
|
|
15
20
|
let v;
|
|
16
|
-
const l = output.length;
|
|
17
21
|
const out = [];
|
|
18
|
-
const nl = items.length;
|
|
19
22
|
const itemContext = context.extend();
|
|
20
|
-
for (i = 0; i <
|
|
23
|
+
for (i = 0; i < nl; i++) {
|
|
21
24
|
itemRule = items[i];
|
|
22
25
|
itemContext.scope = output;
|
|
23
|
-
itemContext.label = context.label
|
|
24
|
-
? context.label + `[${i}]`
|
|
25
|
-
: undefined;
|
|
26
26
|
itemContext.index = i;
|
|
27
27
|
itemContext.location = location + '[' + i + ']';
|
|
28
28
|
itemContext.label =
|
|
29
|
-
(
|
|
30
|
-
v = itemRule(output[i], itemContext);
|
|
29
|
+
(context.label || context.property || 'Value at ') + `[${i}]`;
|
|
30
|
+
v = itemRule(output[i], undefined, itemContext);
|
|
31
31
|
out.push(v);
|
|
32
32
|
}
|
|
33
33
|
return context.errors.length ? undefined : out;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { type ValidationOptions } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
* Validates if the value is undefined
|
|
3
|
+
* Validates if the value is undefined.
|
|
4
|
+
* If `coerce` is `true`, always succeeds and returns `undefined` regardless
|
|
5
|
+
* of the input value - "coerce" here means "force to undefined", not
|
|
6
|
+
* "convert values that merely look like undefined".
|
|
4
7
|
* @validator isUndefined
|
|
5
8
|
*/
|
|
6
9
|
export declare function isUndefined(options?: isUndefined.Options): import("../../core/validator.js").Validator<any, unknown, import("../../core/types.js").ExecutionOptions>;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { validator, } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
* Validates if the value is undefined
|
|
3
|
+
* Validates if the value is undefined.
|
|
4
|
+
* If `coerce` is `true`, always succeeds and returns `undefined` regardless
|
|
5
|
+
* of the input value - "coerce" here means "force to undefined", not
|
|
6
|
+
* "convert values that merely look like undefined".
|
|
4
7
|
* @validator isUndefined
|
|
5
8
|
*/
|
|
6
9
|
export function isUndefined(options) {
|
|
@@ -10,8 +10,9 @@ export function allOf(rules, options) {
|
|
|
10
10
|
const l = rules.length;
|
|
11
11
|
for (i = 0; i < l; i++) {
|
|
12
12
|
c = rules[i];
|
|
13
|
-
|
|
13
|
+
// See pipe.ts for why context goes in the 3rd slot, not the 2nd.
|
|
14
|
+
c(input, undefined, context);
|
|
14
15
|
}
|
|
15
16
|
return input;
|
|
16
|
-
});
|
|
17
|
+
}, options);
|
|
17
18
|
}
|
|
@@ -7,7 +7,8 @@ export function exists(options) {
|
|
|
7
7
|
return validator(exists.name, (input, context, _this) => {
|
|
8
8
|
if (input !== undefined ||
|
|
9
9
|
(context.scope &&
|
|
10
|
-
|
|
10
|
+
context.property != null &&
|
|
11
|
+
Object.getOwnPropertyDescriptor(context.scope, context.property))) {
|
|
11
12
|
return input;
|
|
12
13
|
}
|
|
13
14
|
context.fail(_this, `{{label}} must exist`, input);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* @validator
|
|
2
|
+
* Ignores the input and always returns the given constant value.
|
|
3
|
+
* @validator fixed
|
|
4
4
|
*/
|
|
5
5
|
export declare function fixed<T, I>(value: T): import("../../core/validator.js").Validator<T, I, import("../../core/types.js").ExecutionOptions>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { validator } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
* @validator
|
|
3
|
+
* Ignores the input and always returns the given constant value.
|
|
4
|
+
* @validator fixed
|
|
5
5
|
*/
|
|
6
6
|
export function fixed(value) {
|
|
7
7
|
return validator(fixed.name, () => {
|
|
@@ -4,7 +4,8 @@ type ExtractLengthInput = string | any[] | ArrayBuffer | {
|
|
|
4
4
|
size: number;
|
|
5
5
|
};
|
|
6
6
|
/**
|
|
7
|
-
* Returns length of an Array, String, ArrayBuffer, Buffer or any
|
|
7
|
+
* Returns length of an Array, String, ArrayBuffer, Buffer, Set, Map, or any
|
|
8
|
+
* object with a "length" or "size" property.
|
|
8
9
|
* @validator getLength
|
|
9
10
|
*/
|
|
10
11
|
export declare function getLength(): import("../../core/validator.js").Validator<number, ExtractLengthInput, import("../../core/types.js").ExecutionOptions>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { validator } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
* Returns length of an Array, String, ArrayBuffer, Buffer or any
|
|
3
|
+
* Returns length of an Array, String, ArrayBuffer, Buffer, Set, Map, or any
|
|
4
|
+
* object with a "length" or "size" property.
|
|
4
5
|
* @validator getLength
|
|
5
6
|
*/
|
|
6
7
|
export function getLength() {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { Nullish } from 'ts-gems';
|
|
2
2
|
import { type ValidationOptions, type Validator } from '../../core/index.js';
|
|
3
3
|
/**
|
|
4
|
-
* Makes the sub-rule nullable (undefined
|
|
5
|
-
* @validator
|
|
4
|
+
* Makes the sub-rule nullable (accepts undefined or null)
|
|
5
|
+
* @validator nullable
|
|
6
6
|
*/
|
|
7
7
|
export declare function nullable<T, I>(nested: Validator<T, I>, options?: nullable.Options): Validator<Nullish<T>, Nullish<I>, import("../../core/types.js").ExecutionOptions>;
|
|
8
8
|
export declare namespace nullable {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { validator, } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
* Makes the sub-rule nullable (undefined
|
|
4
|
-
* @validator
|
|
3
|
+
* Makes the sub-rule nullable (accepts undefined or null)
|
|
4
|
+
* @validator nullable
|
|
5
5
|
*/
|
|
6
6
|
export function nullable(nested, options) {
|
|
7
7
|
return validator(nullable.name, (input, context) => {
|
|
8
8
|
if (input == null)
|
|
9
9
|
return input;
|
|
10
|
-
return nested(input, context);
|
|
10
|
+
return nested(input, undefined, context);
|
|
11
11
|
}, options);
|
|
12
12
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { ValidationOptions, Validator } from '../../core/index.js';
|
|
2
2
|
type DiscriminatorRecord = Record<string, Validator>;
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Tries each rule against the input in order and returns the first one that
|
|
5
|
+
* passes. An optional discriminator record narrows which rule to try based
|
|
6
|
+
* on a distinguishing field of the input.
|
|
7
|
+
* @validator oneOf
|
|
5
8
|
*/
|
|
6
9
|
export declare function oneOf(rules: (Validator | [Validator, DiscriminatorRecord])[], options?: oneOf.Options): Validator<any, any, import("../../core/types.js").ExecutionOptions>;
|
|
7
10
|
export declare namespace oneOf {
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { validator } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Tries each rule against the input in order and returns the first one that
|
|
4
|
+
* passes. An optional discriminator record narrows which rule to try based
|
|
5
|
+
* on a distinguishing field of the input.
|
|
6
|
+
* @validator oneOf
|
|
4
7
|
*/
|
|
5
8
|
export function oneOf(rules, options) {
|
|
6
9
|
const l = rules.length;
|
|
@@ -10,8 +13,21 @@ export function oneOf(rules, options) {
|
|
|
10
13
|
let discriminator;
|
|
11
14
|
let v;
|
|
12
15
|
let passed = false;
|
|
13
|
-
//
|
|
14
|
-
|
|
16
|
+
// Every candidate failing is normal control flow here (that's how
|
|
17
|
+
// "try the next one" works), so a candidate's own context.fail must
|
|
18
|
+
// not throw or accumulate into the real error list. But swallowing it
|
|
19
|
+
// completely would hide the *reason* every candidate failed - including
|
|
20
|
+
// a genuine bug in a candidate rule, which would otherwise look
|
|
21
|
+
// identical to "the input just didn't match". So the mock still
|
|
22
|
+
// records the last failure's message, and it's reported directly as
|
|
23
|
+
// the final error (oneOf can only report one message anyway) instead
|
|
24
|
+
// of being discarded in favor of a generic one.
|
|
25
|
+
let lastFailMessage;
|
|
26
|
+
context.fail = (_rule, message) => {
|
|
27
|
+
passed = false;
|
|
28
|
+
lastFailMessage =
|
|
29
|
+
message instanceof Error ? message.message : String(message);
|
|
30
|
+
};
|
|
15
31
|
for (i = 0; i < l; i++) {
|
|
16
32
|
passed = true;
|
|
17
33
|
if (Array.isArray(rules[i])) {
|
|
@@ -23,15 +39,29 @@ export function oneOf(rules, options) {
|
|
|
23
39
|
continue;
|
|
24
40
|
}
|
|
25
41
|
try {
|
|
26
|
-
|
|
27
|
-
|
|
42
|
+
const keys = Object.keys(discriminator);
|
|
43
|
+
const len = keys.length;
|
|
44
|
+
let j;
|
|
45
|
+
let k;
|
|
46
|
+
for (j = 0; j < len; j++) {
|
|
47
|
+
k = keys[j];
|
|
48
|
+
discriminator[k](input[k], undefined, context);
|
|
28
49
|
if (!passed)
|
|
29
50
|
break;
|
|
30
51
|
}
|
|
31
52
|
if (!passed)
|
|
32
53
|
continue;
|
|
33
54
|
}
|
|
34
|
-
catch {
|
|
55
|
+
catch (e) {
|
|
56
|
+
// A discriminator/rule that throws directly (bypassing
|
|
57
|
+
// context.fail entirely, e.g. a plain function rather than one
|
|
58
|
+
// built with validator()) must still count as "this candidate
|
|
59
|
+
// failed" - otherwise `passed` is left at its top-of-loop `true`
|
|
60
|
+
// and, if this is the last candidate, oneOf would silently
|
|
61
|
+
// return an unvalidated value instead of failing.
|
|
62
|
+
passed = false;
|
|
63
|
+
lastFailMessage =
|
|
64
|
+
e?.message != null ? String(e.message) : String(e);
|
|
35
65
|
continue;
|
|
36
66
|
}
|
|
37
67
|
}
|
|
@@ -39,18 +69,20 @@ export function oneOf(rules, options) {
|
|
|
39
69
|
c = rules[i];
|
|
40
70
|
if (passed)
|
|
41
71
|
try {
|
|
42
|
-
v = c(input, context
|
|
72
|
+
v = c(input, undefined, context);
|
|
43
73
|
if (passed)
|
|
44
74
|
break;
|
|
45
75
|
}
|
|
46
|
-
catch {
|
|
47
|
-
|
|
76
|
+
catch (e) {
|
|
77
|
+
passed = false;
|
|
78
|
+
lastFailMessage =
|
|
79
|
+
e?.message != null ? String(e.message) : String(e);
|
|
48
80
|
}
|
|
49
81
|
}
|
|
50
82
|
// Restore fail method
|
|
51
83
|
delete context.fail;
|
|
52
84
|
if (passed)
|
|
53
85
|
return v;
|
|
54
|
-
context.fail(_this, `Value didn't match one of required rules`, input);
|
|
55
|
-
});
|
|
86
|
+
context.fail(_this, lastFailMessage || `Value didn't match one of required rules`, input);
|
|
87
|
+
}, options);
|
|
56
88
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ValidationOptions, type Validator } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Chains rules so each one's output becomes the next one's input.
|
|
4
4
|
* @validator pipe
|
|
5
5
|
*/
|
|
6
6
|
export declare function pipe<T>(rules: Validator[], options?: pipe.Options): Validator<T>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { validator, } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Chains rules so each one's output becomes the next one's input.
|
|
4
4
|
* @validator pipe
|
|
5
5
|
*/
|
|
6
6
|
export function pipe(rules, options) {
|
|
@@ -14,7 +14,13 @@ export function pipe(rules, options) {
|
|
|
14
14
|
const oldErrors = context.errors.length;
|
|
15
15
|
for (i = 0; i < l; i++) {
|
|
16
16
|
c = rules[i];
|
|
17
|
-
|
|
17
|
+
// Pass context in its own (3rd) slot, not the 2nd (options) slot.
|
|
18
|
+
// The validator wrapper only extends the context when there's an
|
|
19
|
+
// actual options object to merge in - passing context as "options"
|
|
20
|
+
// instead makes it match `instanceof Context` and forces an
|
|
21
|
+
// unconditional (and needless, most of the time) extend() on every
|
|
22
|
+
// step.
|
|
23
|
+
v = c(v, undefined, context);
|
|
18
24
|
if (returnIndex == null || i <= returnIndex)
|
|
19
25
|
returnValue = v;
|
|
20
26
|
if (context.errors.length > oldErrors)
|
package/factories.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './rules/index.js';
|
package/factories.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './rules/index.js';
|
package/helpers/object.utils.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export function omitKeys(o, keys) {
|
|
2
|
-
return Object.keys(o).reduce((a, k) => {
|
|
3
|
-
if (!keys.includes(k))
|
|
4
|
-
a[k] = o[k];
|
|
5
|
-
return a;
|
|
6
|
-
}, {});
|
|
7
|
-
}
|
|
8
|
-
export function pickKeys(o, keys) {
|
|
9
|
-
return Object.keys(o).reduce((a, k) => {
|
|
10
|
-
if (keys.includes(k))
|
|
11
|
-
a[k] = o[k];
|
|
12
|
-
return a;
|
|
13
|
-
}, {});
|
|
14
|
-
}
|