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.js CHANGED
@@ -1,37 +1,8 @@
1
+ "use strict";
1
2
  var __defProp = Object.defineProperty;
2
- var __defProps = Object.defineProperties;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
9
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
10
- var __spreadValues = (a, b) => {
11
- for (var prop in b || (b = {}))
12
- if (__hasOwnProp.call(b, prop))
13
- __defNormalProp(a, prop, b[prop]);
14
- if (__getOwnPropSymbols)
15
- for (var prop of __getOwnPropSymbols(b)) {
16
- if (__propIsEnum.call(b, prop))
17
- __defNormalProp(a, prop, b[prop]);
18
- }
19
- return a;
20
- };
21
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
22
- var __restKey = (key) => typeof key === "symbol" ? key : key + "";
23
- var __objRest = (source, exclude) => {
24
- var target = {};
25
- for (var prop in source)
26
- if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
27
- target[prop] = source[prop];
28
- if (source != null && __getOwnPropSymbols)
29
- for (var prop of __getOwnPropSymbols(source)) {
30
- if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
31
- target[prop] = source[prop];
32
- }
33
- return target;
34
- };
35
6
  var __export = (target, all) => {
36
7
  for (var name in all)
37
8
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -49,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
49
20
  // src/index.ts
50
21
  var src_exports = {};
51
22
  __export(src_exports, {
23
+ AbstractValidator: () => AbstractValidator,
52
24
  AllOfValidator: () => AllOfValidator,
53
25
  AnyArrayValidator: () => AnyArrayValidator,
54
26
  AnyNumberValidator: () => AnyNumberValidator,
@@ -59,17 +31,19 @@ __export(src_exports, {
59
31
  BooleanValidator: () => BooleanValidator,
60
32
  ConstantValidator: () => ConstantValidator,
61
33
  DateValidator: () => DateValidator,
34
+ NeverValidator: () => NeverValidator,
62
35
  NumberValidator: () => NumberValidator,
63
36
  ObjectValidator: () => ObjectValidator,
64
37
  OneOfValidator: () => OneOfValidator,
38
+ OptionalValidator: () => OptionalValidator,
65
39
  StringValidator: () => StringValidator,
66
40
  TupleValidator: () => TupleValidator,
67
41
  URLValidator: () => URLValidator,
68
42
  ValidationError: () => ValidationError,
69
43
  ValidationErrorBuilder: () => ValidationErrorBuilder,
70
- Validator: () => Validator,
71
44
  _allowAdditionalProperties: () => _allowAdditionalProperties,
72
45
  _array: () => _array,
46
+ _boolean: () => _boolean,
73
47
  _date: () => _date,
74
48
  _number: () => _number,
75
49
  _object: () => _object,
@@ -87,14 +61,13 @@ __export(src_exports, {
87
61
  constant: () => constant,
88
62
  date: () => date,
89
63
  getValidator: () => getValidator,
90
- isModifier: () => isModifier,
91
- modifierValidator: () => modifierValidator,
64
+ isValidator: () => isValidator,
65
+ makeValidatorFactory: () => makeValidatorFactory,
92
66
  never: () => never,
93
67
  number: () => number,
94
68
  object: () => object,
95
69
  oneOf: () => oneOf,
96
70
  optional: () => optional,
97
- readonly: () => readonly,
98
71
  restValidator: () => restValidator,
99
72
  schemaValidator: () => schemaValidator,
100
73
  string: () => string,
@@ -114,7 +87,9 @@ function pathToString(path) {
114
87
  }, "");
115
88
  }
116
89
  var ValidationError = class extends Error {
90
+ /** An `Array` of validation errors encountered while validating */
117
91
  errors;
92
+ /** Our stack, always present as we enforce it in the constructor */
118
93
  stack;
119
94
  constructor(builderOrCause, constructorOrPath, maybeConstructor) {
120
95
  let constructor;
@@ -140,7 +115,16 @@ var ValidationError = class extends Error {
140
115
  }
141
116
  };
142
117
  var ValidationErrorBuilder = class {
118
+ /** The current list of validation errors */
143
119
  errors = [];
120
+ /**
121
+ * Record a validation error associated with the specified key.
122
+ *
123
+ * @param error - The error (normally a `string` or a `ValidationError`)
124
+ * to record and associate with the given key
125
+ * @param key - The key in an object, or index in an array where the
126
+ * vaildation error was encountered
127
+ */
144
128
  record(error, ...key) {
145
129
  const path = [...key];
146
130
  if (error instanceof ValidationError) {
@@ -152,6 +136,12 @@ var ValidationErrorBuilder = class {
152
136
  }
153
137
  return this;
154
138
  }
139
+ /**
140
+ * Assert there are no validation errors and return the specified value, or
141
+ * throw a `ValidationError` combining all errors
142
+ *
143
+ * @param value - The value to return if no errors have been recorded
144
+ */
155
145
  assert(value) {
156
146
  if (this.errors.length > 0)
157
147
  throw new ValidationError(this);
@@ -168,19 +158,29 @@ function assertSchema(what, message) {
168
158
  }
169
159
 
170
160
  // src/types.ts
161
+ var isValidator = Symbol.for("justus.isValidator");
171
162
  var restValidator = Symbol.for("justus.restValidator");
172
163
  var schemaValidator = Symbol.for("justus.schemaValidator");
173
- var modifierValidator = Symbol.for("justus.modifierValidator");
174
164
  var additionalValidator = Symbol.for("justus.additionalValidator");
175
- var never = Symbol.for("justus.never");
176
- var Validator = class {
165
+ function makeValidatorFactory(validator, factory) {
166
+ return Object.assign(factory, {
167
+ optional: validator.optional,
168
+ validate: validator.validate.bind(validator),
169
+ [Symbol.iterator]: validator[Symbol.iterator].bind(validator),
170
+ [isValidator]: true
171
+ });
172
+ }
173
+ var AbstractValidator = class {
174
+ [isValidator] = true;
175
+ optional = void 0;
176
+ /** Allow any `Validator` to be used as a rest parameter in `Tuple`s */
177
177
  *[Symbol.iterator]() {
178
178
  yield { [restValidator]: this };
179
179
  }
180
180
  };
181
181
 
182
182
  // src/validators/any.ts
183
- var AnyValidator = class extends Validator {
183
+ var AnyValidator = class extends AbstractValidator {
184
184
  validate(value) {
185
185
  return value;
186
186
  }
@@ -188,7 +188,7 @@ var AnyValidator = class extends Validator {
188
188
  var any = new AnyValidator();
189
189
 
190
190
  // src/validators/constant.ts
191
- var ConstantValidator = class extends Validator {
191
+ var ConstantValidator = class extends AbstractValidator {
192
192
  constant;
193
193
  constructor(constant2) {
194
194
  super();
@@ -205,7 +205,7 @@ function constant(constant2) {
205
205
  var nullValidator = new ConstantValidator(null);
206
206
 
207
207
  // src/validators/tuple.ts
208
- var TupleValidator = class extends Validator {
208
+ var TupleValidator = class extends AbstractValidator {
209
209
  members;
210
210
  tuple;
211
211
  constructor(tuple2) {
@@ -264,65 +264,38 @@ var TupleValidator = class extends Validator {
264
264
  function tuple(tuple2) {
265
265
  return new TupleValidator(tuple2);
266
266
  }
267
- function makeTupleRestIterable(create) {
268
- const validator = create();
269
- create[Symbol.iterator] = function* () {
270
- yield { [restValidator]: validator };
271
- };
272
- return create;
273
- }
274
267
 
275
268
  // src/validators/object.ts
276
- var AnyObjectValidator = class extends Validator {
269
+ var AnyObjectValidator = class extends AbstractValidator {
277
270
  validate(value) {
278
271
  assertValidation(typeof value == "object", 'Value is not an "object"');
279
272
  assertValidation(value !== null, 'Value is "null"');
280
273
  return value;
281
274
  }
282
275
  };
283
- var ObjectValidator = class extends Validator {
276
+ var ObjectValidator = class extends AbstractValidator {
284
277
  schema;
285
- properties = /* @__PURE__ */ new Map();
278
+ validators = /* @__PURE__ */ new Map();
286
279
  additionalProperties;
287
280
  constructor(schema) {
288
281
  super();
289
- var _a;
290
- const _b = schema, { [_a = additionalValidator]: additional } = _b, properties = __objRest(_b, [__restKey(_a)]);
282
+ const { [additionalValidator]: additional, ...properties } = schema;
291
283
  if (additional)
292
284
  this.additionalProperties = getValidator(additional);
293
285
  for (const key of Object.keys(properties)) {
294
- const definition = properties[key];
295
- if (definition === never) {
296
- this.properties.set(key, void 0);
297
- } else if (isModifier(definition)) {
298
- this.properties.set(key, {
299
- validator: definition[modifierValidator],
300
- readonly: definition.readonly,
301
- optional: definition.optional
302
- });
303
- } else {
304
- this.properties.set(key, { validator: getValidator(definition) });
305
- }
286
+ this.validators.set(key, getValidator(properties[key]));
306
287
  }
307
288
  this.schema = schema;
308
289
  }
309
290
  validate(value, options) {
310
291
  assertValidation(typeof value === "object", 'Value is not an "object"');
311
292
  assertValidation(value !== null, 'Value is "null"');
312
- const { stripAdditionalProperties, stripForbiddenProperties, stripOptionalNulls } = options;
293
+ const { stripAdditionalProperties, stripOptionalNulls } = options;
313
294
  const record = value;
314
295
  const builder = new ValidationErrorBuilder();
315
296
  const clone = {};
316
- for (const [key, property] of this.properties.entries()) {
317
- const { validator, optional: optional2 } = property || {};
318
- if (!validator) {
319
- if (record[key] === void 0)
320
- continue;
321
- if (stripForbiddenProperties)
322
- continue;
323
- builder.record("Forbidden property", key);
324
- continue;
325
- }
297
+ for (const [key, validator] of this.validators.entries()) {
298
+ const optional2 = !!validator.optional;
326
299
  if (record[key] === void 0) {
327
300
  if (!optional2)
328
301
  builder.record("Required property missing", key);
@@ -332,12 +305,14 @@ var ObjectValidator = class extends Validator {
332
305
  continue;
333
306
  }
334
307
  try {
335
- clone[key] = validator.validate(record[key], options);
308
+ const value2 = validator.validate(record[key], options);
309
+ if (!(optional2 && value2 == void 0))
310
+ clone[key] = value2;
336
311
  } catch (error) {
337
312
  builder.record(error, key);
338
313
  }
339
314
  }
340
- const additionalKeys = Object.keys(record).filter((k) => !this.properties.has(k));
315
+ const additionalKeys = Object.keys(record).filter((k) => !this.validators.has(k));
341
316
  const additional = this.additionalProperties;
342
317
  if (additional) {
343
318
  additionalKeys.forEach((key) => {
@@ -358,10 +333,7 @@ var ObjectValidator = class extends Validator {
358
333
  return builder.assert(clone);
359
334
  }
360
335
  };
361
- var anyObjectValidator = new AnyObjectValidator();
362
336
  function _object(schema) {
363
- if (!schema)
364
- return anyObjectValidator;
365
337
  const validator = new ObjectValidator(schema);
366
338
  function* iterator() {
367
339
  yield { [restValidator]: validator };
@@ -371,23 +343,19 @@ function _object(schema) {
371
343
  [Symbol.iterator]: { value: iterator, enumerable: false }
372
344
  });
373
345
  }
374
- var object = makeTupleRestIterable(_object);
346
+ var object = makeValidatorFactory(new AnyObjectValidator(), _object);
375
347
 
376
348
  // src/utilities.ts
377
349
  function getValidator(validation) {
378
- if (validation === void 0)
379
- return any;
380
350
  if (validation === null)
381
351
  return nullValidator;
382
- if (validation instanceof Validator)
352
+ if (validation[isValidator] === true)
383
353
  return validation;
384
354
  switch (typeof validation) {
385
355
  case "boolean":
386
356
  case "string":
387
357
  case "number":
388
358
  return new ConstantValidator(validation);
389
- case "function":
390
- return validation();
391
359
  case "object":
392
360
  if (schemaValidator in validation)
393
361
  return validation[schemaValidator];
@@ -405,26 +373,13 @@ function _allowAdditionalProperties(options) {
405
373
  return { [additionalValidator]: false };
406
374
  if (options === true)
407
375
  return { [additionalValidator]: any };
408
- return { [additionalValidator]: getValidator(options) };
376
+ return { [additionalValidator]: options ? getValidator(options) : any };
409
377
  }
410
378
  var allowAdditionalProperties = _allowAdditionalProperties;
411
379
  allowAdditionalProperties[additionalValidator] = any;
412
- function isModifier(what) {
413
- return what && typeof what === "object" && modifierValidator in what;
414
- }
415
- function readonly(options) {
416
- const { [modifierValidator]: validation = any, optional: optional2 = false } = isModifier(options) ? options : { [modifierValidator]: options };
417
- const validator = getValidator(validation);
418
- return optional2 ? { [modifierValidator]: validator, optional: optional2, readonly: true } : { [modifierValidator]: validator, readonly: true };
419
- }
420
- function optional(options) {
421
- const { [modifierValidator]: validation = any, readonly: readonly2 = false } = isModifier(options) ? options : { [modifierValidator]: options };
422
- const validator = getValidator(validation);
423
- return readonly2 ? { [modifierValidator]: validator, readonly: readonly2, optional: true } : { [modifierValidator]: validator, optional: true };
424
- }
425
380
 
426
381
  // src/validators/union.ts
427
- var OneOfValidator = class extends Validator {
382
+ var OneOfValidator = class extends AbstractValidator {
428
383
  validators;
429
384
  constructor(args) {
430
385
  super();
@@ -445,7 +400,7 @@ var OneOfValidator = class extends Validator {
445
400
  function oneOf(...args) {
446
401
  return new OneOfValidator(args);
447
402
  }
448
- var AllOfValidator = class extends Validator {
403
+ var AllOfValidator = class extends AbstractValidator {
449
404
  validators;
450
405
  constructor(args) {
451
406
  super();
@@ -463,13 +418,13 @@ function allOf(...args) {
463
418
  }
464
419
 
465
420
  // src/validators/array.ts
466
- var AnyArrayValidator = class extends Validator {
421
+ var AnyArrayValidator = class extends AbstractValidator {
467
422
  validate(value, options) {
468
423
  assertValidation(Array.isArray(value), 'Value is not an "array"');
469
424
  return [...value];
470
425
  }
471
426
  };
472
- var ArrayValidator = class extends Validator {
427
+ var ArrayValidator = class extends AbstractValidator {
473
428
  maxItems;
474
429
  minItems;
475
430
  uniqueItems;
@@ -492,8 +447,14 @@ var ArrayValidator = class extends Validator {
492
447
  }
493
448
  validate(value, options) {
494
449
  assertValidation(Array.isArray(value), 'Value is not an "array"');
495
- assertValidation(value.length >= this.minItems, `Array must have a minimum length of ${this.minItems}`);
496
- assertValidation(value.length <= this.maxItems, `Array must have a maximum length of ${this.maxItems}`);
450
+ assertValidation(
451
+ value.length >= this.minItems,
452
+ `Array must have a minimum length of ${this.minItems}`
453
+ );
454
+ assertValidation(
455
+ value.length <= this.maxItems,
456
+ `Array must have a maximum length of ${this.maxItems}`
457
+ );
497
458
  const builder = new ValidationErrorBuilder();
498
459
  const clone = new Array(value.length);
499
460
  value.forEach((item, i) => {
@@ -513,30 +474,42 @@ var ArrayValidator = class extends Validator {
513
474
  return builder.assert(clone);
514
475
  }
515
476
  };
516
- var anyArrayValidator = new AnyArrayValidator();
517
- function _array(options) {
518
- if (!options)
519
- return anyArrayValidator;
520
- const items = getValidator(options.items);
521
- return new ArrayValidator(__spreadProps(__spreadValues({}, options), { items }));
477
+ function _array(constraints) {
478
+ const items = constraints.items ? getValidator(constraints.items) : any;
479
+ return new ArrayValidator({ ...constraints, items });
522
480
  }
523
- var array = makeTupleRestIterable(_array);
481
+ var array = makeValidatorFactory(new AnyArrayValidator(), _array);
524
482
  function arrayOf(validation) {
525
483
  return new ArrayValidator({ items: getValidator(validation) });
526
484
  }
527
485
 
528
486
  // src/validators/boolean.ts
529
- var BooleanValidator = class extends Validator {
487
+ var BooleanValidator = class extends AbstractValidator {
488
+ fromString;
489
+ constructor(constraints = {}) {
490
+ super();
491
+ const { fromString = false } = constraints;
492
+ this.fromString = fromString;
493
+ }
530
494
  validate(value) {
495
+ if (typeof value == "string" && this.fromString) {
496
+ const string2 = value.toLowerCase();
497
+ const parsed = string2 === "true" ? true : string2 === "false" ? false : void 0;
498
+ assertValidation(parsed !== void 0, "Boolean can not be parsed from string");
499
+ value = parsed;
500
+ }
531
501
  assertValidation(typeof value === "boolean", 'Value is not a "boolean"');
532
502
  return value;
533
503
  }
534
504
  };
535
- var boolean = new BooleanValidator();
505
+ function _boolean(constraints) {
506
+ return new BooleanValidator(constraints);
507
+ }
508
+ var boolean = makeValidatorFactory(new BooleanValidator(), _boolean);
536
509
 
537
510
  // src/validators/date.ts
538
511
  var ISO_8601_REGEX = /^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|(?:(?:\+|-)\d{2}:\d{2}))?)?$/;
539
- var DateValidator = class extends Validator {
512
+ var DateValidator = class extends AbstractValidator {
540
513
  format;
541
514
  from;
542
515
  until;
@@ -544,7 +517,10 @@ var DateValidator = class extends Validator {
544
517
  super();
545
518
  const { format, from, until } = constraints;
546
519
  if (from != void 0 && until !== void 0) {
547
- assertSchema(until.getTime() >= from.getTime(), `Constraint "until" (${until.toISOString()}) must not be before "from" (${from.toISOString()})`);
520
+ assertSchema(
521
+ until.getTime() >= from.getTime(),
522
+ `Constraint "until" (${until.toISOString()}) must not be before "from" (${from.toISOString()})`
523
+ );
548
524
  }
549
525
  this.format = format;
550
526
  this.from = from;
@@ -574,11 +550,22 @@ var DateValidator = class extends Validator {
574
550
  return date2;
575
551
  }
576
552
  };
577
- var anyDateValidator = new DateValidator();
578
553
  function _date(constraints) {
579
- return constraints ? new DateValidator(constraints) : anyDateValidator;
554
+ return new DateValidator(constraints);
580
555
  }
581
- var date = makeTupleRestIterable(_date);
556
+ var date = makeValidatorFactory(new DateValidator(), _date);
557
+
558
+ // src/validators/never.ts
559
+ var NeverValidator = class extends AbstractValidator {
560
+ optional = true;
561
+ validate(value, options) {
562
+ const { stripForbiddenProperties } = options;
563
+ if (stripForbiddenProperties || value === void 0)
564
+ return;
565
+ throw new ValidationError("Forbidden property");
566
+ }
567
+ };
568
+ var never = new NeverValidator();
582
569
 
583
570
  // src/validators/number.ts
584
571
  var PRECISION = 6;
@@ -590,18 +577,19 @@ function countDecimals(n) {
590
577
  const digits = (match[1] || ".").length - 1 - parseInt(match[2]);
591
578
  return digits < 0 ? 0 : digits;
592
579
  }
593
- var AnyNumberValidator = class extends Validator {
580
+ var AnyNumberValidator = class extends AbstractValidator {
594
581
  validate(value) {
595
582
  assertValidation(typeof value == "number", 'Value is not a "number"');
596
583
  assertValidation(!isNaN(value), 'Number is "NaN"');
597
584
  return value;
598
585
  }
599
586
  };
600
- var NumberValidator = class extends Validator {
587
+ var NumberValidator = class extends AbstractValidator {
601
588
  #isMultipleOf;
602
589
  allowNaN;
603
590
  exclusiveMaximum;
604
591
  exclusiveMinimum;
592
+ fromString;
605
593
  maximum;
606
594
  minimum;
607
595
  multipleOf;
@@ -612,6 +600,7 @@ var NumberValidator = class extends Validator {
612
600
  allowNaN = false,
613
601
  exclusiveMaximum,
614
602
  exclusiveMinimum,
603
+ fromString = false,
615
604
  maximum = Number.POSITIVE_INFINITY,
616
605
  minimum = Number.NEGATIVE_INFINITY,
617
606
  multipleOf
@@ -620,13 +609,22 @@ var NumberValidator = class extends Validator {
620
609
  this.brand = constraints.brand;
621
610
  assertSchema(maximum >= minimum, `Constraint "minimum" (${minimum}) is greater than "maximum" (${maximum})`);
622
611
  if (exclusiveMaximum !== void 0) {
623
- assertSchema(exclusiveMaximum > minimum, `Constraint "exclusiveMaximum" (${exclusiveMaximum}) must be greater than "minimum" (${minimum})`);
612
+ assertSchema(
613
+ exclusiveMaximum > minimum,
614
+ `Constraint "exclusiveMaximum" (${exclusiveMaximum}) must be greater than "minimum" (${minimum})`
615
+ );
624
616
  }
625
617
  if (exclusiveMinimum !== void 0) {
626
- assertSchema(maximum > exclusiveMinimum, `Constraint "maximum" (${maximum}) must be greater than "exclusiveMinimum" (${exclusiveMinimum})`);
618
+ assertSchema(
619
+ maximum > exclusiveMinimum,
620
+ `Constraint "maximum" (${maximum}) must be greater than "exclusiveMinimum" (${exclusiveMinimum})`
621
+ );
627
622
  }
628
623
  if (exclusiveMinimum != void 0 && exclusiveMaximum !== void 0) {
629
- assertSchema(exclusiveMaximum > exclusiveMinimum, `Constraint "exclusiveMaximum" (${exclusiveMaximum}) must be greater than "exclusiveMinimum" (${exclusiveMinimum})`);
624
+ assertSchema(
625
+ exclusiveMaximum > exclusiveMinimum,
626
+ `Constraint "exclusiveMaximum" (${exclusiveMaximum}) must be greater than "exclusiveMinimum" (${exclusiveMinimum})`
627
+ );
630
628
  }
631
629
  if (multipleOf !== void 0) {
632
630
  assertSchema(multipleOf > 0, `Constraint "multipleOf" (${multipleOf}) must be greater than zero`);
@@ -650,11 +648,17 @@ var NumberValidator = class extends Validator {
650
648
  this.allowNaN = allowNaN;
651
649
  this.exclusiveMaximum = exclusiveMaximum;
652
650
  this.exclusiveMinimum = exclusiveMinimum;
651
+ this.fromString = fromString;
653
652
  this.maximum = maximum;
654
653
  this.minimum = minimum;
655
654
  this.multipleOf = multipleOf;
656
655
  }
657
656
  validate(value) {
657
+ if (typeof value == "string" && this.fromString) {
658
+ const parsed = +`${value}`;
659
+ assertValidation(!isNaN(parsed), "Number can not be parsed from string");
660
+ value = parsed;
661
+ }
658
662
  assertValidation(typeof value == "number", 'Value is not a "number"');
659
663
  if (isNaN(value)) {
660
664
  assertValidation(this.allowNaN, 'Number is "NaN"');
@@ -662,26 +666,53 @@ var NumberValidator = class extends Validator {
662
666
  }
663
667
  assertValidation(value >= this.minimum, `Number is less than ${this.minimum}`);
664
668
  assertValidation(value <= this.maximum, `Number is greater than ${this.maximum}`);
665
- assertValidation(this.exclusiveMinimum == void 0 || value > this.exclusiveMinimum, `Number is less than or equal to ${this.exclusiveMinimum}`);
666
- assertValidation(this.exclusiveMaximum == void 0 || value < this.exclusiveMaximum, `Number is greater than or equal to ${this.exclusiveMaximum}`);
667
- assertValidation(this.#isMultipleOf ? this.#isMultipleOf(value) : true, `Number is not a multiple of ${this.multipleOf}`);
669
+ assertValidation(
670
+ this.exclusiveMinimum == void 0 || value > this.exclusiveMinimum,
671
+ `Number is less than or equal to ${this.exclusiveMinimum}`
672
+ );
673
+ assertValidation(
674
+ this.exclusiveMaximum == void 0 || value < this.exclusiveMaximum,
675
+ `Number is greater than or equal to ${this.exclusiveMaximum}`
676
+ );
677
+ assertValidation(
678
+ this.#isMultipleOf ? this.#isMultipleOf(value) : true,
679
+ `Number is not a multiple of ${this.multipleOf}`
680
+ );
668
681
  return value;
669
682
  }
670
683
  };
671
- var anyNumberValidator = new AnyNumberValidator();
672
684
  function _number(constraints) {
673
- return constraints ? new NumberValidator(constraints) : anyNumberValidator;
685
+ return new NumberValidator(constraints);
686
+ }
687
+ var number = makeValidatorFactory(new AnyNumberValidator(), _number);
688
+
689
+ // src/validators/optional.ts
690
+ var OptionalValidator = class extends AbstractValidator {
691
+ validator;
692
+ optional = true;
693
+ constructor(validator) {
694
+ super();
695
+ this.validator = validator;
696
+ }
697
+ validate(value, options) {
698
+ if (value === void 0)
699
+ return value;
700
+ return this.validator.validate(value, options);
701
+ }
702
+ };
703
+ function optional(validation) {
704
+ const validator = getValidator(validation);
705
+ return new OptionalValidator(validator);
674
706
  }
675
- var number = makeTupleRestIterable(_number);
676
707
 
677
708
  // src/validators/string.ts
678
- var AnyStringValidator = class extends Validator {
709
+ var AnyStringValidator = class extends AbstractValidator {
679
710
  validate(value) {
680
711
  assertValidation(typeof value == "string", 'Value is not a "string"');
681
712
  return value;
682
713
  }
683
714
  };
684
- var StringValidator = class extends Validator {
715
+ var StringValidator = class extends AbstractValidator {
685
716
  maxLength;
686
717
  minLength;
687
718
  pattern;
@@ -704,17 +735,25 @@ var StringValidator = class extends Validator {
704
735
  }
705
736
  validate(value) {
706
737
  assertValidation(typeof value == "string", 'Value is not a "string"');
707
- assertValidation(value.length >= this.minLength, `String must have a minimum length of ${this.minLength}`);
708
- assertValidation(value.length <= this.maxLength, `String must have a maximum length of ${this.maxLength}`);
709
- assertValidation(this.pattern ? this.pattern.test(value) : true, `String does not match required pattern ${this.pattern}`);
738
+ assertValidation(
739
+ value.length >= this.minLength,
740
+ `String must have a minimum length of ${this.minLength}`
741
+ );
742
+ assertValidation(
743
+ value.length <= this.maxLength,
744
+ `String must have a maximum length of ${this.maxLength}`
745
+ );
746
+ assertValidation(
747
+ this.pattern ? this.pattern.test(value) : true,
748
+ `String does not match required pattern ${this.pattern}`
749
+ );
710
750
  return value;
711
751
  }
712
752
  };
713
- var anyStringValidator = new AnyStringValidator();
714
753
  function _string(constraints) {
715
- return constraints ? new StringValidator(constraints) : anyStringValidator;
754
+ return new StringValidator(constraints);
716
755
  }
717
- var string = makeTupleRestIterable(_string);
756
+ var string = makeValidatorFactory(new AnyStringValidator(), _string);
718
757
 
719
758
  // src/validators/url.ts
720
759
  var KEYS = [
@@ -735,7 +774,7 @@ var OPTIONS = {
735
774
  stripForbiddenProperties: false,
736
775
  stripOptionalNulls: false
737
776
  };
738
- var URLValidator = class extends Validator {
777
+ var URLValidator = class extends AbstractValidator {
739
778
  href;
740
779
  origin;
741
780
  protocol;
@@ -796,29 +835,32 @@ var URLValidator = class extends Validator {
796
835
  };
797
836
  var anyURLValidator = new URLValidator();
798
837
  function _url(constraints) {
799
- return constraints ? new URLValidator(constraints) : anyURLValidator;
838
+ return new URLValidator(constraints);
800
839
  }
801
- var url = makeTupleRestIterable(_url);
840
+ var url = makeValidatorFactory(anyURLValidator, _url);
802
841
 
803
842
  // src/index.ts
804
843
  function validate(validation, value, options = {}) {
805
- const opts = __spreadValues({
844
+ const opts = {
806
845
  stripAdditionalProperties: false,
807
846
  stripForbiddenProperties: false,
808
- stripOptionalNulls: false
809
- }, options);
847
+ stripOptionalNulls: false,
848
+ ...options
849
+ };
810
850
  return getValidator(validation).validate(value, opts);
811
851
  }
812
852
  function strip(validation, value, options = {}) {
813
- const opts = __spreadValues({
853
+ const opts = {
814
854
  stripAdditionalProperties: true,
815
855
  stripForbiddenProperties: false,
816
- stripOptionalNulls: true
817
- }, options);
856
+ stripOptionalNulls: true,
857
+ ...options
858
+ };
818
859
  return getValidator(validation).validate(value, opts);
819
860
  }
820
861
  // Annotate the CommonJS export names for ESM import in node:
821
862
  0 && (module.exports = {
863
+ AbstractValidator,
822
864
  AllOfValidator,
823
865
  AnyArrayValidator,
824
866
  AnyNumberValidator,
@@ -829,17 +871,19 @@ function strip(validation, value, options = {}) {
829
871
  BooleanValidator,
830
872
  ConstantValidator,
831
873
  DateValidator,
874
+ NeverValidator,
832
875
  NumberValidator,
833
876
  ObjectValidator,
834
877
  OneOfValidator,
878
+ OptionalValidator,
835
879
  StringValidator,
836
880
  TupleValidator,
837
881
  URLValidator,
838
882
  ValidationError,
839
883
  ValidationErrorBuilder,
840
- Validator,
841
884
  _allowAdditionalProperties,
842
885
  _array,
886
+ _boolean,
843
887
  _date,
844
888
  _number,
845
889
  _object,
@@ -857,14 +901,13 @@ function strip(validation, value, options = {}) {
857
901
  constant,
858
902
  date,
859
903
  getValidator,
860
- isModifier,
861
- modifierValidator,
904
+ isValidator,
905
+ makeValidatorFactory,
862
906
  never,
863
907
  number,
864
908
  object,
865
909
  oneOf,
866
910
  optional,
867
- readonly,
868
911
  restValidator,
869
912
  schemaValidator,
870
913
  string,