valgen 6.2.2 → 7.0.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 +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 +13 -5
- 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
package/README.md
CHANGED
|
@@ -5,32 +5,119 @@
|
|
|
5
5
|
[![CI Tests][ci-test-image]][ci-test-url]
|
|
6
6
|
[![Test Coverage][coveralls-image]][coveralls-url]
|
|
7
7
|
|
|
8
|
-
Fast runtime type validator, converter and io (encoding/decoding) library
|
|
8
|
+
Fast runtime type validator, converter and io (encoding/decoding) library for TypeScript and
|
|
9
|
+
JavaScript.
|
|
10
|
+
|
|
11
|
+
- **Composable** - build complex schemas out of small validators with `allOf`, `oneOf`, `pipe`,
|
|
12
|
+
`optional`, `nullable`, `isObject`, `isArray`, ...
|
|
13
|
+
- **Coercing** - most rules can convert compatible input (`"42"` -> `42`, `"true"` -> `true`, ...)
|
|
14
|
+
instead of just rejecting it, via the `coerce` option.
|
|
15
|
+
- **Two calling conventions** - call a validator directly and catch a `ValidationError`, or use
|
|
16
|
+
`.silent(...)` to get back `{ value }` / `{ errors }` without throwing.
|
|
17
|
+
- **Typed** - every validator infers its output type, so a passing call narrows the type of its
|
|
18
|
+
return value.
|
|
19
|
+
- **Fast** - the core dispatch path and every rule are covered by a dedicated benchmark suite (see
|
|
20
|
+
[Benchmarking](#benchmarking) below); performance regressions are something this project
|
|
21
|
+
actively measures, not just hopes for.
|
|
9
22
|
|
|
10
23
|
## Installation
|
|
11
24
|
|
|
12
|
-
|
|
25
|
+
```sh
|
|
26
|
+
npm install valgen --save
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quick start
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { vg, isEmail, ValidationError } from 'valgen';
|
|
33
|
+
|
|
34
|
+
// Individual, ready-to-use validators
|
|
35
|
+
isEmail('a@b.com'); // => 'a@b.com'
|
|
36
|
+
isEmail('not-an-email'); // throws ValidationError
|
|
37
|
+
|
|
38
|
+
// A full object schema, built from composable rules
|
|
39
|
+
const userSchema = vg.isObject({
|
|
40
|
+
id: vg.isUUID(),
|
|
41
|
+
email: vg.isEmail(),
|
|
42
|
+
age: vg.optional(vg.pipe([vg.isNumber({ coerce: true }), vg.isGt(0)])),
|
|
43
|
+
role: vg.isEnum(['admin', 'user']),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const user = userSchema({
|
|
48
|
+
id: 'e6a3b1c0-70b6-4a3e-9b34-1e2f2e3d1a11',
|
|
49
|
+
email: 'a@b.com',
|
|
50
|
+
age: '30', // coerced to a number
|
|
51
|
+
role: 'admin',
|
|
52
|
+
});
|
|
53
|
+
} catch (e) {
|
|
54
|
+
if (e instanceof ValidationError) {
|
|
55
|
+
console.error(e.issues); // one entry per failing field
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Or avoid the try/catch entirely
|
|
60
|
+
const result = userSchema.silent({ email: 'not-an-email' });
|
|
61
|
+
if (result.errors) {
|
|
62
|
+
// result.errors: ErrorIssue[]
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Documentation
|
|
67
|
+
|
|
68
|
+
The full API reference lives under [`docs/`](docs/api.md):
|
|
69
|
+
|
|
70
|
+
- **[API overview](docs/api.md)** - the `Validator` shape, `.silent()`, pre-built instances vs.
|
|
71
|
+
factories, `ExecutionOptions`, error shape, composition patterns, and how to write a custom rule.
|
|
72
|
+
- **[Type Rules](docs/api/type-rules.md)** - `isString`, `isNumber`, `isObject`, `isArray`,
|
|
73
|
+
`isTuple`, `isEnum`, `isDate`, `isRecord`, `isInstanceOf`, ...
|
|
74
|
+
- **[Logical Rules](docs/api/logical-rules.md)** - `isEqual`, `isGt`/`isGte`/`isLt`/`isLte`,
|
|
75
|
+
`range`, `lengthMin`/`lengthMax`, `isEmpty`/`isNotEmpty`, `isDefined`.
|
|
76
|
+
- **[Utility Rules](docs/api/utility-rules.md)** - `allOf`, `oneOf`, `pipe`, `optional`,
|
|
77
|
+
`nullable`, `required`, `fixed`, `getLength`, `forwardRef`, `iif`, string helpers.
|
|
78
|
+
- **[Format Rules](docs/api/format-rules.md)** - `isEmail`, `isURL`, `isUUID`, `isIBAN`,
|
|
79
|
+
`isMACAddress`, `isCreditCard`, and every other string-format check.
|
|
80
|
+
|
|
81
|
+
## Scripts
|
|
82
|
+
|
|
83
|
+
| Command | Description |
|
|
84
|
+
|---|---|
|
|
85
|
+
| `npm test` | Run the test suite (mocha). |
|
|
86
|
+
| `npm run citest` | Run the test suite with coverage (c8). |
|
|
87
|
+
| `npm run qc` | Lint + circular-dependency check. |
|
|
88
|
+
| `npm run bench` | Run the benchmark suite (see below). |
|
|
89
|
+
| `npm run build` | Type-check and compile to `build/`. |
|
|
90
|
+
|
|
91
|
+
## Benchmarking
|
|
92
|
+
|
|
93
|
+
Every validator rule has a dedicated benchmark case measuring throughput (ops/sec) and per-call
|
|
94
|
+
memory allocation (heap/RSS), under `benchmark/rules/`.
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
# Run every rule
|
|
98
|
+
npm run bench
|
|
99
|
+
|
|
100
|
+
# Run one or more rules (case-insensitive, comma-separated, "*" wildcards allowed)
|
|
101
|
+
npm run bench -- -s isEmail,isURL
|
|
102
|
+
npm run bench -- -s "is*"
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Results print to the console as they complete and are also written to [`BENCHMARKS.md`](BENCHMARKS.md)
|
|
106
|
+
at the end of the run.
|
|
13
107
|
|
|
14
108
|
## Node Compatibility
|
|
15
109
|
|
|
16
|
-
|
|
17
|
-
|
|
110
|
+
- node `>= 20.0`
|
|
111
|
+
|
|
18
112
|
### License
|
|
113
|
+
|
|
19
114
|
[MIT](LICENSE)
|
|
20
115
|
|
|
21
|
-
[npm-image]: https://img.shields.io/npm/v/valgen
|
|
116
|
+
[npm-image]: https://img.shields.io/npm/v/valgen
|
|
22
117
|
[npm-url]: https://npmjs.org/package/valgen
|
|
118
|
+
[downloads-image]: https://img.shields.io/npm/dm/valgen.svg
|
|
119
|
+
[downloads-url]: https://npmjs.org/package/valgen
|
|
23
120
|
[ci-test-image]: https://github.com/panates/valgen/actions/workflows/test.yml/badge.svg
|
|
24
121
|
[ci-test-url]: https://github.com/panates/valgen/actions/workflows/test.yml
|
|
25
122
|
[coveralls-image]: https://img.shields.io/coveralls/panates/valgen/master.svg
|
|
26
123
|
[coveralls-url]: https://coveralls.io/r/panates/valgen
|
|
27
|
-
[downloads-image]: https://img.shields.io/npm/dm/valgen.svg
|
|
28
|
-
[downloads-url]: https://npmjs.org/package/valgen
|
|
29
|
-
[gitter-image]: https://badges.gitter.im/panates/valgen.svg
|
|
30
|
-
[gitter-url]: https://gitter.im/panates/valgen?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
|
31
|
-
[dependencies-image]: https://david-dm.org/panates/valgen/status.svg
|
|
32
|
-
[dependencies-url]:https://david-dm.org/panates/valgen
|
|
33
|
-
[devdependencies-image]: https://david-dm.org/panates/valgen/dev-status.svg
|
|
34
|
-
[devdependencies-url]:https://david-dm.org/panates/valgen?type=dev
|
|
35
|
-
[quality-image]: http://npm.packagequality.com/shield/valgen.png
|
|
36
|
-
[quality-url]: http://packagequality.com/#?package=valgen
|
package/constants.js
CHANGED
package/core/context.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { omitUndefined } from '../helpers/omit-undefined.js';
|
|
2
2
|
import { ValidationError } from './validation-error.js';
|
|
3
3
|
const VARIABLE_REPLACE_PATTERN = /{{([^}]*)}}/g;
|
|
4
|
-
const OPTIONAL_VAR_PATTERN = /^([
|
|
4
|
+
const OPTIONAL_VAR_PATTERN = /^([^|]+)(?:\|(.*))?$/;
|
|
5
5
|
export class Context {
|
|
6
6
|
isRoot = true;
|
|
7
7
|
errors = [];
|
|
@@ -66,15 +66,26 @@ export class Context {
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
extend(options) {
|
|
69
|
-
|
|
69
|
+
// Object.create(this) sets the prototype at creation time. Setting it
|
|
70
|
+
// afterward via Object.setPrototypeOf() (the previous approach) is one
|
|
71
|
+
// of the slowest object operations in V8 - it invalidates hidden-class
|
|
72
|
+
// based optimizations for the object - and this runs on every nested
|
|
73
|
+
// validator call, so it showed up heavily in profiling.
|
|
74
|
+
const extended = Object.create(this);
|
|
70
75
|
if (options) {
|
|
71
|
-
|
|
76
|
+
// Same filtering as the old Object.entries()+destructure (skip
|
|
77
|
+
// undefined values, so an unset option falls through to the
|
|
78
|
+
// prototype chain instead of shadowing it) but without allocating an
|
|
79
|
+
// array of [key, value] pairs just to throw it away.
|
|
80
|
+
const keys = Object.keys(options);
|
|
81
|
+
for (let i = 0; i < keys.length; i++) {
|
|
82
|
+
const k = keys[i];
|
|
83
|
+
const v = options[k];
|
|
72
84
|
if (v !== undefined)
|
|
73
85
|
extended[k] = v;
|
|
74
86
|
}
|
|
75
87
|
}
|
|
76
88
|
extended.isRoot = false;
|
|
77
|
-
Object.setPrototypeOf(extended, this);
|
|
78
89
|
return extended;
|
|
79
90
|
}
|
|
80
91
|
}
|
package/core/utilities.js
CHANGED
|
@@ -6,21 +6,21 @@ import { isValidator, validator } from './validator.js';
|
|
|
6
6
|
export function forwardRef(fn) {
|
|
7
7
|
return validator('forwardRef', (input, context) => {
|
|
8
8
|
const nested = fn(context);
|
|
9
|
-
return nested(input, context);
|
|
9
|
+
return nested(input, undefined, context);
|
|
10
10
|
});
|
|
11
11
|
}
|
|
12
12
|
export function iif(check, _then, _else) {
|
|
13
13
|
return validator('iif', (input, context) => {
|
|
14
14
|
let c = _else;
|
|
15
15
|
try {
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
check(input);
|
|
17
|
+
c = _then;
|
|
18
18
|
}
|
|
19
19
|
catch {
|
|
20
20
|
// ignored
|
|
21
21
|
}
|
|
22
22
|
if (isValidator(c))
|
|
23
|
-
return c(input, context);
|
|
23
|
+
return c(input, undefined, context);
|
|
24
24
|
return c;
|
|
25
25
|
});
|
|
26
26
|
}
|
package/index.js
CHANGED
|
@@ -73,15 +73,17 @@ const toDate = vg.isDate({ coerce: true });
|
|
|
73
73
|
const toDateStringValidators = new Map();
|
|
74
74
|
const toDateString = (input, options, ctx) => {
|
|
75
75
|
const precisionMax = options?.trim ?? 'ms';
|
|
76
|
-
|
|
76
|
+
const separators = options?.separators ?? true;
|
|
77
|
+
const cacheKey = precisionMax + '|' + separators;
|
|
78
|
+
let validator = toDateStringValidators.get(cacheKey);
|
|
77
79
|
if (!validator) {
|
|
78
80
|
validator = vg.isDateString({
|
|
79
81
|
coerce: true,
|
|
80
82
|
precisionMax,
|
|
81
83
|
trim: true,
|
|
82
|
-
separators
|
|
84
|
+
separators,
|
|
83
85
|
});
|
|
84
|
-
toDateStringValidators.set(
|
|
86
|
+
toDateStringValidators.set(cacheKey, validator);
|
|
85
87
|
}
|
|
86
88
|
return validator(input, options, ctx);
|
|
87
89
|
};
|
package/package.json
CHANGED
|
@@ -8,6 +8,6 @@ export function isAlpha(options) {
|
|
|
8
8
|
return validator(isAlpha.name, (input, context, _this) => {
|
|
9
9
|
if (typeof input === 'string' && validatorJS.isAlpha(input))
|
|
10
10
|
return input;
|
|
11
|
-
context.fail(_this, `
|
|
11
|
+
context.fail(_this, `Value must be an alpha string`, input);
|
|
12
12
|
}, options);
|
|
13
13
|
}
|
|
@@ -9,6 +9,6 @@ export function isAlphanumeric(options) {
|
|
|
9
9
|
if (typeof input === 'string' && validatorJS.isAlphanumeric(input)) {
|
|
10
10
|
return input;
|
|
11
11
|
}
|
|
12
|
-
context.fail(_this, `
|
|
12
|
+
context.fail(_this, `Value must be an alphanumeric string`, input);
|
|
13
13
|
}, options);
|
|
14
14
|
}
|
|
@@ -9,6 +9,6 @@ export function isBase64(options) {
|
|
|
9
9
|
if (typeof input === 'string' && validatorJS.isBase64(input, options)) {
|
|
10
10
|
return input;
|
|
11
11
|
}
|
|
12
|
-
context.fail(_this, `
|
|
12
|
+
context.fail(_this, `Value must be a Base64 string`, input);
|
|
13
13
|
}, options);
|
|
14
14
|
}
|
|
@@ -8,8 +8,9 @@ export function isEmail(options) {
|
|
|
8
8
|
const emailOptions = {
|
|
9
9
|
allow_display_name: true,
|
|
10
10
|
allow_utf8_local_part: options?.utf8LocalPart,
|
|
11
|
-
ignore_max_length:
|
|
11
|
+
ignore_max_length: options?.ignoreMaxLength,
|
|
12
12
|
allow_ip_domain: options?.allowIpDomain,
|
|
13
|
+
domain_specific_validation: options?.domainSpecificValidation,
|
|
13
14
|
};
|
|
14
15
|
return validator(isEmail.name, (input, context, _this) => {
|
|
15
16
|
if (typeof input === 'string' &&
|
|
@@ -57,6 +58,6 @@ export function isEmail(options) {
|
|
|
57
58
|
}
|
|
58
59
|
return input;
|
|
59
60
|
}
|
|
60
|
-
context.fail(_this, `Value must
|
|
61
|
+
context.fail(_this, `Value must match required e-mail format`, input);
|
|
61
62
|
}, options);
|
|
62
63
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type IsIBANOptions as _IsIBANOptions } from '@browsery/validator';
|
|
1
2
|
import { type ValidationOptions } from '../../core/index.js';
|
|
2
3
|
/**
|
|
3
4
|
* Validates if value is an IBAN (International Bank Account Number)
|
|
@@ -5,6 +6,6 @@ import { type ValidationOptions } from '../../core/index.js';
|
|
|
5
6
|
*/
|
|
6
7
|
export declare function isIBAN(options?: isIBAN.Options): import("../../core/validator.js").Validator<string, string, import("../../core/types.js").ExecutionOptions>;
|
|
7
8
|
export declare namespace isIBAN {
|
|
8
|
-
interface Options extends ValidationOptions {
|
|
9
|
+
interface Options extends ValidationOptions, _IsIBANOptions {
|
|
9
10
|
}
|
|
10
11
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import validatorJS from '@browsery/validator';
|
|
1
|
+
import validatorJS, {} from '@browsery/validator';
|
|
2
2
|
import { validator, } from '../../core/index.js';
|
|
3
3
|
/**
|
|
4
4
|
* Validates if value is an IBAN (International Bank Account Number)
|
|
@@ -6,7 +6,7 @@ import { validator, } from '../../core/index.js';
|
|
|
6
6
|
*/
|
|
7
7
|
export function isIBAN(options) {
|
|
8
8
|
return validator(isIBAN.name, (input, context, _this) => {
|
|
9
|
-
if (typeof input === 'string' && validatorJS.isIBAN(input))
|
|
9
|
+
if (typeof input === 'string' && validatorJS.isIBAN(input, options))
|
|
10
10
|
return input;
|
|
11
11
|
context.fail(_this, `Value must be a valid IBAN (International Bank Account Number)`, input);
|
|
12
12
|
}, options);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type MobilePhoneLocale as _MobilePhoneLocale } from '@browsery/validator';
|
|
2
2
|
import { type ValidationOptions } from '../../core/index.js';
|
|
3
3
|
/**
|
|
4
|
-
* Validates if value is a valid
|
|
4
|
+
* Validates if value is a valid mobile phone number
|
|
5
5
|
* @validator isMobilePhone
|
|
6
6
|
*/
|
|
7
7
|
export declare function isMobilePhone(options?: isMobilePhone.Options): import("../../core/validator.js").Validator<string, string, import("../../core/types.js").ExecutionOptions>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import validatorJS, {} from '@browsery/validator';
|
|
2
2
|
import { validator, } from '../../core/index.js';
|
|
3
3
|
/**
|
|
4
|
-
* Validates if value is a valid
|
|
4
|
+
* Validates if value is a valid mobile phone number
|
|
5
5
|
* @validator isMobilePhone
|
|
6
6
|
*/
|
|
7
7
|
export function isMobilePhone(options) {
|
|
@@ -13,6 +13,6 @@ export function isMobilePhone(options) {
|
|
|
13
13
|
validatorJS.isMobilePhone(input, options?.locale, opts)) {
|
|
14
14
|
return input;
|
|
15
15
|
}
|
|
16
|
-
context.fail(_this, `Value must be a valid
|
|
16
|
+
context.fail(_this, `Value must be a valid Mobile Phone Number`, input);
|
|
17
17
|
}, options);
|
|
18
18
|
}
|
|
@@ -10,6 +10,6 @@ export function isPassportNumber(countryCode, options) {
|
|
|
10
10
|
validatorJS.isPassportNumber(input, countryCode)) {
|
|
11
11
|
return input;
|
|
12
12
|
}
|
|
13
|
-
context.fail(_this, `Value must be a valid ${countryCode}
|
|
13
|
+
context.fail(_this, `Value must be a valid ${countryCode} Passport Number`, input);
|
|
14
14
|
}, options);
|
|
15
15
|
}
|
|
@@ -8,6 +8,6 @@ export function isSWIFT(options) {
|
|
|
8
8
|
return validator(isSWIFT.name, (input, context, _this) => {
|
|
9
9
|
if (typeof input === 'string' && validatorJS.isBIC(input))
|
|
10
10
|
return input;
|
|
11
|
-
context.fail(_this, `Value must be a valid
|
|
11
|
+
context.fail(_this, `Value must be a valid BIC (Bank Identification Code) or SWIFT code`, input);
|
|
12
12
|
}, options);
|
|
13
13
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { validator, } from '../../core/index.js';
|
|
2
|
-
const TIME_PATTERN = /^(\d{2}):?(\d{2})(?::?(\d{2})?(?:\.(\d{1,3}))
|
|
2
|
+
const TIME_PATTERN = /^(\d{2}):?(\d{2})(?::?(\d{2}))?(?:\.(\d{1,3}))?$/;
|
|
3
3
|
/**
|
|
4
4
|
* Validates if value is a time formatted string
|
|
5
5
|
* @validator isTime
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ValidationOptions } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
* @validator
|
|
3
|
+
* Validates if value matches the given regular expression, or returns undefined if nullish
|
|
4
|
+
* @validator matches
|
|
5
5
|
*/
|
|
6
6
|
export declare function matches(format: string | RegExp, options?: matches.Options): import("../../core/validator.js").Validator<string, string, import("../../core/types.js").ExecutionOptions>;
|
|
7
7
|
export declare namespace matches {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { validator, } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
* @validator
|
|
3
|
+
* Validates if value matches the given regular expression, or returns undefined if nullish
|
|
4
|
+
* @validator matches
|
|
5
5
|
*/
|
|
6
6
|
export function matches(format, options) {
|
|
7
7
|
const regExp = format instanceof RegExp ? format : new RegExp(format);
|
|
@@ -9,6 +9,7 @@ export function matches(format, options) {
|
|
|
9
9
|
return validator(matches.name, (input, context, _this) => {
|
|
10
10
|
if (input == null)
|
|
11
11
|
return;
|
|
12
|
+
regExp.lastIndex = 0;
|
|
12
13
|
if (typeof input === 'string' && regExp.test(input))
|
|
13
14
|
return input;
|
|
14
15
|
context.fail(_this, `Value must match ${formatName || 'requested'} format`, input, {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ValidationOptions } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
* Validates if value is not "undefined"
|
|
3
|
+
* Validates if value is not "undefined". Note that "null" is considered
|
|
4
|
+
* defined; use `isNotNullish` to reject both "undefined" and "null".
|
|
4
5
|
* @validator isDefined
|
|
5
6
|
*/
|
|
6
7
|
export declare function isDefined(options?: isDefined.Options): import("../../core/validator.js").Validator<any, unknown, import("../../core/types.js").ExecutionOptions>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { validator, } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
* Validates if value is not "undefined"
|
|
3
|
+
* Validates if value is not "undefined". Note that "null" is considered
|
|
4
|
+
* defined; use `isNotNullish` to reject both "undefined" and "null".
|
|
4
5
|
* @validator isDefined
|
|
5
6
|
*/
|
|
6
7
|
export function isDefined(options) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ValidationOptions } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Validates if the value is strictly equal ("===") to "compare".
|
|
4
|
+
* `null`/`undefined` input is passed through unchanged.
|
|
4
5
|
* @validator isEqual
|
|
5
6
|
*/
|
|
6
7
|
export declare function isEqual<T>(compare: T, options?: isEqual.Options): import("../../core/validator.js").Validator<any, any, import("../../core/types.js").ExecutionOptions>;
|
|
@@ -9,7 +10,8 @@ export declare namespace isEqual {
|
|
|
9
10
|
}
|
|
10
11
|
}
|
|
11
12
|
/**
|
|
12
|
-
*
|
|
13
|
+
* Validates if the value is not strictly equal ("===") to "compare".
|
|
14
|
+
* `null`/`undefined` input is passed through unchanged.
|
|
13
15
|
* @validator isNotEqual
|
|
14
16
|
*/
|
|
15
17
|
export declare function isNotEqual(compare: any, options?: isNotEqual.Options): import("../../core/validator.js").Validator<any, any, import("../../core/types.js").ExecutionOptions>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { validator, } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Validates if the value is strictly equal ("===") to "compare".
|
|
4
|
+
* `null`/`undefined` input is passed through unchanged.
|
|
4
5
|
* @validator isEqual
|
|
5
6
|
*/
|
|
6
7
|
export function isEqual(compare, options) {
|
|
@@ -13,7 +14,8 @@ export function isEqual(compare, options) {
|
|
|
13
14
|
}, options);
|
|
14
15
|
}
|
|
15
16
|
/**
|
|
16
|
-
*
|
|
17
|
+
* Validates if the value is not strictly equal ("===") to "compare".
|
|
18
|
+
* `null`/`undefined` input is passed through unchanged.
|
|
17
19
|
* @validator isNotEqual
|
|
18
20
|
*/
|
|
19
21
|
export function isNotEqual(compare, options) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type ValidationOptions, type Validator } from '../../core/index.js';
|
|
2
2
|
import type { range } from './range.js';
|
|
3
3
|
/**
|
|
4
|
-
* Checks if value is
|
|
5
|
-
* @validator
|
|
4
|
+
* Checks if value is greater than "minValue"
|
|
5
|
+
* @validator isGt
|
|
6
6
|
*/
|
|
7
7
|
export declare function isGt<T extends range.Input>(minValue: T, options?: isGt.Options): Validator;
|
|
8
8
|
export declare namespace isGt {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { validator, } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
* Checks if value is
|
|
4
|
-
* @validator
|
|
3
|
+
* Checks if value is greater than "minValue"
|
|
4
|
+
* @validator isGt
|
|
5
5
|
*/
|
|
6
6
|
export function isGt(minValue, options) {
|
|
7
7
|
return validator(isGt.name, (input, context, _this) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ValidationOptions, type Validator } from '../../core/index.js';
|
|
2
2
|
import type { range } from './range.js';
|
|
3
3
|
/**
|
|
4
|
-
* Checks if value is
|
|
4
|
+
* Checks if value is greater than or equal to minValue
|
|
5
5
|
* @validator isGte
|
|
6
6
|
*/
|
|
7
7
|
export declare function isGte<T extends range.Input>(minValue: T, options?: isGte.Options): Validator<T>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ValidationOptions, type Validator } from '../../core/index.js';
|
|
2
2
|
import type { range } from './range.js';
|
|
3
3
|
/**
|
|
4
|
-
* Checks if the value is
|
|
4
|
+
* Checks if the value is lower than maxValue
|
|
5
5
|
* @validator isLt
|
|
6
6
|
*/
|
|
7
7
|
export declare function isLt<T extends range.Input>(maxValue: T, options?: isLt.Options): Validator;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { validator, } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
* Checks if the value is
|
|
3
|
+
* Checks if the value is lower than maxValue
|
|
4
4
|
* @validator isLt
|
|
5
5
|
*/
|
|
6
6
|
export function isLt(maxValue, options) {
|
|
@@ -22,6 +22,6 @@ export function isLt(maxValue, options) {
|
|
|
22
22
|
input.toLowerCase() < maxValue.toLowerCase()))) {
|
|
23
23
|
return input;
|
|
24
24
|
}
|
|
25
|
-
context.fail(_this, `Value must be
|
|
25
|
+
context.fail(_this, `Value must be lower than ${typeof maxValue === 'string' ? `"${maxValue}"` : maxValue}`, input);
|
|
26
26
|
}, options);
|
|
27
27
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ValidationOptions, type Validator } from '../../core/index.js';
|
|
2
2
|
import type { range } from './range.js';
|
|
3
3
|
/**
|
|
4
|
-
* Checks if the value is
|
|
4
|
+
* Checks if the value is lower than or equal to maxValue
|
|
5
5
|
* @validator isLte
|
|
6
6
|
*/
|
|
7
7
|
export declare function isLte<T extends range.Input>(maxValue: T, options?: isLte.Options): Validator;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { validator, } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
* Checks if the value is
|
|
3
|
+
* Checks if the value is lower than or equal to maxValue
|
|
4
4
|
* @validator isLte
|
|
5
5
|
*/
|
|
6
6
|
export function isLte(maxValue, options) {
|
|
@@ -22,6 +22,6 @@ export function isLte(maxValue, options) {
|
|
|
22
22
|
input.toLowerCase() <= maxValue.toLowerCase()))) {
|
|
23
23
|
return input;
|
|
24
24
|
}
|
|
25
|
-
context.fail(_this, `Value must be
|
|
25
|
+
context.fail(_this, `Value must be lower than or equal to ${typeof maxValue === 'string' ? `"${maxValue}"` : maxValue}`, input);
|
|
26
26
|
}, options);
|
|
27
27
|
}
|
|
@@ -16,25 +16,27 @@ export function isArray(itemValidator, options) {
|
|
|
16
16
|
}
|
|
17
17
|
if (!itemValidator)
|
|
18
18
|
return output;
|
|
19
|
-
// const location = context.location || '';
|
|
20
19
|
const itemContext = context.extend();
|
|
21
20
|
let i;
|
|
22
21
|
let v;
|
|
23
22
|
const l = output.length;
|
|
24
23
|
const out = [];
|
|
24
|
+
// Set directly on the (already reused) context instead of passed as
|
|
25
|
+
// a fresh {onFail} options object on every call - `i` is read at call
|
|
26
|
+
// time (synchronously, before it's incremented), so a single closure
|
|
27
|
+
// works for the whole loop. This also lets the item call below pass
|
|
28
|
+
// `undefined` for options, which the validator wrapper needs in order
|
|
29
|
+
// to skip a needless context.extend() when the item rule has no
|
|
30
|
+
// options of its own.
|
|
31
|
+
itemContext.onFail = (issue) => `Item at index [${i}] is not valid. ` + issue.message;
|
|
25
32
|
for (i = 0; i < l; i++) {
|
|
26
33
|
v = output[i];
|
|
27
34
|
itemContext.scope = output;
|
|
28
|
-
// itemContext.location = location + '[' + i + ']';
|
|
29
35
|
itemContext.location = context.location
|
|
30
36
|
? context.location + `[${i}]`
|
|
31
37
|
: `<Array>[${i}]`;
|
|
32
38
|
itemContext.index = i;
|
|
33
|
-
v = itemValidator(v,
|
|
34
|
-
onFail(issue) {
|
|
35
|
-
return `Item at index [${i}] is not valid. ` + issue.message;
|
|
36
|
-
},
|
|
37
|
-
}, itemContext);
|
|
39
|
+
v = itemValidator(v, undefined, itemContext);
|
|
38
40
|
out.push(v);
|
|
39
41
|
}
|
|
40
42
|
return out;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type ValidationOptions } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Validates if value is "BigInt".
|
|
4
|
-
* Converts input value to
|
|
5
|
-
* @validator
|
|
4
|
+
* Converts input value to BigInt if the coerce option is set to 'true'.
|
|
5
|
+
* @validator isBigint
|
|
6
6
|
*/
|
|
7
7
|
export declare function isBigint(options?: isBigint.Options): import("../../core/validator.js").Validator<bigint, unknown, import("../../core/types.js").ExecutionOptions>;
|
|
8
8
|
export declare namespace isBigint {
|
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import { validator, } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Validates if value is "BigInt".
|
|
4
|
-
* Converts input value to
|
|
5
|
-
* @validator
|
|
4
|
+
* Converts input value to BigInt if the coerce option is set to 'true'.
|
|
5
|
+
* @validator isBigint
|
|
6
6
|
*/
|
|
7
7
|
export function isBigint(options) {
|
|
8
8
|
return validator(isBigint.name, (input, context, _this) => {
|
|
9
9
|
const coerce = options?.coerce ?? context.coerce;
|
|
10
10
|
if (typeof input === 'bigint')
|
|
11
11
|
return input;
|
|
12
|
-
if ((typeof input === 'number'
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
if (coerce && (typeof input === 'number' || typeof input === 'string')) {
|
|
13
|
+
try {
|
|
14
|
+
return BigInt(input);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
// falls through to context.fail below
|
|
18
|
+
}
|
|
15
19
|
}
|
|
16
20
|
context.fail(_this, `Value must be a BigInt`, input);
|
|
17
21
|
}, options);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { validator, } from '../../core/index.js';
|
|
2
|
-
const TRUE_PATTERN = /^true|t|1|yes|y$/i;
|
|
3
|
-
const FALSE_PATTERN = /^false|f|0|no|n$/i;
|
|
2
|
+
const TRUE_PATTERN = /^(?:true|t|1|yes|y)$/i;
|
|
3
|
+
const FALSE_PATTERN = /^(?:false|f|0|no|n)$/i;
|
|
4
4
|
/**
|
|
5
5
|
* Validates if value is "boolean".
|
|
6
6
|
* Converts input value to boolean if the coerce option is set to 'true'.
|