schema-shield 0.0.4 → 0.0.6

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/README.md CHANGED
@@ -8,36 +8,35 @@ Despite its feature-rich and easy extendable nature, SchemaShield is designed to
8
8
 
9
9
  ## Table of Contents
10
10
 
11
- - [SchemaShield](#schemashield)
12
- - [Table of Contents](#table-of-contents)
13
- - [Features](#features)
14
- - [Usage](#usage)
15
- - [No Code Generation](#no-code-generation)
16
- - [Error Handling](#error-handling)
17
- - [ValidationError Properties](#validationerror-properties)
18
- - [Get the cause of the error](#get-the-cause-of-the-error)
19
- - [Adding Custom Types](#adding-custom-types)
20
- - [Method Signature](#method-signature)
21
- - [Example: Adding a Custom Type](#example-adding-a-custom-type)
22
- - [Adding Custom Formats](#adding-custom-formats)
23
- - [Method Signature](#method-signature-1)
24
- - [Example: Adding a Custom Format](#example-adding-a-custom-format)
25
- - [Adding Custom Keywords](#adding-custom-keywords)
26
- - [Method Signature](#method-signature-2)
27
- - [About the `defineError` Function](#about-the-defineerror-function)
28
- - [About the `instance` Argument](#about-the-instance-argument)
29
- - [Example: Adding a Custom Keyword](#example-adding-a-custom-keyword)
30
- - [Complex example: Adding a Custom Keyword that uses the instance](#complex-example-adding-a-custom-keyword-that-uses-the-instance)
31
- - [No Code Generation Opened Possibilities](#no-code-generation-opened-possibilities)
32
- - [Immutable Mode](#immutable-mode)
33
- - [TypeScript Support](#typescript-support)
34
- - [Known Limitations](#known-limitations)
35
- - [Schema References and Schema Definitions](#schema-references-and-schema-definitions)
36
- - [Unsupported Formats](#unsupported-formats)
37
- - [Internationalized Formats](#internationalized-formats)
38
- - [Testing](#testing)
39
- - [Contribute](#contribute)
40
- - [Legal](#legal)
11
+ - [Table of Contents](#table-of-contents)
12
+ - [Features](#features)
13
+ - [Usage](#usage)
14
+ - [No Code Generation](#no-code-generation)
15
+ - [Error Handling](#error-handling)
16
+ - [Adding Custom Types](#adding-custom-types)
17
+ - [Method Signature](#method-signature)
18
+ - [Example: Adding a Custom Type](#example-adding-a-custom-type)
19
+ - [Adding Custom Formats](#adding-custom-formats)
20
+ - [Method Signature](#method-signature-1)
21
+ - [Example: Adding a Custom Format](#example-adding-a-custom-format)
22
+ - [Adding Custom Keywords](#adding-custom-keywords)
23
+ - [Method Signature](#method-signature-2)
24
+ - [Example: Adding a Custom Keyword](#example-adding-a-custom-keyword)
25
+ - [Complex example: Adding a Custom Keyword that uses the instance](#complex-example-adding-a-custom-keyword-that-uses-the-instance)
26
+ - [No Code Generation Opened Possibilities](#no-code-generation-opened-possibilities)
27
+ - [More on Error Handling](#more-on-error-handling)
28
+ - [ValidationError Properties](#validationerror-properties)
29
+ - [Get the path to the error location](#get-the-path-to-the-error-location)
30
+ - [Get the full error chain as a tree](#get-the-full-error-chain-as-a-tree)
31
+ - [Get the cause of the error](#get-the-cause-of-the-error)
32
+ - [Immutable Mode](#immutable-mode)
33
+ - [TypeScript Support](#typescript-support)
34
+ - [Known Limitations](#known-limitations)
35
+ - [Schema References and Schema Definitions](#schema-references-and-schema-definitions)
36
+ - [Unsupported Formats](#unsupported-formats)
37
+ - [Testing](#testing)
38
+ - [Contribute](#contribute)
39
+ - [Legal](#legal)
41
40
 
42
41
  ## Features
43
42
 
@@ -47,6 +46,7 @@ Despite its feature-rich and easy extendable nature, SchemaShield is designed to
47
46
  - Immutable mode for data protection.
48
47
  - Lightweight and fast.
49
48
  - Easy to use and extend.
49
+ - No dependencies.
50
50
  - Typescript support.
51
51
 
52
52
  ## Usage
@@ -127,9 +127,9 @@ if (validationResult.valid) {
127
127
 
128
128
  **`validationResult`**: Contains the following properties:
129
129
 
130
- - `data`: The validated (and potentially modified) data
131
- - `error`: A `ValidationError` instance if validation failed, otherwise null
132
- - `valid`: true if validation was successful, otherwise false
130
+ - `data`: The validated (and potentially modified) data.
131
+ - `error`: A `ValidationError` instance if validation failed, otherwise null.
132
+ - `valid`: true if validation was successful, otherwise false.
133
133
 
134
134
  ## No Code Generation
135
135
 
@@ -150,30 +150,14 @@ You can see a full example of this in the [No Code Generation opened possibiliti
150
150
 
151
151
  ## Error Handling
152
152
 
153
- SchemaShield provides a `ValidationError` class to handle errors that occur during schema validation. When a validation error is encountered, a `ValidationError` instance is returned in the error property of the validation result.
154
-
155
- This returned error instance uses the new [Error: cause](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause) property introduced in ES6. This allows you to analyze the whole error chain or to retrieve the root cause of the error using the `getCause()` method.
156
-
157
- ### ValidationError Properties
158
-
159
- - `message`: A string containing a description of the error
160
- - `item`: The final item in the path that caused the error
161
- - `keyword`: The keyword that triggered the error
162
- - `cause`: A nested ValidationError that caused the current error
163
- - `path`: The JSON Pointer path to the error location in the schema (Only available using the `getCause()` method)
164
- - `data`: The data that caused the error (optional)
165
- - `schema`: The compiled schema that caused the error (optional)
166
-
167
- ### Get the cause of the error
168
-
169
- You can use the `getCause()` method to retrieve the root cause of a validation error. This method returns the nested ValidationError instance that triggered the current error and contains the `path` property.
153
+ SchemaShield provides comprehensive error handling for schema validation. When a validation error occurs, a `ValidationError` instance is returned in the error property of the validation result. This error has the `getPath()` method, which is particularly useful for quickly identifying the location of an error in both the schema and the data.
170
154
 
171
155
  **Example:**
172
156
 
173
157
  ```javascript
174
158
  import { SchemaShield } from "schema-shield";
175
159
 
176
- const schemaShield = new SchemaShield({ immutable: true });
160
+ const schemaShield = new SchemaShield();
177
161
 
178
162
  const schema = {
179
163
  type: "object",
@@ -200,16 +184,15 @@ if (validationResult.valid) {
200
184
  } else {
201
185
  console.error("Validation error:", validationResult.error.message); // "Property is invalid"
202
186
 
203
- // Get the root cause of the error
204
- const errorCause = validationResult.error.getCause();
205
- console.error("Root cause:", errorCause.message); // "Value is less than the minimum"
206
- console.error("Error path:", errorCause.path); // "#/properties/age/minimum"
207
- console.error("Error data:", errorCause.data); // 15
208
- console.error("Error schema:", errorCause.schema); // 18
209
- console.error("Error keyword:", errorCause.keyword); // "minimum"
187
+ // Get the paths to the error location in the schema and in the data
188
+ const errorPaths = validationResult.error.getPath();
189
+ console.error("Schema path:", errorPaths.schemaPath); // "#/properties/age/minimum"
190
+ console.error("Instance path:", errorPaths.instancePath); // "#/age"
210
191
  }
211
192
  ```
212
193
 
194
+ For more advanced error handling and a detailed explanation of the ValidationError properties and methods, refer to the [More on Error Handling](#more-on-error-handling) section.
195
+
213
196
  ## Adding Custom Types
214
197
 
215
198
  SchemaShield allows you to add custom types for validation using the `addType` method.
@@ -418,7 +401,7 @@ In this example, we'll add a custom keyword called divisibleBy that validates if
418
401
  ```javascript
419
402
  import { SchemaShield, ValidationError } from "./path/to/SchemaShield";
420
403
 
421
- const schemaShield = new SchemaShield({ immutable: true });
404
+ const schemaShield = new SchemaShield();
422
405
 
423
406
  // Custom keyword 'divisibleBy' validator function
424
407
  const divisibleByValidator = (schema, data, defineError, instance) => {
@@ -681,6 +664,255 @@ if (validationResult.valid) {
681
664
 
682
665
  In this example, SchemaShield safely accesses instances of custom classes and utilizes them in the validation process. This level of complexity and flexibility would not be possible or would require a lot of boilerplate code with other libraries that rely on code generation.
683
666
 
667
+ ## More on Error Handling
668
+
669
+ SchemaShield provides a `ValidationError` class to handle errors that occur during schema validation. When a validation error is encountered, a `ValidationError` instance is returned in the error property of the validation result.
670
+
671
+ This error instance uses the new [Error: cause](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause) property introduced in ES6. This allows you to analyze the whole error chain or to retrieve the root cause of the error using the `getCause()` `getTree()` and `getPath()` methods.
672
+
673
+ ### ValidationError Properties
674
+
675
+ - `message`: A string containing a description of the error.
676
+ - `item`: The final item in the path that caused the error (either a string or a number) (optional).
677
+ - `keyword`: The keyword that triggered the error.
678
+ - `cause`: A nested ValidationError or a normal Error that caused the current error.
679
+ - `schemaPath`: The JSON Pointer path to the error location in the schema.
680
+ - `instancePath`: The JSON Pointer path to the error location in the data.
681
+ - `data`: The data that caused the error (optional).
682
+ - `schema`: The schema that caused the error (optional).
683
+
684
+ _Note:_ The `schemaPath` and `instancePath` will be only available after using the `getCause()` `getTree()` or `getPath()` methods.
685
+
686
+ ### Get the path to the error location
687
+
688
+ You can use the `getPath` method to get the JSON Pointer path to the error location in the schema and in the data. This method returns an object containing the `schemaPath` and `instancePath`.
689
+
690
+ **Example:**
691
+
692
+ ```javascript
693
+ import { SchemaShield } from "schema-shield";
694
+
695
+ const schemaShield = new SchemaShield();
696
+
697
+ const schema = {
698
+ type: "object",
699
+ properties: {
700
+ description: { type: "string" },
701
+ shouldLoadDb: { type: "boolean" },
702
+ enableNetConnectFor: { type: "array", items: { type: "string" } },
703
+ params: {
704
+ type: "object",
705
+ additionalProperties: {
706
+ type: "object",
707
+ properties: {
708
+ description: { type: "string" },
709
+ default: { type: "string" }
710
+ },
711
+ required: ["description"]
712
+ }
713
+ },
714
+ run: { type: "string" }
715
+ }
716
+ };
717
+
718
+ const validator = schemaShield.compile(schema);
719
+
720
+ const invalidData = {
721
+ description: "Say hello to the bot.",
722
+ shouldLoadDb: false,
723
+ enableNetConnectFor: [],
724
+ params: {
725
+ color: {
726
+ type: "string",
727
+ // description: "The color of the text", // Missing description on purpose
728
+ default: "red"
729
+ }
730
+ },
731
+ run: "run"
732
+ };
733
+
734
+ const validationResult = validator(invalidData);
735
+
736
+ if (validationResult.valid) {
737
+ console.log("Data is valid:", validationResult.data);
738
+ } else {
739
+ console.error("Validation error:", validationResult.error.message); // "Property is invalid"
740
+
741
+ // Get the paths to the error location in the schema and in the data
742
+ const errorPaths = validationResult.error.getPath();
743
+ console.error("Schema path:", errorPaths.schemaPath); // "#/properties/params/additionalProperties/required"
744
+ console.error("Instance path:", errorPaths.instancePath); // "#/params/color/description"
745
+ }
746
+ ```
747
+
748
+ ### Get the full error chain as a tree
749
+
750
+ You can use the `getTree()` method to retrieve the full error chain as a tree. This method returns an ErrorTree object with the complete nested error structure, allowing you to analyze the full chain of errors that occurred during validation.
751
+
752
+ #### ErrorTree Signature
753
+
754
+ ```typescript
755
+ interface ErrorTree {
756
+ message: string; // The error message
757
+ keyword: string; // The keyword that triggered the error
758
+ item?: string | number; // The final item in the path that caused the error (either a string or a number) (optional)
759
+ schemaPath: string; // The JSON Pointer path to the error location in the schema
760
+ instancePath: string; // The JSON Pointer path to the error location in the data
761
+ data?: any; // The data that caused the error (optional)
762
+ cause?: ErrorTree; // A nested ErrorTree representation of the nested error that caused the current error
763
+ }
764
+ ```
765
+
766
+ **Example:**
767
+
768
+ ```javascript
769
+ import { SchemaShield } from "schema-shield";
770
+
771
+ const schemaShield = new SchemaShield();
772
+
773
+ const schema = {
774
+ type: "object",
775
+ properties: {
776
+ description: { type: "string" },
777
+ shouldLoadDb: { type: "boolean" },
778
+ enableNetConnectFor: { type: "array", items: { type: "string" } },
779
+ params: {
780
+ type: "object",
781
+ additionalProperties: {
782
+ type: "object",
783
+ properties: {
784
+ description: { type: "string" },
785
+ default: { type: "string" }
786
+ },
787
+ required: ["description"]
788
+ }
789
+ },
790
+ run: { type: "string" }
791
+ }
792
+ };
793
+
794
+ const validator = schemaShield.compile(schema);
795
+
796
+ const invalidData = {
797
+ description: "Say hello to the bot.",
798
+ shouldLoadDb: false,
799
+ enableNetConnectFor: [],
800
+ params: {
801
+ color: {
802
+ type: "string",
803
+ // description: "The color of the text", // Missing description on purpose
804
+ default: "red"
805
+ }
806
+ },
807
+ run: "run"
808
+ };
809
+
810
+ const validationResult = validator(invalidData);
811
+
812
+ if (validationResult.valid) {
813
+ console.log("Data is valid:", validationResult.data);
814
+ } else {
815
+ console.error("Validation error:", validationResult.error.message); // "Property is invalid"
816
+
817
+ // Get the full error chain as a tree
818
+ const errorTree = validationResult.error.getTree();
819
+ console.error(errorTree);
820
+
821
+ /*
822
+ {
823
+ message: "Property is invalid",
824
+ keyword: "properties",
825
+ item: "params",
826
+ schemaPath: "#/properties/params",
827
+ instancePath: "#/params",
828
+ data: { color: { type: "string", default: "red" } },
829
+ cause: {
830
+ message: "Additional properties are invalid",
831
+ keyword: "additionalProperties",
832
+ item: "color",
833
+ schemaPath: "#/properties/params/additionalProperties",
834
+ instancePath: "#/params/color",
835
+ data: { type: "string", default: "red" },
836
+ cause: {
837
+ message: "Required property is missing",
838
+ keyword: "required",
839
+ item: "description",
840
+ schemaPath: "#/properties/params/additionalProperties/required",
841
+ instancePath: "#/params/color/description",
842
+ data: undefined
843
+ }
844
+ }
845
+ }
846
+ */
847
+ }
848
+ ```
849
+
850
+ The `errorTree` object contains the full error chain with nested causes, allowing you to analyze the entire error structure.
851
+
852
+ ### Get the cause of the error
853
+
854
+ You can use the `getCause()` method to retrieve the root cause of a validation error. This method returns the nested ValidationError instance that triggered the current error and contains the `schemaPath` and `instancePath` properties.
855
+
856
+ ```javascript
857
+ import { SchemaShield } from "schema-shield";
858
+
859
+ const schemaShield = new SchemaShield();
860
+
861
+ const schema = {
862
+ type: "object",
863
+ properties: {
864
+ description: { type: "string" },
865
+ shouldLoadDb: { type: "boolean" },
866
+ enableNetConnectFor: { type: "array", items: { type: "string" } },
867
+ params: {
868
+ type: "object",
869
+ additionalProperties: {
870
+ type: "object",
871
+ properties: {
872
+ description: { type: "string" },
873
+ default: { type: "string" }
874
+ },
875
+ required: ["description"]
876
+ }
877
+ },
878
+ run: { type: "string" }
879
+ }
880
+ };
881
+
882
+ const validator = schemaShield.compile(schema);
883
+
884
+ const invalidData = {
885
+ description: "Say hello to the bot.",
886
+ shouldLoadDb: false,
887
+ enableNetConnectFor: [],
888
+ params: {
889
+ color: {
890
+ type: "string",
891
+ // description: "The color of the text", // Missing description on purpose
892
+ default: "red"
893
+ }
894
+ },
895
+ run: "run"
896
+ };
897
+
898
+ const validationResult = validator(invalidData);
899
+
900
+ if (validationResult.valid) {
901
+ console.log("Data is valid:", validationResult.data);
902
+ } else {
903
+ console.error("Validation error:", validationResult.error.message); // "Property is invalid"
904
+
905
+ // Get the root cause of the error
906
+ const errorCause = validationResult.error.getCause();
907
+ console.error("Root cause:", errorCause.message); // "Required property is missing"
908
+ console.error("Schema path:", errorCause.schemaPath); // "#/properties/params/additionalProperties/required"
909
+ console.error("Instance path:", errorCause.instancePath); // "#/params/color/description"
910
+ console.error("Error data:", errorCause.data); // undefined
911
+ console.error("Error schema:", errorCause.schema); // ["description"]
912
+ console.error("Error keyword:", errorCause.keyword); // "required"
913
+ }
914
+ ```
915
+
684
916
  ## Immutable Mode
685
917
 
686
918
  SchemaShield offers an optional immutable mode to prevent modifications to the input data during validation. In some cases, SchemaShield may mutate the data when using the `default` keyword or within custom added keywords.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { DefineErrorFunction, ValidationError } from "./utils";
2
+ export { ValidationError } from "./utils";
3
+ export { deepClone } from "./utils";
2
4
  export type Result = void | ValidationError;
3
5
  export interface KeywordFunction {
4
6
  (schema: CompiledSchema, data: any, defineError: DefineErrorFunction, instance: SchemaShield): Result;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,eAAe,EAKhB,MAAM,SAAS,CAAC;AAMjB,MAAM,MAAM,MAAM,GAAG,IAAI,GAAG,eAAe,CAAC;AAE5C,MAAM,WAAW,eAAe;IAC9B,CACE,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,GAAG,EACT,WAAW,EAAE,mBAAmB,EAChC,QAAQ,EAAE,YAAY,GACrB,MAAM,CAAC;CACX;AAED,MAAM,WAAW,YAAY;IAC3B,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,CAAC,IAAI,EAAE,GAAG,GAAG;QAAE,IAAI,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IAC1E,cAAc,EAAE,cAAc,CAAC;CAChC;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAA4C;IACzD,OAAO,CAAC,OAAO,CAA8C;IAC7D,OAAO,CAAC,QAAQ,CAA+C;IAC/D,OAAO,CAAC,SAAS,CAAS;gBAEd,EACV,SAAiB,EAClB,GAAE;QACD,SAAS,CAAC,EAAE,OAAO,CAAC;KAChB;IAoBN,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,UAAQ;IAOhE,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,KAAK;IAI3C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,SAAS,UAAQ;IAOpE,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,GAAG,KAAK;IAIjD,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,SAAS,UAAQ;IAOtE,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,GAAG,KAAK;IAIpD,OAAO,CAAC,MAAM,EAAE,GAAG,GAAG,SAAS;IA6B/B,OAAO,CAAC,aAAa;IAiIrB,YAAY,CAAC,SAAS,EAAE,GAAG,GAAG,OAAO;CActC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,eAAe,EAKhB,MAAM,SAAS,CAAC;AAMjB,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE1C,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC,MAAM,MAAM,MAAM,GAAG,IAAI,GAAG,eAAe,CAAC;AAE5C,MAAM,WAAW,eAAe;IAC9B,CACE,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,GAAG,EACT,WAAW,EAAE,mBAAmB,EAChC,QAAQ,EAAE,YAAY,GACrB,MAAM,CAAC;CACX;AAED,MAAM,WAAW,YAAY;IAC3B,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,CAAC,IAAI,EAAE,GAAG,GAAG;QAAE,IAAI,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IAC1E,cAAc,EAAE,cAAc,CAAC;CAChC;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAA4C;IACzD,OAAO,CAAC,OAAO,CAA8C;IAC7D,OAAO,CAAC,QAAQ,CAA+C;IAC/D,OAAO,CAAC,SAAS,CAAS;gBAEd,EACV,SAAiB,EAClB,GAAE;QACD,SAAS,CAAC,EAAE,OAAO,CAAC;KAChB;IAoBN,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,UAAQ;IAOhE,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,KAAK;IAI3C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,SAAS,UAAQ;IAOpE,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,GAAG,KAAK;IAIjD,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,SAAS,UAAQ;IAOtE,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,GAAG,KAAK;IAIpD,OAAO,CAAC,MAAM,EAAE,GAAG,GAAG,SAAS;IA6B/B,OAAO,CAAC,aAAa;IA0IrB,YAAY,CAAC,SAAS,EAAE,GAAG,GAAG,OAAO;CActC"}
package/dist/index.js CHANGED
@@ -19,7 +19,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
19
19
  // lib/index.ts
20
20
  var lib_exports = {};
21
21
  __export(lib_exports, {
22
- SchemaShield: () => SchemaShield
22
+ SchemaShield: () => SchemaShield,
23
+ ValidationError: () => ValidationError,
24
+ deepClone: () => deepClone
23
25
  });
24
26
  module.exports = __toCommonJS(lib_exports);
25
27
 
@@ -29,20 +31,54 @@ var ValidationError = class extends Error {
29
31
  item;
30
32
  keyword;
31
33
  cause;
32
- path = "";
34
+ schemaPath = "";
35
+ instancePath = "";
33
36
  data;
34
37
  schema;
35
- _getCause(pointer = "#") {
36
- const path = pointer + "/" + this.keyword + (typeof this.item !== "undefined" ? "/" + this.item : "");
37
- if (!this.cause) {
38
- this.path = path;
38
+ _getCause(pointer = "#", instancePointer = "#") {
39
+ let schemaPath = `${pointer}/${this.keyword}`;
40
+ let instancePath = `${instancePointer}`;
41
+ if (typeof this.item !== "undefined") {
42
+ if (typeof this.item === "string" && this.item in this.schema) {
43
+ schemaPath += `/${this.item}`;
44
+ }
45
+ instancePath += `/${this.item}`;
46
+ }
47
+ this.instancePath = instancePath;
48
+ this.schemaPath = schemaPath;
49
+ if (!this.cause || !(this.cause instanceof ValidationError)) {
39
50
  return this;
40
51
  }
41
- return this.cause._getCause(path);
52
+ return this.cause._getCause(schemaPath, instancePath);
42
53
  }
43
54
  getCause() {
44
55
  return this._getCause();
45
56
  }
57
+ _getTree() {
58
+ const tree = {
59
+ message: this.message,
60
+ keyword: this.keyword,
61
+ item: this.item,
62
+ schemaPath: this.schemaPath,
63
+ instancePath: this.instancePath,
64
+ data: this.data
65
+ };
66
+ if (this.cause) {
67
+ tree.cause = this.cause._getTree();
68
+ }
69
+ return tree;
70
+ }
71
+ getTree() {
72
+ this.getCause();
73
+ return this._getTree();
74
+ }
75
+ getPath() {
76
+ const cause = this.getCause();
77
+ return {
78
+ schemaPath: cause.schemaPath,
79
+ instancePath: cause.instancePath
80
+ };
81
+ }
46
82
  };
47
83
  function getDefinedErrorFunctionForKey(key, schema) {
48
84
  const KeywordError = new ValidationError(`Invalid ${key}`);
@@ -1127,7 +1163,7 @@ var SchemaShield = class {
1127
1163
  };
1128
1164
  }
1129
1165
  }
1130
- const compiledSchema = { ...schema };
1166
+ const compiledSchema = deepClone(schema);
1131
1167
  const defineTypeError = getDefinedErrorFunctionForKey("type", schema);
1132
1168
  const typeValidations = [];
1133
1169
  let methodName = "";
@@ -1208,6 +1244,14 @@ var SchemaShield = class {
1208
1244
  }
1209
1245
  }
1210
1246
  if (isObject(schema[key])) {
1247
+ if (key === "properties") {
1248
+ for (const subKey of Object.keys(schema[key])) {
1249
+ compiledSchema[key][subKey] = this.compileSchema(
1250
+ schema[key][subKey]
1251
+ );
1252
+ }
1253
+ continue;
1254
+ }
1211
1255
  compiledSchema[key] = this.compileSchema(schema[key]);
1212
1256
  continue;
1213
1257
  }
package/dist/index.min.js CHANGED
@@ -1 +1 @@
1
- (()=>{var e=class extends Error{message;item;keyword;cause;path="";data;schema;_getCause(e="#"){const t=e+"/"+this.keyword+(void 0!==this.item?"/"+this.item:"");return this.cause?this.cause._getCause(t):(this.path=t,this)}getCause(){return this._getCause()}};function t(t,i){const r=new e(`Invalid ${t}`);r.keyword=t,r.schema=i;return o(`defineError_${t}`,(e,t={})=>(r.message=e,r.item=t.item,r.cause=t.cause,r.data=t.data,r))}function i(e,t){if(Array.isArray(e)&&Array.isArray(t)){if(e.length!==t.length)return!1;for(let r=0;r<e.length;r++)if(!i(e[r],t[r]))return!1;return!0}if("object"==typeof e&&"object"==typeof t){if(null===e||null===t)return e===t;const r=Object.keys(e);if(r.length!==Object.keys(t).length)return!1;for(const n of r)if(!i(e[n],t[n]))return!1;return!0}return e===t}function r(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function n(e){if(Array.isArray(e)){const t=[];for(let i=0;i<e.length;i++)t[i]=n(e[i]);return t}if(e&&e.constructor&&"Object"!==e.constructor.name)return e;if(r(e)){const t={...e};for(const i in e)t[i]=n(e[i]);return t}return e}function a(e){return r(e)&&"$validate"in e}function o(e,t){return Object.defineProperty(t,"name",{value:e})}var s={"date-time"(e){const t=e.match(/^(\d{4})-(0[0-9]|1[0-2])-(\d{2})T(0[0-9]|1\d|2[0-3]):([0-5]\d):((?:[0-5]\d|60))(?:.\d+)?(?:([+-])(0[0-9]|1\d|2[0-3]):([0-5]\d)|Z)?$/i);if(!t)return!1;let i=Number(t[3]);if("02"===t[2]&&i>29)return!1;const[,r,n,,a,o,s,l,f,u]=t;let d=Number(r),m=Number(n),c=Number(a),p=Number(o),y=Number(s);if("-"===l||"+"===l){const e=Number(f),t=Number(u);if("-"===l?(c+=e,p+=t):"+"===l&&(c-=e,p-=t),p>59?(c+=1,p-=60):p<0&&(c-=1,p+=60),c>23?(i+=1,c-=24):c<0&&(i-=1,c+=24),i>31?(m+=1,i-=31):i<1&&(m-=1,i+=31),m>12?(d+=1,m-=12):m<1&&(d-=1,m+=12),d<0)return!1}return!(i>(2===m?d%4!=0||d%100==0&&d%400!=0?28:29:[31,,31,30,31,30,31,31,30,31,30,31][m-1]))&&(60!==y||59===p&&23===c)},uri:e=>/^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/.test(e),email:e=>/^(?!\.)(?!.*\.$)[a-z0-9!#$%&'*+/=?^_`{|}~-]{1,20}(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]{1,21}){0,2}@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,60}[a-z0-9])?){0,3}$/i.test(e),ipv4:e=>/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])$/.test(e),ipv6(e){if("::"===e)return!0;if(-1===e.indexOf(":")||/(?:\s+|:::+|^\w{5,}|\w{5}$|^:{1}\w|\w:{1}$)/.test(e))return!1;const t=-1!==e.indexOf(".");let i=e;if(t){i=e.split(":");const t=i.pop();if(!/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])$/.test(t))return!1}const r=-1!==e.indexOf("::"),n=t?i.join(":"):e;if(r)return!(n.split("::").length-1>1)&&(!!/^[0-9a-fA-F:.]*$/.test(n)&&/^(?:(?:(?:[0-9a-fA-F]{1,4}(?::|$)){1,6}))|(?:::(?:[0-9a-fA-F]{1,4})){0,5}$/.test(n));const a=/^(?:(?:[0-9a-fA-F]{1,4}:){7}(?:[0-9a-fA-F]{1,4}|:))$/.test(n),o=/(?:[0-9a-fA-F]{5,}|\D[0-9a-fA-F]{3}:)/.test(n);return t?a||!o:a&&!o},hostname:e=>/^[a-z0-9][a-z0-9-]{0,62}(?:\.[a-z0-9][a-z0-9-]{0,62})*[a-z0-9]$/i.test(e),date:e=>!1!==/^(\d{4})-(\d{2})-(\d{2})$/.test(e)&&!isNaN(new Date(e).getTime()),regex(e){try{return new RegExp(e),!0}catch(e){return!1}},"json-pointer":e=>""===e||/^\/(?:[^~]|~0|~1)*$/.test(e),"relative-json-pointer":e=>""===e||/^([0-9]+)(#|\/(?:[^~]|~0|~1)*)?$/.test(e),time:e=>/^(\d{2}):(\d{2}):(\d{2})(\.\d+)?(Z|([+-])(\d{2}):(\d{2}))$/.test(e),"uri-reference":e=>!/\\/.test(e)&&/^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#((?![^#]*\\)[^#]*))?/i.test(e),"uri-template":e=>/^(?:(?:https?:\/\/[\w.-]+)?\/?)?[\w- ;,.\/?%&=]*(?:\{[\w-]+(?::\d+)?\}[\w- ;,.\/?%&=]*)*\/?$/.test(e),duration:!1,uuid:!1,"idn-email":!1,"idn-hostname":!1,iri:!1,"iri-reference":!1},l={object:e=>r(e),array:e=>!!Array.isArray(e)||"object"==typeof e&&null!==e&&"length"in e&&"0"in e&&Object.keys(e).length-1===e.length,string:e=>"string"==typeof e,number:e=>"number"==typeof e,integer:e=>"number"==typeof e&&e%1==0,boolean:e=>"boolean"==typeof e,null:e=>null===e,timestamp:!1,int8:!1,unit8:!1,int16:!1,unit16:!1,int32:!1,unit32:!1,float32:!1,float64:!1},f={...{required(e,t,i){if(r(t))for(let r=0;r<e.required.length;r++){const n=e.required[r];if(!t.hasOwnProperty(n))return i("Required property is missing",{item:n,data:t[n]})}},properties(e,t,i){if(r(t))for(const n of Object.keys(e.properties))if(t.hasOwnProperty(n)){if("boolean"!=typeof e.properties[n]){if("$validate"in e.properties[n]){const r=e.properties[n].$validate(t[n]);if(r)return i("Property is invalid",{item:n,cause:r,data:t[n]})}}else if(!1===e.properties[n])return i("Property is not allowed",{item:n,data:t[n]})}else{const i=e.properties[n];r(i)&&"default"in i&&(t[n]=i.default)}},values(e,t,i){if(!r(t)||!a(e.values))return;const n=Object.keys(t);for(const r of n){const n=e.values.$validate(t[r]);if(n)return i("Property is invalid",{item:r,cause:n,data:t[r]})}},maxProperties(e,t,i){if(r(t)&&!(Object.keys(t).length<=e.maxProperties))return i("Too many properties",{data:t})},minProperties(e,t,i){if(r(t)&&!(Object.keys(t).length>=e.minProperties))return i("Too few properties",{data:t})},additionalProperties(e,t,i){if(!r(t))return;const n=Object.keys(t),o=a(e.additionalProperties);for(const r of n)if(!e.properties||!e.properties.hasOwnProperty(r)){if(e.patternProperties){let t=!1;for(const i in e.patternProperties)if(new RegExp(i,"u").test(r)){t=!0;break}if(t)continue}if(!1===e.additionalProperties)return i("Additional properties are not allowed",{item:r,data:t[r]});if(o){const n=e.additionalProperties.$validate(t[r]);if(n)return i("Additional properties are invalid",{item:r,cause:n,data:t[r]})}}},patternProperties(e,t,i){if(!r(t))return;const n=Object.keys(e.patternProperties);for(const r of n){const n=new RegExp(r,"u");if("boolean"==typeof e.patternProperties[r]){if(!1===e.patternProperties[r])for(const e in t)if(n.test(e))return i("Property is not allowed",{item:e,data:t[e]});continue}const a=Object.keys(t);for(const o of a)if(n.test(o)&&"$validate"in e.patternProperties[r]){const n=e.patternProperties[r].$validate(t[o]);if(n)return i("Property is invalid",{item:o,cause:n,data:t[o]})}}},propertyNames(e,t,i){if(r(t)){if("boolean"==typeof e.propertyNames&&!1===e.propertyNames&&Object.keys(t).length>0)return i("Properties are not allowed",{data:t});if(a(e.propertyNames))for(let r in t){const n=e.propertyNames.$validate(r);if(n)return i("Property name is invalid",{item:r,cause:n,data:t[r]})}}},dependencies(e,t,i){if(r(t))for(const r in e.dependencies){if(r in t==!1)continue;const n=e.dependencies[r];if(Array.isArray(n)){for(let e=0;e<n.length;e++)if(!(n[e]in t))return i("Dependency is not satisfied",{item:e,data:n[e]});continue}if("boolean"==typeof n){if(n)continue;return i("Dependency is not satisfied",{data:n})}if("string"==typeof n){if(n in t)continue;return i("Dependency is not satisfied",{data:n})}const a=n.$validate(t);if(a)return i("Dependency is not satisfied",{cause:a,data:t})}},then:!1,else:!1,default:!1,$ref:!1,definitions:!1,$id:!1,$schema:!1,title:!1,description:!1,$comment:!1,examples:!1,contentMediaType:!1,contentEncoding:!1,discriminator:!1,nullable:!1},...{items(e,t,i){if(!Array.isArray(t))return;const r=e.items,n=t.length;if("boolean"==typeof r)return!1===r&&n>0?i("Array items are not allowed",{data:t}):void 0;if(Array.isArray(r)){const e=r.length,o=Math.min(e,n);for(let e=0;e<o;e++){const n=r[e];if("boolean"!=typeof n){if(a(n)){const r=n.$validate(t[e]);if(r)return i("Array item is invalid",{item:e,cause:r,data:t[e]})}}else if(!1===n&&void 0!==t[e])return i("Array item is not allowed",{item:e,data:t[e]})}}else if(a(r))for(let e=0;e<n;e++){const n=r.$validate(t[e]);if(n)return i("Array item is invalid",{item:e,cause:n,data:t[e]})}},elements(e,t,i){if(Array.isArray(t)&&a(e.elements))for(let r=0;r<t.length;r++){const n=e.elements.$validate(t[r]);if(n)return i("Array item is invalid",{item:r,cause:n,data:t[r]})}},minItems(e,t,i){if(Array.isArray(t)&&!(t.length>=e.minItems))return i("Array is too short",{data:t})},maxItems(e,t,i){if(Array.isArray(t)&&!(t.length<=e.maxItems))return i("Array is too long",{data:t})},additionalItems(e,t,i){if(e.items&&!r(e.items)){if(!1===e.additionalItems)return t.length>e.items.length?i("Array is too long",{data:t}):void 0;if(r(e.additionalItems)){if(a(e.additionalItems)){for(let r=e.items.length;r<t.length;r++){const n=e.additionalItems.$validate(t[r]);if(n)return i("Array item is invalid",{item:r,cause:n,data:t[r]})}return}}else;}},uniqueItems(e,t,i){if(!Array.isArray(t)||!e.uniqueItems)return;const n=new Set;for(const e of t){let t;if(t="string"==typeof e?`s:${e}`:r(e)?`o:${JSON.stringify(Object.fromEntries(Object.entries(e).sort(([e],[t])=>e.localeCompare(t))))}`:Array.isArray(e)?JSON.stringify(e):String(e),n.has(t))return i("Array items are not unique",{data:e});n.add(t)}},contains(e,t,i){if(Array.isArray(t)){if("boolean"==typeof e.contains)return e.contains?0===t.length?i("Array must contain at least one item",{data:t}):void 0:i("Array must not contain any items",{data:t});for(let i=0;i<t.length;i++){if(!e.contains.$validate(t[i]))return}return i("Array must contain at least one item",{data:t})}}},...{minLength(e,t,i){if(!("string"!=typeof t||t.length>=e.minLength))return i("Value is shorter than the minimum length",{data:t})},maxLength(e,t,i){if(!("string"!=typeof t||t.length<=e.maxLength))return i("Value is longer than the maximum length",{data:t})},pattern(e,t,i){if("string"!=typeof t)return;const r=new RegExp(e.pattern,"u");return r instanceof RegExp==!1?i("Invalid regular expression",{data:t}):r.test(t)?void 0:i("Value does not match the pattern",{data:t})},format(e,t,i,r){if("string"!=typeof t)return;const n=r.getFormat(e.format);return n&&!n(t)?i("Value does not match the format",{data:t}):void 0}},...{minimum(e,t,i,r){if("number"!=typeof t)return;let n=e.minimum;return"number"==typeof e.exclusiveMinimum?n=e.exclusiveMinimum+1e-15:!0===e.exclusiveMinimum&&(n+=1e-15),t<n?i("Value is less than the minimum",{data:t}):void 0},maximum(e,t,i,r){if("number"!=typeof t)return;let n=e.maximum;return"number"==typeof e.exclusiveMaximum?n=e.exclusiveMaximum-1e-15:!0===e.exclusiveMaximum&&(n-=1e-15),t>n?i("Value is greater than the maximum",{data:t}):void 0},multipleOf(e,t,i,r){if("number"!=typeof t)return;const n=t/e.multipleOf;return isFinite(n)?function(e,t,i=1e-15){return Math.abs(e-t)<=i*Math.max(Math.abs(e),Math.abs(t))}(n,Math.round(n))?void 0:i("Value is not a multiple of the multipleOf",{data:t}):void 0},exclusiveMinimum(e,t,i,r){if("number"==typeof t&&"number"==typeof e.exclusiveMinimum&&!("minimum"in e))return t<=e.exclusiveMinimum+1e-15?i("Value is less than or equal to the exclusiveMinimum"):void 0},exclusiveMaximum(e,t,i,r){if("number"==typeof t&&"number"==typeof e.exclusiveMaximum&&!("maximum"in e))return t>=e.exclusiveMaximum?i("Value is greater than or equal to the exclusiveMaximum",{data:t}):void 0}},...{enum(e,t,r){const n=Array.isArray(t),a="object"==typeof t&&null!==t;for(let r=0;r<e.enum.length;r++){const o=e.enum[r];if(o===t)return;if((n&&Array.isArray(o)||a&&"object"==typeof o&&null!==o)&&i(o,t))return}return r("Value is not one of the allowed values",{data:t})},allOf(e,t,i){for(let n=0;n<e.allOf.length;n++)if(r(e.allOf[n])){if("$validate"in e.allOf[n]){const r=e.allOf[n].$validate(t);if(r)return i("Value is not valid",{cause:r,data:t})}}else if("boolean"!=typeof e.allOf[n]){if(t!==e.allOf[n])return i("Value is not valid",{data:t})}else if(Boolean(t)!==e.allOf[n])return i("Value is not valid",{data:t})},anyOf(e,t,i){for(let i=0;i<e.anyOf.length;i++){if(r(e.anyOf[i])){if("$validate"in e.anyOf[i]){if(!e.anyOf[i].$validate(t))return;continue}return}if("boolean"==typeof e.anyOf[i]&&Boolean(t)===e.anyOf[i])return;if(t===e.anyOf[i])return}return i("Value is not valid",{data:t})},oneOf(e,t,i){let n=0;for(let i=0;i<e.oneOf.length;i++)if(r(e.oneOf[i])){if("$validate"in e.oneOf[i]){e.oneOf[i].$validate(t)||n++;continue}n++}else"boolean"!=typeof e.oneOf[i]?t===e.oneOf[i]&&n++:Boolean(t)===e.oneOf[i]&&n++;if(1!==n)return i("Value is not valid",{data:t})},const(e,t,n){if(!(t===e.const||r(t)&&r(e.const)&&i(t,e.const)||Array.isArray(t)&&Array.isArray(e.const)&&i(t,e.const)))return n("Value is not valid",{data:t})},if(e,t,i){if("then"in e==!1&&"else"in e==!1)return;if("boolean"==typeof e.if){if(e.if){if(a(e.then))return e.then.$validate(t)}else if(a(e.else))return e.else.$validate(t);return}if(!a(e.if))return;return e.if.$validate(t)?a(e.else)?e.else.$validate(t):void 0:a(e.then)?e.then.$validate(t):void 0},not(e,t,i){if("boolean"==typeof e.not)return e.not?i("Value is not valid",{data:t}):void 0;if(r(e.not)){if("$validate"in e.not){const r=e.not.$validate(t);return r?void 0:i("Value is not valid",{cause:r,data:t})}return i("Value is not valid",{data:t})}return i("Value is not valid",{data:t})}}},u={SchemaShield:class{types={};formats={};keywords={};immutable=!1;constructor({immutable:e=!1}={}){this.immutable=e;for(const[e,t]of Object.entries(l))t&&this.addType(e,t);for(const[e,t]of Object.entries(f))this.addKeyword(e,t);for(const[e,t]of Object.entries(s))t&&this.addFormat(e,t)}addType(t,i,r=!1){if(this.types[t]&&!r)throw new e(`Type "${t}" already exists`);this.types[t]=i}getType(e){return this.types[e]}addFormat(t,i,r=!1){if(this.formats[t]&&!r)throw new e(`Format "${t}" already exists`);this.formats[t]=i}getFormat(e){return this.formats[e]}addKeyword(t,i,r=!1){if(this.keywords[t]&&!r)throw new e(`Keyword "${t}" already exists`);this.keywords[t]=i}getKeyword(e){return this.keywords[e]}compile(t){const i=this.compileSchema(t);if(!i.$validate){if(!1===this.isSchemaLike(t))throw new e("Invalid schema");i.$validate=o("any",()=>{})}const r=e=>{const t=this.immutable?n(e):e,r=i.$validate(t);return{data:t,error:r||null,valid:!r}};return r.compiledSchema=i,r}compileSchema(e){r(e)||(e=!0===e?{anyOf:[{}]}:!1===e?{oneOf:[]}:{oneOf:[e]});const i={...e},n=t("type",e),a=[];let s="";if("type"in e){const t=Array.isArray(e.type)?e.type:e.type.split(",").map(e=>e.trim());for(const e of t){const t=this.getType(e);t&&(a.push(t),s+=(s?"_OR_":"")+t.name)}const r=a.length;if(0===r)throw n("Invalid type for schema",{data:e.type});if(1===r){const e=a[0];i.$validate=o(s,t=>{if(!e(t))return n("Invalid type",{data:t})})}else r>1&&(i.$validate=o(s,e=>{for(let t=0;t<r;t++)if(a[t](e))return;return n("Invalid type",{data:e})}))}for(const n of Object.keys(e)){if("type"===n){i.type=e.type;continue}const a=this.getKeyword(n);if(a){const r=t(n,e[n]);if(i.$validate){const e=i.$validate;s+=`_AND_${a.name}`,i.$validate=o(s,t=>{const n=e(t);return n||a(i,t,r,this)})}else s=a.name,i.$validate=o(s,e=>a(i,e,r,this))}r(e[n])?i[n]=this.compileSchema(e[n]):Array.isArray(e[n])?i[n]=e[n].map((e,t)=>this.isSchemaLike(e)?this.compileSchema(e):e):i[n]=e[n]}return i}isSchemaLike(e){if(r(e)){if("type"in e)return!0;for(let t in e)if(t in this.keywords)return!0}return!1}}};"undefined"!=typeof module?module.exports=u:self.SchemaShield=u})();//# sourceMappingURL=index.min.js.map
1
+ (()=>{var e=class extends Error{message;item;keyword;cause;schemaPath="";instancePath="";data;schema;_getCause(t="#",i="#"){let r=`${t}/${this.keyword}`,a=`${i}`;return void 0!==this.item&&("string"==typeof this.item&&this.item in this.schema&&(r+=`/${this.item}`),a+=`/${this.item}`),this.instancePath=a,this.schemaPath=r,this.cause&&this.cause instanceof e?this.cause._getCause(r,a):this}getCause(){return this._getCause()}_getTree(){const e={message:this.message,keyword:this.keyword,item:this.item,schemaPath:this.schemaPath,instancePath:this.instancePath,data:this.data};return this.cause&&(e.cause=this.cause._getTree()),e}getTree(){return this.getCause(),this._getTree()}getPath(){const e=this.getCause();return{schemaPath:e.schemaPath,instancePath:e.instancePath}}};function t(t,i){const r=new e(`Invalid ${t}`);r.keyword=t,r.schema=i;return s(`defineError_${t}`,(e,t={})=>(r.message=e,r.item=t.item,r.cause=t.cause,r.data=t.data,r))}function i(e,t){if(Array.isArray(e)&&Array.isArray(t)){if(e.length!==t.length)return!1;for(let r=0;r<e.length;r++)if(!i(e[r],t[r]))return!1;return!0}if("object"==typeof e&&"object"==typeof t){if(null===e||null===t)return e===t;const r=Object.keys(e);if(r.length!==Object.keys(t).length)return!1;for(const a of r)if(!i(e[a],t[a]))return!1;return!0}return e===t}function r(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function a(e){if(Array.isArray(e)){const t=[];for(let i=0;i<e.length;i++)t[i]=a(e[i]);return t}if(e&&e.constructor&&"Object"!==e.constructor.name)return e;if(r(e)){const t={...e};for(const i in e)t[i]=a(e[i]);return t}return e}function n(e){return r(e)&&"$validate"in e}function s(e,t){return Object.defineProperty(t,"name",{value:e})}var o={"date-time"(e){const t=e.match(/^(\d{4})-(0[0-9]|1[0-2])-(\d{2})T(0[0-9]|1\d|2[0-3]):([0-5]\d):((?:[0-5]\d|60))(?:.\d+)?(?:([+-])(0[0-9]|1\d|2[0-3]):([0-5]\d)|Z)?$/i);if(!t)return!1;let i=Number(t[3]);if("02"===t[2]&&i>29)return!1;const[,r,a,,n,s,o,l,u,f]=t;let d=Number(r),m=Number(a),c=Number(n),p=Number(s),y=Number(o);if("-"===l||"+"===l){const e=Number(u),t=Number(f);if("-"===l?(c+=e,p+=t):"+"===l&&(c-=e,p-=t),p>59?(c+=1,p-=60):p<0&&(c-=1,p+=60),c>23?(i+=1,c-=24):c<0&&(i-=1,c+=24),i>31?(m+=1,i-=31):i<1&&(m-=1,i+=31),m>12?(d+=1,m-=12):m<1&&(d-=1,m+=12),d<0)return!1}return!(i>(2===m?d%4!=0||d%100==0&&d%400!=0?28:29:[31,,31,30,31,30,31,31,30,31,30,31][m-1]))&&(60!==y||59===p&&23===c)},uri:e=>/^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/.test(e),email:e=>/^(?!\.)(?!.*\.$)[a-z0-9!#$%&'*+/=?^_`{|}~-]{1,20}(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]{1,21}){0,2}@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,60}[a-z0-9])?){0,3}$/i.test(e),ipv4:e=>/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])$/.test(e),ipv6(e){if("::"===e)return!0;if(-1===e.indexOf(":")||/(?:\s+|:::+|^\w{5,}|\w{5}$|^:{1}\w|\w:{1}$)/.test(e))return!1;const t=-1!==e.indexOf(".");let i=e;if(t){i=e.split(":");const t=i.pop();if(!/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])$/.test(t))return!1}const r=-1!==e.indexOf("::"),a=t?i.join(":"):e;if(r)return!(a.split("::").length-1>1)&&(!!/^[0-9a-fA-F:.]*$/.test(a)&&/^(?:(?:(?:[0-9a-fA-F]{1,4}(?::|$)){1,6}))|(?:::(?:[0-9a-fA-F]{1,4})){0,5}$/.test(a));const n=/^(?:(?:[0-9a-fA-F]{1,4}:){7}(?:[0-9a-fA-F]{1,4}|:))$/.test(a),s=/(?:[0-9a-fA-F]{5,}|\D[0-9a-fA-F]{3}:)/.test(a);return t?n||!s:n&&!s},hostname:e=>/^[a-z0-9][a-z0-9-]{0,62}(?:\.[a-z0-9][a-z0-9-]{0,62})*[a-z0-9]$/i.test(e),date:e=>!1!==/^(\d{4})-(\d{2})-(\d{2})$/.test(e)&&!isNaN(new Date(e).getTime()),regex(e){try{return new RegExp(e),!0}catch(e){return!1}},"json-pointer":e=>""===e||/^\/(?:[^~]|~0|~1)*$/.test(e),"relative-json-pointer":e=>""===e||/^([0-9]+)(#|\/(?:[^~]|~0|~1)*)?$/.test(e),time:e=>/^(\d{2}):(\d{2}):(\d{2})(\.\d+)?(Z|([+-])(\d{2}):(\d{2}))$/.test(e),"uri-reference":e=>!/\\/.test(e)&&/^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#((?![^#]*\\)[^#]*))?/i.test(e),"uri-template":e=>/^(?:(?:https?:\/\/[\w.-]+)?\/?)?[\w- ;,.\/?%&=]*(?:\{[\w-]+(?::\d+)?\}[\w- ;,.\/?%&=]*)*\/?$/.test(e),duration:!1,uuid:!1,"idn-email":!1,"idn-hostname":!1,iri:!1,"iri-reference":!1},l={object:e=>r(e),array:e=>!!Array.isArray(e)||"object"==typeof e&&null!==e&&"length"in e&&"0"in e&&Object.keys(e).length-1===e.length,string:e=>"string"==typeof e,number:e=>"number"==typeof e,integer:e=>"number"==typeof e&&e%1==0,boolean:e=>"boolean"==typeof e,null:e=>null===e,timestamp:!1,int8:!1,unit8:!1,int16:!1,unit16:!1,int32:!1,unit32:!1,float32:!1,float64:!1},u={...{required(e,t,i){if(r(t))for(let r=0;r<e.required.length;r++){const a=e.required[r];if(!t.hasOwnProperty(a))return i("Required property is missing",{item:a,data:t[a]})}},properties(e,t,i){if(r(t))for(const a of Object.keys(e.properties))if(t.hasOwnProperty(a)){if("boolean"!=typeof e.properties[a]){if("$validate"in e.properties[a]){const r=e.properties[a].$validate(t[a]);if(r)return i("Property is invalid",{item:a,cause:r,data:t[a]})}}else if(!1===e.properties[a])return i("Property is not allowed",{item:a,data:t[a]})}else{const i=e.properties[a];r(i)&&"default"in i&&(t[a]=i.default)}},values(e,t,i){if(!r(t)||!n(e.values))return;const a=Object.keys(t);for(const r of a){const a=e.values.$validate(t[r]);if(a)return i("Property is invalid",{item:r,cause:a,data:t[r]})}},maxProperties(e,t,i){if(r(t)&&!(Object.keys(t).length<=e.maxProperties))return i("Too many properties",{data:t})},minProperties(e,t,i){if(r(t)&&!(Object.keys(t).length>=e.minProperties))return i("Too few properties",{data:t})},additionalProperties(e,t,i){if(!r(t))return;const a=Object.keys(t),s=n(e.additionalProperties);for(const r of a)if(!e.properties||!e.properties.hasOwnProperty(r)){if(e.patternProperties){let t=!1;for(const i in e.patternProperties)if(new RegExp(i,"u").test(r)){t=!0;break}if(t)continue}if(!1===e.additionalProperties)return i("Additional properties are not allowed",{item:r,data:t[r]});if(s){const a=e.additionalProperties.$validate(t[r]);if(a)return i("Additional properties are invalid",{item:r,cause:a,data:t[r]})}}},patternProperties(e,t,i){if(!r(t))return;const a=Object.keys(e.patternProperties);for(const r of a){const a=new RegExp(r,"u");if("boolean"==typeof e.patternProperties[r]){if(!1===e.patternProperties[r])for(const e in t)if(a.test(e))return i("Property is not allowed",{item:e,data:t[e]});continue}const n=Object.keys(t);for(const s of n)if(a.test(s)&&"$validate"in e.patternProperties[r]){const a=e.patternProperties[r].$validate(t[s]);if(a)return i("Property is invalid",{item:s,cause:a,data:t[s]})}}},propertyNames(e,t,i){if(r(t)){if("boolean"==typeof e.propertyNames&&!1===e.propertyNames&&Object.keys(t).length>0)return i("Properties are not allowed",{data:t});if(n(e.propertyNames))for(let r in t){const a=e.propertyNames.$validate(r);if(a)return i("Property name is invalid",{item:r,cause:a,data:t[r]})}}},dependencies(e,t,i){if(r(t))for(const r in e.dependencies){if(r in t==!1)continue;const a=e.dependencies[r];if(Array.isArray(a)){for(let e=0;e<a.length;e++)if(!(a[e]in t))return i("Dependency is not satisfied",{item:e,data:a[e]});continue}if("boolean"==typeof a){if(a)continue;return i("Dependency is not satisfied",{data:a})}if("string"==typeof a){if(a in t)continue;return i("Dependency is not satisfied",{data:a})}const n=a.$validate(t);if(n)return i("Dependency is not satisfied",{cause:n,data:t})}},then:!1,else:!1,default:!1,$ref:!1,definitions:!1,$id:!1,$schema:!1,title:!1,description:!1,$comment:!1,examples:!1,contentMediaType:!1,contentEncoding:!1,discriminator:!1,nullable:!1},...{items(e,t,i){if(!Array.isArray(t))return;const r=e.items,a=t.length;if("boolean"==typeof r)return!1===r&&a>0?i("Array items are not allowed",{data:t}):void 0;if(Array.isArray(r)){const e=r.length,s=Math.min(e,a);for(let e=0;e<s;e++){const a=r[e];if("boolean"!=typeof a){if(n(a)){const r=a.$validate(t[e]);if(r)return i("Array item is invalid",{item:e,cause:r,data:t[e]})}}else if(!1===a&&void 0!==t[e])return i("Array item is not allowed",{item:e,data:t[e]})}}else if(n(r))for(let e=0;e<a;e++){const a=r.$validate(t[e]);if(a)return i("Array item is invalid",{item:e,cause:a,data:t[e]})}},elements(e,t,i){if(Array.isArray(t)&&n(e.elements))for(let r=0;r<t.length;r++){const a=e.elements.$validate(t[r]);if(a)return i("Array item is invalid",{item:r,cause:a,data:t[r]})}},minItems(e,t,i){if(Array.isArray(t)&&!(t.length>=e.minItems))return i("Array is too short",{data:t})},maxItems(e,t,i){if(Array.isArray(t)&&!(t.length<=e.maxItems))return i("Array is too long",{data:t})},additionalItems(e,t,i){if(e.items&&!r(e.items)){if(!1===e.additionalItems)return t.length>e.items.length?i("Array is too long",{data:t}):void 0;if(r(e.additionalItems)){if(n(e.additionalItems)){for(let r=e.items.length;r<t.length;r++){const a=e.additionalItems.$validate(t[r]);if(a)return i("Array item is invalid",{item:r,cause:a,data:t[r]})}return}}else;}},uniqueItems(e,t,i){if(!Array.isArray(t)||!e.uniqueItems)return;const a=new Set;for(const e of t){let t;if(t="string"==typeof e?`s:${e}`:r(e)?`o:${JSON.stringify(Object.fromEntries(Object.entries(e).sort(([e],[t])=>e.localeCompare(t))))}`:Array.isArray(e)?JSON.stringify(e):String(e),a.has(t))return i("Array items are not unique",{data:e});a.add(t)}},contains(e,t,i){if(Array.isArray(t)){if("boolean"==typeof e.contains)return e.contains?0===t.length?i("Array must contain at least one item",{data:t}):void 0:i("Array must not contain any items",{data:t});for(let i=0;i<t.length;i++){if(!e.contains.$validate(t[i]))return}return i("Array must contain at least one item",{data:t})}}},...{minLength(e,t,i){if(!("string"!=typeof t||t.length>=e.minLength))return i("Value is shorter than the minimum length",{data:t})},maxLength(e,t,i){if(!("string"!=typeof t||t.length<=e.maxLength))return i("Value is longer than the maximum length",{data:t})},pattern(e,t,i){if("string"!=typeof t)return;const r=new RegExp(e.pattern,"u");return r instanceof RegExp==!1?i("Invalid regular expression",{data:t}):r.test(t)?void 0:i("Value does not match the pattern",{data:t})},format(e,t,i,r){if("string"!=typeof t)return;const a=r.getFormat(e.format);return a&&!a(t)?i("Value does not match the format",{data:t}):void 0}},...{minimum(e,t,i,r){if("number"!=typeof t)return;let a=e.minimum;return"number"==typeof e.exclusiveMinimum?a=e.exclusiveMinimum+1e-15:!0===e.exclusiveMinimum&&(a+=1e-15),t<a?i("Value is less than the minimum",{data:t}):void 0},maximum(e,t,i,r){if("number"!=typeof t)return;let a=e.maximum;return"number"==typeof e.exclusiveMaximum?a=e.exclusiveMaximum-1e-15:!0===e.exclusiveMaximum&&(a-=1e-15),t>a?i("Value is greater than the maximum",{data:t}):void 0},multipleOf(e,t,i,r){if("number"!=typeof t)return;const a=t/e.multipleOf;return isFinite(a)?function(e,t,i=1e-15){return Math.abs(e-t)<=i*Math.max(Math.abs(e),Math.abs(t))}(a,Math.round(a))?void 0:i("Value is not a multiple of the multipleOf",{data:t}):void 0},exclusiveMinimum(e,t,i,r){if("number"==typeof t&&"number"==typeof e.exclusiveMinimum&&!("minimum"in e))return t<=e.exclusiveMinimum+1e-15?i("Value is less than or equal to the exclusiveMinimum"):void 0},exclusiveMaximum(e,t,i,r){if("number"==typeof t&&"number"==typeof e.exclusiveMaximum&&!("maximum"in e))return t>=e.exclusiveMaximum?i("Value is greater than or equal to the exclusiveMaximum",{data:t}):void 0}},...{enum(e,t,r){const a=Array.isArray(t),n="object"==typeof t&&null!==t;for(let r=0;r<e.enum.length;r++){const s=e.enum[r];if(s===t)return;if((a&&Array.isArray(s)||n&&"object"==typeof s&&null!==s)&&i(s,t))return}return r("Value is not one of the allowed values",{data:t})},allOf(e,t,i){for(let a=0;a<e.allOf.length;a++)if(r(e.allOf[a])){if("$validate"in e.allOf[a]){const r=e.allOf[a].$validate(t);if(r)return i("Value is not valid",{cause:r,data:t})}}else if("boolean"!=typeof e.allOf[a]){if(t!==e.allOf[a])return i("Value is not valid",{data:t})}else if(Boolean(t)!==e.allOf[a])return i("Value is not valid",{data:t})},anyOf(e,t,i){for(let i=0;i<e.anyOf.length;i++){if(r(e.anyOf[i])){if("$validate"in e.anyOf[i]){if(!e.anyOf[i].$validate(t))return;continue}return}if("boolean"==typeof e.anyOf[i]&&Boolean(t)===e.anyOf[i])return;if(t===e.anyOf[i])return}return i("Value is not valid",{data:t})},oneOf(e,t,i){let a=0;for(let i=0;i<e.oneOf.length;i++)if(r(e.oneOf[i])){if("$validate"in e.oneOf[i]){e.oneOf[i].$validate(t)||a++;continue}a++}else"boolean"!=typeof e.oneOf[i]?t===e.oneOf[i]&&a++:Boolean(t)===e.oneOf[i]&&a++;if(1!==a)return i("Value is not valid",{data:t})},const(e,t,a){if(!(t===e.const||r(t)&&r(e.const)&&i(t,e.const)||Array.isArray(t)&&Array.isArray(e.const)&&i(t,e.const)))return a("Value is not valid",{data:t})},if(e,t,i){if("then"in e==!1&&"else"in e==!1)return;if("boolean"==typeof e.if){if(e.if){if(n(e.then))return e.then.$validate(t)}else if(n(e.else))return e.else.$validate(t);return}if(!n(e.if))return;return e.if.$validate(t)?n(e.else)?e.else.$validate(t):void 0:n(e.then)?e.then.$validate(t):void 0},not(e,t,i){if("boolean"==typeof e.not)return e.not?i("Value is not valid",{data:t}):void 0;if(r(e.not)){if("$validate"in e.not){const r=e.not.$validate(t);return r?void 0:i("Value is not valid",{cause:r,data:t})}return i("Value is not valid",{data:t})}return i("Value is not valid",{data:t})}}},f={SchemaShield:class{types={};formats={};keywords={};immutable=!1;constructor({immutable:e=!1}={}){this.immutable=e;for(const[e,t]of Object.entries(l))t&&this.addType(e,t);for(const[e,t]of Object.entries(u))this.addKeyword(e,t);for(const[e,t]of Object.entries(o))t&&this.addFormat(e,t)}addType(t,i,r=!1){if(this.types[t]&&!r)throw new e(`Type "${t}" already exists`);this.types[t]=i}getType(e){return this.types[e]}addFormat(t,i,r=!1){if(this.formats[t]&&!r)throw new e(`Format "${t}" already exists`);this.formats[t]=i}getFormat(e){return this.formats[e]}addKeyword(t,i,r=!1){if(this.keywords[t]&&!r)throw new e(`Keyword "${t}" already exists`);this.keywords[t]=i}getKeyword(e){return this.keywords[e]}compile(t){const i=this.compileSchema(t);if(!i.$validate){if(!1===this.isSchemaLike(t))throw new e("Invalid schema");i.$validate=s("any",()=>{})}const r=e=>{const t=this.immutable?a(e):e,r=i.$validate(t);return{data:t,error:r||null,valid:!r}};return r.compiledSchema=i,r}compileSchema(e){r(e)||(e=!0===e?{anyOf:[{}]}:!1===e?{oneOf:[]}:{oneOf:[e]});const i=a(e),n=t("type",e),o=[];let l="";if("type"in e){const t=Array.isArray(e.type)?e.type:e.type.split(",").map(e=>e.trim());for(const e of t){const t=this.getType(e);t&&(o.push(t),l+=(l?"_OR_":"")+t.name)}const r=o.length;if(0===r)throw n("Invalid type for schema",{data:e.type});if(1===r){const e=o[0];i.$validate=s(l,t=>{if(!e(t))return n("Invalid type",{data:t})})}else r>1&&(i.$validate=s(l,e=>{for(let t=0;t<r;t++)if(o[t](e))return;return n("Invalid type",{data:e})}))}for(const a of Object.keys(e)){if("type"===a){i.type=e.type;continue}const n=this.getKeyword(a);if(n){const r=t(a,e[a]);if(i.$validate){const e=i.$validate;l+=`_AND_${n.name}`,i.$validate=s(l,t=>{const a=e(t);return a||n(i,t,r,this)})}else l=n.name,i.$validate=s(l,e=>n(i,e,r,this))}if(r(e[a])){if("properties"===a){for(const t of Object.keys(e[a]))i[a][t]=this.compileSchema(e[a][t]);continue}i[a]=this.compileSchema(e[a])}else Array.isArray(e[a])?i[a]=e[a].map((e,t)=>this.isSchemaLike(e)?this.compileSchema(e):e):i[a]=e[a]}return i}isSchemaLike(e){if(r(e)){if("type"in e)return!0;for(let t in e)if(t in this.keywords)return!0}return!1}},ValidationError:e,deepClone:a};"undefined"!=typeof module?module.exports=f:self.SchemaShield=f})();//# sourceMappingURL=index.min.js.map