@fgv/ts-utils 5.0.0-17 → 5.0.0-18

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.
Files changed (31) hide show
  1. package/dist/ts-utils.d.ts +11 -8
  2. package/lib/packlets/validation/array.d.ts +2 -1
  3. package/lib/packlets/validation/array.js +2 -1
  4. package/lib/packlets/validation/common.d.ts +0 -8
  5. package/lib/packlets/validation/field.d.ts +1 -1
  6. package/lib/packlets/validation/field.js +1 -1
  7. package/lib/packlets/validation/genericValidator.d.ts +1 -6
  8. package/lib/packlets/validation/genericValidator.js +11 -11
  9. package/lib/packlets/validation/object.d.ts +1 -1
  10. package/lib/packlets/validation/object.js +1 -1
  11. package/lib/packlets/validation/oneOf.d.ts +2 -1
  12. package/lib/packlets/validation/oneOf.js +2 -1
  13. package/lib/packlets/validation/typeGuard.d.ts +3 -2
  14. package/lib/packlets/validation/typeGuard.js +2 -1
  15. package/lib/packlets/validation/validator.d.ts +7 -0
  16. package/lib/packlets/validation/validatorBase.d.ts +2 -1
  17. package/lib/packlets/validation/validatorBase.js +1 -1
  18. package/lib/packlets/validation/validators.d.ts +2 -2
  19. package/lib/packlets/validation/validators.js +3 -3
  20. package/lib/test/unit/validation/recursiveValidation.test.d.ts +2 -0
  21. package/package.json +1 -1
  22. package/src/packlets/validation/array.ts +3 -2
  23. package/src/packlets/validation/common.ts +0 -10
  24. package/src/packlets/validation/field.ts +1 -1
  25. package/src/packlets/validation/genericValidator.ts +18 -19
  26. package/src/packlets/validation/object.ts +1 -1
  27. package/src/packlets/validation/oneOf.ts +2 -1
  28. package/src/packlets/validation/typeGuard.ts +3 -2
  29. package/src/packlets/validation/validator.ts +12 -0
  30. package/src/packlets/validation/validatorBase.ts +7 -2
  31. package/src/packlets/validation/validators.ts +13 -5
@@ -58,10 +58,11 @@ declare class ArrayValidator<T, TC = unknown> extends ValidatorBase<T[], TC> {
58
58
  * validator.
59
59
  * @param from - The `unknown` value to be tested.
60
60
  * @param context - Optional validation context will be propagated to element validator.
61
+ * @param self - Optional self-reference for recursive validation.
61
62
  * @returns Returns `true` if `from` is an `array` of valid elements, or
62
63
  * {@link Failure} with an error message if not.
63
64
  */
64
- protected _validate<T>(from: unknown, context?: TC): boolean | Failure<T>;
65
+ protected _validate(from: unknown, context?: TC, self?: Validator<T[], TC>): boolean | Failure<T[]>;
65
66
  }
66
67
 
67
68
  /**
@@ -74,7 +75,6 @@ declare interface ArrayValidatorConstructorParams<T, TC = unknown> extends Valid
74
75
 
75
76
  declare namespace Base {
76
77
  export {
77
- ValidatorFunc,
78
78
  GenericValidatorConstructorParams,
79
79
  GenericValidator
80
80
  }
@@ -3420,7 +3420,7 @@ declare class Collectible<TKEY extends string = string, TINDEX extends number =
3420
3420
  * {@inheritdoc Validation.ValidatorBase._validate}
3421
3421
  * @internal
3422
3422
  */
3423
- protected _validate(from: unknown, context?: TC): boolean | Failure<T>;
3423
+ protected _validate(from: unknown, context?: TC, self?: Validator<T, TC>): boolean | Failure<T>;
3424
3424
  }
3425
3425
 
3426
3426
  /**
@@ -3522,10 +3522,11 @@ declare class Collectible<TKEY extends string = string, TINDEX extends number =
3522
3522
  * of the configured validators.
3523
3523
  * @param from - The `unknown` value to be tested.
3524
3524
  * @param context - Optional validation context will be propagated to element validator.
3525
+ * @param self - Optional self-reference for recursive validation.
3525
3526
  * @returns Returns `true` if `from` is an `array` of valid elements, or
3526
3527
  * {@link Failure} with an error message if not.
3527
3528
  */
3528
- protected _validate<T>(from: unknown, context?: TC): boolean | Failure<T>;
3529
+ protected _validate<T>(from: unknown, context?: TC, self?: Validator<T, TC>): boolean | Failure<T>;
3529
3530
  }
3530
3531
 
3531
3532
  /**
@@ -4439,11 +4440,12 @@ declare class Collectible<TKEY extends string = string, TINDEX extends number =
4439
4440
  * type guard, returning a `Failure<T>` containing more information about a failure.
4440
4441
  * @param from - Value to be converted.
4441
4442
  * @param context - Optional validation context.
4443
+ * @param self - Optional self-reference for recursive validation.
4442
4444
  * @returns `true` if `from` is valid, {@link Failure | Failure<T>}
4443
4445
  * with an error message if `from` is invalid.
4444
4446
  * @internal
4445
4447
  */
4446
- protected _validate(from: unknown, context?: TC): boolean | Failure<T>;
4448
+ protected _validate(from: unknown, context?: TC, self?: Validator<T, TC>): boolean | Failure<T>;
4447
4449
  }
4448
4450
 
4449
4451
  /**
@@ -4601,12 +4603,12 @@ declare class Collectible<TKEY extends string = string, TINDEX extends number =
4601
4603
  Classes,
4602
4604
  Validators,
4603
4605
  TypeGuardWithContext,
4604
- ValidatorFunc,
4605
4606
  FunctionConstraintTrait,
4606
4607
  ConstraintTrait,
4607
4608
  ValidatorTraitValues,
4608
4609
  defaultValidatorTraits,
4609
4610
  ValidatorTraits,
4611
+ ValidatorFunc,
4610
4612
  ValidatorOptions,
4611
4613
  Constraint,
4612
4614
  ValidationErrorFormatter,
@@ -4722,11 +4724,12 @@ declare class Collectible<TKEY extends string = string, TINDEX extends number =
4722
4724
  * Abstract validation method to me implemented by derived classes.
4723
4725
  * @param from - Value to be converted.
4724
4726
  * @param context - Optional validation context.
4727
+ * @param self - Optional self-reference for recursive validation.
4725
4728
  * @returns `true` if `from` is valid, {@link Failure | Failure<T>}
4726
4729
  * with an error message if `from` is invalid.
4727
4730
  * @internal
4728
4731
  */
4729
- protected abstract _validate(from: unknown, context?: TC): boolean | Failure<T>;
4732
+ protected abstract _validate(from: unknown, context?: TC, self?: Validator<T, TC>): boolean | Failure<T>;
4730
4733
  }
4731
4734
 
4732
4735
  /**
@@ -4740,7 +4743,7 @@ declare class Collectible<TKEY extends string = string, TINDEX extends number =
4740
4743
  * an optionally-supplied validation context of type `<TC>`.
4741
4744
  * @public
4742
4745
  */
4743
- declare type ValidatorFunc<T, TC> = (from: unknown, context?: TC) => boolean | Failure<T>;
4746
+ declare type ValidatorFunc<T, TC> = (from: unknown, context?: TC, self?: Validator<T, TC>) => boolean | Failure<T>;
4744
4747
 
4745
4748
  /**
4746
4749
  * Options that apply to any {@link Validation.Validator | Validator}.
@@ -32,9 +32,10 @@ export declare class ArrayValidator<T, TC = unknown> extends ValidatorBase<T[],
32
32
  * validator.
33
33
  * @param from - The `unknown` value to be tested.
34
34
  * @param context - Optional validation context will be propagated to element validator.
35
+ * @param self - Optional self-reference for recursive validation.
35
36
  * @returns Returns `true` if `from` is an `array` of valid elements, or
36
37
  * {@link Failure} with an error message if not.
37
38
  */
38
- protected _validate<T>(from: unknown, context?: TC): boolean | Failure<T>;
39
+ protected _validate(from: unknown, context?: TC, self?: Validator<T[], TC>): boolean | Failure<T[]>;
39
40
  }
40
41
  //# sourceMappingURL=array.d.ts.map
@@ -47,10 +47,11 @@ class ArrayValidator extends validatorBase_1.ValidatorBase {
47
47
  * validator.
48
48
  * @param from - The `unknown` value to be tested.
49
49
  * @param context - Optional validation context will be propagated to element validator.
50
+ * @param self - Optional self-reference for recursive validation.
50
51
  * @returns Returns `true` if `from` is an `array` of valid elements, or
51
52
  * {@link Failure} with an error message if not.
52
53
  */
53
- _validate(from, context) {
54
+ _validate(from, context, self) {
54
55
  if (Array.isArray(from)) {
55
56
  for (const elem of from) {
56
57
  const result = this._validateElement.validate(elem, context);
@@ -1,15 +1,7 @@
1
- import { Failure } from '../base';
2
1
  /**
3
2
  * A type guard function which validates a specific type, with an optional context
4
3
  * that can be used to shape the validation.
5
4
  * @public
6
5
  */
7
6
  export type TypeGuardWithContext<T, TC = unknown> = (from: unknown, context?: TC) => from is T;
8
- /**
9
- * Type for a validation function, which validates that a supplied `unknown`
10
- * value is a valid value of type `<T>`, possibly as influenced by
11
- * an optionally-supplied validation context of type `<TC>`.
12
- * @public
13
- */
14
- export type ValidatorFunc<T, TC> = (from: unknown, context?: TC) => boolean | Failure<T>;
15
7
  //# sourceMappingURL=common.d.ts.map
@@ -38,6 +38,6 @@ export declare class FieldValidator<T, TC = unknown> extends ValidatorBase<T, TC
38
38
  /**
39
39
  * {@inheritdoc Validation.ValidatorBase._validate}
40
40
  */
41
- protected _validate(from: unknown, context?: TC): boolean | Failure<T>;
41
+ protected _validate(from: unknown, context?: TC, self?: Validator<T, TC>): boolean | Failure<T>;
42
42
  }
43
43
  //# sourceMappingURL=field.d.ts.map
@@ -48,7 +48,7 @@ class FieldValidator extends validatorBase_1.ValidatorBase {
48
48
  /**
49
49
  * {@inheritdoc Validation.ValidatorBase._validate}
50
50
  */
51
- _validate(from, context) {
51
+ _validate(from, context, self) {
52
52
  if (typeof from === 'object' && !Array.isArray(from) && from !== null) {
53
53
  const optional = this._fieldOptions.optional === true;
54
54
  if ((0, base_1.isKeyOf)(this.fieldName, from)) {
@@ -1,11 +1,6 @@
1
1
  import { Brand, Result } from '../base';
2
2
  import { ConstraintTrait, ValidatorTraits } from './traits';
3
- import { Constraint, ValidationErrorFormatter, Validator, ValidatorOptions } from './validator';
4
- import { ValidatorFunc } from './common';
5
- /**
6
- * @deprecated Use {@link Validation.Common.ValidatorFunc | Validation.Common.ValidatorFunc} instead.
7
- */
8
- export { ValidatorFunc };
3
+ import { Constraint, ValidationErrorFormatter, Validator, ValidatorFunc, ValidatorOptions } from './validator';
9
4
  /**
10
5
  * Options used to initialize a {@link Validation.Base.GenericValidator | GenericValidator}.
11
6
  * @public
@@ -59,7 +59,7 @@ class GenericValidator {
59
59
  * {@inheritdoc Validation.Validator.validate}
60
60
  */
61
61
  validate(from, context) {
62
- const result = this._validator(from, this._context(context));
62
+ const result = this._validator(from, this._context(context), this);
63
63
  if (typeof result === 'boolean') {
64
64
  return result ? (0, base_1.succeed)(from) : (0, base_1.fail)('Invalid value');
65
65
  }
@@ -69,7 +69,7 @@ class GenericValidator {
69
69
  * {@inheritdoc Validation.Validator.convert}
70
70
  */
71
71
  convert(from, context) {
72
- const result = this._validator(from, this._context(context));
72
+ const result = this._validator(from, this._context(context), this);
73
73
  if (typeof result === 'boolean') {
74
74
  return result ? (0, base_1.succeed)(from) : (0, base_1.fail)('Invalid value');
75
75
  }
@@ -85,15 +85,15 @@ class GenericValidator {
85
85
  * {@inheritdoc Validation.Validator.guard}
86
86
  */
87
87
  guard(from, context) {
88
- return this._validator(from, this._context(context)) === true;
88
+ return this._validator(from, this._context(context), this) === true;
89
89
  }
90
90
  /**
91
91
  * {@inheritdoc Validation.Validator.optional}
92
92
  */
93
93
  optional() {
94
94
  return new GenericValidator({
95
- validator: (from, context) => {
96
- return from === undefined || this._validator(from, this._context(context));
95
+ validator: (from, context, self) => {
96
+ return from === undefined || this._validator(from, this._context(context), this);
97
97
  },
98
98
  traits: { isOptional: true }
99
99
  });
@@ -104,8 +104,8 @@ class GenericValidator {
104
104
  withConstraint(constraint, trait) {
105
105
  trait = trait !== null && trait !== void 0 ? trait : { type: 'function' };
106
106
  return new GenericValidator({
107
- validator: (from, context) => {
108
- const result = this._validator(from, this._context(context));
107
+ validator: (from, context, self) => {
108
+ const result = this._validator(from, this._context(context), this);
109
109
  if (result === true) {
110
110
  const constraintResult = constraint(from);
111
111
  if (typeof constraintResult === 'boolean') {
@@ -128,8 +128,8 @@ class GenericValidator {
128
128
  throw new Error(`Cannot replace existing brand "${this.brand}" with "${brand}".`);
129
129
  }
130
130
  return new GenericValidator({
131
- validator: (from, context) => {
132
- return this._validator(from, this._context(context));
131
+ validator: (from, context, self) => {
132
+ return this._validator(from, this._context(context), this);
133
133
  },
134
134
  traits: { brand }
135
135
  });
@@ -139,8 +139,8 @@ class GenericValidator {
139
139
  */
140
140
  withFormattedError(formatter) {
141
141
  return new GenericValidator({
142
- validator: (from, context) => {
143
- const result = this._validator(from, this._context(context));
142
+ validator: (from, context, self) => {
143
+ const result = this._validator(from, this._context(context), this);
144
144
  if (result === true) {
145
145
  return true;
146
146
  }
@@ -110,6 +110,6 @@ export declare class ObjectValidator<T, TC = unknown> extends ValidatorBase<T, T
110
110
  * {@inheritdoc Validation.ValidatorBase._validate}
111
111
  * @internal
112
112
  */
113
- protected _validate(from: unknown, context?: TC): boolean | Failure<T>;
113
+ protected _validate(from: unknown, context?: TC, self?: Validator<T, TC>): boolean | Failure<T>;
114
114
  }
115
115
  //# sourceMappingURL=object.d.ts.map
@@ -109,7 +109,7 @@ class ObjectValidator extends validatorBase_1.ValidatorBase {
109
109
  * {@inheritdoc Validation.ValidatorBase._validate}
110
110
  * @internal
111
111
  */
112
- _validate(from, context) {
112
+ _validate(from, context, self) {
113
113
  if (typeof from !== 'object' || from === null || Array.isArray(from)) {
114
114
  return (0, base_1.fail)('source is not an object');
115
115
  }
@@ -31,9 +31,10 @@ export declare class OneOfValidator<T, TC = unknown> extends ValidatorBase<T, TC
31
31
  * of the configured validators.
32
32
  * @param from - The `unknown` value to be tested.
33
33
  * @param context - Optional validation context will be propagated to element validator.
34
+ * @param self - Optional self-reference for recursive validation.
34
35
  * @returns Returns `true` if `from` is an `array` of valid elements, or
35
36
  * {@link Failure} with an error message if not.
36
37
  */
37
- protected _validate<T>(from: unknown, context?: TC): boolean | Failure<T>;
38
+ protected _validate<T>(from: unknown, context?: TC, self?: Validator<T, TC>): boolean | Failure<T>;
38
39
  }
39
40
  //# sourceMappingURL=oneOf.d.ts.map
@@ -46,10 +46,11 @@ class OneOfValidator extends validatorBase_1.ValidatorBase {
46
46
  * of the configured validators.
47
47
  * @param from - The `unknown` value to be tested.
48
48
  * @param context - Optional validation context will be propagated to element validator.
49
+ * @param self - Optional self-reference for recursive validation.
49
50
  * @returns Returns `true` if `from` is an `array` of valid elements, or
50
51
  * {@link Failure} with an error message if not.
51
52
  */
52
- _validate(from, context) {
53
+ _validate(from, context, self) {
53
54
  const found = this._validators.some((v) => v.validate(from).success);
54
55
  if (found) {
55
56
  return true;
@@ -1,7 +1,7 @@
1
1
  import { Failure } from '../base';
2
2
  import { ValidatorBase, ValidatorBaseConstructorParams } from './validatorBase';
3
3
  import { TypeGuardWithContext } from './common';
4
- import { ValidatorOptions } from './validator';
4
+ import { Validator, ValidatorOptions } from './validator';
5
5
  /**
6
6
  * Parameters used to construct a {@link Validation.Classes.TypeGuardValidator}.
7
7
  * @public
@@ -34,10 +34,11 @@ export declare class TypeGuardValidator<T, TC = unknown> extends ValidatorBase<T
34
34
  * type guard, returning a `Failure<T>` containing more information about a failure.
35
35
  * @param from - Value to be converted.
36
36
  * @param context - Optional validation context.
37
+ * @param self - Optional self-reference for recursive validation.
37
38
  * @returns `true` if `from` is valid, {@link Failure | Failure<T>}
38
39
  * with an error message if `from` is invalid.
39
40
  * @internal
40
41
  */
41
- protected _validate(from: unknown, context?: TC): boolean | Failure<T>;
42
+ protected _validate(from: unknown, context?: TC, self?: Validator<T, TC>): boolean | Failure<T>;
42
43
  }
43
44
  //# sourceMappingURL=typeGuard.d.ts.map
@@ -47,11 +47,12 @@ class TypeGuardValidator extends validatorBase_1.ValidatorBase {
47
47
  * type guard, returning a `Failure<T>` containing more information about a failure.
48
48
  * @param from - Value to be converted.
49
49
  * @param context - Optional validation context.
50
+ * @param self - Optional self-reference for recursive validation.
50
51
  * @returns `true` if `from` is valid, {@link Failure | Failure<T>}
51
52
  * with an error message if `from` is invalid.
52
53
  * @internal
53
54
  */
54
- _validate(from, context) {
55
+ _validate(from, context, self) {
55
56
  if (this._guard(from, context)) {
56
57
  return true;
57
58
  }
@@ -1,5 +1,12 @@
1
1
  import { Brand, Failure, Result } from '../base';
2
2
  import { ConstraintTrait, ValidatorTraits } from './traits';
3
+ /**
4
+ * Type for a validation function, which validates that a supplied `unknown`
5
+ * value is a valid value of type `<T>`, possibly as influenced by
6
+ * an optionally-supplied validation context of type `<TC>`.
7
+ * @public
8
+ */
9
+ export type ValidatorFunc<T, TC> = (from: unknown, context?: TC, self?: Validator<T, TC>) => boolean | Failure<T>;
3
10
  /**
4
11
  * Options that apply to any {@link Validation.Validator | Validator}.
5
12
  * @public
@@ -19,10 +19,11 @@ export declare abstract class ValidatorBase<T, TC = unknown> extends GenericVali
19
19
  * Abstract validation method to me implemented by derived classes.
20
20
  * @param from - Value to be converted.
21
21
  * @param context - Optional validation context.
22
+ * @param self - Optional self-reference for recursive validation.
22
23
  * @returns `true` if `from` is valid, {@link Failure | Failure<T>}
23
24
  * with an error message if `from` is invalid.
24
25
  * @internal
25
26
  */
26
- protected abstract _validate(from: unknown, context?: TC): boolean | Failure<T>;
27
+ protected abstract _validate(from: unknown, context?: TC, self?: import('./validator').Validator<T, TC>): boolean | Failure<T>;
27
28
  }
28
29
  //# sourceMappingURL=validatorBase.d.ts.map
@@ -34,7 +34,7 @@ class ValidatorBase extends genericValidator_1.GenericValidator {
34
34
  * @internal
35
35
  */
36
36
  constructor(params) {
37
- super(Object.assign({ validator: (from, context) => this._validate(from, context) }, params));
37
+ super(Object.assign({ validator: (from, context, self) => this._validate(from, context, self) }, params));
38
38
  }
39
39
  }
40
40
  exports.ValidatorBase = ValidatorBase;
@@ -1,9 +1,9 @@
1
1
  import { ArrayValidator, ArrayValidatorConstructorParams } from './array';
2
2
  import { FieldValidators, ObjectValidator, ObjectValidatorConstructorParams } from './object';
3
3
  import { TypeGuardValidator, TypeGuardValidatorConstructorParams } from './typeGuard';
4
- import { TypeGuardWithContext, ValidatorFunc } from './common';
4
+ import { TypeGuardWithContext } from './common';
5
5
  import { OneOfValidator, OneOfValidatorConstructorParams } from './oneOf';
6
- import { Validator } from './validator';
6
+ import { Validator, ValidatorFunc } from './validator';
7
7
  /**
8
8
  * A {@link Validation.Classes.StringValidator | StringValidator} which validates a string in place.
9
9
  * @public
@@ -94,7 +94,7 @@ function arrayOf(validateElement, params) {
94
94
  function recordOf(validator, options) {
95
95
  const opts = Object.assign({ onError: 'fail' }, options);
96
96
  return new genericValidator_1.GenericValidator({
97
- validator: (from, context) => {
97
+ validator: (from, context, self) => {
98
98
  if (typeof from !== 'object' || from === null || Array.isArray(from)) {
99
99
  return (0, base_1.fail)(`Not a string-keyed object: ${JSON.stringify(from)}`);
100
100
  }
@@ -139,7 +139,7 @@ function recordOf(validator, options) {
139
139
  */
140
140
  function enumeratedValue(values) {
141
141
  return new genericValidator_1.GenericValidator({
142
- validator: (from, context) => {
142
+ validator: (from, context, self) => {
143
143
  if (typeof from === 'string') {
144
144
  const v = context !== null && context !== void 0 ? context : values;
145
145
  const index = v.indexOf(from);
@@ -156,7 +156,7 @@ function enumeratedValue(values) {
156
156
  */
157
157
  function literal(value) {
158
158
  return new genericValidator_1.GenericValidator({
159
- validator: (from) => {
159
+ validator: (from, context, self) => {
160
160
  return from === value
161
161
  ? true
162
162
  : (0, base_1.fail)(`Expected literal ${String(value)}, found "${JSON.stringify(from, undefined, 2)}`);
@@ -0,0 +1,2 @@
1
+ import '../../helpers/jest';
2
+ //# sourceMappingURL=recursiveValidation.test.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fgv/ts-utils",
3
- "version": "5.0.0-17",
3
+ "version": "5.0.0-18",
4
4
  "description": "Assorted Typescript Utilities",
5
5
  "main": "lib/index.js",
6
6
  "types": "dist/ts-utils.d.ts",
@@ -65,10 +65,11 @@ export class ArrayValidator<T, TC = unknown> extends ValidatorBase<T[], TC> {
65
65
  * validator.
66
66
  * @param from - The `unknown` value to be tested.
67
67
  * @param context - Optional validation context will be propagated to element validator.
68
+ * @param self - Optional self-reference for recursive validation.
68
69
  * @returns Returns `true` if `from` is an `array` of valid elements, or
69
70
  * {@link Failure} with an error message if not.
70
71
  */
71
- protected _validate<T>(from: unknown, context?: TC): boolean | Failure<T> {
72
+ protected _validate(from: unknown, context?: TC, self?: Validator<T[], TC>): boolean | Failure<T[]> {
72
73
  if (Array.isArray(from)) {
73
74
  for (const elem of from) {
74
75
  const result = this._validateElement.validate(elem, context);
@@ -78,6 +79,6 @@ export class ArrayValidator<T, TC = unknown> extends ValidatorBase<T[], TC> {
78
79
  }
79
80
  return true;
80
81
  }
81
- return fail<T>(`"${from}": not an array`);
82
+ return fail<T[]>(`"${from}": not an array`);
82
83
  }
83
84
  }
@@ -20,19 +20,9 @@
20
20
  * SOFTWARE.
21
21
  */
22
22
 
23
- import { Failure } from '../base';
24
-
25
23
  /**
26
24
  * A type guard function which validates a specific type, with an optional context
27
25
  * that can be used to shape the validation.
28
26
  * @public
29
27
  */
30
28
  export type TypeGuardWithContext<T, TC = unknown> = (from: unknown, context?: TC) => from is T;
31
-
32
- /**
33
- * Type for a validation function, which validates that a supplied `unknown`
34
- * value is a valid value of type `<T>`, possibly as influenced by
35
- * an optionally-supplied validation context of type `<TC>`.
36
- * @public
37
- */
38
- export type ValidatorFunc<T, TC> = (from: unknown, context?: TC) => boolean | Failure<T>;
@@ -75,7 +75,7 @@ export class FieldValidator<T, TC = unknown> extends ValidatorBase<T, TC> {
75
75
  /**
76
76
  * {@inheritdoc Validation.ValidatorBase._validate}
77
77
  */
78
- protected _validate(from: unknown, context?: TC): boolean | Failure<T> {
78
+ protected _validate(from: unknown, context?: TC, self?: Validator<T, TC>): boolean | Failure<T> {
79
79
  if (typeof from === 'object' && !Array.isArray(from) && from !== null) {
80
80
  const optional = this._fieldOptions.optional === true;
81
81
 
@@ -22,14 +22,13 @@
22
22
 
23
23
  import { Brand, Failure, Result, fail, succeed } from '../base';
24
24
  import { ConstraintTrait, ValidatorTraits } from './traits';
25
- import { Constraint, ValidationErrorFormatter, Validator, ValidatorOptions } from './validator';
26
-
27
- import { ValidatorFunc } from './common';
28
-
29
- /**
30
- * @deprecated Use {@link Validation.Common.ValidatorFunc | Validation.Common.ValidatorFunc} instead.
31
- */
32
- export { ValidatorFunc };
25
+ import {
26
+ Constraint,
27
+ ValidationErrorFormatter,
28
+ Validator,
29
+ ValidatorFunc,
30
+ ValidatorOptions
31
+ } from './validator';
33
32
 
34
33
  /**
35
34
  * Options used to initialize a {@link Validation.Base.GenericValidator | GenericValidator}.
@@ -93,7 +92,7 @@ export class GenericValidator<T, TC = unknown> implements Validator<T, TC> {
93
92
  * {@inheritdoc Validation.Validator.validate}
94
93
  */
95
94
  public validate(from: unknown, context?: TC): Result<T> {
96
- const result = this._validator(from, this._context(context));
95
+ const result = this._validator(from, this._context(context), this);
97
96
  if (typeof result === 'boolean') {
98
97
  return result ? succeed(from as T) : fail<T>('Invalid value');
99
98
  }
@@ -104,7 +103,7 @@ export class GenericValidator<T, TC = unknown> implements Validator<T, TC> {
104
103
  * {@inheritdoc Validation.Validator.convert}
105
104
  */
106
105
  public convert(from: unknown, context?: TC): Result<T> {
107
- const result = this._validator(from, this._context(context));
106
+ const result = this._validator(from, this._context(context), this);
108
107
  if (typeof result === 'boolean') {
109
108
  return result ? succeed(from as T) : fail<T>('Invalid value');
110
109
  }
@@ -122,7 +121,7 @@ export class GenericValidator<T, TC = unknown> implements Validator<T, TC> {
122
121
  * {@inheritdoc Validation.Validator.guard}
123
122
  */
124
123
  public guard(from: unknown, context?: TC): from is T {
125
- return this._validator(from, this._context(context)) === true;
124
+ return this._validator(from, this._context(context), this) === true;
126
125
  }
127
126
 
128
127
  /**
@@ -130,8 +129,8 @@ export class GenericValidator<T, TC = unknown> implements Validator<T, TC> {
130
129
  */
131
130
  public optional(): Validator<T | undefined, TC> {
132
131
  return new GenericValidator({
133
- validator: (from: unknown, context?: TC) => {
134
- return from === undefined || this._validator(from, this._context(context));
132
+ validator: (from: unknown, context?: TC, self?: Validator<T | undefined, TC>) => {
133
+ return from === undefined || this._validator(from, this._context(context), this);
135
134
  },
136
135
  traits: { isOptional: true }
137
136
  });
@@ -143,8 +142,8 @@ export class GenericValidator<T, TC = unknown> implements Validator<T, TC> {
143
142
  public withConstraint(constraint: Constraint<T>, trait?: ConstraintTrait): Validator<T, TC> {
144
143
  trait = trait ?? { type: 'function' };
145
144
  return new GenericValidator({
146
- validator: (from: unknown, context?: TC): boolean | Failure<T> => {
147
- const result = this._validator(from, this._context(context));
145
+ validator: (from: unknown, context?: TC, self?: Validator<T, TC>): boolean | Failure<T> => {
146
+ const result = this._validator(from, this._context(context), this);
148
147
  if (result === true) {
149
148
  const constraintResult = constraint(from as T);
150
149
  if (typeof constraintResult === 'boolean') {
@@ -169,8 +168,8 @@ export class GenericValidator<T, TC = unknown> implements Validator<T, TC> {
169
168
  }
170
169
 
171
170
  return new GenericValidator<Brand<T, B>, TC>({
172
- validator: (from: unknown, context?: TC) => {
173
- return this._validator(from, this._context(context)) as boolean | Failure<Brand<T, B>>;
171
+ validator: (from: unknown, context?: TC, self?: Validator<Brand<T, B>, TC>) => {
172
+ return this._validator(from, this._context(context), this) as boolean | Failure<Brand<T, B>>;
174
173
  },
175
174
  traits: { brand }
176
175
  });
@@ -181,8 +180,8 @@ export class GenericValidator<T, TC = unknown> implements Validator<T, TC> {
181
180
  */
182
181
  public withFormattedError(formatter: ValidationErrorFormatter<TC>): Validator<T, TC> {
183
182
  return new GenericValidator<T, TC>({
184
- validator: (from: unknown, context?: TC) => {
185
- const result = this._validator(from, this._context(context));
183
+ validator: (from: unknown, context?: TC, self?: Validator<T, TC>) => {
184
+ const result = this._validator(from, this._context(context), this);
186
185
  if (result === true) {
187
186
  return true;
188
187
  }
@@ -179,7 +179,7 @@ export class ObjectValidator<T, TC = unknown> extends ValidatorBase<T, TC> {
179
179
  * {@inheritdoc Validation.ValidatorBase._validate}
180
180
  * @internal
181
181
  */
182
- protected _validate(from: unknown, context?: TC): boolean | Failure<T> {
182
+ protected _validate(from: unknown, context?: TC, self?: Validator<T, TC>): boolean | Failure<T> {
183
183
  if (typeof from !== 'object' || from === null || Array.isArray(from)) {
184
184
  return fail('source is not an object');
185
185
  }
@@ -64,10 +64,11 @@ export class OneOfValidator<T, TC = unknown> extends ValidatorBase<T, TC> {
64
64
  * of the configured validators.
65
65
  * @param from - The `unknown` value to be tested.
66
66
  * @param context - Optional validation context will be propagated to element validator.
67
+ * @param self - Optional self-reference for recursive validation.
67
68
  * @returns Returns `true` if `from` is an `array` of valid elements, or
68
69
  * {@link Failure} with an error message if not.
69
70
  */
70
- protected _validate<T>(from: unknown, context?: TC): boolean | Failure<T> {
71
+ protected _validate<T>(from: unknown, context?: TC, self?: Validator<T, TC>): boolean | Failure<T> {
71
72
  const found = this._validators.some((v) => v.validate(from).success);
72
73
  if (found) {
73
74
  return true;
@@ -24,7 +24,7 @@ import { Failure, fail } from '../base';
24
24
  import { ValidatorBase, ValidatorBaseConstructorParams } from './validatorBase';
25
25
 
26
26
  import { TypeGuardWithContext } from './common';
27
- import { ValidatorOptions } from './validator';
27
+ import { Validator, ValidatorOptions } from './validator';
28
28
 
29
29
  /**
30
30
  * Parameters used to construct a {@link Validation.Classes.TypeGuardValidator}.
@@ -69,11 +69,12 @@ export class TypeGuardValidator<T, TC = unknown> extends ValidatorBase<T, TC> {
69
69
  * type guard, returning a `Failure<T>` containing more information about a failure.
70
70
  * @param from - Value to be converted.
71
71
  * @param context - Optional validation context.
72
+ * @param self - Optional self-reference for recursive validation.
72
73
  * @returns `true` if `from` is valid, {@link Failure | Failure<T>}
73
74
  * with an error message if `from` is invalid.
74
75
  * @internal
75
76
  */
76
- protected _validate(from: unknown, context?: TC): boolean | Failure<T> {
77
+ protected _validate(from: unknown, context?: TC, self?: Validator<T, TC>): boolean | Failure<T> {
77
78
  if (this._guard(from, context)) {
78
79
  return true;
79
80
  }
@@ -23,6 +23,18 @@
23
23
  import { Brand, Failure, Result } from '../base';
24
24
  import { ConstraintTrait, ValidatorTraits } from './traits';
25
25
 
26
+ /**
27
+ * Type for a validation function, which validates that a supplied `unknown`
28
+ * value is a valid value of type `<T>`, possibly as influenced by
29
+ * an optionally-supplied validation context of type `<TC>`.
30
+ * @public
31
+ */
32
+ export type ValidatorFunc<T, TC> = (
33
+ from: unknown,
34
+ context?: TC,
35
+ self?: Validator<T, TC>
36
+ ) => boolean | Failure<T>;
37
+
26
38
  /**
27
39
  * Options that apply to any {@link Validation.Validator | Validator}.
28
40
  * @public
@@ -44,7 +44,7 @@ export abstract class ValidatorBase<T, TC = unknown> extends GenericValidator<T,
44
44
  */
45
45
  protected constructor(params: Partial<ValidatorBaseConstructorParams<T, TC>>) {
46
46
  super({
47
- validator: (from, context) => this._validate(from, context),
47
+ validator: (from, context, self) => this._validate(from, context, self),
48
48
  ...params
49
49
  });
50
50
  }
@@ -53,9 +53,14 @@ export abstract class ValidatorBase<T, TC = unknown> extends GenericValidator<T,
53
53
  * Abstract validation method to me implemented by derived classes.
54
54
  * @param from - Value to be converted.
55
55
  * @param context - Optional validation context.
56
+ * @param self - Optional self-reference for recursive validation.
56
57
  * @returns `true` if `from` is valid, {@link Failure | Failure<T>}
57
58
  * with an error message if `from` is invalid.
58
59
  * @internal
59
60
  */
60
- protected abstract _validate(from: unknown, context?: TC): boolean | Failure<T>;
61
+ protected abstract _validate(
62
+ from: unknown,
63
+ context?: TC,
64
+ self?: import('./validator').Validator<T, TC>
65
+ ): boolean | Failure<T>;
61
66
  }
@@ -26,12 +26,12 @@ import { FieldValidators, ObjectValidator, ObjectValidatorConstructorParams } fr
26
26
  import { TypeGuardValidator, TypeGuardValidatorConstructorParams } from './typeGuard';
27
27
 
28
28
  import { BooleanValidator } from './boolean';
29
- import { TypeGuardWithContext, ValidatorFunc } from './common';
29
+ import { TypeGuardWithContext } from './common';
30
30
  import { GenericValidator } from './genericValidator';
31
31
  import { NumberValidator } from './number';
32
32
  import { OneOfValidator, OneOfValidatorConstructorParams } from './oneOf';
33
33
  import { StringValidator } from './string';
34
- import { Validator } from './validator';
34
+ import { Validator, ValidatorFunc } from './validator';
35
35
 
36
36
  /**
37
37
  * A {@link Validation.Classes.StringValidator | StringValidator} which validates a string in place.
@@ -121,7 +121,11 @@ export function recordOf<T, TC = unknown, TK extends string = string>(
121
121
  const opts: IRecordOfValidatorOptions<TK, TC> = { onError: 'fail', ...options };
122
122
 
123
123
  return new GenericValidator({
124
- validator: (from: unknown, context?: TC): boolean | Failure<Record<TK, T>> => {
124
+ validator: (
125
+ from: unknown,
126
+ context?: TC,
127
+ self?: Validator<Record<TK, T>, TC>
128
+ ): boolean | Failure<Record<TK, T>> => {
125
129
  if (typeof from !== 'object' || from === null || Array.isArray(from)) {
126
130
  return fail(`Not a string-keyed object: ${JSON.stringify(from)}`);
127
131
  }
@@ -171,7 +175,11 @@ export function recordOf<T, TC = unknown, TK extends string = string>(
171
175
  */
172
176
  export function enumeratedValue<T extends string>(values: ReadonlyArray<T>): Validator<T, ReadonlyArray<T>> {
173
177
  return new GenericValidator({
174
- validator: (from: unknown, context?: ReadonlyArray<T>): boolean | Failure<T> => {
178
+ validator: (
179
+ from: unknown,
180
+ context?: ReadonlyArray<T>,
181
+ self?: Validator<T, ReadonlyArray<T>>
182
+ ): boolean | Failure<T> => {
175
183
  if (typeof from === 'string') {
176
184
  const v = context ?? values;
177
185
  const index = v.indexOf(from as T);
@@ -191,7 +199,7 @@ export function literal<T extends string | number | boolean | symbol | null | un
191
199
  value: T
192
200
  ): Validator<T> {
193
201
  return new GenericValidator({
194
- validator: (from: unknown): boolean | Failure<T> => {
202
+ validator: (from: unknown, context?: unknown, self?: Validator<T>): boolean | Failure<T> => {
195
203
  return from === value
196
204
  ? true
197
205
  : fail(`Expected literal ${String(value)}, found "${JSON.stringify(from, undefined, 2)}`);