@serum-enterprises/schema 3.0.0-beta.1 → 3.1.0-beta.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.
- package/build/index.js +387 -240
- package/build/index.js.map +4 -4
- package/package.json +1 -1
- package/types/Validator.d.ts +1 -1
- package/types/index.d.ts +4 -1
- package/types/lib/fromJSON.d.ts +2 -0
- package/types/lib/isEquals.d.ts +2 -0
- package/types/validators/Array.d.ts +1 -0
- package/types/validators/Boolean.d.ts +1 -0
- package/types/validators/JSON.d.ts +1 -0
- package/types/validators/Number.d.ts +1 -0
- package/types/validators/Object.d.ts +1 -0
- package/types/validators/String.d.ts +1 -0
- package/test.ts +0 -13
package/build/index.js
CHANGED
|
@@ -181,6 +181,28 @@ __export(index_exports, {
|
|
|
181
181
|
});
|
|
182
182
|
module.exports = __toCommonJS(index_exports);
|
|
183
183
|
|
|
184
|
+
// src/Validator.ts
|
|
185
|
+
var Validator = class {
|
|
186
|
+
validate(data, path = "data") {
|
|
187
|
+
this.assert(data, path);
|
|
188
|
+
return data;
|
|
189
|
+
}
|
|
190
|
+
is(data, path = "data") {
|
|
191
|
+
try {
|
|
192
|
+
this.assert(data, path);
|
|
193
|
+
return true;
|
|
194
|
+
} catch (e) {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// src/lib/fromJSON.ts
|
|
201
|
+
var import_json7 = __toESM(require_build());
|
|
202
|
+
|
|
203
|
+
// src/validators/JSON.ts
|
|
204
|
+
var import_json = __toESM(require_build());
|
|
205
|
+
|
|
184
206
|
// src/lib/util.ts
|
|
185
207
|
var AssertError = class extends Error {
|
|
186
208
|
};
|
|
@@ -188,7 +210,6 @@ var DefinitionError = class extends Error {
|
|
|
188
210
|
};
|
|
189
211
|
|
|
190
212
|
// src/validators/JSON.ts
|
|
191
|
-
var import_json = __toESM(require_build());
|
|
192
213
|
var JSONValidator = class _JSONValidator extends Validator {
|
|
193
214
|
static fromJSON(_definition, _path = "definition") {
|
|
194
215
|
return new _JSONValidator();
|
|
@@ -200,6 +221,9 @@ var JSONValidator = class _JSONValidator extends Validator {
|
|
|
200
221
|
isSubset(other) {
|
|
201
222
|
return other instanceof _JSONValidator;
|
|
202
223
|
}
|
|
224
|
+
isEquals(other) {
|
|
225
|
+
return other instanceof _JSONValidator;
|
|
226
|
+
}
|
|
203
227
|
toJSON() {
|
|
204
228
|
return {
|
|
205
229
|
type: "json"
|
|
@@ -260,6 +284,17 @@ var BooleanValidator = class _BooleanValidator extends Validator {
|
|
|
260
284
|
}
|
|
261
285
|
return true;
|
|
262
286
|
}
|
|
287
|
+
isEquals(other) {
|
|
288
|
+
if (!(other instanceof _BooleanValidator))
|
|
289
|
+
return false;
|
|
290
|
+
if (this._nullable.isSome() !== other._nullable.isSome())
|
|
291
|
+
return false;
|
|
292
|
+
if (this._equals.isSome() !== other._equals.isSome())
|
|
293
|
+
return false;
|
|
294
|
+
if (this._equals.isSome() && other._equals.isSome() && this._equals.value !== other._equals.value)
|
|
295
|
+
return false;
|
|
296
|
+
return true;
|
|
297
|
+
}
|
|
263
298
|
toJSON() {
|
|
264
299
|
const definition = {
|
|
265
300
|
type: "boolean"
|
|
@@ -390,6 +425,27 @@ var NumberValidator = class _NumberValidator extends Validator {
|
|
|
390
425
|
return false;
|
|
391
426
|
return true;
|
|
392
427
|
}
|
|
428
|
+
isEquals(other) {
|
|
429
|
+
if (!(other instanceof _NumberValidator))
|
|
430
|
+
return false;
|
|
431
|
+
if (this._nullable.isSome() !== other._nullable.isSome())
|
|
432
|
+
return false;
|
|
433
|
+
if (this._integer.isSome() !== other._integer.isSome())
|
|
434
|
+
return false;
|
|
435
|
+
if (this._equals.isSome() !== other._equals.isSome())
|
|
436
|
+
return false;
|
|
437
|
+
if (this._equals.isSome() && other._equals.isSome() && this._equals.value !== other._equals.value)
|
|
438
|
+
return false;
|
|
439
|
+
if (this._min.isSome() !== other._min.isSome())
|
|
440
|
+
return false;
|
|
441
|
+
if (this._min.isSome() && other._min.isSome() && this._min.value !== other._min.value)
|
|
442
|
+
return false;
|
|
443
|
+
if (this._max.isSome() !== other._max.isSome())
|
|
444
|
+
return false;
|
|
445
|
+
if (this._max.isSome() && other._max.isSome() && this._max.value !== other._max.value)
|
|
446
|
+
return false;
|
|
447
|
+
return true;
|
|
448
|
+
}
|
|
393
449
|
toJSON() {
|
|
394
450
|
const definition = {
|
|
395
451
|
type: "number"
|
|
@@ -510,6 +566,25 @@ var StringValidator = class _StringValidator extends Validator {
|
|
|
510
566
|
return false;
|
|
511
567
|
return true;
|
|
512
568
|
}
|
|
569
|
+
isEquals(other) {
|
|
570
|
+
if (!(other instanceof _StringValidator))
|
|
571
|
+
return false;
|
|
572
|
+
if (this._nullable.isSome() !== other._nullable.isSome())
|
|
573
|
+
return false;
|
|
574
|
+
if (this._equals.isSome() !== other._equals.isSome())
|
|
575
|
+
return false;
|
|
576
|
+
if (this._equals.isSome() && other._equals.isSome() && this._equals.value !== other._equals.value)
|
|
577
|
+
return false;
|
|
578
|
+
if (this._min.isSome() !== other._min.isSome())
|
|
579
|
+
return false;
|
|
580
|
+
if (this._min.isSome() && other._min.isSome() && this._min.value !== other._min.value)
|
|
581
|
+
return false;
|
|
582
|
+
if (this._max.isSome() !== other._max.isSome())
|
|
583
|
+
return false;
|
|
584
|
+
if (this._max.isSome() && other._max.isSome() && this._max.value !== other._max.value)
|
|
585
|
+
return false;
|
|
586
|
+
return true;
|
|
587
|
+
}
|
|
513
588
|
toJSON() {
|
|
514
589
|
const definition = {
|
|
515
590
|
type: "string"
|
|
@@ -527,230 +602,46 @@ var StringValidator = class _StringValidator extends Validator {
|
|
|
527
602
|
};
|
|
528
603
|
|
|
529
604
|
// src/validators/Array.ts
|
|
530
|
-
var import_json5 = __toESM(require_build());
|
|
531
|
-
var import_option4 = __toESM(require_Option());
|
|
532
|
-
var ArrayValidator = class _ArrayValidator extends Validator {
|
|
533
|
-
static fromJSON(definition, path = "definition") {
|
|
534
|
-
const validatorInstance = new _ArrayValidator();
|
|
535
|
-
if ("nullable" in definition) {
|
|
536
|
-
if (!import_json5.JSON.isBoolean(definition["nullable"]))
|
|
537
|
-
throw new DefinitionError(`Expected ${path}.nullable to be a Boolean`);
|
|
538
|
-
validatorInstance.nullable(definition["nullable"]);
|
|
539
|
-
}
|
|
540
|
-
if ("min" in definition) {
|
|
541
|
-
if (!import_json5.JSON.isNumber(definition["min"]))
|
|
542
|
-
throw new DefinitionError(`Expected ${path}.min to be a Number`);
|
|
543
|
-
validatorInstance.min(definition["min"], `${path}.min`);
|
|
544
|
-
}
|
|
545
|
-
if ("max" in definition) {
|
|
546
|
-
if (!import_json5.JSON.isNumber(definition["max"]))
|
|
547
|
-
throw new DefinitionError(`Expected ${path}.max to be a Number`);
|
|
548
|
-
validatorInstance.max(definition["max"], `${path}.max`);
|
|
549
|
-
}
|
|
550
|
-
if ("every" in definition) {
|
|
551
|
-
if (!import_json5.JSON.isObject(definition["every"]))
|
|
552
|
-
throw new DefinitionError(`Expected ${path}.every to be an Object`);
|
|
553
|
-
validatorInstance.every(
|
|
554
|
-
super.fromJSON(definition["every"], `${path}.every`)
|
|
555
|
-
);
|
|
556
|
-
}
|
|
557
|
-
if ("tuple" in definition) {
|
|
558
|
-
if (!import_json5.JSON.isShallowArray(definition["tuple"]))
|
|
559
|
-
throw new DefinitionError(`Expected ${path}.tuple to be an Array`);
|
|
560
|
-
const tupleSchemas = [];
|
|
561
|
-
const errors = [];
|
|
562
|
-
definition["tuple"].forEach((tupleDef, index) => {
|
|
563
|
-
try {
|
|
564
|
-
tupleSchemas.push(super.fromJSON(tupleDef, `${path}.tuple[${index}]`));
|
|
565
|
-
} catch (e) {
|
|
566
|
-
if (!(e instanceof DefinitionError))
|
|
567
|
-
throw new DefinitionError(`Fatal Error: Undefined Error thrown by Domain.fromJSON at ${path}`);
|
|
568
|
-
errors.push(e);
|
|
569
|
-
}
|
|
570
|
-
});
|
|
571
|
-
if (errors.length > 0)
|
|
572
|
-
throw new DefinitionError(`Multiple Definition Errors detected at ${path} (see cause)`, { cause: errors });
|
|
573
|
-
validatorInstance.tuple(tupleSchemas, `${path}.tuple`);
|
|
574
|
-
}
|
|
575
|
-
return validatorInstance;
|
|
576
|
-
}
|
|
577
|
-
_nullable = import_option4.Option.None();
|
|
578
|
-
_every = import_option4.Option.None();
|
|
579
|
-
_tuple = import_option4.Option.None();
|
|
580
|
-
_min = import_option4.Option.None();
|
|
581
|
-
_max = import_option4.Option.None();
|
|
582
|
-
nullable(flag) {
|
|
583
|
-
this._nullable = flag ?? true ? import_option4.Option.Some(null) : import_option4.Option.None();
|
|
584
|
-
return this;
|
|
585
|
-
}
|
|
586
|
-
min(value, path = "min") {
|
|
587
|
-
if (this._max.isSome() && this._max.value < value)
|
|
588
|
-
throw new DefinitionError(`Expected Minimum Rule to be smaller than or equal to Maximum Rule at Path ${path}`);
|
|
589
|
-
if (this._tuple.isSome() && value < this._tuple.value.length)
|
|
590
|
-
throw new DefinitionError(`Expected Minimum Rule to be larger than or equal to Tuple Length at Path ${path}`);
|
|
591
|
-
this._min = import_option4.Option.Some(value);
|
|
592
|
-
return this;
|
|
593
|
-
}
|
|
594
|
-
max(value, path = "max") {
|
|
595
|
-
if (this._min.isSome() && this._min.value > value)
|
|
596
|
-
throw new DefinitionError(`Expected Maximum Rule to be larger than or equal to Minimum Rule at Path ${path}`);
|
|
597
|
-
if (this._tuple.isSome() && value < this._tuple.value.length)
|
|
598
|
-
throw new DefinitionError(`Expected Maximum Rule to be larger than or equal to Tuple Length at Path ${path}`);
|
|
599
|
-
this._max = import_option4.Option.Some(value);
|
|
600
|
-
return this;
|
|
601
|
-
}
|
|
602
|
-
every(validator) {
|
|
603
|
-
this._every = import_option4.Option.Some(validator);
|
|
604
|
-
return this;
|
|
605
|
-
}
|
|
606
|
-
/**
|
|
607
|
-
* Applies ONLY to prefix indices [0..validators.length - 1]
|
|
608
|
-
* If every() is set, prefix elements are effectively `T[i] & E`.
|
|
609
|
-
*/
|
|
610
|
-
tuple(validators, path = "tuple") {
|
|
611
|
-
if (this._min.isSome() && this._min.value < validators.length)
|
|
612
|
-
throw new DefinitionError(`Expected Tuple Length to be smaller than or equal to Minimum Rule at Path ${path}`);
|
|
613
|
-
if (this._max.isSome() && this._max.value < validators.length)
|
|
614
|
-
throw new DefinitionError(`Expected Tuple Length to be smaller than or equal to Maximum Rule at Path ${path}`);
|
|
615
|
-
this._tuple = import_option4.Option.Some(validators);
|
|
616
|
-
return this;
|
|
617
|
-
}
|
|
618
|
-
assert(data, path = "data") {
|
|
619
|
-
if (import_json5.JSON.isShallowArray(data)) {
|
|
620
|
-
if (this._min.isSome() && this._min.value > data.length)
|
|
621
|
-
throw new AssertError(`Expected ${path} to be at least ${this._min.value} Elements long`);
|
|
622
|
-
if (this._max.isSome() && this._max.value < data.length)
|
|
623
|
-
throw new AssertError(`Expected ${path} to be at most ${this._max.value} Elements long`);
|
|
624
|
-
const errors = [];
|
|
625
|
-
if (this._every.isSome()) {
|
|
626
|
-
const validator = this._every.value;
|
|
627
|
-
data.forEach((value, index) => {
|
|
628
|
-
try {
|
|
629
|
-
validator.assert(value, `${path}[${index}]`);
|
|
630
|
-
} catch (e) {
|
|
631
|
-
if (!(e instanceof AssertError))
|
|
632
|
-
throw new AssertError(`Fatal Error: Undefined Error thrown by an Assert Method at ${path}[${index}]`);
|
|
633
|
-
errors.push(e);
|
|
634
|
-
}
|
|
635
|
-
});
|
|
636
|
-
}
|
|
637
|
-
if (this._tuple.isSome()) {
|
|
638
|
-
if (data.length < this._tuple.value.length)
|
|
639
|
-
throw new AssertError(`Expected ${path} to be at least ${this._tuple.value.length} Elements long (Tuple Constraint)`);
|
|
640
|
-
this._tuple.value.forEach((validator, index) => {
|
|
641
|
-
try {
|
|
642
|
-
validator.assert(data[index], `${path}[${index}]`);
|
|
643
|
-
} catch (e) {
|
|
644
|
-
if (!(e instanceof AssertError))
|
|
645
|
-
throw new AssertError(`Fatal Error: Undefined Error thrown by an Assert Method at ${path}[${index}]`);
|
|
646
|
-
errors.push(e);
|
|
647
|
-
}
|
|
648
|
-
});
|
|
649
|
-
}
|
|
650
|
-
if (errors.length > 0)
|
|
651
|
-
throw new AssertError(`Multiple Errors while asserting ${path} (see cause)`, { cause: errors });
|
|
652
|
-
} else if (import_json5.JSON.isNull(data)) {
|
|
653
|
-
if (!this._nullable.isSome())
|
|
654
|
-
throw new AssertError(`Expected ${path} to be an Array${this._nullable.isSome() ? " or Null" : ""}`);
|
|
655
|
-
} else
|
|
656
|
-
throw new AssertError(`Expected ${path} to be an Array${this._nullable.isSome() ? " or Null" : ""}`);
|
|
657
|
-
}
|
|
658
|
-
isSubset(other) {
|
|
659
|
-
if (other instanceof JSONValidator)
|
|
660
|
-
return true;
|
|
661
|
-
if (!(other instanceof _ArrayValidator))
|
|
662
|
-
return false;
|
|
663
|
-
if (this._nullable.isSome() && !other._nullable.isSome())
|
|
664
|
-
return false;
|
|
665
|
-
const thisTupleLen = this._tuple.isSome() ? this._tuple.value.length : 0;
|
|
666
|
-
const otherTupleLen = other._tuple.isSome() ? other._tuple.value.length : 0;
|
|
667
|
-
const thisMin = this._min.isSome() ? this._min.value : 0;
|
|
668
|
-
const otherMin = other._min.isSome() ? other._min.value : 0;
|
|
669
|
-
const thisMax = this._max.isSome() ? this._max.value : Infinity;
|
|
670
|
-
const otherMax = other._max.isSome() ? other._max.value : Infinity;
|
|
671
|
-
const thisEffectiveMin = Math.max(thisMin, thisTupleLen);
|
|
672
|
-
const otherEffectiveMin = Math.max(otherMin, otherTupleLen);
|
|
673
|
-
if (thisEffectiveMin < otherEffectiveMin)
|
|
674
|
-
return false;
|
|
675
|
-
if (thisMax > otherMax)
|
|
676
|
-
return false;
|
|
677
|
-
const indexConjuncts = (i) => {
|
|
678
|
-
const conjuncts = [];
|
|
679
|
-
if (this._every.isSome())
|
|
680
|
-
conjuncts.push(this._every.value);
|
|
681
|
-
if (this._tuple.isSome() && i < this._tuple.value.length)
|
|
682
|
-
conjuncts.push(this._tuple.value[i]);
|
|
683
|
-
return conjuncts;
|
|
684
|
-
};
|
|
685
|
-
const conjunctsSubset = (conjuncts, target) => {
|
|
686
|
-
if (conjuncts.length === 0)
|
|
687
|
-
return false;
|
|
688
|
-
return conjuncts.some((c) => c.isSubset(target));
|
|
689
|
-
};
|
|
690
|
-
if (other._tuple.isSome()) {
|
|
691
|
-
for (let i = 0; i < other._tuple.value.length; i++) {
|
|
692
|
-
const aConj = indexConjuncts(i);
|
|
693
|
-
if (!conjunctsSubset(aConj, other._tuple.value[i]))
|
|
694
|
-
return false;
|
|
695
|
-
if (other._every.isSome() && !conjunctsSubset(aConj, other._every.value))
|
|
696
|
-
return false;
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
return !(other._every.isSome() && (thisMax === Infinity ? true : thisMax > Math.max(thisTupleLen, otherTupleLen)) && (!this._every.isSome() || !this._every.value.isSubset(other._every.value)));
|
|
700
|
-
}
|
|
701
|
-
toJSON() {
|
|
702
|
-
const definition = { type: "array" };
|
|
703
|
-
if (this._nullable.isSome())
|
|
704
|
-
definition.nullable = true;
|
|
705
|
-
if (this._min.isSome())
|
|
706
|
-
definition.min = this._min.value;
|
|
707
|
-
if (this._max.isSome())
|
|
708
|
-
definition.max = this._max.value;
|
|
709
|
-
if (this._every.isSome())
|
|
710
|
-
definition.every = this._every.value.toJSON();
|
|
711
|
-
if (this._tuple.isSome())
|
|
712
|
-
definition.tuple = this._tuple.value.map((validator) => validator.toJSON());
|
|
713
|
-
return definition;
|
|
714
|
-
}
|
|
715
|
-
};
|
|
716
|
-
|
|
717
|
-
// src/validators/Object.ts
|
|
718
605
|
var import_json6 = __toESM(require_build());
|
|
719
606
|
var import_option5 = __toESM(require_Option());
|
|
607
|
+
|
|
608
|
+
// src/validators/Object.ts
|
|
609
|
+
var import_json5 = __toESM(require_build());
|
|
610
|
+
var import_option4 = __toESM(require_Option());
|
|
720
611
|
var ObjectValidator = class _ObjectValidator extends Validator {
|
|
721
612
|
static fromJSON(definition, path = "definition") {
|
|
722
613
|
const validatorInstance = new _ObjectValidator();
|
|
723
614
|
if ("nullable" in definition) {
|
|
724
|
-
if (!
|
|
615
|
+
if (!import_json5.JSON.isBoolean(definition["nullable"]))
|
|
725
616
|
throw new DefinitionError(`Expected ${path}.nullable to be a Boolean`);
|
|
726
617
|
validatorInstance.nullable(definition["nullable"]);
|
|
727
618
|
}
|
|
728
619
|
if ("exact" in definition) {
|
|
729
|
-
if (!
|
|
620
|
+
if (!import_json5.JSON.isBoolean(definition["exact"]))
|
|
730
621
|
throw new DefinitionError(`Expected ${path}.exact to be a Boolean`);
|
|
731
622
|
validatorInstance.exact(definition["exact"], `${path}.exact`);
|
|
732
623
|
}
|
|
733
624
|
if ("min" in definition) {
|
|
734
|
-
if (!
|
|
625
|
+
if (!import_json5.JSON.isNumber(definition["min"]))
|
|
735
626
|
throw new DefinitionError(`Expected ${path}.min to be a Number`);
|
|
736
627
|
validatorInstance.min(definition["min"], `${path}.min`);
|
|
737
628
|
}
|
|
738
629
|
if ("max" in definition) {
|
|
739
|
-
if (!
|
|
630
|
+
if (!import_json5.JSON.isNumber(definition["max"]))
|
|
740
631
|
throw new DefinitionError(`Expected ${path}.max to be a Number`);
|
|
741
632
|
validatorInstance.max(definition["max"], `${path}.max`);
|
|
742
633
|
}
|
|
743
634
|
if ("every" in definition) {
|
|
744
|
-
validatorInstance.every(
|
|
635
|
+
validatorInstance.every(fromJSON(definition["every"], `${path}.every`));
|
|
745
636
|
}
|
|
746
637
|
if ("shape" in definition) {
|
|
747
|
-
if (!
|
|
638
|
+
if (!import_json5.JSON.isShallowObject(definition["shape"]))
|
|
748
639
|
throw new DefinitionError(`Expected ${path}.shape to be an Object`);
|
|
749
640
|
const shape = {};
|
|
750
641
|
const errors = [];
|
|
751
642
|
for (const [key, value] of Object.entries(definition["shape"])) {
|
|
752
643
|
try {
|
|
753
|
-
shape[key] =
|
|
644
|
+
shape[key] = fromJSON(value, `${path}.shape.${key}`);
|
|
754
645
|
} catch (e) {
|
|
755
646
|
if (!(e instanceof DefinitionError))
|
|
756
647
|
throw new DefinitionError(`Fatal Error: Undefined Error thrown by Domain.fromJSON at ${path}.shape.${key}`);
|
|
@@ -764,14 +655,14 @@ var ObjectValidator = class _ObjectValidator extends Validator {
|
|
|
764
655
|
}
|
|
765
656
|
return validatorInstance;
|
|
766
657
|
}
|
|
767
|
-
_nullable =
|
|
768
|
-
_min =
|
|
769
|
-
_max =
|
|
770
|
-
_every =
|
|
771
|
-
_shape =
|
|
772
|
-
_exact =
|
|
658
|
+
_nullable = import_option4.Option.None();
|
|
659
|
+
_min = import_option4.Option.None();
|
|
660
|
+
_max = import_option4.Option.None();
|
|
661
|
+
_every = import_option4.Option.None();
|
|
662
|
+
_shape = import_option4.Option.None();
|
|
663
|
+
_exact = import_option4.Option.None();
|
|
773
664
|
nullable(flag) {
|
|
774
|
-
this._nullable = flag ?? true ?
|
|
665
|
+
this._nullable = flag ?? true ? import_option4.Option.Some(null) : import_option4.Option.None();
|
|
775
666
|
return this;
|
|
776
667
|
}
|
|
777
668
|
min(value, path = "min") {
|
|
@@ -781,7 +672,7 @@ var ObjectValidator = class _ObjectValidator extends Validator {
|
|
|
781
672
|
throw new DefinitionError(`Expected Minimum Rule to be larger than or equal to Shape Key Count at Path ${path}`);
|
|
782
673
|
if (this._exact.isSome() && this._shape.isSome() && value > Object.keys(this._shape.value).length)
|
|
783
674
|
throw new DefinitionError(`Expected Minimum Rule to be smaller than or equal to Shape Key Count due to Exact Rule at Path ${path}`);
|
|
784
|
-
this._min =
|
|
675
|
+
this._min = import_option4.Option.Some(value);
|
|
785
676
|
return this;
|
|
786
677
|
}
|
|
787
678
|
max(value, path = "max") {
|
|
@@ -789,11 +680,11 @@ var ObjectValidator = class _ObjectValidator extends Validator {
|
|
|
789
680
|
throw new DefinitionError(`Expected Maximum Rule to be larger than or equal to Minimum Rule at Path ${path}`);
|
|
790
681
|
if (this._shape.isSome() && value < Object.keys(this._shape.value).length)
|
|
791
682
|
throw new DefinitionError(`Expected Maximum Rule to be larger than or equal to Shape Key Count at Path ${path}`);
|
|
792
|
-
this._max =
|
|
683
|
+
this._max = import_option4.Option.Some(value);
|
|
793
684
|
return this;
|
|
794
685
|
}
|
|
795
686
|
every(validator) {
|
|
796
|
-
this._every =
|
|
687
|
+
this._every = import_option4.Option.Some(validator);
|
|
797
688
|
return this;
|
|
798
689
|
}
|
|
799
690
|
shape(value, path = "shape") {
|
|
@@ -806,7 +697,7 @@ var ObjectValidator = class _ObjectValidator extends Validator {
|
|
|
806
697
|
throw new DefinitionError(`Expected Shape Key Count to be larger than or equal to Minimum Rule due to Exact Rule at Path ${path}`);
|
|
807
698
|
if (this._exact.isSome() && this._max.isSome() && this._max.value < shapeKeyCount)
|
|
808
699
|
throw new DefinitionError(`Expected Shape Key Count to be smaller than or equal to Maximum Rule due to Exact Rule at Path ${path}`);
|
|
809
|
-
this._shape =
|
|
700
|
+
this._shape = import_option4.Option.Some(value);
|
|
810
701
|
return this;
|
|
811
702
|
}
|
|
812
703
|
exact(flag, path = "exact") {
|
|
@@ -817,11 +708,11 @@ var ObjectValidator = class _ObjectValidator extends Validator {
|
|
|
817
708
|
if (this._max.isSome() && this._max.value < shapeKeyCount)
|
|
818
709
|
throw new DefinitionError(`Expected Exact Rule to be false due to Maximum Rule allowing fewer Properties than Shape defines at Path ${path}`);
|
|
819
710
|
}
|
|
820
|
-
this._exact = flag ?? true ?
|
|
711
|
+
this._exact = flag ?? true ? import_option4.Option.Some(null) : import_option4.Option.None();
|
|
821
712
|
return this;
|
|
822
713
|
}
|
|
823
714
|
assert(data, path = "data") {
|
|
824
|
-
if (
|
|
715
|
+
if (import_json5.JSON.isShallowObject(data)) {
|
|
825
716
|
const keys = Object.keys(data);
|
|
826
717
|
if (this._min.isSome() && keys.length < this._min.value)
|
|
827
718
|
throw new AssertError(`Expected ${path} to have at least ${this._min.value} Properties`);
|
|
@@ -861,7 +752,7 @@ var ObjectValidator = class _ObjectValidator extends Validator {
|
|
|
861
752
|
}
|
|
862
753
|
if (errors.length > 0)
|
|
863
754
|
throw new AssertError(`Multiple Errors while asserting ${path} (see cause)`, { cause: errors });
|
|
864
|
-
} else if (
|
|
755
|
+
} else if (import_json5.JSON.isNull(data)) {
|
|
865
756
|
if (!this._nullable.isSome())
|
|
866
757
|
throw new AssertError(`Expected ${path} to be an Object${this._nullable.isSome() ? " or Null" : ""}`);
|
|
867
758
|
} else
|
|
@@ -933,6 +824,39 @@ var ObjectValidator = class _ObjectValidator extends Validator {
|
|
|
933
824
|
}
|
|
934
825
|
return true;
|
|
935
826
|
}
|
|
827
|
+
isEquals(other) {
|
|
828
|
+
if (!(other instanceof _ObjectValidator))
|
|
829
|
+
return false;
|
|
830
|
+
if (this._nullable.isSome() !== other._nullable.isSome())
|
|
831
|
+
return false;
|
|
832
|
+
if (this._min.isSome() !== other._min.isSome())
|
|
833
|
+
return false;
|
|
834
|
+
if (this._min.isSome() && other._min.isSome() && this._min.value !== other._min.value)
|
|
835
|
+
return false;
|
|
836
|
+
if (this._max.isSome() !== other._max.isSome())
|
|
837
|
+
return false;
|
|
838
|
+
if (this._max.isSome() && other._max.isSome() && this._max.value !== other._max.value)
|
|
839
|
+
return false;
|
|
840
|
+
if (this._every.isSome() !== other._every.isSome())
|
|
841
|
+
return false;
|
|
842
|
+
if (this._every.isSome() && other._every.isSome())
|
|
843
|
+
return isEquals(this._every.value, other._every.value);
|
|
844
|
+
if (this._shape.isSome() !== other._shape.isSome())
|
|
845
|
+
return false;
|
|
846
|
+
if (this._shape.isSome() && other._shape.isSome()) {
|
|
847
|
+
if (Object.keys(this._shape.value).length !== Object.keys(other._shape.value).length)
|
|
848
|
+
return false;
|
|
849
|
+
for (const [k, v] of Object.entries(this._shape.value)) {
|
|
850
|
+
if (!(other._shape.value[k] instanceof Validator))
|
|
851
|
+
return false;
|
|
852
|
+
if (!isEquals(v, other._shape.value[k]))
|
|
853
|
+
return false;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
if (this._exact.isSome() !== other._exact.isSome())
|
|
857
|
+
return false;
|
|
858
|
+
return true;
|
|
859
|
+
}
|
|
936
860
|
toJSON() {
|
|
937
861
|
const schema = { type: "object" };
|
|
938
862
|
if (this._nullable.isSome())
|
|
@@ -954,45 +878,262 @@ var ObjectValidator = class _ObjectValidator extends Validator {
|
|
|
954
878
|
}
|
|
955
879
|
};
|
|
956
880
|
|
|
957
|
-
// src/
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
881
|
+
// src/lib/isEquals.ts
|
|
882
|
+
function isEquals(a, b) {
|
|
883
|
+
if (a instanceof JSONValidator)
|
|
884
|
+
return a.isEquals(b);
|
|
885
|
+
if (a instanceof BooleanValidator)
|
|
886
|
+
return a.isEquals(b);
|
|
887
|
+
if (a instanceof NumberValidator)
|
|
888
|
+
return a.isEquals(b);
|
|
889
|
+
if (a instanceof StringValidator)
|
|
890
|
+
return a.isEquals(b);
|
|
891
|
+
if (a instanceof ArrayValidator)
|
|
892
|
+
return a.isEquals(b);
|
|
893
|
+
if (a instanceof ObjectValidator)
|
|
894
|
+
return a.isEquals(b);
|
|
895
|
+
return false;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
// src/validators/Array.ts
|
|
899
|
+
var ArrayValidator = class _ArrayValidator extends Validator {
|
|
900
|
+
static fromJSON(definition, path = "definition") {
|
|
901
|
+
const validatorInstance = new _ArrayValidator();
|
|
902
|
+
if ("nullable" in definition) {
|
|
903
|
+
if (!import_json6.JSON.isBoolean(definition["nullable"]))
|
|
904
|
+
throw new DefinitionError(`Expected ${path}.nullable to be a Boolean`);
|
|
905
|
+
validatorInstance.nullable(definition["nullable"]);
|
|
906
|
+
}
|
|
907
|
+
if ("min" in definition) {
|
|
908
|
+
if (!import_json6.JSON.isNumber(definition["min"]))
|
|
909
|
+
throw new DefinitionError(`Expected ${path}.min to be a Number`);
|
|
910
|
+
validatorInstance.min(definition["min"], `${path}.min`);
|
|
911
|
+
}
|
|
912
|
+
if ("max" in definition) {
|
|
913
|
+
if (!import_json6.JSON.isNumber(definition["max"]))
|
|
914
|
+
throw new DefinitionError(`Expected ${path}.max to be a Number`);
|
|
915
|
+
validatorInstance.max(definition["max"], `${path}.max`);
|
|
980
916
|
}
|
|
917
|
+
if ("every" in definition) {
|
|
918
|
+
if (!import_json6.JSON.isObject(definition["every"]))
|
|
919
|
+
throw new DefinitionError(`Expected ${path}.every to be an Object`);
|
|
920
|
+
validatorInstance.every(
|
|
921
|
+
fromJSON(definition["every"], `${path}.every`)
|
|
922
|
+
);
|
|
923
|
+
}
|
|
924
|
+
if ("tuple" in definition) {
|
|
925
|
+
if (!import_json6.JSON.isShallowArray(definition["tuple"]))
|
|
926
|
+
throw new DefinitionError(`Expected ${path}.tuple to be an Array`);
|
|
927
|
+
const tupleSchemas = [];
|
|
928
|
+
const errors = [];
|
|
929
|
+
definition["tuple"].forEach((tupleDef, index) => {
|
|
930
|
+
try {
|
|
931
|
+
tupleSchemas.push(fromJSON(tupleDef, `${path}.tuple[${index}]`));
|
|
932
|
+
} catch (e) {
|
|
933
|
+
if (!(e instanceof DefinitionError))
|
|
934
|
+
throw new DefinitionError(`Fatal Error: Undefined Error thrown by Domain.fromJSON at ${path}`);
|
|
935
|
+
errors.push(e);
|
|
936
|
+
}
|
|
937
|
+
});
|
|
938
|
+
if (errors.length > 0)
|
|
939
|
+
throw new DefinitionError(`Multiple Definition Errors detected at ${path} (see cause)`, { cause: errors });
|
|
940
|
+
validatorInstance.tuple(tupleSchemas, `${path}.tuple`);
|
|
941
|
+
}
|
|
942
|
+
return validatorInstance;
|
|
981
943
|
}
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
944
|
+
_nullable = import_option5.Option.None();
|
|
945
|
+
_every = import_option5.Option.None();
|
|
946
|
+
_tuple = import_option5.Option.None();
|
|
947
|
+
_min = import_option5.Option.None();
|
|
948
|
+
_max = import_option5.Option.None();
|
|
949
|
+
nullable(flag) {
|
|
950
|
+
this._nullable = flag ?? true ? import_option5.Option.Some(null) : import_option5.Option.None();
|
|
951
|
+
return this;
|
|
985
952
|
}
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
953
|
+
min(value, path = "min") {
|
|
954
|
+
if (this._max.isSome() && this._max.value < value)
|
|
955
|
+
throw new DefinitionError(`Expected Minimum Rule to be smaller than or equal to Maximum Rule at Path ${path}`);
|
|
956
|
+
if (this._tuple.isSome() && value < this._tuple.value.length)
|
|
957
|
+
throw new DefinitionError(`Expected Minimum Rule to be larger than or equal to Tuple Length at Path ${path}`);
|
|
958
|
+
this._min = import_option5.Option.Some(value);
|
|
959
|
+
return this;
|
|
960
|
+
}
|
|
961
|
+
max(value, path = "max") {
|
|
962
|
+
if (this._min.isSome() && this._min.value > value)
|
|
963
|
+
throw new DefinitionError(`Expected Maximum Rule to be larger than or equal to Minimum Rule at Path ${path}`);
|
|
964
|
+
if (this._tuple.isSome() && value < this._tuple.value.length)
|
|
965
|
+
throw new DefinitionError(`Expected Maximum Rule to be larger than or equal to Tuple Length at Path ${path}`);
|
|
966
|
+
this._max = import_option5.Option.Some(value);
|
|
967
|
+
return this;
|
|
968
|
+
}
|
|
969
|
+
every(validator) {
|
|
970
|
+
this._every = import_option5.Option.Some(validator);
|
|
971
|
+
return this;
|
|
972
|
+
}
|
|
973
|
+
/**
|
|
974
|
+
* Applies ONLY to prefix indices [0..validators.length - 1]
|
|
975
|
+
* If every() is set, prefix elements are effectively `T[i] & E`.
|
|
976
|
+
*/
|
|
977
|
+
tuple(validators, path = "tuple") {
|
|
978
|
+
if (this._min.isSome() && this._min.value < validators.length)
|
|
979
|
+
throw new DefinitionError(`Expected Tuple Length to be smaller than or equal to Minimum Rule at Path ${path}`);
|
|
980
|
+
if (this._max.isSome() && this._max.value < validators.length)
|
|
981
|
+
throw new DefinitionError(`Expected Tuple Length to be smaller than or equal to Maximum Rule at Path ${path}`);
|
|
982
|
+
this._tuple = import_option5.Option.Some(validators);
|
|
983
|
+
return this;
|
|
984
|
+
}
|
|
985
|
+
assert(data, path = "data") {
|
|
986
|
+
if (import_json6.JSON.isShallowArray(data)) {
|
|
987
|
+
if (this._min.isSome() && this._min.value > data.length)
|
|
988
|
+
throw new AssertError(`Expected ${path} to be at least ${this._min.value} Elements long`);
|
|
989
|
+
if (this._max.isSome() && this._max.value < data.length)
|
|
990
|
+
throw new AssertError(`Expected ${path} to be at most ${this._max.value} Elements long`);
|
|
991
|
+
const errors = [];
|
|
992
|
+
if (this._every.isSome()) {
|
|
993
|
+
const validator = this._every.value;
|
|
994
|
+
data.forEach((value, index) => {
|
|
995
|
+
try {
|
|
996
|
+
validator.assert(value, `${path}[${index}]`);
|
|
997
|
+
} catch (e) {
|
|
998
|
+
if (!(e instanceof AssertError))
|
|
999
|
+
throw new AssertError(`Fatal Error: Undefined Error thrown by an Assert Method at ${path}[${index}]`);
|
|
1000
|
+
errors.push(e);
|
|
1001
|
+
}
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
if (this._tuple.isSome()) {
|
|
1005
|
+
if (data.length < this._tuple.value.length)
|
|
1006
|
+
throw new AssertError(`Expected ${path} to be at least ${this._tuple.value.length} Elements long (Tuple Constraint)`);
|
|
1007
|
+
this._tuple.value.forEach((validator, index) => {
|
|
1008
|
+
try {
|
|
1009
|
+
validator.assert(data[index], `${path}[${index}]`);
|
|
1010
|
+
} catch (e) {
|
|
1011
|
+
if (!(e instanceof AssertError))
|
|
1012
|
+
throw new AssertError(`Fatal Error: Undefined Error thrown by an Assert Method at ${path}[${index}]`);
|
|
1013
|
+
errors.push(e);
|
|
1014
|
+
}
|
|
1015
|
+
});
|
|
1016
|
+
}
|
|
1017
|
+
if (errors.length > 0)
|
|
1018
|
+
throw new AssertError(`Multiple Errors while asserting ${path} (see cause)`, { cause: errors });
|
|
1019
|
+
} else if (import_json6.JSON.isNull(data)) {
|
|
1020
|
+
if (!this._nullable.isSome())
|
|
1021
|
+
throw new AssertError(`Expected ${path} to be an Array${this._nullable.isSome() ? " or Null" : ""}`);
|
|
1022
|
+
} else
|
|
1023
|
+
throw new AssertError(`Expected ${path} to be an Array${this._nullable.isSome() ? " or Null" : ""}`);
|
|
1024
|
+
}
|
|
1025
|
+
isSubset(other) {
|
|
1026
|
+
if (other instanceof JSONValidator)
|
|
989
1027
|
return true;
|
|
990
|
-
|
|
1028
|
+
if (!(other instanceof _ArrayValidator))
|
|
1029
|
+
return false;
|
|
1030
|
+
if (this._nullable.isSome() && !other._nullable.isSome())
|
|
1031
|
+
return false;
|
|
1032
|
+
const thisTupleLen = this._tuple.isSome() ? this._tuple.value.length : 0;
|
|
1033
|
+
const otherTupleLen = other._tuple.isSome() ? other._tuple.value.length : 0;
|
|
1034
|
+
const thisMin = this._min.isSome() ? this._min.value : 0;
|
|
1035
|
+
const otherMin = other._min.isSome() ? other._min.value : 0;
|
|
1036
|
+
const thisMax = this._max.isSome() ? this._max.value : Infinity;
|
|
1037
|
+
const otherMax = other._max.isSome() ? other._max.value : Infinity;
|
|
1038
|
+
const thisEffectiveMin = Math.max(thisMin, thisTupleLen);
|
|
1039
|
+
const otherEffectiveMin = Math.max(otherMin, otherTupleLen);
|
|
1040
|
+
if (thisEffectiveMin < otherEffectiveMin)
|
|
1041
|
+
return false;
|
|
1042
|
+
if (thisMax > otherMax)
|
|
1043
|
+
return false;
|
|
1044
|
+
const indexConjuncts = (i) => {
|
|
1045
|
+
const conjuncts = [];
|
|
1046
|
+
if (this._every.isSome())
|
|
1047
|
+
conjuncts.push(this._every.value);
|
|
1048
|
+
if (this._tuple.isSome() && i < this._tuple.value.length)
|
|
1049
|
+
conjuncts.push(this._tuple.value[i]);
|
|
1050
|
+
return conjuncts;
|
|
1051
|
+
};
|
|
1052
|
+
const conjunctsSubset = (conjuncts, target) => {
|
|
1053
|
+
if (conjuncts.length === 0)
|
|
1054
|
+
return false;
|
|
1055
|
+
return conjuncts.some((c) => c.isSubset(target));
|
|
1056
|
+
};
|
|
1057
|
+
if (other._tuple.isSome()) {
|
|
1058
|
+
for (let i = 0; i < other._tuple.value.length; i++) {
|
|
1059
|
+
const aConj = indexConjuncts(i);
|
|
1060
|
+
if (!conjunctsSubset(aConj, other._tuple.value[i]))
|
|
1061
|
+
return false;
|
|
1062
|
+
if (other._every.isSome() && !conjunctsSubset(aConj, other._every.value))
|
|
1063
|
+
return false;
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
return !(other._every.isSome() && (thisMax === Infinity ? true : thisMax > Math.max(thisTupleLen, otherTupleLen)) && (!this._every.isSome() || !this._every.value.isSubset(other._every.value)));
|
|
1067
|
+
}
|
|
1068
|
+
isEquals(other) {
|
|
1069
|
+
if (!(other instanceof _ArrayValidator))
|
|
1070
|
+
return false;
|
|
1071
|
+
if (this._nullable.isSome() !== other._nullable.isSome())
|
|
991
1072
|
return false;
|
|
1073
|
+
if (this._min.isSome() !== other._min.isSome())
|
|
1074
|
+
return false;
|
|
1075
|
+
if (this._min.isSome() && other._min.isSome() && this._min.value !== other._min.value)
|
|
1076
|
+
return false;
|
|
1077
|
+
if (this._max.isSome() !== other._max.isSome())
|
|
1078
|
+
return false;
|
|
1079
|
+
if (this._max.isSome() && other._max.isSome() && this._max.value !== other._max.value)
|
|
1080
|
+
return false;
|
|
1081
|
+
if (this._every.isSome() !== other._every.isSome())
|
|
1082
|
+
return false;
|
|
1083
|
+
if (this._every.isSome() && other._every.isSome() && !isEquals(this._every.value, other._every.value))
|
|
1084
|
+
return false;
|
|
1085
|
+
if (this._tuple.isSome() !== other._tuple.isSome())
|
|
1086
|
+
return false;
|
|
1087
|
+
if (this._tuple.isSome() && other._tuple.isSome()) {
|
|
1088
|
+
if (this._tuple.value.length !== other._tuple.value.length)
|
|
1089
|
+
return false;
|
|
1090
|
+
for (let i = 0; i < this._tuple.value.length; i++) {
|
|
1091
|
+
if (!isEquals(this._tuple.value[i], other._tuple.value[i]))
|
|
1092
|
+
return false;
|
|
1093
|
+
}
|
|
992
1094
|
}
|
|
1095
|
+
return true;
|
|
1096
|
+
}
|
|
1097
|
+
toJSON() {
|
|
1098
|
+
const definition = { type: "array" };
|
|
1099
|
+
if (this._nullable.isSome())
|
|
1100
|
+
definition.nullable = true;
|
|
1101
|
+
if (this._min.isSome())
|
|
1102
|
+
definition.min = this._min.value;
|
|
1103
|
+
if (this._max.isSome())
|
|
1104
|
+
definition.max = this._max.value;
|
|
1105
|
+
if (this._every.isSome())
|
|
1106
|
+
definition.every = this._every.value.toJSON();
|
|
1107
|
+
if (this._tuple.isSome())
|
|
1108
|
+
definition.tuple = this._tuple.value.map((validator) => validator.toJSON());
|
|
1109
|
+
return definition;
|
|
993
1110
|
}
|
|
994
1111
|
};
|
|
995
1112
|
|
|
1113
|
+
// src/lib/fromJSON.ts
|
|
1114
|
+
function fromJSON(definition, path) {
|
|
1115
|
+
if (!import_json7.JSON.isShallowObject(definition))
|
|
1116
|
+
throw new DefinitionError(`Expected ${path} to be an Object`);
|
|
1117
|
+
if (!import_json7.JSON.isString(definition["type"]))
|
|
1118
|
+
throw new DefinitionError(`Expected ${path}.type to be a String`);
|
|
1119
|
+
switch (definition["type"]) {
|
|
1120
|
+
case "json":
|
|
1121
|
+
return JSONValidator.fromJSON(definition, path);
|
|
1122
|
+
case "boolean":
|
|
1123
|
+
return BooleanValidator.fromJSON(definition, path);
|
|
1124
|
+
case "number":
|
|
1125
|
+
return NumberValidator.fromJSON(definition, path);
|
|
1126
|
+
case "string":
|
|
1127
|
+
return StringValidator.fromJSON(definition, path);
|
|
1128
|
+
case "array":
|
|
1129
|
+
return ArrayValidator.fromJSON(definition, path);
|
|
1130
|
+
case "object":
|
|
1131
|
+
return ObjectValidator.fromJSON(definition, path);
|
|
1132
|
+
default:
|
|
1133
|
+
throw new DefinitionError(`Expected ${path}.type to be a registered Validator`);
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
|
|
996
1137
|
// src/index.ts
|
|
997
1138
|
var Schema = class {
|
|
998
1139
|
static get JSON() {
|
|
@@ -1013,6 +1154,12 @@ var Schema = class {
|
|
|
1013
1154
|
static get Object() {
|
|
1014
1155
|
return new ObjectValidator();
|
|
1015
1156
|
}
|
|
1157
|
+
static fromJSON(definition, path = "definition") {
|
|
1158
|
+
return fromJSON(definition, path);
|
|
1159
|
+
}
|
|
1160
|
+
static isEquals(a, b) {
|
|
1161
|
+
return isEquals(a, b);
|
|
1162
|
+
}
|
|
1016
1163
|
};
|
|
1017
1164
|
var Validators = {
|
|
1018
1165
|
JSON: JSONValidator,
|