valgen 7.0.1 → 7.0.3
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 +1 -1
- package/constants.js +1 -1
- package/core/constants.d.ts +11 -0
- package/core/constants.js +11 -0
- package/core/context.d.ts +57 -0
- package/core/context.js +57 -0
- package/core/types.d.ts +40 -0
- package/core/utilities.d.ts +42 -2
- package/core/utilities.js +21 -1
- package/core/validation-error.d.ts +13 -0
- package/core/validation-error.js +13 -0
- package/core/validator.d.ts +100 -0
- package/core/validator.js +6 -0
- package/package.json +1 -1
- package/rules/format-rules/is-alpha.d.ts +10 -1
- package/rules/format-rules/is-alpha.js +10 -1
- package/rules/format-rules/is-alphanumeric.d.ts +10 -1
- package/rules/format-rules/is-alphanumeric.js +10 -1
- package/rules/format-rules/is-ascii.d.ts +10 -1
- package/rules/format-rules/is-ascii.js +10 -1
- package/rules/format-rules/is-base64.d.ts +20 -1
- package/rules/format-rules/is-base64.js +10 -1
- package/rules/format-rules/is-btc-address.d.ts +10 -1
- package/rules/format-rules/is-btc-address.js +10 -1
- package/rules/format-rules/is-credit-card.d.ts +16 -1
- package/rules/format-rules/is-credit-card.js +11 -1
- package/rules/format-rules/is-decimal.d.ts +12 -2
- package/rules/format-rules/is-decimal.js +12 -2
- package/rules/format-rules/is-ean.d.ts +11 -1
- package/rules/format-rules/is-ean.js +11 -1
- package/rules/format-rules/is-email.d.ts +19 -7
- package/rules/format-rules/is-email.js +13 -1
- package/rules/format-rules/is-eth-address.d.ts +10 -1
- package/rules/format-rules/is-eth-address.js +10 -1
- package/rules/format-rules/is-fqdn.d.ts +13 -2
- package/rules/format-rules/is-fqdn.js +12 -1
- package/rules/format-rules/is-hash.d.ts +17 -1
- package/rules/format-rules/is-hash.js +16 -1
- package/rules/format-rules/is-hex-color.d.ts +13 -1
- package/rules/format-rules/is-hex-color.js +13 -1
- package/rules/format-rules/is-hex.d.ts +13 -1
- package/rules/format-rules/is-hex.js +13 -1
- package/rules/format-rules/is-iban.d.ts +33 -2
- package/rules/format-rules/is-iban.js +19 -1
- package/rules/format-rules/is-ip.d.ts +44 -2
- package/rules/format-rules/is-ip.js +42 -2
- package/rules/format-rules/is-issn.d.ts +19 -2
- package/rules/format-rules/is-issn.js +18 -1
- package/rules/format-rules/is-jwt.d.ts +16 -1
- package/rules/format-rules/is-jwt.js +16 -1
- package/rules/format-rules/is-lowercase.d.ts +13 -1
- package/rules/format-rules/is-lowercase.js +13 -1
- package/rules/format-rules/is-mac-address.d.ts +19 -2
- package/rules/format-rules/is-mac-address.js +16 -1
- package/rules/format-rules/is-mobile-phone.d.ts +19 -3
- package/rules/format-rules/is-mobile-phone.js +17 -1
- package/rules/format-rules/is-object-id.d.ts +20 -1
- package/rules/format-rules/is-object-id.js +19 -1
- package/rules/format-rules/is-passport-number.d.ts +17 -1
- package/rules/format-rules/is-passport-number.js +17 -1
- package/rules/format-rules/is-port.d.ts +16 -1
- package/rules/format-rules/is-port.js +16 -1
- package/rules/format-rules/is-swift.d.ts +15 -1
- package/rules/format-rules/is-swift.js +15 -1
- package/rules/format-rules/is-time.d.ts +22 -1
- package/rules/format-rules/is-time.js +22 -1
- package/rules/format-rules/is-uppercase.d.ts +15 -1
- package/rules/format-rules/is-uppercase.js +15 -1
- package/rules/format-rules/is-url.d.ts +99 -1
- package/rules/format-rules/is-url.js +19 -1
- package/rules/format-rules/is-uuid.d.ts +23 -1
- package/rules/format-rules/is-uuid.js +23 -1
- package/rules/format-rules/is-vat-number.d.ts +19 -2
- package/rules/format-rules/is-vat-number.js +19 -2
- package/rules/format-rules/matches.d.ts +27 -1
- package/rules/format-rules/matches.js +23 -1
- package/rules/logical-rules/is-defined.d.ts +14 -2
- package/rules/logical-rules/is-defined.js +13 -2
- package/rules/logical-rules/is-empty.d.ts +40 -2
- package/rules/logical-rules/is-empty.js +38 -2
- package/rules/logical-rules/is-equal.d.ts +31 -4
- package/rules/logical-rules/is-equal.js +29 -4
- package/rules/logical-rules/is-gt.d.ts +26 -1
- package/rules/logical-rules/is-gt.js +20 -1
- package/rules/logical-rules/is-gte.d.ts +25 -1
- package/rules/logical-rules/is-gte.js +20 -1
- package/rules/logical-rules/is-lt.d.ts +24 -1
- package/rules/logical-rules/is-lt.js +19 -1
- package/rules/logical-rules/is-lte.d.ts +25 -1
- package/rules/logical-rules/is-lte.js +20 -1
- package/rules/logical-rules/length.d.ts +38 -2
- package/rules/logical-rules/length.js +38 -2
- package/rules/logical-rules/range.d.ts +25 -1
- package/rules/logical-rules/range.js +23 -1
- package/rules/type-rules/is-any.d.ts +12 -1
- package/rules/type-rules/is-any.js +12 -1
- package/rules/type-rules/is-array.d.ts +23 -2
- package/rules/type-rules/is-array.js +23 -2
- package/rules/type-rules/is-bigint.d.ts +14 -2
- package/rules/type-rules/is-bigint.js +14 -2
- package/rules/type-rules/is-boolean.d.ts +17 -2
- package/rules/type-rules/is-boolean.js +17 -2
- package/rules/type-rules/is-date.d.ts +47 -5
- package/rules/type-rules/is-date.js +42 -5
- package/rules/type-rules/is-enum.d.ts +23 -1
- package/rules/type-rules/is-enum.js +21 -1
- package/rules/type-rules/is-instanceof.d.ts +21 -1
- package/rules/type-rules/is-instanceof.js +21 -1
- package/rules/type-rules/is-integer.d.ts +17 -2
- package/rules/type-rules/is-integer.js +17 -2
- package/rules/type-rules/is-null.d.ts +51 -4
- package/rules/type-rules/is-null.js +51 -4
- package/rules/type-rules/is-number.d.ts +17 -2
- package/rules/type-rules/is-number.js +17 -2
- package/rules/type-rules/is-object.d.ts +45 -7
- package/rules/type-rules/is-object.js +40 -7
- package/rules/type-rules/is-record.d.ts +21 -2
- package/rules/type-rules/is-record.js +21 -2
- package/rules/type-rules/is-string.d.ts +16 -2
- package/rules/type-rules/is-string.js +16 -2
- package/rules/type-rules/is-tuple.d.ts +21 -2
- package/rules/type-rules/is-undefined.d.ts +16 -4
- package/rules/type-rules/is-undefined.js +16 -4
- package/rules/utility-rules/all-of.d.ts +28 -1
- package/rules/utility-rules/all-of.js +27 -1
- package/rules/utility-rules/exists.d.ts +30 -1
- package/rules/utility-rules/exists.js +29 -1
- package/rules/utility-rules/fixed.d.ts +19 -1
- package/rules/utility-rules/fixed.js +19 -1
- package/rules/utility-rules/get-length.d.ts +25 -2
- package/rules/utility-rules/get-length.js +25 -2
- package/rules/utility-rules/nullable.d.ts +28 -1
- package/rules/utility-rules/nullable.js +27 -1
- package/rules/utility-rules/one-of.d.ts +52 -3
- package/rules/utility-rules/one-of.js +51 -3
- package/rules/utility-rules/optional.d.ts +29 -1
- package/rules/utility-rules/optional.js +28 -1
- package/rules/utility-rules/pipe.d.ts +38 -1
- package/rules/utility-rules/pipe.js +30 -1
- package/rules/utility-rules/required.d.ts +39 -1
- package/rules/utility-rules/required.js +32 -1
- package/rules/utility-rules/string-utils.d.ts +99 -5
- package/rules/utility-rules/string-utils.js +53 -3
package/README.md
CHANGED
|
@@ -119,5 +119,5 @@ at the end of the run.
|
|
|
119
119
|
[downloads-url]: https://npmjs.org/package/valgen
|
|
120
120
|
[ci-test-image]: https://github.com/panates/valgen/actions/workflows/test.yml/badge.svg
|
|
121
121
|
[ci-test-url]: https://github.com/panates/valgen/actions/workflows/test.yml
|
|
122
|
-
[coveralls-image]: https://img.shields.io/coveralls/panates/valgen/
|
|
122
|
+
[coveralls-image]: https://img.shields.io/coveralls/panates/valgen/dev.svg
|
|
123
123
|
[coveralls-url]: https://coveralls.io/r/panates/valgen
|
package/constants.js
CHANGED
package/core/constants.d.ts
CHANGED
|
@@ -1,2 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Symbol key used to store a {@link Validator}'s underlying
|
|
3
|
+
* {@link ValidateFunction} on itself. Exported only because it appears in
|
|
4
|
+
* `Validator`'s type signature; not intended for direct use.
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
1
7
|
export declare const kValidatorFn: unique symbol;
|
|
8
|
+
/**
|
|
9
|
+
* Symbol key used to store a {@link Validator}'s construction-time
|
|
10
|
+
* {@link ValidationOptions} on itself. Not intended for direct use.
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
2
13
|
export declare const kOptions: unique symbol;
|
package/core/constants.js
CHANGED
|
@@ -1,2 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Symbol key used to store a {@link Validator}'s underlying
|
|
3
|
+
* {@link ValidateFunction} on itself. Exported only because it appears in
|
|
4
|
+
* `Validator`'s type signature; not intended for direct use.
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
1
7
|
export const kValidatorFn = Symbol.for('kValidatorFn');
|
|
8
|
+
/**
|
|
9
|
+
* Symbol key used to store a {@link Validator}'s construction-time
|
|
10
|
+
* {@link ValidationOptions} on itself. Not intended for direct use.
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
2
13
|
export const kOptions = Symbol.for('kOptions');
|
package/core/context.d.ts
CHANGED
|
@@ -1,20 +1,77 @@
|
|
|
1
1
|
import type { ErrorIssue, ExecutionOptions, OnFailFunction } from './types.js';
|
|
2
2
|
import type { Validator } from './validator.js';
|
|
3
|
+
/**
|
|
4
|
+
* Carries execution options and accumulated failures through a single
|
|
5
|
+
* validation run, including across nested validator calls.
|
|
6
|
+
*
|
|
7
|
+
* A root `Context` is created once for a top-level `validator(...)` call;
|
|
8
|
+
* nested rules (properties of an `isObject` schema, items of an `isArray`,
|
|
9
|
+
* steps of a `pipe`, ...) share it via {@link Context.extend}, so failures
|
|
10
|
+
* from anywhere in the run accumulate into the same `errors` array and are
|
|
11
|
+
* thrown together as a single {@link ValidationError}.
|
|
12
|
+
*/
|
|
3
13
|
export declare class Context implements ExecutionOptions {
|
|
14
|
+
/** `true` for the context created at the top-level call; `false` for every context produced by {@link Context.extend}. */
|
|
4
15
|
isRoot: boolean;
|
|
16
|
+
/** Issues recorded so far during this validation run (shared across nested contexts). */
|
|
5
17
|
errors: ErrorIssue[];
|
|
18
|
+
/** Stops collecting further issues (and throws immediately) once this many have been recorded. */
|
|
6
19
|
maxErrors?: number;
|
|
20
|
+
/** Intercepts every failure recorded through this context. */
|
|
7
21
|
onFail?: OnFailFunction;
|
|
22
|
+
/** Enables coercion for rules that support it. */
|
|
8
23
|
coerce?: boolean;
|
|
24
|
+
/** An identifying name for the root value being validated (e.g. a schema's class name), set once and inherited by every nested context. */
|
|
9
25
|
root?: string;
|
|
26
|
+
/** A dotted/bracketed path to the value currently being validated, e.g. `"user.address"` or `"items[0]"`. */
|
|
10
27
|
location?: string;
|
|
28
|
+
/** The object a nested property/item belongs to - used by rules like `exists` to look up property descriptors. */
|
|
11
29
|
scope?: object;
|
|
30
|
+
/** A human-readable name for the object/schema the current value belongs to. */
|
|
12
31
|
context?: string;
|
|
32
|
+
/** The name of the property currently being validated, when nested inside an object schema. */
|
|
13
33
|
property?: string;
|
|
34
|
+
/** The index of the item currently being validated, when nested inside an array/tuple. */
|
|
14
35
|
index?: number;
|
|
36
|
+
/** A human-readable label for the current value, used to resolve `{{label}}` in message templates. */
|
|
15
37
|
label?: string;
|
|
16
38
|
[key: string]: any;
|
|
39
|
+
/**
|
|
40
|
+
* @param options - Initial execution options, assigned directly onto the new context.
|
|
41
|
+
*/
|
|
17
42
|
constructor(options?: ExecutionOptions);
|
|
43
|
+
/**
|
|
44
|
+
* Records a validation failure as an {@link ErrorIssue}.
|
|
45
|
+
*
|
|
46
|
+
* Resolves `{{key}}` / `{{key|fallback}}` placeholders in `message` against
|
|
47
|
+
* the issue's own fields (falling back to this context's `location`/
|
|
48
|
+
* `property` for `{{label}}`), runs the context's `onFail` interceptor if
|
|
49
|
+
* set, then appends the result to `errors`. Throws immediately once
|
|
50
|
+
* `errors.length` reaches `maxErrors`; otherwise the root call throws a
|
|
51
|
+
* single {@link ValidationError} once the whole run completes.
|
|
52
|
+
*
|
|
53
|
+
* @param rule - The validator reporting the failure; its `id` is recorded on the issue.
|
|
54
|
+
* @param message - The failure message, or an `Error` whose `.message` is
|
|
55
|
+
* used instead. May contain `{{key}}`/`{{key|fallback}}` placeholders.
|
|
56
|
+
* @param value - The offending value.
|
|
57
|
+
* @param details - Additional fields to merge onto the recorded issue.
|
|
58
|
+
*/
|
|
18
59
|
fail(rule: Validator, message: string | Error, value: any, details?: Record<string, any>): void;
|
|
60
|
+
/**
|
|
61
|
+
* Creates a child context for a nested validator call, inheriting every
|
|
62
|
+
* field from this context via the prototype chain and overriding it with
|
|
63
|
+
* `options` where given.
|
|
64
|
+
*
|
|
65
|
+
* Nested rules (an object schema's properties, an array's items, a pipe's
|
|
66
|
+
* steps, ...) should reuse the *same* extended context across every call
|
|
67
|
+
* within one loop rather than calling `extend()` per call, and should
|
|
68
|
+
* prefer the 3-argument form `nestedRule(input, undefined, context)` so
|
|
69
|
+
* the validator wrapper doesn't extend the context a second time.
|
|
70
|
+
*
|
|
71
|
+
* @param options - Fields to override on the child context; `undefined`
|
|
72
|
+
* values are skipped so they fall through to the parent instead of
|
|
73
|
+
* shadowing it.
|
|
74
|
+
* @returns A new `Context` with `isRoot: false`, prototypically inheriting from this one.
|
|
75
|
+
*/
|
|
19
76
|
extend(options?: ExecutionOptions): Context;
|
|
20
77
|
}
|
package/core/context.js
CHANGED
|
@@ -2,22 +2,63 @@ import { omitUndefined } from '../helpers/omit-undefined.js';
|
|
|
2
2
|
import { ValidationError } from './validation-error.js';
|
|
3
3
|
const VARIABLE_REPLACE_PATTERN = /{{([^}]*)}}/g;
|
|
4
4
|
const OPTIONAL_VAR_PATTERN = /^([^|]+)(?:\|(.*))?$/;
|
|
5
|
+
/**
|
|
6
|
+
* Carries execution options and accumulated failures through a single
|
|
7
|
+
* validation run, including across nested validator calls.
|
|
8
|
+
*
|
|
9
|
+
* A root `Context` is created once for a top-level `validator(...)` call;
|
|
10
|
+
* nested rules (properties of an `isObject` schema, items of an `isArray`,
|
|
11
|
+
* steps of a `pipe`, ...) share it via {@link Context.extend}, so failures
|
|
12
|
+
* from anywhere in the run accumulate into the same `errors` array and are
|
|
13
|
+
* thrown together as a single {@link ValidationError}.
|
|
14
|
+
*/
|
|
5
15
|
export class Context {
|
|
16
|
+
/** `true` for the context created at the top-level call; `false` for every context produced by {@link Context.extend}. */
|
|
6
17
|
isRoot = true;
|
|
18
|
+
/** Issues recorded so far during this validation run (shared across nested contexts). */
|
|
7
19
|
errors = [];
|
|
20
|
+
/** Stops collecting further issues (and throws immediately) once this many have been recorded. */
|
|
8
21
|
maxErrors;
|
|
22
|
+
/** Intercepts every failure recorded through this context. */
|
|
9
23
|
onFail;
|
|
24
|
+
/** Enables coercion for rules that support it. */
|
|
10
25
|
coerce;
|
|
26
|
+
/** An identifying name for the root value being validated (e.g. a schema's class name), set once and inherited by every nested context. */
|
|
11
27
|
root;
|
|
28
|
+
/** A dotted/bracketed path to the value currently being validated, e.g. `"user.address"` or `"items[0]"`. */
|
|
12
29
|
location;
|
|
30
|
+
/** The object a nested property/item belongs to - used by rules like `exists` to look up property descriptors. */
|
|
13
31
|
scope;
|
|
32
|
+
/** A human-readable name for the object/schema the current value belongs to. */
|
|
14
33
|
context;
|
|
34
|
+
/** The name of the property currently being validated, when nested inside an object schema. */
|
|
15
35
|
property;
|
|
36
|
+
/** The index of the item currently being validated, when nested inside an array/tuple. */
|
|
16
37
|
index;
|
|
38
|
+
/** A human-readable label for the current value, used to resolve `{{label}}` in message templates. */
|
|
17
39
|
label;
|
|
40
|
+
/**
|
|
41
|
+
* @param options - Initial execution options, assigned directly onto the new context.
|
|
42
|
+
*/
|
|
18
43
|
constructor(options) {
|
|
19
44
|
Object.assign(this, options);
|
|
20
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Records a validation failure as an {@link ErrorIssue}.
|
|
48
|
+
*
|
|
49
|
+
* Resolves `{{key}}` / `{{key|fallback}}` placeholders in `message` against
|
|
50
|
+
* the issue's own fields (falling back to this context's `location`/
|
|
51
|
+
* `property` for `{{label}}`), runs the context's `onFail` interceptor if
|
|
52
|
+
* set, then appends the result to `errors`. Throws immediately once
|
|
53
|
+
* `errors.length` reaches `maxErrors`; otherwise the root call throws a
|
|
54
|
+
* single {@link ValidationError} once the whole run completes.
|
|
55
|
+
*
|
|
56
|
+
* @param rule - The validator reporting the failure; its `id` is recorded on the issue.
|
|
57
|
+
* @param message - The failure message, or an `Error` whose `.message` is
|
|
58
|
+
* used instead. May contain `{{key}}`/`{{key|fallback}}` placeholders.
|
|
59
|
+
* @param value - The offending value.
|
|
60
|
+
* @param details - Additional fields to merge onto the recorded issue.
|
|
61
|
+
*/
|
|
21
62
|
fail(rule, message, value, details) {
|
|
22
63
|
const issue = omitUndefined({
|
|
23
64
|
message: message instanceof Error ? message.message : String(message),
|
|
@@ -65,6 +106,22 @@ export class Context {
|
|
|
65
106
|
throw new ValidationError(this.errors);
|
|
66
107
|
}
|
|
67
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Creates a child context for a nested validator call, inheriting every
|
|
111
|
+
* field from this context via the prototype chain and overriding it with
|
|
112
|
+
* `options` where given.
|
|
113
|
+
*
|
|
114
|
+
* Nested rules (an object schema's properties, an array's items, a pipe's
|
|
115
|
+
* steps, ...) should reuse the *same* extended context across every call
|
|
116
|
+
* within one loop rather than calling `extend()` per call, and should
|
|
117
|
+
* prefer the 3-argument form `nestedRule(input, undefined, context)` so
|
|
118
|
+
* the validator wrapper doesn't extend the context a second time.
|
|
119
|
+
*
|
|
120
|
+
* @param options - Fields to override on the child context; `undefined`
|
|
121
|
+
* values are skipped so they fall through to the parent instead of
|
|
122
|
+
* shadowing it.
|
|
123
|
+
* @returns A new `Context` with `isRoot: false`, prototypically inheriting from this one.
|
|
124
|
+
*/
|
|
68
125
|
extend(options) {
|
|
69
126
|
// Object.create(this) sets the prototype at creation time. Setting it
|
|
70
127
|
// afterward via Object.setPrototypeOf() (the previous approach) is one
|
package/core/types.d.ts
CHANGED
|
@@ -1,24 +1,64 @@
|
|
|
1
1
|
import type { Context } from './context.js';
|
|
2
|
+
/**
|
|
3
|
+
* Describes a single validation failure recorded during a validator run.
|
|
4
|
+
*
|
|
5
|
+
* One `ErrorIssue` is created per failed check - a single {@link ValidationError}
|
|
6
|
+
* can carry more than one, e.g. when `isObject` validates several properties.
|
|
7
|
+
*/
|
|
2
8
|
export interface ErrorIssue {
|
|
9
|
+
/** The (already template-resolved) human-readable failure message. */
|
|
3
10
|
message: string;
|
|
11
|
+
/** The id of the validator that reported this issue, e.g. `"isEmail"`. */
|
|
4
12
|
rule: string;
|
|
13
|
+
/** The offending value that failed validation. */
|
|
5
14
|
value: any;
|
|
15
|
+
/** An identifying name for the root value being validated (e.g. a schema's class name), inherited from the root {@link Context}. */
|
|
6
16
|
root?: string;
|
|
17
|
+
/** A dotted/bracketed path to the failing value, e.g. `"user.email"` or `"items[0]"`. */
|
|
7
18
|
location?: string;
|
|
19
|
+
/** A human-readable name for the object/schema the failing property belongs to. */
|
|
8
20
|
context?: string;
|
|
21
|
+
/** The name of the failing property, when the issue originates from an object schema. */
|
|
9
22
|
property?: string;
|
|
23
|
+
/** The index of the failing item, when the issue originates from an array/tuple. */
|
|
10
24
|
index?: number;
|
|
25
|
+
/** A human-readable label for the failing value, used to resolve `{{label}}` in message templates. */
|
|
11
26
|
label?: string;
|
|
12
27
|
[key: string]: any;
|
|
13
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Intercepts a validation failure before it is recorded.
|
|
31
|
+
*
|
|
32
|
+
* Return a `string` to replace the issue's message, a partial {@link ErrorIssue}
|
|
33
|
+
* to merge onto it, or a falsy value to discard the issue entirely (as if
|
|
34
|
+
* validation had passed for this particular check).
|
|
35
|
+
*
|
|
36
|
+
* @param issue - The issue that is about to be recorded.
|
|
37
|
+
* @param context - The {@link Context} the failure occurred in.
|
|
38
|
+
* @returns A replacement message, a partial issue to merge in, or a falsy value to discard the issue.
|
|
39
|
+
*/
|
|
14
40
|
export type OnFailFunction = (issue: ErrorIssue, context: Context) => string | Omit<ErrorIssue, 'id' | 'input'>;
|
|
41
|
+
/**
|
|
42
|
+
* Options accepted by the {@link validator} factory - as opposed to per-call
|
|
43
|
+
* {@link ExecutionOptions}, these configure a rule's default behavior for
|
|
44
|
+
* every call unless overridden.
|
|
45
|
+
*/
|
|
15
46
|
export interface ValidationOptions {
|
|
47
|
+
/** Intercepts every failure this rule records. */
|
|
16
48
|
onFail?: OnFailFunction;
|
|
49
|
+
/** Enables coercion by default, for rules that support it. */
|
|
17
50
|
coerce?: boolean;
|
|
18
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Options accepted on a per-call basis by every {@link Validator}, in
|
|
54
|
+
* addition to whatever rule-specific options a given validator documents.
|
|
55
|
+
*/
|
|
19
56
|
export interface ExecutionOptions extends ValidationOptions {
|
|
57
|
+
/** When `true`, and the rule supports it, coerces compatible input into the target type instead of rejecting it. */
|
|
20
58
|
coerce?: boolean;
|
|
59
|
+
/** Stops collecting further issues (and throws immediately) once this many have been recorded. Defaults to unlimited. */
|
|
21
60
|
maxErrors?: number;
|
|
61
|
+
/** A human-readable name for the value being validated, used to resolve `{{label}}` in message templates instead of the raw property name. */
|
|
22
62
|
label?: string;
|
|
23
63
|
[key: string]: any;
|
|
24
64
|
}
|
package/core/utilities.d.ts
CHANGED
|
@@ -1,12 +1,52 @@
|
|
|
1
1
|
import type { Context } from './context.js';
|
|
2
2
|
import { type Validator } from './validator.js';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Defers to a validator produced lazily by `fn`, so a schema can reference
|
|
5
|
+
* itself (directly, or through a cycle of other schemas) without a
|
|
6
|
+
* "used before defined" error.
|
|
7
|
+
*
|
|
8
|
+
* @typeParam T - The output type of the resolved validator.
|
|
9
|
+
* @typeParam I - The input type of the resolved validator.
|
|
10
|
+
* @param fn - Called on every validation to resolve the actual validator to
|
|
11
|
+
* delegate to - receives the current {@link Context} in case the
|
|
12
|
+
* resolution needs it.
|
|
13
|
+
* @returns A validator that resolves and delegates to `fn(context)` on every call.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { forwardRef, vg } from 'valgen';
|
|
18
|
+
*
|
|
19
|
+
* // self-referential schema, e.g. a tree node
|
|
20
|
+
* const treeNode = vg.isObject({
|
|
21
|
+
* value: vg.isNumber(),
|
|
22
|
+
* children: vg.optional(vg.isArray(forwardRef(() => treeNode))),
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
5
25
|
* @validator forwardRef
|
|
6
26
|
*/
|
|
7
27
|
export declare function forwardRef<T, I>(fn: (context: Context) => Validator<T, I>): Validator<T, I, import("./types.js").ExecutionOptions>;
|
|
8
28
|
/**
|
|
9
|
-
*
|
|
29
|
+
* Picks between two validators (or plain values) based on whether `check`
|
|
30
|
+
* passes against the input.
|
|
31
|
+
*
|
|
32
|
+
* @typeParam TOutput1 - The output type when `check` passes and `than_` is a validator.
|
|
33
|
+
* @typeParam TOutput2 - The output type when `check` fails and `else_` is a validator.
|
|
34
|
+
* @typeParam TDefault1 - The type of `than_` when it is a plain (non-validator) value.
|
|
35
|
+
* @typeParam TDefault2 - The type of `else_` when it is a plain (non-validator) value.
|
|
36
|
+
* @param check - Tried against the input; success (no throw) selects `than_`, failure selects `else_`.
|
|
37
|
+
* @param than_ - Used when `check` passes: a validator to run against the
|
|
38
|
+
* input, or a constant value to return as-is (ignoring the input).
|
|
39
|
+
* @param else_ - Used when `check` fails: a validator to run against the
|
|
40
|
+
* input, or a constant value to return as-is. Defaults to `undefined` when omitted.
|
|
41
|
+
* @returns A validator that resolves to whichever branch `check` selects.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* import { iif, isDefined, isNumber, isString } from 'valgen';
|
|
46
|
+
*
|
|
47
|
+
* // coerce differently depending on whether the value is present
|
|
48
|
+
* iif(isDefined, isString, isNumber)(1, { coerce: true }); // => '1'
|
|
49
|
+
* ```
|
|
10
50
|
* @validator iif
|
|
11
51
|
*/
|
|
12
52
|
export declare function iif<TOutput1, TOutput2, TDefault1, TDefault2>(check: Validator<any>, than_: TDefault1 | Validator<TOutput1, any>, else_?: TDefault2 | Validator<TOutput2, any>): any;
|
package/core/utilities.js
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
import { isValidator, validator } from './validator.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Defers to a validator produced lazily by `fn`, so a schema can reference
|
|
4
|
+
* itself (directly, or through a cycle of other schemas) without a
|
|
5
|
+
* "used before defined" error.
|
|
6
|
+
*
|
|
7
|
+
* @typeParam T - The output type of the resolved validator.
|
|
8
|
+
* @typeParam I - The input type of the resolved validator.
|
|
9
|
+
* @param fn - Called on every validation to resolve the actual validator to
|
|
10
|
+
* delegate to - receives the current {@link Context} in case the
|
|
11
|
+
* resolution needs it.
|
|
12
|
+
* @returns A validator that resolves and delegates to `fn(context)` on every call.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { forwardRef, vg } from 'valgen';
|
|
17
|
+
*
|
|
18
|
+
* // self-referential schema, e.g. a tree node
|
|
19
|
+
* const treeNode = vg.isObject({
|
|
20
|
+
* value: vg.isNumber(),
|
|
21
|
+
* children: vg.optional(vg.isArray(forwardRef(() => treeNode))),
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
4
24
|
* @validator forwardRef
|
|
5
25
|
*/
|
|
6
26
|
export function forwardRef(fn) {
|
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
import { type ErrorIssue } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown by a {@link Validator} when validation fails at the root call (as
|
|
4
|
+
* opposed to `.silent()`, which returns a `{ errors }` result instead).
|
|
5
|
+
*
|
|
6
|
+
* Carries every {@link ErrorIssue} recorded during the run, not just the
|
|
7
|
+
* first one - inspect `issues` for the full list of failures, e.g. every
|
|
8
|
+
* failing property of an `isObject` schema.
|
|
9
|
+
*/
|
|
2
10
|
export declare class ValidationError extends Error {
|
|
11
|
+
/** Every issue recorded during this validation run, in the order they occurred. */
|
|
3
12
|
issues: ErrorIssue[];
|
|
13
|
+
/**
|
|
14
|
+
* @param issues - The recorded issues. The error's own `message` (and
|
|
15
|
+
* optional `\n at <location>` suffix) is derived from `issues[0]`.
|
|
16
|
+
*/
|
|
4
17
|
constructor(issues: ErrorIssue[]);
|
|
5
18
|
}
|
package/core/validation-error.js
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import {} from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown by a {@link Validator} when validation fails at the root call (as
|
|
4
|
+
* opposed to `.silent()`, which returns a `{ errors }` result instead).
|
|
5
|
+
*
|
|
6
|
+
* Carries every {@link ErrorIssue} recorded during the run, not just the
|
|
7
|
+
* first one - inspect `issues` for the full list of failures, e.g. every
|
|
8
|
+
* failing property of an `isObject` schema.
|
|
9
|
+
*/
|
|
2
10
|
export class ValidationError extends Error {
|
|
11
|
+
/** Every issue recorded during this validation run, in the order they occurred. */
|
|
3
12
|
issues = [];
|
|
13
|
+
/**
|
|
14
|
+
* @param issues - The recorded issues. The error's own `message` (and
|
|
15
|
+
* optional `\n at <location>` suffix) is derived from `issues[0]`.
|
|
16
|
+
*/
|
|
4
17
|
constructor(issues) {
|
|
5
18
|
super(issues[0].message +
|
|
6
19
|
(issues[0].location ? `\n at ${issues[0].location}` : ''));
|
package/core/validator.d.ts
CHANGED
|
@@ -2,17 +2,117 @@ import type { Nullish } from 'ts-gems';
|
|
|
2
2
|
import { kValidatorFn } from './constants.js';
|
|
3
3
|
import { Context } from './context.js';
|
|
4
4
|
import type { ErrorIssue, ExecutionOptions, ValidationOptions } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* The validation logic a {@link Validator} is built from - the function
|
|
7
|
+
* passed to {@link validator}.
|
|
8
|
+
*
|
|
9
|
+
* @typeParam T - The output type on success.
|
|
10
|
+
* @typeParam I - The accepted input type.
|
|
11
|
+
* @typeParam R - The `Validator` this function is built into.
|
|
12
|
+
* @param input - The value to validate.
|
|
13
|
+
* @param context - The current {@link Context}: carries execution options
|
|
14
|
+
* (`coerce`, `label`, ...) and is used to report failures via `context.fail(...)`.
|
|
15
|
+
* @param _this - The `Validator` this function was built into - pass it to
|
|
16
|
+
* `context.fail()` so a reported issue is attributed to the right rule.
|
|
17
|
+
* @returns The validated (and possibly coerced) value. To reject the input,
|
|
18
|
+
* call `context.fail(_this, message, input)` instead of throwing directly.
|
|
19
|
+
*/
|
|
5
20
|
export type ValidateFunction<T, I = T, R extends Validator<T, I> = Validator<T, I>> = (input: I, context: Context, _this: R) => Nullish<T>;
|
|
21
|
+
/**
|
|
22
|
+
* A callable validation rule, as produced by {@link validator}. Every rule in
|
|
23
|
+
* this library - and any custom rule built with `validator()` - has this shape.
|
|
24
|
+
*
|
|
25
|
+
* @typeParam T - The validated output type.
|
|
26
|
+
* @typeParam I - The accepted input type.
|
|
27
|
+
* @typeParam O - The shape of the per-call options this validator accepts.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* import { isEmail } from 'valgen';
|
|
32
|
+
*
|
|
33
|
+
* isEmail('a@b.com'); // => 'a@b.com'
|
|
34
|
+
* isEmail('invalid'); // throws ValidationError
|
|
35
|
+
* isEmail.silent('invalid'); // => { errors: [...] }
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
6
38
|
export interface Validator<T = any, I = any, O extends ExecutionOptions = ExecutionOptions> {
|
|
39
|
+
/**
|
|
40
|
+
* Validates `input`, returning the (possibly coerced) value on success.
|
|
41
|
+
*
|
|
42
|
+
* @param input - The value to validate.
|
|
43
|
+
* @param options - Per-call execution options (`coerce`, `label`, ...).
|
|
44
|
+
* @param context - An existing {@link Context} to nest this call under
|
|
45
|
+
* another validator's run. When calling a validator *from inside another
|
|
46
|
+
* rule*, pass the shared context here (3rd argument) and `undefined` for
|
|
47
|
+
* `options`, so the wrapper can skip an unneeded `context.extend()`.
|
|
48
|
+
* @returns The validated (and possibly coerced) value.
|
|
49
|
+
* @throws {@link ValidationError} if validation fails at the root call
|
|
50
|
+
* (i.e. `context` was not passed in, meaning this is the outermost call).
|
|
51
|
+
*/
|
|
7
52
|
(input: I, options?: O, context?: Context): T;
|
|
53
|
+
/**
|
|
54
|
+
* Like calling the validator directly, but never throws.
|
|
55
|
+
*
|
|
56
|
+
* @returns `{ value }` on success, or `{ errors }` (the recorded {@link ErrorIssue}s) on failure.
|
|
57
|
+
*/
|
|
8
58
|
silent(input: I, options?: O, context?: Context): {
|
|
9
59
|
value?: T;
|
|
10
60
|
errors?: ErrorIssue[];
|
|
11
61
|
};
|
|
62
|
+
/** This rule's identifier (e.g. `"isEmail"`), used to attribute reported issues to it. */
|
|
12
63
|
id: string;
|
|
13
64
|
args?: Record<string, any>;
|
|
14
65
|
[kValidatorFn]: ValidateFunction<T, I>;
|
|
15
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Builds a {@link Validator} from a validation function.
|
|
69
|
+
*
|
|
70
|
+
* This is the single factory every rule in this library - and any custom
|
|
71
|
+
* rule you write - is built with. See {@link ValidateFunction} for the shape
|
|
72
|
+
* expected of `fn`.
|
|
73
|
+
*
|
|
74
|
+
* @param fn - The validation logic: receives `(input, context, self)` and
|
|
75
|
+
* should return the validated value, or call `context.fail(self, message, input)`
|
|
76
|
+
* to record a failure. The rule's id defaults to `fn.name`.
|
|
77
|
+
* @param validatorOptions - Default options for this rule (e.g. `coerce`,
|
|
78
|
+
* `onFail`), applied to every call unless overridden per-call.
|
|
79
|
+
* @returns A callable {@link Validator}.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* import { validator, type Context, type Nullish, type ValidationOptions } from 'valgen';
|
|
84
|
+
*
|
|
85
|
+
* function isEven(options?: isEven.Options) {
|
|
86
|
+
* return validator<number, unknown>(
|
|
87
|
+
* isEven.name,
|
|
88
|
+
* (input, context, self): Nullish<number> => {
|
|
89
|
+
* const n = Number(input);
|
|
90
|
+
* if (Number.isInteger(n) && n % 2 === 0) return n;
|
|
91
|
+
* context.fail(self, 'Value must be an even number', input);
|
|
92
|
+
* },
|
|
93
|
+
* options,
|
|
94
|
+
* );
|
|
95
|
+
* }
|
|
96
|
+
* namespace isEven {
|
|
97
|
+
* export interface Options extends ValidationOptions {}
|
|
98
|
+
* }
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
16
101
|
export declare function validator<T, I = T, O extends ExecutionOptions = ExecutionOptions>(fn: ValidateFunction<T, I>, validatorOptions?: ValidationOptions): Validator<T, I, O>;
|
|
102
|
+
/**
|
|
103
|
+
* Builds a {@link Validator} from a validation function, with an explicit id.
|
|
104
|
+
*
|
|
105
|
+
* @param id - The rule's identifier, used for `Validator.id` and (unless `fn`
|
|
106
|
+
* is itself named) as the built function's name.
|
|
107
|
+
* @param fn - The validation logic - see the other overload for details.
|
|
108
|
+
* @param validatorOptions - Default options for this rule.
|
|
109
|
+
* @returns A callable {@link Validator}.
|
|
110
|
+
*/
|
|
17
111
|
export declare function validator<T, I = T, O extends ExecutionOptions = ExecutionOptions>(id: string, fn: ValidateFunction<T, I>, validatorOptions?: ValidationOptions): Validator<T, I, O>;
|
|
112
|
+
/**
|
|
113
|
+
* Checks whether `x` is a {@link Validator} built with {@link validator}.
|
|
114
|
+
*
|
|
115
|
+
* @param x - The value to check.
|
|
116
|
+
* @returns `true` if `x` is a validator, narrowing its type accordingly.
|
|
117
|
+
*/
|
|
18
118
|
export declare function isValidator(x: any): x is Validator;
|
package/core/validator.js
CHANGED
|
@@ -62,6 +62,12 @@ export function validator(arg0, arg1, arg2) {
|
|
|
62
62
|
};
|
|
63
63
|
return _rule;
|
|
64
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Checks whether `x` is a {@link Validator} built with {@link validator}.
|
|
67
|
+
*
|
|
68
|
+
* @param x - The value to check.
|
|
69
|
+
* @returns `true` if `x` is a validator, narrowing its type accordingly.
|
|
70
|
+
*/
|
|
65
71
|
export function isValidator(x) {
|
|
66
72
|
return !!(typeof x === 'function' && x.id && x[kValidatorFn]);
|
|
67
73
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import { type ValidationOptions } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Validates that a string contains only letters (`a-zA-Z`). Delegates to
|
|
4
|
+
* `validatorJS.isAlpha`.
|
|
4
5
|
* @validator isAlpha
|
|
6
|
+
* @param options - Validation options.
|
|
7
|
+
* @returns The input string, unchanged, if valid.
|
|
8
|
+
* @throws if `input` is not a string of letters only: `Value must be an alpha string`
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* isAlpha('abcDEF'); // => 'abcDEF'
|
|
12
|
+
* isAlpha('abc123'); // throws ValidationError: "Value must be an alpha string"
|
|
13
|
+
* ```
|
|
5
14
|
*/
|
|
6
15
|
export declare function isAlpha(options?: isAlpha.Options): import("../../core/validator.js").Validator<string, string, import("../../core/types.js").ExecutionOptions>;
|
|
7
16
|
export declare namespace isAlpha {
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import validatorJS from '@browsery/validator';
|
|
2
2
|
import { validator, } from '../../core/index.js';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Validates that a string contains only letters (`a-zA-Z`). Delegates to
|
|
5
|
+
* `validatorJS.isAlpha`.
|
|
5
6
|
* @validator isAlpha
|
|
7
|
+
* @param options - Validation options.
|
|
8
|
+
* @returns The input string, unchanged, if valid.
|
|
9
|
+
* @throws if `input` is not a string of letters only: `Value must be an alpha string`
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* isAlpha('abcDEF'); // => 'abcDEF'
|
|
13
|
+
* isAlpha('abc123'); // throws ValidationError: "Value must be an alpha string"
|
|
14
|
+
* ```
|
|
6
15
|
*/
|
|
7
16
|
export function isAlpha(options) {
|
|
8
17
|
return validator(isAlpha.name, (input, context, _this) => {
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import { type ValidationOptions } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Validates that a string contains only letters and numbers. Delegates to
|
|
4
|
+
* `validatorJS.isAlphanumeric`.
|
|
4
5
|
* @validator isAlphanumeric
|
|
6
|
+
* @param options - Validation options.
|
|
7
|
+
* @returns The input string, unchanged, if valid.
|
|
8
|
+
* @throws if `input` is not a string of letters/numbers only: `Value must be an alphanumeric string`
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* isAlphanumeric('abc123'); // => 'abc123'
|
|
12
|
+
* isAlphanumeric('abc-123'); // throws ValidationError: "Value must be an alphanumeric string"
|
|
13
|
+
* ```
|
|
5
14
|
*/
|
|
6
15
|
export declare function isAlphanumeric(options?: isAlphanumeric.Options): import("../../core/validator.js").Validator<string, string, import("../../core/types.js").ExecutionOptions>;
|
|
7
16
|
export declare namespace isAlphanumeric {
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import validatorJS from '@browsery/validator';
|
|
2
2
|
import { validator, } from '../../core/index.js';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Validates that a string contains only letters and numbers. Delegates to
|
|
5
|
+
* `validatorJS.isAlphanumeric`.
|
|
5
6
|
* @validator isAlphanumeric
|
|
7
|
+
* @param options - Validation options.
|
|
8
|
+
* @returns The input string, unchanged, if valid.
|
|
9
|
+
* @throws if `input` is not a string of letters/numbers only: `Value must be an alphanumeric string`
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* isAlphanumeric('abc123'); // => 'abc123'
|
|
13
|
+
* isAlphanumeric('abc-123'); // throws ValidationError: "Value must be an alphanumeric string"
|
|
14
|
+
* ```
|
|
6
15
|
*/
|
|
7
16
|
export function isAlphanumeric(options) {
|
|
8
17
|
return validator(isAlphanumeric.name, (input, context, _this) => {
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import { type ValidationOptions } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Validates that a string contains only ASCII characters. Delegates to
|
|
4
|
+
* `validatorJS.isAscii`.
|
|
4
5
|
* @validator isAscii
|
|
6
|
+
* @param options - Validation options.
|
|
7
|
+
* @returns The input string, unchanged, if valid.
|
|
8
|
+
* @throws if `input` contains non-ASCII characters: `Value must be an ascii string`
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* isAscii('abc123!@#'); // => 'abc123!@#'
|
|
12
|
+
* isAscii('şiir'); // throws ValidationError: "Value must be an ascii string"
|
|
13
|
+
* ```
|
|
5
14
|
*/
|
|
6
15
|
export declare function isAscii(options?: isAscii.Options): import("../../core/validator.js").Validator<string, string, import("../../core/types.js").ExecutionOptions>;
|
|
7
16
|
export declare namespace isAscii {
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import validatorJS from '@browsery/validator';
|
|
2
2
|
import { validator, } from '../../core/index.js';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Validates that a string contains only ASCII characters. Delegates to
|
|
5
|
+
* `validatorJS.isAscii`.
|
|
5
6
|
* @validator isAscii
|
|
7
|
+
* @param options - Validation options.
|
|
8
|
+
* @returns The input string, unchanged, if valid.
|
|
9
|
+
* @throws if `input` contains non-ASCII characters: `Value must be an ascii string`
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* isAscii('abc123!@#'); // => 'abc123!@#'
|
|
13
|
+
* isAscii('şiir'); // throws ValidationError: "Value must be an ascii string"
|
|
14
|
+
* ```
|
|
6
15
|
*/
|
|
7
16
|
export function isAscii(options) {
|
|
8
17
|
return validator(isAscii.name, (input, context, _this) => {
|