justus 0.0.7 → 0.1.1

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/dist/index.mjs CHANGED
@@ -1,36 +1,3 @@
1
- var __defProp = Object.defineProperty;
2
- var __defProps = Object.defineProperties;
3
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
- var __spreadValues = (a, b) => {
9
- for (var prop in b || (b = {}))
10
- if (__hasOwnProp.call(b, prop))
11
- __defNormalProp(a, prop, b[prop]);
12
- if (__getOwnPropSymbols)
13
- for (var prop of __getOwnPropSymbols(b)) {
14
- if (__propIsEnum.call(b, prop))
15
- __defNormalProp(a, prop, b[prop]);
16
- }
17
- return a;
18
- };
19
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
- var __restKey = (key) => typeof key === "symbol" ? key : key + "";
21
- var __objRest = (source, exclude) => {
22
- var target = {};
23
- for (var prop in source)
24
- if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
25
- target[prop] = source[prop];
26
- if (source != null && __getOwnPropSymbols)
27
- for (var prop of __getOwnPropSymbols(source)) {
28
- if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
29
- target[prop] = source[prop];
30
- }
31
- return target;
32
- };
33
-
34
1
  // src/errors.ts
35
2
  function pathToString(path) {
36
3
  return path.reduce((string2, key, index) => {
@@ -40,7 +7,9 @@ function pathToString(path) {
40
7
  }, "");
41
8
  }
42
9
  var ValidationError = class extends Error {
10
+ /** An `Array` of validation errors encountered while validating */
43
11
  errors;
12
+ /** Our stack, always present as we enforce it in the constructor */
44
13
  stack;
45
14
  constructor(builderOrCause, constructorOrPath, maybeConstructor) {
46
15
  let constructor;
@@ -66,7 +35,16 @@ var ValidationError = class extends Error {
66
35
  }
67
36
  };
68
37
  var ValidationErrorBuilder = class {
38
+ /** The current list of validation errors */
69
39
  errors = [];
40
+ /**
41
+ * Record a validation error associated with the specified key.
42
+ *
43
+ * @param error - The error (normally a `string` or a `ValidationError`)
44
+ * to record and associate with the given key
45
+ * @param key - The key in an object, or index in an array where the
46
+ * vaildation error was encountered
47
+ */
70
48
  record(error, ...key) {
71
49
  const path = [...key];
72
50
  if (error instanceof ValidationError) {
@@ -78,6 +56,12 @@ var ValidationErrorBuilder = class {
78
56
  }
79
57
  return this;
80
58
  }
59
+ /**
60
+ * Assert there are no validation errors and return the specified value, or
61
+ * throw a `ValidationError` combining all errors
62
+ *
63
+ * @param value - The value to return if no errors have been recorded
64
+ */
81
65
  assert(value) {
82
66
  if (this.errors.length > 0)
83
67
  throw new ValidationError(this);
@@ -94,19 +78,29 @@ function assertSchema(what, message) {
94
78
  }
95
79
 
96
80
  // src/types.ts
81
+ var isValidator = Symbol.for("justus.isValidator");
97
82
  var restValidator = Symbol.for("justus.restValidator");
98
83
  var schemaValidator = Symbol.for("justus.schemaValidator");
99
- var modifierValidator = Symbol.for("justus.modifierValidator");
100
84
  var additionalValidator = Symbol.for("justus.additionalValidator");
101
- var never = Symbol.for("justus.never");
102
- var Validator = class {
85
+ function makeValidatorFactory(validator, factory) {
86
+ return Object.assign(factory, {
87
+ optional: validator.optional,
88
+ validate: validator.validate.bind(validator),
89
+ [Symbol.iterator]: validator[Symbol.iterator].bind(validator),
90
+ [isValidator]: true
91
+ });
92
+ }
93
+ var AbstractValidator = class {
94
+ [isValidator] = true;
95
+ optional = void 0;
96
+ /** Allow any `Validator` to be used as a rest parameter in `Tuple`s */
103
97
  *[Symbol.iterator]() {
104
98
  yield { [restValidator]: this };
105
99
  }
106
100
  };
107
101
 
108
102
  // src/validators/any.ts
109
- var AnyValidator = class extends Validator {
103
+ var AnyValidator = class extends AbstractValidator {
110
104
  validate(value) {
111
105
  return value;
112
106
  }
@@ -114,7 +108,7 @@ var AnyValidator = class extends Validator {
114
108
  var any = new AnyValidator();
115
109
 
116
110
  // src/validators/constant.ts
117
- var ConstantValidator = class extends Validator {
111
+ var ConstantValidator = class extends AbstractValidator {
118
112
  constant;
119
113
  constructor(constant2) {
120
114
  super();
@@ -131,7 +125,7 @@ function constant(constant2) {
131
125
  var nullValidator = new ConstantValidator(null);
132
126
 
133
127
  // src/validators/tuple.ts
134
- var TupleValidator = class extends Validator {
128
+ var TupleValidator = class extends AbstractValidator {
135
129
  members;
136
130
  tuple;
137
131
  constructor(tuple2) {
@@ -190,65 +184,38 @@ var TupleValidator = class extends Validator {
190
184
  function tuple(tuple2) {
191
185
  return new TupleValidator(tuple2);
192
186
  }
193
- function makeTupleRestIterable(create) {
194
- const validator = create();
195
- create[Symbol.iterator] = function* () {
196
- yield { [restValidator]: validator };
197
- };
198
- return create;
199
- }
200
187
 
201
188
  // src/validators/object.ts
202
- var AnyObjectValidator = class extends Validator {
189
+ var AnyObjectValidator = class extends AbstractValidator {
203
190
  validate(value) {
204
191
  assertValidation(typeof value == "object", 'Value is not an "object"');
205
192
  assertValidation(value !== null, 'Value is "null"');
206
193
  return value;
207
194
  }
208
195
  };
209
- var ObjectValidator = class extends Validator {
196
+ var ObjectValidator = class extends AbstractValidator {
210
197
  schema;
211
- properties = /* @__PURE__ */ new Map();
198
+ validators = /* @__PURE__ */ new Map();
212
199
  additionalProperties;
213
200
  constructor(schema) {
214
201
  super();
215
- var _a;
216
- const _b = schema, { [_a = additionalValidator]: additional } = _b, properties = __objRest(_b, [__restKey(_a)]);
202
+ const { [additionalValidator]: additional, ...properties } = schema;
217
203
  if (additional)
218
204
  this.additionalProperties = getValidator(additional);
219
205
  for (const key of Object.keys(properties)) {
220
- const definition = properties[key];
221
- if (definition === never) {
222
- this.properties.set(key, void 0);
223
- } else if (isModifier(definition)) {
224
- this.properties.set(key, {
225
- validator: definition[modifierValidator],
226
- readonly: definition.readonly,
227
- optional: definition.optional
228
- });
229
- } else {
230
- this.properties.set(key, { validator: getValidator(definition) });
231
- }
206
+ this.validators.set(key, getValidator(properties[key]));
232
207
  }
233
208
  this.schema = schema;
234
209
  }
235
210
  validate(value, options) {
236
211
  assertValidation(typeof value === "object", 'Value is not an "object"');
237
212
  assertValidation(value !== null, 'Value is "null"');
238
- const { stripAdditionalProperties, stripForbiddenProperties, stripOptionalNulls } = options;
213
+ const { stripAdditionalProperties, stripOptionalNulls } = options;
239
214
  const record = value;
240
215
  const builder = new ValidationErrorBuilder();
241
216
  const clone = {};
242
- for (const [key, property] of this.properties.entries()) {
243
- const { validator, optional: optional2 } = property || {};
244
- if (!validator) {
245
- if (record[key] === void 0)
246
- continue;
247
- if (stripForbiddenProperties)
248
- continue;
249
- builder.record("Forbidden property", key);
250
- continue;
251
- }
217
+ for (const [key, validator] of this.validators.entries()) {
218
+ const optional2 = !!validator.optional;
252
219
  if (record[key] === void 0) {
253
220
  if (!optional2)
254
221
  builder.record("Required property missing", key);
@@ -258,12 +225,14 @@ var ObjectValidator = class extends Validator {
258
225
  continue;
259
226
  }
260
227
  try {
261
- clone[key] = validator.validate(record[key], options);
228
+ const value2 = validator.validate(record[key], options);
229
+ if (!(optional2 && value2 == void 0))
230
+ clone[key] = value2;
262
231
  } catch (error) {
263
232
  builder.record(error, key);
264
233
  }
265
234
  }
266
- const additionalKeys = Object.keys(record).filter((k) => !this.properties.has(k));
235
+ const additionalKeys = Object.keys(record).filter((k) => !this.validators.has(k));
267
236
  const additional = this.additionalProperties;
268
237
  if (additional) {
269
238
  additionalKeys.forEach((key) => {
@@ -284,10 +253,7 @@ var ObjectValidator = class extends Validator {
284
253
  return builder.assert(clone);
285
254
  }
286
255
  };
287
- var anyObjectValidator = new AnyObjectValidator();
288
256
  function _object(schema) {
289
- if (!schema)
290
- return anyObjectValidator;
291
257
  const validator = new ObjectValidator(schema);
292
258
  function* iterator() {
293
259
  yield { [restValidator]: validator };
@@ -297,23 +263,19 @@ function _object(schema) {
297
263
  [Symbol.iterator]: { value: iterator, enumerable: false }
298
264
  });
299
265
  }
300
- var object = makeTupleRestIterable(_object);
266
+ var object = makeValidatorFactory(new AnyObjectValidator(), _object);
301
267
 
302
268
  // src/utilities.ts
303
269
  function getValidator(validation) {
304
- if (validation === void 0)
305
- return any;
306
270
  if (validation === null)
307
271
  return nullValidator;
308
- if (validation instanceof Validator)
272
+ if (validation[isValidator] === true)
309
273
  return validation;
310
274
  switch (typeof validation) {
311
275
  case "boolean":
312
276
  case "string":
313
277
  case "number":
314
278
  return new ConstantValidator(validation);
315
- case "function":
316
- return validation();
317
279
  case "object":
318
280
  if (schemaValidator in validation)
319
281
  return validation[schemaValidator];
@@ -331,26 +293,13 @@ function _allowAdditionalProperties(options) {
331
293
  return { [additionalValidator]: false };
332
294
  if (options === true)
333
295
  return { [additionalValidator]: any };
334
- return { [additionalValidator]: getValidator(options) };
296
+ return { [additionalValidator]: options ? getValidator(options) : any };
335
297
  }
336
298
  var allowAdditionalProperties = _allowAdditionalProperties;
337
299
  allowAdditionalProperties[additionalValidator] = any;
338
- function isModifier(what) {
339
- return what && typeof what === "object" && modifierValidator in what;
340
- }
341
- function readonly(options) {
342
- const { [modifierValidator]: validation = any, optional: optional2 = false } = isModifier(options) ? options : { [modifierValidator]: options };
343
- const validator = getValidator(validation);
344
- return optional2 ? { [modifierValidator]: validator, optional: optional2, readonly: true } : { [modifierValidator]: validator, readonly: true };
345
- }
346
- function optional(options) {
347
- const { [modifierValidator]: validation = any, readonly: readonly2 = false } = isModifier(options) ? options : { [modifierValidator]: options };
348
- const validator = getValidator(validation);
349
- return readonly2 ? { [modifierValidator]: validator, readonly: readonly2, optional: true } : { [modifierValidator]: validator, optional: true };
350
- }
351
300
 
352
301
  // src/validators/union.ts
353
- var OneOfValidator = class extends Validator {
302
+ var OneOfValidator = class extends AbstractValidator {
354
303
  validators;
355
304
  constructor(args) {
356
305
  super();
@@ -371,7 +320,7 @@ var OneOfValidator = class extends Validator {
371
320
  function oneOf(...args) {
372
321
  return new OneOfValidator(args);
373
322
  }
374
- var AllOfValidator = class extends Validator {
323
+ var AllOfValidator = class extends AbstractValidator {
375
324
  validators;
376
325
  constructor(args) {
377
326
  super();
@@ -389,13 +338,13 @@ function allOf(...args) {
389
338
  }
390
339
 
391
340
  // src/validators/array.ts
392
- var AnyArrayValidator = class extends Validator {
341
+ var AnyArrayValidator = class extends AbstractValidator {
393
342
  validate(value, options) {
394
343
  assertValidation(Array.isArray(value), 'Value is not an "array"');
395
344
  return [...value];
396
345
  }
397
346
  };
398
- var ArrayValidator = class extends Validator {
347
+ var ArrayValidator = class extends AbstractValidator {
399
348
  maxItems;
400
349
  minItems;
401
350
  uniqueItems;
@@ -418,8 +367,14 @@ var ArrayValidator = class extends Validator {
418
367
  }
419
368
  validate(value, options) {
420
369
  assertValidation(Array.isArray(value), 'Value is not an "array"');
421
- assertValidation(value.length >= this.minItems, `Array must have a minimum length of ${this.minItems}`);
422
- assertValidation(value.length <= this.maxItems, `Array must have a maximum length of ${this.maxItems}`);
370
+ assertValidation(
371
+ value.length >= this.minItems,
372
+ `Array must have a minimum length of ${this.minItems}`
373
+ );
374
+ assertValidation(
375
+ value.length <= this.maxItems,
376
+ `Array must have a maximum length of ${this.maxItems}`
377
+ );
423
378
  const builder = new ValidationErrorBuilder();
424
379
  const clone = new Array(value.length);
425
380
  value.forEach((item, i) => {
@@ -439,30 +394,42 @@ var ArrayValidator = class extends Validator {
439
394
  return builder.assert(clone);
440
395
  }
441
396
  };
442
- var anyArrayValidator = new AnyArrayValidator();
443
- function _array(options) {
444
- if (!options)
445
- return anyArrayValidator;
446
- const items = getValidator(options.items);
447
- return new ArrayValidator(__spreadProps(__spreadValues({}, options), { items }));
397
+ function _array(constraints) {
398
+ const items = constraints.items ? getValidator(constraints.items) : any;
399
+ return new ArrayValidator({ ...constraints, items });
448
400
  }
449
- var array = makeTupleRestIterable(_array);
401
+ var array = makeValidatorFactory(new AnyArrayValidator(), _array);
450
402
  function arrayOf(validation) {
451
403
  return new ArrayValidator({ items: getValidator(validation) });
452
404
  }
453
405
 
454
406
  // src/validators/boolean.ts
455
- var BooleanValidator = class extends Validator {
407
+ var BooleanValidator = class extends AbstractValidator {
408
+ fromString;
409
+ constructor(constraints = {}) {
410
+ super();
411
+ const { fromString = false } = constraints;
412
+ this.fromString = fromString;
413
+ }
456
414
  validate(value) {
415
+ if (typeof value == "string" && this.fromString) {
416
+ const string2 = value.toLowerCase();
417
+ const parsed = string2 === "true" ? true : string2 === "false" ? false : void 0;
418
+ assertValidation(parsed !== void 0, "Boolean can not be parsed from string");
419
+ value = parsed;
420
+ }
457
421
  assertValidation(typeof value === "boolean", 'Value is not a "boolean"');
458
422
  return value;
459
423
  }
460
424
  };
461
- var boolean = new BooleanValidator();
425
+ function _boolean(constraints) {
426
+ return new BooleanValidator(constraints);
427
+ }
428
+ var boolean = makeValidatorFactory(new BooleanValidator(), _boolean);
462
429
 
463
430
  // src/validators/date.ts
464
431
  var ISO_8601_REGEX = /^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|(?:(?:\+|-)\d{2}:\d{2}))?)?$/;
465
- var DateValidator = class extends Validator {
432
+ var DateValidator = class extends AbstractValidator {
466
433
  format;
467
434
  from;
468
435
  until;
@@ -470,7 +437,10 @@ var DateValidator = class extends Validator {
470
437
  super();
471
438
  const { format, from, until } = constraints;
472
439
  if (from != void 0 && until !== void 0) {
473
- assertSchema(until.getTime() >= from.getTime(), `Constraint "until" (${until.toISOString()}) must not be before "from" (${from.toISOString()})`);
440
+ assertSchema(
441
+ until.getTime() >= from.getTime(),
442
+ `Constraint "until" (${until.toISOString()}) must not be before "from" (${from.toISOString()})`
443
+ );
474
444
  }
475
445
  this.format = format;
476
446
  this.from = from;
@@ -500,11 +470,22 @@ var DateValidator = class extends Validator {
500
470
  return date2;
501
471
  }
502
472
  };
503
- var anyDateValidator = new DateValidator();
504
473
  function _date(constraints) {
505
- return constraints ? new DateValidator(constraints) : anyDateValidator;
474
+ return new DateValidator(constraints);
506
475
  }
507
- var date = makeTupleRestIterable(_date);
476
+ var date = makeValidatorFactory(new DateValidator(), _date);
477
+
478
+ // src/validators/never.ts
479
+ var NeverValidator = class extends AbstractValidator {
480
+ optional = true;
481
+ validate(value, options) {
482
+ const { stripForbiddenProperties } = options;
483
+ if (stripForbiddenProperties || value === void 0)
484
+ return;
485
+ throw new ValidationError("Forbidden property");
486
+ }
487
+ };
488
+ var never = new NeverValidator();
508
489
 
509
490
  // src/validators/number.ts
510
491
  var PRECISION = 6;
@@ -516,18 +497,19 @@ function countDecimals(n) {
516
497
  const digits = (match[1] || ".").length - 1 - parseInt(match[2]);
517
498
  return digits < 0 ? 0 : digits;
518
499
  }
519
- var AnyNumberValidator = class extends Validator {
500
+ var AnyNumberValidator = class extends AbstractValidator {
520
501
  validate(value) {
521
502
  assertValidation(typeof value == "number", 'Value is not a "number"');
522
503
  assertValidation(!isNaN(value), 'Number is "NaN"');
523
504
  return value;
524
505
  }
525
506
  };
526
- var NumberValidator = class extends Validator {
507
+ var NumberValidator = class extends AbstractValidator {
527
508
  #isMultipleOf;
528
509
  allowNaN;
529
510
  exclusiveMaximum;
530
511
  exclusiveMinimum;
512
+ fromString;
531
513
  maximum;
532
514
  minimum;
533
515
  multipleOf;
@@ -538,6 +520,7 @@ var NumberValidator = class extends Validator {
538
520
  allowNaN = false,
539
521
  exclusiveMaximum,
540
522
  exclusiveMinimum,
523
+ fromString = false,
541
524
  maximum = Number.POSITIVE_INFINITY,
542
525
  minimum = Number.NEGATIVE_INFINITY,
543
526
  multipleOf
@@ -546,13 +529,22 @@ var NumberValidator = class extends Validator {
546
529
  this.brand = constraints.brand;
547
530
  assertSchema(maximum >= minimum, `Constraint "minimum" (${minimum}) is greater than "maximum" (${maximum})`);
548
531
  if (exclusiveMaximum !== void 0) {
549
- assertSchema(exclusiveMaximum > minimum, `Constraint "exclusiveMaximum" (${exclusiveMaximum}) must be greater than "minimum" (${minimum})`);
532
+ assertSchema(
533
+ exclusiveMaximum > minimum,
534
+ `Constraint "exclusiveMaximum" (${exclusiveMaximum}) must be greater than "minimum" (${minimum})`
535
+ );
550
536
  }
551
537
  if (exclusiveMinimum !== void 0) {
552
- assertSchema(maximum > exclusiveMinimum, `Constraint "maximum" (${maximum}) must be greater than "exclusiveMinimum" (${exclusiveMinimum})`);
538
+ assertSchema(
539
+ maximum > exclusiveMinimum,
540
+ `Constraint "maximum" (${maximum}) must be greater than "exclusiveMinimum" (${exclusiveMinimum})`
541
+ );
553
542
  }
554
543
  if (exclusiveMinimum != void 0 && exclusiveMaximum !== void 0) {
555
- assertSchema(exclusiveMaximum > exclusiveMinimum, `Constraint "exclusiveMaximum" (${exclusiveMaximum}) must be greater than "exclusiveMinimum" (${exclusiveMinimum})`);
544
+ assertSchema(
545
+ exclusiveMaximum > exclusiveMinimum,
546
+ `Constraint "exclusiveMaximum" (${exclusiveMaximum}) must be greater than "exclusiveMinimum" (${exclusiveMinimum})`
547
+ );
556
548
  }
557
549
  if (multipleOf !== void 0) {
558
550
  assertSchema(multipleOf > 0, `Constraint "multipleOf" (${multipleOf}) must be greater than zero`);
@@ -576,11 +568,17 @@ var NumberValidator = class extends Validator {
576
568
  this.allowNaN = allowNaN;
577
569
  this.exclusiveMaximum = exclusiveMaximum;
578
570
  this.exclusiveMinimum = exclusiveMinimum;
571
+ this.fromString = fromString;
579
572
  this.maximum = maximum;
580
573
  this.minimum = minimum;
581
574
  this.multipleOf = multipleOf;
582
575
  }
583
576
  validate(value) {
577
+ if (typeof value == "string" && this.fromString) {
578
+ const parsed = +`${value}`;
579
+ assertValidation(!isNaN(parsed), "Number can not be parsed from string");
580
+ value = parsed;
581
+ }
584
582
  assertValidation(typeof value == "number", 'Value is not a "number"');
585
583
  if (isNaN(value)) {
586
584
  assertValidation(this.allowNaN, 'Number is "NaN"');
@@ -588,26 +586,53 @@ var NumberValidator = class extends Validator {
588
586
  }
589
587
  assertValidation(value >= this.minimum, `Number is less than ${this.minimum}`);
590
588
  assertValidation(value <= this.maximum, `Number is greater than ${this.maximum}`);
591
- assertValidation(this.exclusiveMinimum == void 0 || value > this.exclusiveMinimum, `Number is less than or equal to ${this.exclusiveMinimum}`);
592
- assertValidation(this.exclusiveMaximum == void 0 || value < this.exclusiveMaximum, `Number is greater than or equal to ${this.exclusiveMaximum}`);
593
- assertValidation(this.#isMultipleOf ? this.#isMultipleOf(value) : true, `Number is not a multiple of ${this.multipleOf}`);
589
+ assertValidation(
590
+ this.exclusiveMinimum == void 0 || value > this.exclusiveMinimum,
591
+ `Number is less than or equal to ${this.exclusiveMinimum}`
592
+ );
593
+ assertValidation(
594
+ this.exclusiveMaximum == void 0 || value < this.exclusiveMaximum,
595
+ `Number is greater than or equal to ${this.exclusiveMaximum}`
596
+ );
597
+ assertValidation(
598
+ this.#isMultipleOf ? this.#isMultipleOf(value) : true,
599
+ `Number is not a multiple of ${this.multipleOf}`
600
+ );
594
601
  return value;
595
602
  }
596
603
  };
597
- var anyNumberValidator = new AnyNumberValidator();
598
604
  function _number(constraints) {
599
- return constraints ? new NumberValidator(constraints) : anyNumberValidator;
605
+ return new NumberValidator(constraints);
606
+ }
607
+ var number = makeValidatorFactory(new AnyNumberValidator(), _number);
608
+
609
+ // src/validators/optional.ts
610
+ var OptionalValidator = class extends AbstractValidator {
611
+ validator;
612
+ optional = true;
613
+ constructor(validator) {
614
+ super();
615
+ this.validator = validator;
616
+ }
617
+ validate(value, options) {
618
+ if (value === void 0)
619
+ return value;
620
+ return this.validator.validate(value, options);
621
+ }
622
+ };
623
+ function optional(validation) {
624
+ const validator = getValidator(validation);
625
+ return new OptionalValidator(validator);
600
626
  }
601
- var number = makeTupleRestIterable(_number);
602
627
 
603
628
  // src/validators/string.ts
604
- var AnyStringValidator = class extends Validator {
629
+ var AnyStringValidator = class extends AbstractValidator {
605
630
  validate(value) {
606
631
  assertValidation(typeof value == "string", 'Value is not a "string"');
607
632
  return value;
608
633
  }
609
634
  };
610
- var StringValidator = class extends Validator {
635
+ var StringValidator = class extends AbstractValidator {
611
636
  maxLength;
612
637
  minLength;
613
638
  pattern;
@@ -630,17 +655,25 @@ var StringValidator = class extends Validator {
630
655
  }
631
656
  validate(value) {
632
657
  assertValidation(typeof value == "string", 'Value is not a "string"');
633
- assertValidation(value.length >= this.minLength, `String must have a minimum length of ${this.minLength}`);
634
- assertValidation(value.length <= this.maxLength, `String must have a maximum length of ${this.maxLength}`);
635
- assertValidation(this.pattern ? this.pattern.test(value) : true, `String does not match required pattern ${this.pattern}`);
658
+ assertValidation(
659
+ value.length >= this.minLength,
660
+ `String must have a minimum length of ${this.minLength}`
661
+ );
662
+ assertValidation(
663
+ value.length <= this.maxLength,
664
+ `String must have a maximum length of ${this.maxLength}`
665
+ );
666
+ assertValidation(
667
+ this.pattern ? this.pattern.test(value) : true,
668
+ `String does not match required pattern ${this.pattern}`
669
+ );
636
670
  return value;
637
671
  }
638
672
  };
639
- var anyStringValidator = new AnyStringValidator();
640
673
  function _string(constraints) {
641
- return constraints ? new StringValidator(constraints) : anyStringValidator;
674
+ return new StringValidator(constraints);
642
675
  }
643
- var string = makeTupleRestIterable(_string);
676
+ var string = makeValidatorFactory(new AnyStringValidator(), _string);
644
677
 
645
678
  // src/validators/url.ts
646
679
  var KEYS = [
@@ -661,7 +694,7 @@ var OPTIONS = {
661
694
  stripForbiddenProperties: false,
662
695
  stripOptionalNulls: false
663
696
  };
664
- var URLValidator = class extends Validator {
697
+ var URLValidator = class extends AbstractValidator {
665
698
  href;
666
699
  origin;
667
700
  protocol;
@@ -722,28 +755,31 @@ var URLValidator = class extends Validator {
722
755
  };
723
756
  var anyURLValidator = new URLValidator();
724
757
  function _url(constraints) {
725
- return constraints ? new URLValidator(constraints) : anyURLValidator;
758
+ return new URLValidator(constraints);
726
759
  }
727
- var url = makeTupleRestIterable(_url);
760
+ var url = makeValidatorFactory(anyURLValidator, _url);
728
761
 
729
762
  // src/index.ts
730
763
  function validate(validation, value, options = {}) {
731
- const opts = __spreadValues({
764
+ const opts = {
732
765
  stripAdditionalProperties: false,
733
766
  stripForbiddenProperties: false,
734
- stripOptionalNulls: false
735
- }, options);
767
+ stripOptionalNulls: false,
768
+ ...options
769
+ };
736
770
  return getValidator(validation).validate(value, opts);
737
771
  }
738
772
  function strip(validation, value, options = {}) {
739
- const opts = __spreadValues({
773
+ const opts = {
740
774
  stripAdditionalProperties: true,
741
775
  stripForbiddenProperties: false,
742
- stripOptionalNulls: true
743
- }, options);
776
+ stripOptionalNulls: true,
777
+ ...options
778
+ };
744
779
  return getValidator(validation).validate(value, opts);
745
780
  }
746
781
  export {
782
+ AbstractValidator,
747
783
  AllOfValidator,
748
784
  AnyArrayValidator,
749
785
  AnyNumberValidator,
@@ -754,17 +790,19 @@ export {
754
790
  BooleanValidator,
755
791
  ConstantValidator,
756
792
  DateValidator,
793
+ NeverValidator,
757
794
  NumberValidator,
758
795
  ObjectValidator,
759
796
  OneOfValidator,
797
+ OptionalValidator,
760
798
  StringValidator,
761
799
  TupleValidator,
762
800
  URLValidator,
763
801
  ValidationError,
764
802
  ValidationErrorBuilder,
765
- Validator,
766
803
  _allowAdditionalProperties,
767
804
  _array,
805
+ _boolean,
768
806
  _date,
769
807
  _number,
770
808
  _object,
@@ -782,14 +820,13 @@ export {
782
820
  constant,
783
821
  date,
784
822
  getValidator,
785
- isModifier,
786
- modifierValidator,
823
+ isValidator,
824
+ makeValidatorFactory,
787
825
  never,
788
826
  number,
789
827
  object,
790
828
  oneOf,
791
829
  optional,
792
- readonly,
793
830
  restValidator,
794
831
  schemaValidator,
795
832
  string,