valgen 4.0.0-alpha.6 → 4.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.
Files changed (57) hide show
  1. package/CHANGELOG.md +13 -2
  2. package/cjs/core/context.js +29 -23
  3. package/cjs/core/validator.js +9 -8
  4. package/cjs/helpers/omit-undefined.js +15 -0
  5. package/cjs/rules/is-array.js +12 -10
  6. package/cjs/rules/is-bigint.js +2 -2
  7. package/cjs/rules/is-boolean.js +2 -2
  8. package/cjs/rules/is-date.js +7 -13
  9. package/cjs/rules/is-empty.js +4 -4
  10. package/cjs/rules/is-enum.js +2 -5
  11. package/cjs/rules/is-integer.js +2 -2
  12. package/cjs/rules/is-matches.js +2 -6
  13. package/cjs/rules/is-null.js +6 -6
  14. package/cjs/rules/is-number.js +2 -2
  15. package/cjs/rules/is-object-id.js +2 -2
  16. package/cjs/rules/is-object.js +16 -18
  17. package/cjs/rules/is-record.js +13 -13
  18. package/cjs/rules/is-string.js +2 -2
  19. package/cjs/rules/is-tuple.js +12 -9
  20. package/cjs/rules/length.js +2 -2
  21. package/cjs/rules/optional.js +8 -8
  22. package/cjs/rules/pipe.js +2 -4
  23. package/cjs/rules/range.js +10 -10
  24. package/cjs/rules/string-formats.js +48 -48
  25. package/cjs/rules/union.js +10 -5
  26. package/cjs/rules/utilities.js +2 -2
  27. package/esm/core/context.js +29 -23
  28. package/esm/core/validator.js +9 -8
  29. package/esm/helpers/omit-undefined.js +11 -0
  30. package/esm/rules/is-array.js +13 -11
  31. package/esm/rules/is-bigint.js +2 -2
  32. package/esm/rules/is-boolean.js +2 -2
  33. package/esm/rules/is-date.js +7 -13
  34. package/esm/rules/is-empty.js +4 -4
  35. package/esm/rules/is-enum.js +2 -5
  36. package/esm/rules/is-integer.js +2 -2
  37. package/esm/rules/is-matches.js +2 -6
  38. package/esm/rules/is-null.js +6 -6
  39. package/esm/rules/is-number.js +2 -2
  40. package/esm/rules/is-object-id.js +2 -2
  41. package/esm/rules/is-object.js +17 -19
  42. package/esm/rules/is-record.js +14 -14
  43. package/esm/rules/is-string.js +2 -2
  44. package/esm/rules/is-tuple.js +13 -10
  45. package/esm/rules/length.js +2 -2
  46. package/esm/rules/optional.js +9 -9
  47. package/esm/rules/pipe.js +3 -5
  48. package/esm/rules/range.js +10 -10
  49. package/esm/rules/string-formats.js +48 -48
  50. package/esm/rules/union.js +10 -5
  51. package/esm/rules/utilities.js +3 -3
  52. package/package.json +4 -4
  53. package/typings/core/context.d.ts +11 -19
  54. package/typings/core/types.d.ts +4 -1
  55. package/typings/core/validator.d.ts +1 -1
  56. package/typings/helpers/omit-undefined.d.ts +1 -0
  57. package/typings/rules/is-object.d.ts +1 -1
package/CHANGELOG.md CHANGED
@@ -1,6 +1,17 @@
1
- # v4.0.0-alpha.1
2
- [2023-06-04]
1
+ # v4.0.0
2
+ [2023-08-17]
3
3
 
4
4
  ### Changes
5
5
 
6
6
  * Initial release of v4.0.0-alpha.1 ([`499af8e`](https://github.com/panates/valgen/commit/499af8eed81feeacb4bba5c254fbf1ede3933564))
7
+ * Implemented all initial validators and tests ([`0ff5c5c`](https://github.com/panates/valgen/commit/0ff5c5c28aa59b44de90d016e8c056c26b3b479d))
8
+ * Updated dependencies ([`804e00c`](https://github.com/panates/valgen/commit/804e00c3fcf344f4dcdb96efe0fc94ea3521cb92))
9
+ * Better error handling ([`91dae2f`](https://github.com/panates/valgen/commit/91dae2f260f1d02ff5ed418f3247b452c1fed214))
10
+ * Updated deps ([`df1cb70`](https://github.com/panates/valgen/commit/df1cb700a3799f09305af774c05ca534e5f88870))
11
+ * Added isBigint validator ([`87ba007`](https://github.com/panates/valgen/commit/87ba00753dc018a4bd06492ec99fa37967046c58))
12
+ * Fixed isObject coerce issue ([`47c7d4e`](https://github.com/panates/valgen/commit/47c7d4ed2d0e483788e939b357995a156ac3b7bc))
13
+ * Improved isDateString ([`59d0d14`](https://github.com/panates/valgen/commit/59d0d14909132a502a9880cc11b9303897a3c79a))
14
+ * Updated dayjs ([`e212dd2`](https://github.com/panates/valgen/commit/e212dd2834a07015fcceede3bf211f2a9db11eb6))
15
+ * Updated deps ([`d20588e`](https://github.com/panates/valgen/commit/d20588eaa51be7547655d3494bb42e35cb6effa8))
16
+ * Updated deps ([`82a2c0d`](https://github.com/panates/valgen/commit/82a2c0dc36c9cc54667231e88dfec6521097a157))
17
+ * Fixed isObject coerce issue ([`b79833b`](https://github.com/panates/valgen/commit/b79833ba032494a18a91b1569da2d244f3c4c4b9))
@@ -1,15 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Context = void 0;
4
+ const omit_undefined_js_1 = require("../helpers/omit-undefined.js");
4
5
  const constants_js_1 = require("./constants.js");
5
6
  const validation_error_js_1 = require("./validation-error.js");
6
7
  const VARIABLE_REPLACE_PATTERN = /{{([^}]*)}}/g;
7
8
  const OPTIONAL_VAR_PATTERN = /^([^?]+)(?:\||(.*))?$/;
8
9
  class Context {
9
- constructor(rule, options) {
10
+ constructor(options) {
10
11
  this.errors = [];
11
- this.input = {};
12
- this.rule = rule;
13
12
  if (options?.maxErrors != null)
14
13
  this.maxErrors = options.maxErrors;
15
14
  if (typeof options?.onFail === 'function')
@@ -17,34 +16,43 @@ class Context {
17
16
  if (options?.coerce != null)
18
17
  this.coerce = options?.coerce;
19
18
  }
20
- failure(message) {
21
- const issue = (typeof message === 'object'
22
- ? { ...message, message: message.message }
23
- : { message: '' + message });
24
- issue.rule = this.rule.id;
25
- Object.assign(issue, this.input);
26
- if (this.onFail) {
19
+ fail(rule, message, value, details) {
20
+ const issue = (0, omit_undefined_js_1.omitUndefined)({
21
+ message: message instanceof Error ? message.message : String(message),
22
+ rule: rule.id,
23
+ root: this.root,
24
+ location: this.location,
25
+ context: this.context,
26
+ property: this.property,
27
+ index: this.index,
28
+ label: this.label,
29
+ value,
30
+ ...details
31
+ });
32
+ issue.value = value;
33
+ const onFail = this.onFail || rule[constants_js_1.kOptions].onFail;
34
+ if (onFail) {
27
35
  const proto = Object.getPrototypeOf(this);
28
- const x = this.onFail(issue, this, proto.onFail);
36
+ const superOnFail = proto.onFail !== onFail ? proto.onFail : undefined;
37
+ const x = onFail(issue, this, superOnFail);
29
38
  if (!x)
30
39
  return;
31
- if (typeof x === 'object') {
32
- delete x.id;
33
- delete x.input;
40
+ if (typeof x === 'object')
34
41
  Object.assign(issue, x);
35
- }
36
42
  else
37
43
  issue.message = String(x);
38
44
  }
39
- issue.message = ('' + issue.message).replace(VARIABLE_REPLACE_PATTERN, (x, g) => {
45
+ issue.message = ('' + issue.message)
46
+ .replace(VARIABLE_REPLACE_PATTERN, (x, g) => {
40
47
  const m = OPTIONAL_VAR_PATTERN.exec(g);
41
48
  if (!m)
42
49
  return x;
43
50
  const k = m[1];
44
- const v = this.input[k] ??
45
- (m[1] === 'label' ? this.input.property : undefined);
51
+ let v = issue[k];
52
+ if (!v && m[1] === 'label' && (this.label || this.property))
53
+ v = '`' + (this.label || this.property) + '`';
46
54
  if (v != null)
47
- return '`' + v + '`';
55
+ return v;
48
56
  if (m[2])
49
57
  return m[2];
50
58
  return m[1] === 'label' ? 'Value' : x;
@@ -53,12 +61,10 @@ class Context {
53
61
  if (this.errors.length >= (this.maxErrors ?? Infinity))
54
62
  throw new validation_error_js_1.ValidationError(this.errors);
55
63
  }
56
- extend(rule, options) {
57
- const extended = new Context(rule, { onFail: undefined, ...rule[constants_js_1.kOptions], ...options });
64
+ extend(options) {
65
+ const extended = new Context({ onFail: undefined, ...options });
58
66
  Object.setPrototypeOf(extended, this);
59
67
  delete extended.errors;
60
- extended.parent = this;
61
- extended.root = this.root || this;
62
68
  return extended;
63
69
  }
64
70
  }
@@ -23,20 +23,21 @@ function validator(arg0, arg1, arg2) {
23
23
  id = id || fn.name || 'unnamed-rule';
24
24
  const name = fn.name || (0, string_utils_js_1.camelCase)(id);
25
25
  const _rule = ({
26
- [name](input, options, parent) {
27
- const ctx = parent ? parent.extend(_rule, options) : new context_js_1.Context(_rule, options);
26
+ [name](input, options) {
27
+ const ctx = options instanceof context_js_1.Context ? options : undefined;
28
+ const opts = (ctx ? undefined : options);
29
+ const context = ctx || new context_js_1.Context(opts);
28
30
  let value;
29
31
  try {
30
- ctx.input.value = input;
31
- value = fn(input, ctx, _rule);
32
+ value = fn(input, context, _rule);
32
33
  }
33
34
  catch (e) {
34
- if (!parent && e instanceof validation_error_js_1.ValidationError)
35
+ if (e instanceof validation_error_js_1.ValidationError)
35
36
  throw e;
36
- ctx.failure(e);
37
+ context.fail(_rule, e, input);
37
38
  }
38
- if (!parent && ctx.errors.length)
39
- throw new validation_error_js_1.ValidationError(ctx.errors);
39
+ if (!ctx && context.errors.length)
40
+ throw new validation_error_js_1.ValidationError(context.errors);
40
41
  return value;
41
42
  }
42
43
  })[name];
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.omitUndefined = void 0;
4
+ function omitUndefined(obj, recursive) {
5
+ if (!(obj && typeof obj === 'object'))
6
+ return obj;
7
+ for (const k of Object.keys(obj)) {
8
+ if (obj[k] === undefined)
9
+ delete obj[k];
10
+ else if (recursive && typeof obj[k] === 'object')
11
+ omitUndefined(obj[k]);
12
+ }
13
+ return obj;
14
+ }
15
+ exports.omitUndefined = omitUndefined;
@@ -8,29 +8,31 @@ const index_js_1 = require("../core/index.js");
8
8
  * @validator isArray
9
9
  */
10
10
  function isArray(itemValidator, options) {
11
- return (0, index_js_1.validator)('isArray', function (input, context) {
11
+ return (0, index_js_1.validator)('isArray', function (input, context, _this) {
12
12
  if (input != null && context.coerce && !Array.isArray(input))
13
13
  input = [input];
14
14
  if (!Array.isArray(input)) {
15
- context.failure(`{{label}} is not an array`);
15
+ context.fail(_this, `{{label}} is not an array`, input);
16
16
  return;
17
17
  }
18
18
  if (!itemValidator)
19
19
  return input;
20
- const location = context.input.location || '';
21
- const itemContext = context.extend(itemValidator);
20
+ const location = context.location || '';
21
+ const itemContext = context.extend();
22
22
  let i;
23
23
  let v;
24
24
  const l = input.length;
25
25
  const out = [];
26
26
  for (i = 0; i < l; i++) {
27
27
  v = input[i];
28
- itemContext.input.value = v;
29
- itemContext.input.label = ((context.input.label || context.input.property) || 'Item') +
30
- `[${i}]`;
31
- itemContext.input.property = i;
32
- itemContext.input.location = location + '[' + i + ']';
33
- out.push(itemValidator[index_js_1.kValidatorFn](v, itemContext, itemValidator));
28
+ itemContext.scope = input;
29
+ itemContext.location = location + '[' + i + ']';
30
+ itemContext.label = context.label
31
+ ? context.label + `[${i}]`
32
+ : `Item at (${i})`;
33
+ itemContext.index = i;
34
+ v = itemValidator(v, itemContext);
35
+ out.push(v);
34
36
  }
35
37
  return out;
36
38
  }, options);
@@ -8,14 +8,14 @@ const index_js_1 = require("../core/index.js");
8
8
  * @validator isNumber
9
9
  */
10
10
  function isBigint(options) {
11
- return (0, index_js_1.validator)('isBigint', function (input, context) {
11
+ return (0, index_js_1.validator)('isBigint', function (input, context, _this) {
12
12
  if (input != null && typeof input !== 'bigint' && context.coerce) {
13
13
  if (typeof input === 'string' || typeof input === 'number')
14
14
  input = BigInt(input);
15
15
  }
16
16
  if (typeof input === 'bigint')
17
17
  return input;
18
- context.failure(`{{label}} is not a valid BigInt`);
18
+ context.fail(_this, `{{label}} is not a valid BigInt`, input);
19
19
  }, options);
20
20
  }
21
21
  exports.isBigint = isBigint;
@@ -10,7 +10,7 @@ const FALSE_PATTERN = /^false|f|0|no|n$/i;
10
10
  * @validator isBoolean
11
11
  */
12
12
  function isBoolean(options) {
13
- return (0, index_js_1.validator)('isBoolean', function (input, context) {
13
+ return (0, index_js_1.validator)('isBoolean', function (input, context, _this) {
14
14
  if (input != null && typeof input !== 'boolean' && context.coerce) {
15
15
  if (typeof input === 'string') {
16
16
  if (TRUE_PATTERN.test(input))
@@ -24,7 +24,7 @@ function isBoolean(options) {
24
24
  }
25
25
  if (typeof input === 'boolean')
26
26
  return input;
27
- context.failure(`{{label}} is not a valid boolean`);
27
+ context.fail(_this, `{{label}} is not a valid boolean`, input);
28
28
  }, options);
29
29
  }
30
30
  exports.isBoolean = isBoolean;
@@ -15,7 +15,7 @@ dayjs_1.default.extend(customParseFormat_1.default);
15
15
  * @validator isDate
16
16
  */
17
17
  function isDate(options) {
18
- return (0, index_js_1.validator)('isDate', function (input, context) {
18
+ return (0, index_js_1.validator)('isDate', function (input, context, _this) {
19
19
  if (input != null && !(input instanceof Date) && context.coerce) {
20
20
  if (typeof input === 'string') {
21
21
  const d = (0, dayjs_1.default)(input, options?.format);
@@ -27,13 +27,10 @@ function isDate(options) {
27
27
  }
28
28
  if (input && input instanceof Date && !isNaN(input.getTime()))
29
29
  return input;
30
- context.failure({
31
- message: `{{label}} is not a valid Date instance` +
32
- (context.coerce
33
- ? ` or a date formatted${options?.format ? " (" + options.format + ")" : ''} string`
34
- : ''),
35
- format: options?.format
36
- });
30
+ context.fail(_this, `{{label}} is not a valid Date instance` +
31
+ (context.coerce
32
+ ? ` or a date formatted${options?.format ? " (" + options.format + ")" : ''} string`
33
+ : ''), input, { format: options?.format });
37
34
  }, (0, object_utils_js_1.omitKeys)(options || {}, ['format']));
38
35
  }
39
36
  exports.isDate = isDate;
@@ -45,7 +42,7 @@ exports.isDate = isDate;
45
42
  function isDateString(options) {
46
43
  const inputFormat = options?.format;
47
44
  const coerceFormat = Array.isArray(options?.format) ? options?.format[0] : options?.format;
48
- return (0, index_js_1.validator)('isDateString', function (input, context) {
45
+ return (0, index_js_1.validator)('isDateString', function (input, context, _this) {
49
46
  if (input instanceof Date) {
50
47
  const d = (0, dayjs_1.default)(input);
51
48
  if (d.isValid())
@@ -59,10 +56,7 @@ function isDateString(options) {
59
56
  return input;
60
57
  }
61
58
  }
62
- context.failure({
63
- message: `{{label}} is not a valid date formatted${options?.format ? " (" + options.format + ")" : ''} string`,
64
- format: options?.format
65
- });
59
+ context.fail(_this, `{{label}} is not a valid date formatted${options?.format ? " (" + options.format + ")" : ''} string`, input, { format: options?.format });
66
60
  }, (0, object_utils_js_1.omitKeys)(options || {}, ['format']));
67
61
  }
68
62
  exports.isDateString = isDateString;
@@ -7,7 +7,7 @@ const index_js_1 = require("../core/index.js");
7
7
  * @validator isEmpty
8
8
  */
9
9
  function isEmpty(options) {
10
- return (0, index_js_1.validator)('isEmpty', function (input, context) {
10
+ return (0, index_js_1.validator)('isEmpty', function (input, context, _this) {
11
11
  if (input != null) {
12
12
  if (typeof input === 'string') {
13
13
  if (!input)
@@ -30,7 +30,7 @@ function isEmpty(options) {
30
30
  return input;
31
31
  }
32
32
  }
33
- context.failure(`{{label}} is not empty`);
33
+ context.fail(_this, `{{label}} is not empty`, input);
34
34
  }, options);
35
35
  }
36
36
  exports.isEmpty = isEmpty;
@@ -39,7 +39,7 @@ exports.isEmpty = isEmpty;
39
39
  * @validator isNotEmpty
40
40
  */
41
41
  function isNotEmpty(options) {
42
- return (0, index_js_1.validator)('isNotEmpty', function (input, context) {
42
+ return (0, index_js_1.validator)('isNotEmpty', function (input, context, _this) {
43
43
  if (input != null) {
44
44
  if (typeof input === 'string') {
45
45
  if (input)
@@ -62,7 +62,7 @@ function isNotEmpty(options) {
62
62
  return input;
63
63
  }
64
64
  }
65
- context.failure(`{{label}} is empty`);
65
+ context.fail(_this, `{{label}} is empty`, input);
66
66
  }, options);
67
67
  }
68
68
  exports.isNotEmpty = isNotEmpty;
@@ -18,13 +18,10 @@ function isEnum(values, options) {
18
18
  a[v] = true;
19
19
  return a;
20
20
  }, {});
21
- return (0, index_js_1.validator)('isEnum', function (input, context) {
21
+ return (0, index_js_1.validator)('isEnum', function (input, context, _this) {
22
22
  if (input != null && valObj[typeof input === 'string' && caseInSensitive ? input.toUpperCase() : input])
23
23
  return input;
24
- context.failure({
25
- message: `Value must be one of enumeration member${enumName ? ` (${enumName})` : ''}`,
26
- enum: enumName
27
- });
24
+ context.fail(_this, `Value must be one of enumeration member${enumName ? ` (${enumName})` : ''}`, input, { enum: enumName });
28
25
  }, options);
29
26
  }
30
27
  exports.isEnum = isEnum;
@@ -8,7 +8,7 @@ const index_js_1 = require("../core/index.js");
8
8
  * @validator isInteger
9
9
  */
10
10
  function isInteger(options) {
11
- return (0, index_js_1.validator)('isInteger', function (input, context) {
11
+ return (0, index_js_1.validator)('isInteger', function (input, context, _this) {
12
12
  if (input != null && typeof input !== 'number' && context.coerce) {
13
13
  if (typeof input === 'string')
14
14
  input = parseFloat(input);
@@ -20,7 +20,7 @@ function isInteger(options) {
20
20
  }
21
21
  if (typeof input === 'number' && !isNaN(input) && Number.isInteger(input))
22
22
  return input;
23
- context.failure(`{{label}} is not a valid integer number`);
23
+ context.fail(_this, `{{label}} is not a valid integer number`, input);
24
24
  }, options);
25
25
  }
26
26
  exports.isInteger = isInteger;
@@ -9,16 +9,12 @@ const index_js_1 = require("../core/index.js");
9
9
  function isMatches(format, options) {
10
10
  const regExp = format instanceof RegExp ? format : new RegExp(format);
11
11
  const formatName = options?.formatName;
12
- return (0, index_js_1.validator)('matches', function (input, context) {
12
+ return (0, index_js_1.validator)('matches', function (input, context, _this) {
13
13
  if (input == null)
14
14
  return;
15
15
  if (typeof input === 'string' && regExp.test(input))
16
16
  return input;
17
- context.failure({
18
- message: `{{label}} does not match ${formatName || 'requested'} format`,
19
- format,
20
- formatName
21
- });
17
+ context.fail(_this, `{{label}} does not match ${formatName || 'requested'} format`, input, { format, formatName });
22
18
  }, options);
23
19
  }
24
20
  exports.isMatches = isMatches;
@@ -7,10 +7,10 @@ const index_js_1 = require("../core/index.js");
7
7
  * @validator isNull
8
8
  */
9
9
  function isNull(options) {
10
- return (0, index_js_1.validator)('isNull', function (input, context) {
10
+ return (0, index_js_1.validator)('isNull', function (input, context, _this) {
11
11
  if (input === null)
12
12
  return input;
13
- context.failure(`{{label}} is not null`);
13
+ context.fail(_this, `{{label}} is not null`, input);
14
14
  }, options);
15
15
  }
16
16
  exports.isNull = isNull;
@@ -19,10 +19,10 @@ exports.isNull = isNull;
19
19
  * @validator isDefined
20
20
  */
21
21
  function isDefined(options) {
22
- return (0, index_js_1.validator)('is-defined', function (input, context) {
22
+ return (0, index_js_1.validator)('is-defined', function (input, context, _this) {
23
23
  if (input !== undefined)
24
24
  return input;
25
- context.failure(`{{label}} is not defined`);
25
+ context.fail(_this, `{{label}} is not defined`, input);
26
26
  }, options);
27
27
  }
28
28
  exports.isDefined = isDefined;
@@ -31,10 +31,10 @@ exports.isDefined = isDefined;
31
31
  * @validator isNotDefined
32
32
  */
33
33
  function isUndefined(options) {
34
- return (0, index_js_1.validator)('isUndefined', function (input, context) {
34
+ return (0, index_js_1.validator)('isUndefined', function (input, context, _this) {
35
35
  if (input === undefined)
36
36
  return;
37
- context.failure(`{{label}} defined`);
37
+ context.fail(_this, `{{label}} defined`, input);
38
38
  }, options);
39
39
  }
40
40
  exports.isUndefined = isUndefined;
@@ -8,7 +8,7 @@ const index_js_1 = require("../core/index.js");
8
8
  * @validator isNumber
9
9
  */
10
10
  function isNumber(options) {
11
- return (0, index_js_1.validator)('isNumber', function (input, context) {
11
+ return (0, index_js_1.validator)('isNumber', function (input, context, _this) {
12
12
  if (input != null && typeof input !== 'number' && context.coerce) {
13
13
  if (typeof input === 'string')
14
14
  input = parseFloat(input);
@@ -20,7 +20,7 @@ function isNumber(options) {
20
20
  }
21
21
  if (typeof input === 'number' && !isNaN(input))
22
22
  return input;
23
- context.failure(`{{label}} is not a valid number`);
23
+ context.fail(_this, `{{label}} is not a valid number`, input);
24
24
  }, options);
25
25
  }
26
26
  exports.isNumber = isNumber;
@@ -11,14 +11,14 @@ const index_js_1 = require("../core/index.js");
11
11
  * @validator isObjectId
12
12
  */
13
13
  function isObjectId(options) {
14
- return (0, index_js_1.validator)('isObjectId', function (input, context) {
14
+ return (0, index_js_1.validator)('isObjectId', function (input, context, _this) {
15
15
  if (input != null &&
16
16
  (_isObjectIdValue(input) ||
17
17
  (typeof input === 'object' &&
18
18
  typeof input.toHexString === 'function' &&
19
19
  _isObjectIdValue(input.toHexString()))))
20
20
  return input;
21
- context.failure(`{{label}} is not a valid ObjectId`);
21
+ context.fail(_this, `{{label}} is not a valid ObjectId`, input);
22
22
  }, options);
23
23
  }
24
24
  exports.isObjectId = isObjectId;
@@ -31,9 +31,9 @@ function isObject(schema, options) {
31
31
  else
32
32
  throw new TypeError(`Invalid definition in validation schema (${k})`);
33
33
  });
34
- const _rule = (0, index_js_1.validator)('isObject', function (input, context) {
34
+ const _rule = (0, index_js_1.validator)('isObject', function (input, context, _this) {
35
35
  if (!(input && typeof input === 'object')) {
36
- context.failure(`{{label}} must be an object`);
36
+ context.fail(_this, `{{label}} is not an object`, input);
37
37
  return;
38
38
  }
39
39
  const keys = [...Object.keys(input), ...Object.keys(schema)];
@@ -52,8 +52,9 @@ function isObject(schema, options) {
52
52
  return context.circMap.get(input);
53
53
  context.circMap.set(input, out);
54
54
  }
55
- const rootName = context.root?.input.context;
56
- const location = context.input.location || '';
55
+ if (context.root == null)
56
+ context.root = context.root || ctorName || '';
57
+ const location = context.location || '';
57
58
  const processedSchemaKeys = {};
58
59
  // Iterate object keys and perform rules
59
60
  for (i = 0; i < l; i++) {
@@ -66,23 +67,20 @@ function isObject(schema, options) {
66
67
  if (processedSchemaKeys[schemaKey])
67
68
  continue;
68
69
  processedSchemaKeys[schemaKey] = true;
69
- const subCtx = context.extend(_propRule);
70
- if (ctorName) {
71
- if (rootName && rootName !== ctorName)
72
- subCtx.input.root = rootName;
73
- subCtx.input.context = ctorName;
74
- }
75
- subCtx.input.value = v;
76
- subCtx.input.label = propertyOptions[schemaKey]?.label || schemaKey;
77
- subCtx.input.location = location + (location ? '.' : '') + schemaKey;
78
- subCtx.input.property = schemaKey;
79
- v = _propRule[index_js_1.kValidatorFn](v, subCtx, _propRule);
70
+ const subCtx = context.extend();
71
+ subCtx.scope = input;
72
+ subCtx.context = ctorName;
73
+ subCtx.location = location + (location ? '.' : '') + schemaKey;
74
+ subCtx.property = schemaKey;
75
+ if (propertyOptions[schemaKey]?.label)
76
+ subCtx.label = propertyOptions[schemaKey]?.label;
77
+ v = _propRule(v, subCtx);
80
78
  }
81
79
  else if (v !== undefined) {
82
- if (additionalFields === 'ignore')
83
- continue;
84
80
  if (!additionalFields)
85
- context.failure(`${ctorName || 'Object'} has no field '${inputKey}' and does not accept additional fields`);
81
+ continue;
82
+ if (additionalFields === 'error')
83
+ context.fail(_propRule, `${ctorName || 'Object'} has no field '${inputKey}' and does not accept additional fields`, v);
86
84
  }
87
85
  if (v !== undefined)
88
86
  out[propertyOptions[schemaKey]?.as || schemaKey] = v;
@@ -8,14 +8,14 @@ const index_js_1 = require("../core/index.js");
8
8
  * @validator isRecord
9
9
  */
10
10
  function isRecord(keyRule, valueRule, options) {
11
- return (0, index_js_1.validator)('isRecord', function (input, context) {
11
+ return (0, index_js_1.validator)('isRecord', function (input, context, _this) {
12
12
  if (!(input && typeof input === 'object')) {
13
- context.failure(`{{label}} is not an object`);
13
+ context.fail(_this, `{{label}} is not an object`, input);
14
14
  return;
15
15
  }
16
- const location = context.input.location || '';
17
- const keyContext = context.extend(keyRule);
18
- const valueContext = context.extend(valueRule);
16
+ const keyContext = context.extend();
17
+ const valueContext = context.extend();
18
+ const location = context.location || '';
19
19
  const keys = Object.keys(input);
20
20
  const l = keys.length;
21
21
  let i;
@@ -25,14 +25,14 @@ function isRecord(keyRule, valueRule, options) {
25
25
  for (i = 0; i < l; i++) {
26
26
  k = keys[i];
27
27
  v = input[k];
28
- keyContext.input.value = k;
29
- keyContext.input.property = '@' + k;
30
- keyContext.input.location = location + (location ? '.@' : '@') + k;
31
- k = keyRule[index_js_1.kValidatorFn](k, keyContext, keyRule);
32
- valueContext.input.value = v;
33
- valueContext.input.property = k;
34
- valueContext.input.location = location + (location ? '.' : '') + k;
35
- v = valueRule[index_js_1.kValidatorFn](v, valueContext, valueRule);
28
+ // Validate key
29
+ keyContext.property = '@' + k;
30
+ keyContext.location = location + (location ? '.@' : '@') + k;
31
+ k = keyRule(k, keyContext);
32
+ // Validate value
33
+ valueContext.property = k;
34
+ valueContext.location = location + (location ? '.' : '') + k;
35
+ v = valueRule(v, valueContext);
36
36
  out[k] = v;
37
37
  }
38
38
  return context.errors.length ? undefined : out;
@@ -8,7 +8,7 @@ const index_js_1 = require("../core/index.js");
8
8
  * @validator isString
9
9
  */
10
10
  function isString(options) {
11
- return (0, index_js_1.validator)('isString', function (input, context) {
11
+ return (0, index_js_1.validator)('isString', function (input, context, _this) {
12
12
  if (input != null && typeof input !== 'string' && context.coerce) {
13
13
  if (typeof input === 'object') {
14
14
  if (typeof input.toJSON === 'function')
@@ -21,7 +21,7 @@ function isString(options) {
21
21
  }
22
22
  if (typeof input === 'string')
23
23
  return input;
24
- context.failure(`{{label}} is not a string`);
24
+ context.fail(_this, `{{label}} is not a string`, input);
25
25
  }, options);
26
26
  }
27
27
  exports.isString = isString;
@@ -3,28 +3,31 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isTuple = void 0;
4
4
  const index_js_1 = require("../core/index.js");
5
5
  function isTuple(items, options) {
6
- return (0, index_js_1.validator)('isTuple', function (input, context) {
6
+ return (0, index_js_1.validator)('isTuple', function (input, context, _this) {
7
7
  if (input != null && context.coerce && !Array.isArray(input))
8
8
  input = [input];
9
9
  if (!Array.isArray(input)) {
10
- context.failure(`{{label}} is not a valid tuple`);
10
+ context.fail(_this, `{{label}} is not a tuple`, input);
11
11
  return;
12
12
  }
13
- const location = context.input.location || '';
13
+ const location = context.location || '';
14
14
  let itemRule;
15
15
  let i;
16
+ let v;
16
17
  const l = input.length;
17
18
  const out = [];
18
19
  const nl = items.length;
20
+ const itemContext = context.extend();
19
21
  for (i = 0; i < l && i < nl; i++) {
20
22
  itemRule = items[i];
21
- const itemContext = context.extend(itemRule);
22
- itemContext.input.value = input[i];
23
- itemContext.input.label = ((context.input.label || context.input.property) || 'Item') +
23
+ itemContext.scope = input;
24
+ itemContext.label = context.label ? context.label + `[${i}]` : undefined;
25
+ itemContext.index = i;
26
+ itemContext.location = location + '[' + i + ']';
27
+ itemContext.label = (itemContext.label || itemContext.property || 'Value at ') +
24
28
  `[${i}]`;
25
- itemContext.input.property = i;
26
- itemContext.input.location = location + '[' + i + ']';
27
- out.push(itemRule[index_js_1.kValidatorFn](input[i], itemContext, itemRule) ?? null);
29
+ v = itemRule(input[i], itemContext);
30
+ out.push(v);
28
31
  }
29
32
  return context.errors.length ? undefined : out;
30
33
  }, options);
@@ -10,7 +10,7 @@ const range_js_1 = require("./range.js");
10
10
  */
11
11
  const extractLength = () => extractLengthRule;
12
12
  exports.extractLength = extractLength;
13
- const extractLengthRule = (0, index_js_1.validator)('extractLength', function (input, context) {
13
+ const extractLengthRule = (0, index_js_1.validator)('extractLength', function (input, context, _this) {
14
14
  if (typeof input === 'string')
15
15
  return input.length;
16
16
  if (Array.isArray(input))
@@ -21,7 +21,7 @@ const extractLengthRule = (0, index_js_1.validator)('extractLength', function (i
21
21
  return input.length;
22
22
  if (input && typeof input === 'object' && typeof input.size === 'number')
23
23
  return input.size;
24
- context.failure(`Unable to extract length of {{label}}`);
24
+ context.fail(_this, `Unable to extract length of {{label}}`, input);
25
25
  });
26
26
  /**
27
27
  * Checks the length is at least "minValue"