@lucania/schema 3.0.1 → 3.0.2

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.
@@ -1,47 +1,158 @@
1
- import { BaseSchemaAny } from "./typing/extended";
2
- import { DefaultValue, ModelValue } from "./typing/toolbox";
1
+ import { BaseSchema, SourceValue } from ".";
3
2
  import { AnySchema } from "./schema/AnySchema";
4
3
  import { ArraySchema, ArraySource } from "./schema/ArraySchema";
5
4
  import { BooleanSchema, BooleanSource } from "./schema/BooleanSchema";
5
+ import { ConstantSchema, ConstantSource } from "./schema/ConstantSchema";
6
6
  import { DateSchema, DateSource } from "./schema/DateSchema";
7
7
  import { DynamicObjectSchema, DynamicObjectSource } from "./schema/DynamicObjectSchema";
8
8
  import { EnumerationSchema } from "./schema/EnumerationSchema";
9
+ import { LenientObjectModel, LenientObjectSchema, LenientObjectSource, LenientObjectSubschema } from "./schema/LenientObject";
9
10
  import { NumberSchema, NumberSource } from "./schema/NumberSchema";
10
11
  import { ObjectSchema, ObjectSource, ObjectSubschema } from "./schema/ObjectSchema";
11
12
  import { OrSetSchema, OrSetSchemaSource } from "./schema/OrSetSchema";
12
13
  import { StringSchema, StringSource } from "./schema/StringSchema";
13
- import { BaseSchema, SourceValue } from ".";
14
+ import { BaseSchemaAny } from "./typing/extended";
15
+ import { DefaultValue, ModelValue } from "./typing/toolbox";
16
+ /**
17
+ * A collection of helper functions used to create the standard set of schemas.
18
+ */
14
19
  export declare namespace Schema {
20
+ /**
21
+ * Creates a schema used to validate a string.
22
+ *
23
+ * @param required Flag representing whether the schema should enforce a value's presence.
24
+ * @param defaultValue A default the schema will use during validation if a value is not present.
25
+ * @returns A schema used to validate a string.
26
+ */
15
27
  function String(): StringSchema<true, undefined>;
16
28
  function String<Required extends boolean>(required: Required): StringSchema<Required, undefined>;
17
29
  function String<Required extends boolean, Default extends DefaultValue<StringSource>>(required: Required, defaultValue: Default): StringSchema<Required, Default>;
30
+ /**
31
+ * Creates a schema used to validate a number.
32
+ *
33
+ * @param required Flag representing whether the schema should enforce a value's presence.
34
+ * @param defaultValue A default the schema will use during validation if a value is not present.
35
+ * @returns A schema used to validate a number.
36
+ */
18
37
  function Number(): NumberSchema<true, undefined>;
19
38
  function Number<Required extends boolean>(required: Required): NumberSchema<Required, undefined>;
20
39
  function Number<Required extends boolean, Default extends DefaultValue<NumberSource>>(required: Required, defaultValue: Default): NumberSchema<Required, Default>;
40
+ /**
41
+ * Creates a schema used to validate a boolean.
42
+ *
43
+ * @param required Flag representing whether the schema should enforce a value's presence.
44
+ * @param defaultValue A default the schema will use during validation if a value is not present.
45
+ * @returns A schema used to validate a boolean.
46
+ */
21
47
  function Boolean(): BooleanSchema<true, undefined>;
22
48
  function Boolean<Required extends boolean>(required: Required): BooleanSchema<Required, undefined>;
23
49
  function Boolean<Required extends boolean, Default extends DefaultValue<BooleanSource>>(required: Required, defaultValue: Default): BooleanSchema<Required, Default>;
50
+ /**
51
+ * Creates a schema used to validate a Date.
52
+ *
53
+ * @param required Flag representing whether the schema should enforce a value's presence.
54
+ * @param defaultValue A default the schema will use during validation if a value is not present.
55
+ * @returns A schema used to validate a Date.
56
+ */
24
57
  function Date(): DateSchema<true, undefined>;
25
58
  function Date<Required extends boolean>(required: Required): DateSchema<Required, undefined>;
26
59
  function Date<Required extends boolean, Default extends DefaultValue<DateSource>>(required: Required, defaultValue: Default): DateSchema<Required, Default>;
60
+ /**
61
+ * Creates a schema used to validate anything! Any value will pass the validation provided by schemas created by this function.
62
+ *
63
+ * @param required Flag representing whether the schema should enforce a value's presence.
64
+ * @param defaultValue A default the schema will use during validation if a value is not present.
65
+ * @returns A schema used to validate anything.
66
+ */
27
67
  function Any(): AnySchema<true, undefined>;
28
68
  function Any<Required extends boolean>(required: Required): AnySchema<Required, undefined>;
29
69
  function Any<Required extends boolean, Default extends DefaultValue<any>>(required: Required, defaultValue: Default): AnySchema<Required, Default>;
70
+ /**
71
+ * Creates a schema used to validate an object.
72
+ *
73
+ * This function can be used to create schemas that describe a value's object hierarchy.
74
+ *
75
+ * @note Values validated by schemas created by this function will only retain properties specified by the schema.
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * $.Object({ name: $.String() }).validate({ name: "Jeremy", age: 1 })
80
+ * ```
81
+ * ->
82
+ * ```ts
83
+ * { "name": "Jeremy" }
84
+ * ```
85
+ *
86
+ * @param subschema An object describing the sole keys and values that must be present within an object.
87
+ * @param required Flag representing whether the schema should enforce a value's presence.
88
+ * @param defaultValue A default the schema will use during validation if a value is not present.
89
+ * @returns A schema used to validate an object.
90
+ */
30
91
  function Object<Subschema extends ObjectSubschema>(subschema: Subschema): ObjectSchema<Subschema, true, undefined>;
31
92
  function Object<Subschema extends ObjectSubschema, Required extends boolean>(subschema: Subschema, required: Required): ObjectSchema<Subschema, Required, undefined>;
32
93
  function Object<Subschema extends ObjectSubschema, Required extends boolean, Default extends DefaultValue<ObjectSource<Subschema>>>(subschema: Subschema, required: Required, defaultValue: Default): ObjectSchema<Subschema, Required, Default>;
94
+ /**
95
+ * Creates a schema used to validate an object.
96
+ *
97
+ * This function can be used to create schemas that describe a value's object hierarchy.
98
+ *
99
+ * @note This function creates schemas that differ from that of `$.Object` in that the values validated by schemas created by this function
100
+ * will RETAIN the properties not specified by the schema.
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * $.LenientObject({ name: $.String() }).validate({ name: "Jeremy", age: 1 })
105
+ * ```
106
+ * ->
107
+ * ```ts
108
+ * { "name": "Jeremy", "age": 1 }
109
+ * ```
110
+ *
111
+ * @param subschema An object describing keys and values that must be present amongst any other keys and values within an object.
112
+ * @param required Flag representing whether the schema should enforce a value's presence.
113
+ * @param defaultValue A default the schema will use during validation if a value is not present.
114
+ * @returns A schema used to validate an object.
115
+ */
116
+ function LenientObject<Subschema extends LenientObjectSubschema>(subschema: Subschema): LenientObjectSchema<Subschema, LenientObjectSource<Subschema>, LenientObjectModel<Subschema>, true, undefined>;
117
+ function LenientObject<Subschema extends LenientObjectSubschema, Required extends boolean>(subschema: Subschema, required: Required): LenientObjectSchema<Subschema, LenientObjectSource<Subschema>, LenientObjectModel<Subschema>, Required, undefined>;
118
+ function LenientObject<Subschema extends LenientObjectSubschema, Required extends boolean, Default extends DefaultValue<LenientObjectSource<Subschema>>>(subschema: Subschema, required: Required, defaultValue: Default): LenientObjectSchema<Subschema, LenientObjectSource<Subschema>, LenientObjectModel<Subschema>, Required, Default>;
119
+ /**
120
+ * Creates a schema used to validate an object.
121
+ *
122
+ * This function can be used to create schemas that describe a value's object hierarchy.
123
+ *
124
+ * @note This function creates schemas that differ from that of `$.Object` in that schemas created by this function can have ANY string keys
125
+ * and only their values will be validated against the supplied `subschema`.
126
+ *
127
+ * @example
128
+ * ```ts
129
+ * $.DynamicObject($.String()).validate({ name: "Jeremy", age: 1, randomKey: true })
130
+ * ```
131
+ * ->
132
+ * ```ts
133
+ * { "name": "Jeremy", "age": "1", "randomKey": "true" }
134
+ * ```
135
+ *
136
+ * @param subschema Schema used to validate values within an object with dynamic keys.
137
+ * @param required Flag representing whether the schema should enforce a value's presence.
138
+ * @param defaultValue A default the schema will use during validation if a value is not present.
139
+ * @returns A schema used to validate an object.
140
+ */
141
+ function DynamicObject<Subschema extends BaseSchemaAny>(subschema: Subschema): DynamicObjectSchema<Subschema, true, undefined>;
142
+ function DynamicObject<Subschema extends BaseSchemaAny, Required extends boolean>(subschema: Subschema, required: Required): DynamicObjectSchema<Subschema, Required, undefined>;
143
+ function DynamicObject<Subschema extends BaseSchemaAny, Required extends boolean, Default extends DefaultValue<DynamicObjectSource<Subschema>>>(subschema: Subschema, required: Required, defaultValue: Default): DynamicObjectSchema<Subschema, Required, Default>;
33
144
  function Array<Subschema extends BaseSchemaAny>(subschema: Subschema): ArraySchema<Subschema, true, undefined>;
34
145
  function Array<Subschema extends BaseSchemaAny, Required extends boolean>(subschema: Subschema, required: Required): ArraySchema<Subschema, Required, undefined>;
35
146
  function Array<Subschema extends BaseSchemaAny, Required extends boolean, Default extends DefaultValue<ArraySource<Subschema>>>(subschema: Subschema, required: Required, defaultValue: Default): ArraySchema<Subschema, Required, Default>;
36
147
  function Enumeration<Member extends string>(subschema: TypedMembers<Member>): EnumerationSchema<Member, true, undefined>;
37
148
  function Enumeration<Member extends string, Required extends boolean>(subschema: TypedMembers<Member>, required: Required): EnumerationSchema<Member, Required, undefined>;
38
149
  function Enumeration<Member extends string, Required extends boolean, Default extends DefaultValue<Member>>(subschema: TypedMembers<Member>, required: Required, defaultValue: Default): EnumerationSchema<Member, Required, Default>;
39
- function DynamicObject<Subschema extends BaseSchemaAny>(subschema: Subschema): DynamicObjectSchema<Subschema, true, undefined>;
40
- function DynamicObject<Subschema extends BaseSchemaAny, Required extends boolean>(subschema: Subschema, required: Required): DynamicObjectSchema<Subschema, Required, undefined>;
41
- function DynamicObject<Subschema extends BaseSchemaAny, Required extends boolean, Default extends DefaultValue<DynamicObjectSource<Subschema>>>(subschema: Subschema, required: Required, defaultValue: Default): DynamicObjectSchema<Subschema, Required, Default>;
42
150
  function OrSet<MemberSchema extends BaseSchemaAny>(subschema: TypedMembers<MemberSchema>): OrSetSchema<MemberSchema, true, undefined>;
43
151
  function OrSet<MemberSchema extends BaseSchemaAny, Required extends boolean>(subschema: TypedMembers<MemberSchema>, required: Required): OrSetSchema<MemberSchema, Required, undefined>;
44
152
  function OrSet<MemberSchema extends BaseSchemaAny, Required extends boolean, Default extends DefaultValue<OrSetSchemaSource<MemberSchema>>>(subschema: TypedMembers<MemberSchema>, required: Required, defaultValue: Default): OrSetSchema<MemberSchema, Required, Default>;
153
+ function Constant<Constant extends ConstantSource>(constant: Constant): ConstantSchema<Constant, true, undefined>;
154
+ function Constant<Constant extends ConstantSource, Required extends boolean>(constant: Constant, required: Required): ConstantSchema<Constant, Required, undefined>;
155
+ function Constant<Constant extends ConstantSource, Required extends boolean, Default extends DefaultValue<Constant>>(constant: Constant, required: Required, defaultValue: Default): ConstantSchema<Constant, Required, Default>;
45
156
  type TypedMembers<Member extends any> = {
46
157
  $members: Member[];
47
158
  };
package/build/index.d.ts CHANGED
@@ -5,9 +5,11 @@ export * from "./schema/AnySchema";
5
5
  export * from "./schema/ArraySchema";
6
6
  export * from "./schema/BaseSchema";
7
7
  export * from "./schema/BooleanSchema";
8
+ export * from "./schema/ConstantSchema";
8
9
  export * from "./schema/DateSchema";
9
10
  export * from "./schema/DynamicObjectSchema";
10
11
  export * from "./schema/EnumerationSchema";
12
+ export * from "./schema/LenientObject";
11
13
  export * from "./schema/NumberSchema";
12
14
  export * from "./schema/ObjectSchema";
13
15
  export * from "./schema/OrSetSchema";
package/build/index.js CHANGED
@@ -99,28 +99,32 @@
99
99
  };
100
100
  try {
101
101
  result = this._executeAdditionalValidator(result, pass, "beforeAll");
102
+ // Handle Default
102
103
  result = this._executeAdditionalValidator(result, pass, "beforeDefault");
103
104
  if (!BaseSchema.isPresent(result) && this.hasDefault()) {
104
105
  result = this.getDefault(pass);
105
106
  }
106
107
  result = this._executeAdditionalValidator(result, pass, "afterDefault");
107
- result = this._executeAdditionalValidator(result, pass, "beforeConversion");
108
- if (BaseSchema.isPresent(result)) {
109
- if (BaseSchema.getType(result) !== this.type) {
110
- result = this.convert(result, pass);
111
- }
112
- result = this._validate(result, presentOptions, pass);
113
- result = this._executeAdditionalValidator(result, pass, "afterConversion");
114
- }
115
- else {
116
- if (this._required) {
117
- throw pass.causeError(pass.path.length > 0 ? `Missing required value at "${pass.path.join(".")}".` : "Missing required value.");
108
+ // Handle Required
109
+ if (!BaseSchema.isPresent(result)) {
110
+ if (this.isRequired()) {
111
+ throw pass.causeError(pass.path.length > 0 ? `Missing required ${this.type} at path "${pass.path.join(".")}".` : `Missing required ${this.type}.`);
118
112
  }
119
113
  else {
120
114
  result = undefined;
121
115
  }
122
116
  }
123
- if (this._required || result !== undefined) {
117
+ // Handle Conversion
118
+ if (result !== undefined) {
119
+ result = this._executeAdditionalValidator(result, pass, "beforeConversion");
120
+ if (BaseSchema.getType(result) !== this.type) {
121
+ result = this.convert(result, pass);
122
+ }
123
+ result = this._executeAdditionalValidator(result, pass, "afterConversion");
124
+ }
125
+ // Handle Validation
126
+ if (this.isRequired() || result !== undefined) {
127
+ result = this._validate(result, presentOptions, pass);
124
128
  result = this._executeAdditionalValidator(result, pass, "afterAll");
125
129
  }
126
130
  }
@@ -245,12 +249,12 @@
245
249
  }
246
250
  }
247
251
  /**
248
- * Checks to see if a value is present. (Not null or undefined)
252
+ * Checks to see if a value is present. (Not undefined)
249
253
  * @param value The value to check the presence of.
250
- * @returns true if value is not null or undefined, false otherwise.
254
+ * @returns true if value is undefined, false otherwise.
251
255
  */
252
256
  static isPresent(value) {
253
- return value !== undefined && value !== null;
257
+ return value !== undefined;
254
258
  }
255
259
  static getType(value) {
256
260
  if (value === null) {
@@ -369,6 +373,31 @@
369
373
  }
370
374
  }
371
375
 
376
+ class ConstantSchema extends BaseSchema {
377
+ value;
378
+ constructor(subschema, required, defaultValue, additionalValidationPasses) {
379
+ super(required, defaultValue, additionalValidationPasses);
380
+ this.value = subschema;
381
+ }
382
+ get type() { return BaseSchema.getType(this.value); }
383
+ _validate(source, options, pass) {
384
+ pass.assert(this.value === source, `Supplied source (${JSON.stringify(source)}) did not match expected constant value (${JSON.stringify(this.value)}).`);
385
+ return source;
386
+ }
387
+ convert(value, pass) {
388
+ return value;
389
+ }
390
+ clone() {
391
+ return new ConstantSchema(this.value, this._required, this._default, this._additionalValidationPasses);
392
+ }
393
+ getJsonSchema() {
394
+ return {
395
+ type: "string",
396
+ description: this._getJsonSchemaDescription(),
397
+ };
398
+ }
399
+ }
400
+
372
401
  const StandardDate = globalThis.Date;
373
402
  class DateSchema extends BaseSchema {
374
403
  get type() { return "Date"; }
@@ -500,6 +529,97 @@
500
529
  }
501
530
  }
502
531
 
532
+ class LenientObjectSchema extends BaseSchema {
533
+ subschema;
534
+ constructor(subschema, required, defaultValue, additionalValidationPasses) {
535
+ super(required, defaultValue, additionalValidationPasses);
536
+ this.subschema = subschema;
537
+ }
538
+ get type() { return "object"; }
539
+ _validate(source, options, pass) {
540
+ const inputObject = source;
541
+ let outputObject = { ...inputObject };
542
+ for (const key in this.subschema) {
543
+ const nestedSchema = this.subschema[key];
544
+ const nestedValue = inputObject[key];
545
+ outputObject[key] = this.subschema[key].validate(inputObject[key], options, pass.next([...pass.path, key], nestedSchema, nestedValue));
546
+ }
547
+ return outputObject;
548
+ }
549
+ convert(value, pass) {
550
+ pass.assert(typeof value === "object", `Unable to convert ${LenientObjectSchema.getType(value)} to object.`);
551
+ const inputObject = value;
552
+ const outputObject = { ...inputObject };
553
+ for (const key in this.subschema) {
554
+ const nestedSchema = this.subschema[key];
555
+ const nestedValue = inputObject[key];
556
+ outputObject[key] = nestedSchema.convert(nestedValue, pass.next([...pass.path, key], nestedSchema, nestedValue));
557
+ }
558
+ return outputObject;
559
+ }
560
+ // Works at runtime, can't figure out typing.
561
+ // public extend<
562
+ // ExtensionSubschema extends LenientObjectSubschema,
563
+ // ExtensionSource extends LenientObjectSource<ExtensionSubschema>,
564
+ // ExtensionModel extends LenientObjectModel<ExtensionSubschema>,
565
+ // ExtensionDefault extends DefaultValue<ExtensionSource>
566
+ // >(schema: LenientObjectSchema<ExtensionSubschema, ExtensionSource, ExtensionModel, Required, ExtensionDefault>):
567
+ // // LenientObjectSchema<ExtensionSubschema & Subschema, ExtensionSource & Source, ExtensionModel & Model, Required, DefaultValue<ExtensionSource & Source>>
568
+ // ExtendedLenientObjectSchema<this, LenientObjectSchema<ExtensionSubschema, ExtensionSource, ExtensionModel, Required, ExtensionDefault>> {
569
+ // let defaultValue: any = undefined;
570
+ // if (this.hasDefault() !== schema.hasDefault()) {
571
+ // throw new Error("Both or neither default values must be specified in order to extend a schema!");
572
+ // }
573
+ // if (this.hasDefault() && schema.hasDefault()) {
574
+ // defaultValue = (pass: ValidationPass) => {
575
+ // return {
576
+ // ...this.getDefault(pass),
577
+ // ...schema.getDefault(pass)
578
+ // };
579
+ // };
580
+ // }
581
+ // const subschema: any = { ...this.subschema };
582
+ // for (const key in schema.subschema) {
583
+ // if (key in this.subschema) {
584
+ // this.subschema[key].extend(schema.subschema[key]);
585
+ // } else {
586
+ // subschema[key] = schema.subschema[key];
587
+ // }
588
+ // }
589
+ // return new LenientObjectSchema(subschema, this._required, defaultValue) as any;
590
+ // }
591
+ getJsonSchema() {
592
+ const properties = {};
593
+ for (const key in this.subschema) {
594
+ properties[key] = this.subschema[key].getJsonSchema();
595
+ }
596
+ return {
597
+ type: "object",
598
+ description: this._getJsonSchemaDescription(),
599
+ properties
600
+ };
601
+ }
602
+ clone() {
603
+ const subschema = {};
604
+ for (const key in this.subschema) {
605
+ subschema[key] = this.subschema[key].clone();
606
+ }
607
+ return new LenientObjectSchema(subschema, this._required, this._default, this._additionalValidationPasses);
608
+ }
609
+ toString(level = 0) {
610
+ const indent = " ";
611
+ const prefix = indent.repeat(level);
612
+ const pieces = [];
613
+ pieces.push(`${super.toString()}({\n`);
614
+ for (const schemaKey in this.subschema) {
615
+ const subschema = this.subschema[schemaKey];
616
+ pieces.push(`${prefix}${indent}${schemaKey}: ${subschema.toString(level + 1)}\n`);
617
+ }
618
+ pieces.push(`${prefix}})`);
619
+ return pieces.join("");
620
+ }
621
+ }
622
+
503
623
  class NumberSchema extends BaseSchema {
504
624
  get type() { return "number"; }
505
625
  _validate(source, options, pass) {
@@ -587,21 +707,6 @@
587
707
  }
588
708
  return model;
589
709
  }
590
- extend(schema) {
591
- let defaultValue = undefined;
592
- if (this.hasDefault() !== schema.hasDefault()) {
593
- throw new Error("Both or neither default values must be specified in order to extend a schema!");
594
- }
595
- if (this.hasDefault() && schema.hasDefault()) {
596
- defaultValue = (pass) => {
597
- return {
598
- ...this.getDefault(pass),
599
- ...schema.getDefault(pass)
600
- };
601
- };
602
- }
603
- return new ObjectSchema({ ...this.subschema, ...schema.subschema }, this._required, defaultValue);
604
- }
605
710
  getJsonSchema() {
606
711
  const properties = {};
607
712
  for (const key in this.subschema) {
@@ -644,34 +749,52 @@
644
749
  return "string";
645
750
  }
646
751
  _validate(source, options, pass) {
647
- let result = source;
648
- if (result !== undefined) {
649
- let done = false;
650
- const failureMessages = [];
651
- for (let i = 0; i < this.schemas.length && !done; i++) {
652
- const schema = this.schemas[i];
653
- try {
654
- if (BaseSchema.getType(result) === schema.type) {
655
- result = schema.validate(result, options, pass);
656
- done = true;
657
- }
658
- }
659
- catch (error) {
660
- if (error instanceof Error) {
661
- failureMessages.push(`Schema #${i + 1}: ${error.message}`);
662
- }
663
- else {
664
- failureMessages.push(`Schema #${i + 1}: ${String(error)}`);
665
- }
752
+ const errors = {};
753
+ for (let i = 0; i < this.schemas.length; i++) {
754
+ const schema = this.schemas[i];
755
+ try {
756
+ if (BaseSchema.getType(source) !== schema.type) {
757
+ throw new ValidationError(new ValidationPass(schema, source, undefined), `Conversions for schemas in an OrSet are disabled.`);
666
758
  }
759
+ return schema.validate(source);
667
760
  }
668
- if (!done) {
669
- failureMessages.push(`Conversions for schemas in an OrSet are disabled.`);
761
+ catch (error) {
762
+ errors[i] = error;
670
763
  }
671
- pass.assert(failureMessages.length === 0, `Provided value (${BaseSchema.getType(result)}) matched no schemas ` +
672
- `(${this.schemas.map((schema) => schema.type).join(", ")}).\n${failureMessages.join("\n")}`);
673
764
  }
674
- return result;
765
+ const errorMessages = Object.entries(errors).map(([index, error]) => `Schema #${parseInt(index) + 1}: ${error === undefined ? "Unknown error." : error.message}`);
766
+ throw pass.causeError(`Provided value (${BaseSchema.getType(source)}) matched no schemas ` +
767
+ `(${this.schemas.map((schema) => schema.type).join(", ")}).\n` +
768
+ `${errorMessages.join("\n")}`);
769
+ // let result = source;
770
+ // if (result !== undefined) {
771
+ // let done = false;
772
+ // const failureMessages: string[] = [];
773
+ // for (let i = 0; i < this.schemas.length && !done; i++) {
774
+ // const schema = this.schemas[i];
775
+ // try {
776
+ // if (BaseSchema.getType(result) === schema.type) {
777
+ // result = schema.validate(result, options, pass);
778
+ // done = true;
779
+ // }
780
+ // } catch (error) {
781
+ // if (error instanceof Error) {
782
+ // failureMessages.push(`Schema #${i + 1}: ${error.message}`);
783
+ // } else {
784
+ // failureMessages.push(`Schema #${i + 1}: ${String(error)}`);
785
+ // }
786
+ // }
787
+ // }
788
+ // if (!done) {
789
+ // failureMessages.push(`Conversions for schemas in an OrSet are disabled.`);
790
+ // }
791
+ // pass.assert(
792
+ // failureMessages.length === 0,
793
+ // `Provided value (${BaseSchema.getType(result)}) matched no schemas ` +
794
+ // `(${this.schemas.map((schema) => schema.type).join(", ")}).\n${failureMessages.join("\n")}`
795
+ // );
796
+ // }
797
+ // return result;
675
798
  }
676
799
  convert(value, pass) {
677
800
  return value;
@@ -753,6 +876,9 @@
753
876
  }
754
877
  }
755
878
 
879
+ /**
880
+ * A collection of helper functions used to create the standard set of schemas.
881
+ */
756
882
  exports.Schema = void 0;
757
883
  (function (Schema) {
758
884
  function String(required = true, defaultValue = undefined) {
@@ -779,6 +905,14 @@
779
905
  return new ObjectSchema(subschema, required, defaultValue);
780
906
  }
781
907
  Schema.Object = Object;
908
+ function LenientObject(subschema, required = true, defaultValue = undefined) {
909
+ return new LenientObjectSchema(subschema, required, defaultValue);
910
+ }
911
+ Schema.LenientObject = LenientObject;
912
+ function DynamicObject(subschema, required = true, defaultValue = undefined) {
913
+ return new DynamicObjectSchema(subschema, required, defaultValue);
914
+ }
915
+ Schema.DynamicObject = DynamicObject;
782
916
  function Array(subschema, required = true, defaultValue = undefined) {
783
917
  return new ArraySchema(subschema, required, defaultValue);
784
918
  }
@@ -787,14 +921,14 @@
787
921
  return new EnumerationSchema(members.$members, required, defaultValue);
788
922
  }
789
923
  Schema.Enumeration = Enumeration;
790
- function DynamicObject(subschema, required = true, defaultValue = undefined) {
791
- return new DynamicObjectSchema(subschema, required, defaultValue);
792
- }
793
- Schema.DynamicObject = DynamicObject;
794
924
  function OrSet(members, required = true, defaultValue = undefined) {
795
925
  return new OrSetSchema(members.$members, required, defaultValue);
796
926
  }
797
927
  Schema.OrSet = OrSet;
928
+ function Constant(value, required = true, defaultValue = undefined) {
929
+ return new ConstantSchema(value, required, defaultValue);
930
+ }
931
+ Schema.Constant = Constant;
798
932
  function Members(...members) {
799
933
  /*
800
934
  * HACK START: The hermes JS engine doesn't use globalThis.Array when interpreting `...members`
@@ -823,9 +957,11 @@
823
957
  exports.ArraySchema = ArraySchema;
824
958
  exports.BaseSchema = BaseSchema;
825
959
  exports.BooleanSchema = BooleanSchema;
960
+ exports.ConstantSchema = ConstantSchema;
826
961
  exports.DateSchema = DateSchema;
827
962
  exports.DynamicObjectSchema = DynamicObjectSchema;
828
963
  exports.EnumerationSchema = EnumerationSchema;
964
+ exports.LenientObjectSchema = LenientObjectSchema;
829
965
  exports.NumberSchema = NumberSchema;
830
966
  exports.ObjectSchema = ObjectSchema;
831
967
  exports.OrSetSchema = OrSetSchema;
@@ -8,6 +8,17 @@ export declare abstract class BaseSchema<Source, Model, Required extends boolean
8
8
  constructor(required: Required, defaultValue: Default, additionalValidationPasses?: AdditionalValidationPasses<Source, Model>);
9
9
  abstract get type(): string;
10
10
  validate(source: SourceValue<Source, Required, Default>, options?: OptionalValidationOptions, pass?: ValidationPass): ModelValue<Source, Model, Required, Default>;
11
+ /**
12
+ * Responsible for validating that a supplied source matches the schema this class represents.
13
+ *
14
+ * Some assumptions can be made about `source`:
15
+ * * It will never be `null`/`undefined`.
16
+ * * Its type returned by `BaseSchema.getType` will match that of this classes `type` property.
17
+ *
18
+ * @param source Source to be validated.
19
+ * @param options Validation options.
20
+ * @param pass Validation pass.
21
+ */
11
22
  protected abstract _validate(source: ModelValue<Source, Model, Required, Default>, options: ValidationOptions, pass: ValidationPass): ModelValue<Source, Model, Required, Default>;
12
23
  abstract convert(value: Source, pass: ValidationPass): Model;
13
24
  custom(additionalValidator: AdditionalValidator<SourceValue<Source, Required, Default>>, type: AdditionalValidatorBeforeType): this;
@@ -47,10 +58,10 @@ export declare abstract class BaseSchema<Source, Model, Required extends boolean
47
58
  */
48
59
  toString(level?: number): string;
49
60
  /**
50
- * Checks to see if a value is present. (Not null or undefined)
61
+ * Checks to see if a value is present. (Not undefined)
51
62
  * @param value The value to check the presence of.
52
- * @returns true if value is not null or undefined, false otherwise.
63
+ * @returns true if value is undefined, false otherwise.
53
64
  */
54
- static isPresent(value: any): value is Exclude<Exclude<any, null>, undefined>;
65
+ static isPresent(value: any): value is Exclude<any, undefined>;
55
66
  static getType(value: any): any;
56
67
  }
@@ -0,0 +1,13 @@
1
+ import { ValidationPass } from "../error/ValidationPass";
2
+ import { AdditionalValidationPasses, DefaultValue, ModelValue, ValidationOptions } from "../typing/toolbox";
3
+ import { BaseSchema } from "./BaseSchema";
4
+ export type ConstantSource = string | number | boolean | null;
5
+ export declare class ConstantSchema<Constant extends ConstantSource, Required extends boolean, Default extends DefaultValue<Constant>> extends BaseSchema<Constant, Constant, Required, Default> {
6
+ readonly value: Constant;
7
+ constructor(subschema: Constant, required: Required, defaultValue: Default, additionalValidationPasses?: AdditionalValidationPasses<Constant, Constant>);
8
+ get type(): any;
9
+ protected _validate(source: ModelValue<Constant, Constant, Required, Default>, options: ValidationOptions, pass: ValidationPass): ModelValue<Constant, Constant, Required, Default>;
10
+ convert(value: Constant, pass: ValidationPass): Constant;
11
+ clone(): ConstantSchema<Constant, Required, Default>;
12
+ getJsonSchema(): object;
13
+ }
@@ -0,0 +1,31 @@
1
+ import { ValidationPass } from "../error/ValidationPass";
2
+ import { BaseSchemaAny } from "../typing/extended";
3
+ import type { AdditionalValidationPasses, DefaultValue, Merge, ModelRequirement, ModelValue, SourceRequirement, SourceValue, ValidationOptions } from "../typing/toolbox";
4
+ import { BaseSchema } from "./BaseSchema";
5
+ export type LenientObjectSubschema = {
6
+ [Key: string]: BaseSchemaAny;
7
+ };
8
+ export type LenientObjectSource<Subschema extends LenientObjectSubschema> = ({
9
+ [Key: string]: any;
10
+ } & Merge<{
11
+ [Key in keyof Subschema as SourceRequirement<Subschema[Key]> extends true ? Key : never]: (Subschema[Key] extends BaseSchema<infer Source, any, infer Required, infer Default> ? (SourceValue<Source, Required, Default>) : never);
12
+ }, {
13
+ [Key in keyof Subschema as SourceRequirement<Subschema[Key]> extends false ? Key : never]?: (Subschema[Key] extends BaseSchema<infer Source, any, infer Required, infer Default> ? (SourceValue<Source, Required, Default>) : never);
14
+ }>);
15
+ export type LenientObjectModel<Subschema extends LenientObjectSubschema> = ({
16
+ [Key: string]: any;
17
+ } & Merge<{
18
+ [Key in keyof Subschema as ModelRequirement<Subschema[Key]> extends true ? Key : never]: (Subschema[Key] extends BaseSchema<infer Source, infer Model, infer Required, infer Default> ? (ModelValue<Source, Model, Required, Default>) : never);
19
+ }, {
20
+ [Key in keyof Subschema as ModelRequirement<Subschema[Key]> extends false ? Key : never]?: (Subschema[Key] extends BaseSchema<infer Source, infer Model, infer Required, infer Default> ? (ModelValue<Source, Model, Required, Default>) : never);
21
+ }>);
22
+ export declare class LenientObjectSchema<Subschema extends LenientObjectSubschema, Source extends LenientObjectSource<Subschema>, Model extends LenientObjectModel<Subschema>, Required extends boolean, Default extends DefaultValue<Source>> extends BaseSchema<Source, Model, Required, Default> {
23
+ readonly subschema: Subschema;
24
+ constructor(subschema: Subschema, required: Required, defaultValue: Default, additionalValidationPasses?: AdditionalValidationPasses<Source, Model>);
25
+ get type(): string;
26
+ protected _validate(source: ModelValue<Source, Model, Required, Default>, options: ValidationOptions, pass: ValidationPass): ModelValue<Source, Model, Required, Default>;
27
+ convert(value: Source, pass: ValidationPass): Model;
28
+ getJsonSchema(): object;
29
+ clone(): LenientObjectSchema<Subschema, Source, Model, Required, Default>;
30
+ toString(level?: number): string;
31
+ }
@@ -21,7 +21,6 @@ export declare class ObjectSchema<Subschema extends ObjectSubschema, Required ex
21
21
  get type(): string;
22
22
  protected _validate(source: ModelValue<ObjectSource<Subschema>, ObjectModel<Subschema>, Required, Default>, options: ValidationOptions, pass: ValidationPass): ModelValue<ObjectSource<Subschema>, ObjectModel<Subschema>, Required, Default>;
23
23
  convert(value: ObjectSource<Subschema>, pass: ValidationPass): ObjectModel<Subschema>;
24
- extend<ExtensionSubschema extends ObjectSubschema, ExtensionDefault extends DefaultValue<ObjectSource<ExtensionSubschema>>>(schema: ObjectSchema<ExtensionSubschema, Required, ExtensionDefault>): ObjectSchema<Subschema & ExtensionSubschema, Required, any>;
25
24
  getJsonSchema(): object;
26
25
  clone(): ObjectSchema<Subschema, Required, Default>;
27
26
  toString(level?: number): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lucania/schema",
3
- "version": "3.0.1",
3
+ "version": "3.0.2",
4
4
  "description": "A schema module for compile-time and runtime type checking.",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",