valgen 6.2.2 → 7.0.0

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