json-schema-library 10.5.4 → 11.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +128 -14
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.d.cts +42 -19
  4. package/dist/index.d.mts +42 -19
  5. package/dist/index.mjs +1 -1
  6. package/dist/jlib.js +2 -2
  7. package/index.ts +8 -4
  8. package/package.json +6 -6
  9. package/src/Keyword.ts +8 -3
  10. package/src/SchemaNode.ts +46 -10
  11. package/src/compileSchema.validate.test.ts +89 -54
  12. package/src/draft04.ts +10 -8
  13. package/src/draft06.ts +10 -8
  14. package/src/draft07.ts +10 -8
  15. package/src/draft2019-09/keywords/additionalItems.ts +2 -2
  16. package/src/draft2019-09/keywords/items.ts +2 -2
  17. package/src/draft2019-09/keywords/unevaluatedItems.ts +12 -6
  18. package/src/draft2019.ts +10 -8
  19. package/src/draft2020.ts +8 -6
  20. package/src/errors/errors.ts +3 -1
  21. package/src/formats/formats.ts +2 -6
  22. package/src/keywords/additionalProperties.ts +2 -2
  23. package/src/keywords/allOf.ts +2 -2
  24. package/src/keywords/dependencies.ts +5 -6
  25. package/src/keywords/dependentRequired.ts +2 -2
  26. package/src/keywords/dependentSchemas.ts +4 -3
  27. package/src/keywords/deprecated.ts +18 -0
  28. package/src/keywords/items.ts +2 -2
  29. package/src/keywords/oneOf.test.ts +150 -15
  30. package/src/keywords/oneOf.ts +64 -4
  31. package/src/keywords/patternProperties.ts +2 -2
  32. package/src/keywords/prefixItems.ts +2 -11
  33. package/src/keywords/properties.ts +2 -2
  34. package/src/keywords/unevaluatedItems.ts +2 -2
  35. package/src/keywords/unevaluatedProperties.ts +2 -2
  36. package/src/methods/getData.test.ts +1779 -1781
  37. package/src/types.ts +32 -18
  38. package/src/utils/sanitizeErrors.ts +9 -8
  39. package/src/validateNode.ts +2 -2
package/README.md CHANGED
@@ -29,7 +29,7 @@ import myData from "./myData.json";
29
29
 
30
30
  const schema: SchemaNode = compileSchema(myJsonSchema);
31
31
  // validate data and collect errors if invalid
32
- const { valid, errors } = schema.validate(myData);
32
+ const { valid, errors, annotations } = schema.validate(myData);
33
33
  // create data which validates to the compiled JSON Schema
34
34
  const defaultData = schema.getData();
35
35
  // access a subschema at a specific JSON Pointer location
@@ -108,6 +108,8 @@ const titleData = titleNode?.getData();
108
108
 
109
109
  <details><summary>Each node has an identity</summary>
110
110
 
111
+ ---
112
+
111
113
  ```ts
112
114
  const titleNode = compileSchema(mySchema).getNode("#/image/title");
113
115
  console.log(titleNode.evaluationPath); // #/properties/image/properties/title
@@ -117,10 +119,14 @@ console.log(titleNode.schemaLocation); // #/properties/image/properties/title
117
119
  - `evaluationPath` refers to the path in schema and is extended by `$ref`, e.g. if image is defined on `$defs`: `#/properties/image/$ref/properties/title`
118
120
  - `schemaLocation` refers to the absolute path within the schema and will not change, e.g. `#/$defs/properties/title`
119
121
 
122
+ ---
123
+
120
124
  </details>
121
125
 
122
126
  <details><summary>Each node has a reference to its parent node</summary>
123
127
 
128
+ ---
129
+
124
130
  The parent-node can be a sub-schema or intermediary node:
125
131
 
126
132
  ```ts
@@ -129,11 +135,13 @@ const { node: childNode } = root.getNode("#/image");
129
135
  assert(root === childNode.parent);
130
136
  ```
131
137
 
138
+ ---
139
+
132
140
  </details>
133
141
 
134
142
  <details><summary>All nodes share a context</summary>
135
143
 
136
- > It is not advised to work on context directly, but it might be useful in some situations
144
+ ---
137
145
 
138
146
  A context is shared across all nodes of a schema
139
147
 
@@ -153,14 +161,21 @@ assert(root === childNode.context.rootNode);
153
161
 
154
162
  Note that rootNodes will change when working across remote schema (using $ref).
155
163
 
164
+ ---
165
+
156
166
  </details>
157
167
 
168
+ > [!CAUTION]
169
+ > It is not advised to work on context directly, but it might be useful in some situations
170
+
158
171
  ### Draft Support
159
172
 
160
173
  _json-schema-library_ fully supports all core features of draft versions draft-04, draft-06, draft-07, draft-2019-09 and draft-2020-12. Additionally, most format-validations are supported per default besides the listed format below. You can always override or extend format validation as is documented in [draft customization](#draft-customization).
161
174
 
162
175
  <details><summary>Overview draft support</summary>
163
176
 
177
+ ---
178
+
164
179
  Draft support is defined by running a validator against the official [json-schema-test-suite](https://github.com/json-schema-org/JSON-Schema-Test-Suite).
165
180
 
166
181
  - Test results for _json-schema-library_ can be inspected in [github actions](https://github.com/sagold/json-schema-library/actions/workflows/ci.yaml)
@@ -168,13 +183,19 @@ Draft support is defined by running a validator against the official [json-schem
168
183
 
169
184
  Please note that these benchmarks refer to validation only. _json-schema-library_ offers tooling outside of validation and strives to be as spec-compliant as possible.
170
185
 
186
+ ---
187
+
171
188
  </details>
172
189
 
173
190
  <details><summary>Overview format validation support</summary>
174
191
 
192
+ ---
193
+
175
194
  - **`❌ unsupported formats`** iri, iri-reference, idn-hostname
176
195
  - **`✅ supported formats`**: date, date-time, date, duration, ecmascript-regex, email, hostname, idn-email, ipv4, ipv6, json-pointer, regex, relative-json-pointer, time, unknown, uri-reference, uri-template, uri, uuid
177
196
 
197
+ ---
198
+
178
199
  </details>
179
200
 
180
201
  ## SchemaNode methods
@@ -193,8 +214,6 @@ Please note that these benchmarks refer to validation only. _json-schema-library
193
214
  [toSchemaNodes](#toschemanodes) ·
194
215
  [validate](#validate)
195
216
 
196
- </details>
197
-
198
217
  ### addRemoteSchema
199
218
 
200
219
  `addRemoteSchema` lets you add additional schemas that can be referenced by an URL using `$ref`. Use this to combine multiple schemas without changing the actual schema.
@@ -243,6 +262,8 @@ const { node, error } = schemaNode.getNodeRef("https://sagold.com/remote");
243
262
 
244
263
  <details><summary>Adding remote schema to compileSchema</summary>
245
264
 
265
+ ---
266
+
246
267
  It is possible to pass remoteSchema on compileSchema by passing a SchemaNode (with all its remote schemas) in `remote`:
247
268
 
248
269
  ```ts
@@ -261,10 +282,14 @@ const remote = compileSchema({
261
282
  const schemaNode = compileSchema({ $ref: "https://sagold.com/remote#/defs/character" }, { remote });
262
283
  ```
263
284
 
285
+ ---
286
+
264
287
  </details>
265
288
 
266
289
  <details><summary>Access local subschemas in remote schemas</summary>
267
290
 
291
+ ---
292
+
268
293
  You can add a local uri reference to the remote schema by using the `#` separator. The following example resolves hte local path `/$defs/character` in the remote schema `https://sagold.com/remote` throught the combined url:
269
294
  `https://sagold.com/remote#/$defs/character`
270
295
 
@@ -317,6 +342,8 @@ schemaNode.getData("A"); // "A" - default value resolved
317
342
  schemaNode.getNodeRef("https://sagold.com/remote#/properties/character");
318
343
  ```
319
344
 
345
+ ---
346
+
320
347
  </details>
321
348
 
322
349
  ### compileSchema
@@ -463,6 +490,8 @@ expect(myData).to.deep.equal({
463
490
 
464
491
  <details><summary>Option: extendDefaults (default: false)</summary>
465
492
 
493
+ ---
494
+
466
495
  Per default, `getData` does try to create data that is valid to the json-schema. Example: array-schemas with `minItems: 1` will add one item to fullfil the validation criteria. You can use the option and pass `{ extendDefaults: false }` to override this behaviour with a default value:
467
496
 
468
497
  ```ts
@@ -483,10 +512,14 @@ const myData = compileSchema(myJsonSchema).getData(undefined, { extendDefaults:
483
512
  expect(myData).to.deep.equal([]);
484
513
  ```
485
514
 
515
+ ---
516
+
486
517
  </details>
487
518
 
488
519
  <details><summary>Option: addOptionalProps (default: false)</summary>
489
520
 
521
+ ---
522
+
490
523
  `getData` will only add required properties per default:
491
524
 
492
525
  ```ts
@@ -513,10 +546,14 @@ const data = compileSchema({
513
546
  console.log(data); // { title: "", subTitle: "sub-title" }
514
547
  ```
515
548
 
549
+ ---
550
+
516
551
  </details>
517
552
 
518
553
  <details><summary>Option: removeInvalidData (default: false)</summary>
519
554
 
555
+ ---
556
+
520
557
  With `removeInvalidData:true`, `getData` will remove data that is invalid to the given schema;
521
558
 
522
559
  ```ts
@@ -537,10 +574,14 @@ const data = compileSchema({
537
574
  console.log(data); // { valid: "stays", invalid: "removed" }
538
575
  ```
539
576
 
577
+ ---
578
+
540
579
  </details>
541
580
 
542
581
  <details><summary>Option: useTypeDefaults (default: true)</summary>
543
582
 
583
+ ---
584
+
544
585
  With `useTypeDefaults:true`, `getData` will return initial values for all primitives (non-objects/arrays) that do not have a default-property set:
545
586
 
546
587
  ```ts
@@ -581,6 +622,8 @@ const data = compileSchema({
581
622
  console.log(data); // { valid: [undefined] }
582
623
  ```
583
624
 
625
+ ---
626
+
584
627
  </details>
585
628
 
586
629
  ### getNode
@@ -673,6 +716,8 @@ expect(node.schema).to.deep.equal({
673
716
 
674
717
  <details><summary>Evaluating errors</summary>
675
718
 
719
+ ---
720
+
676
721
  All returned json-errors have a data property with the following properties
677
722
 
678
723
  - `pointer` JSON Pointer to the location where the error occured. In case of omitted data, this is the last JSON Schema location that could be resolved
@@ -686,12 +731,18 @@ if (error) {
686
731
  }
687
732
  ```
688
733
 
734
+ ---
735
+
689
736
  </details>
690
737
 
691
738
  <details><summary>About JsonPointer</summary>
692
739
 
740
+ ---
741
+
693
742
  **[JSON Pointer](https://tools.ietf.org/html/rfc6901)** defines a string syntax for identifying a specific value within a Json document and is [supported by Json-Schema](https://json-schema.org/understanding-json-schema/structuring.html). Given a Json document, it behaves similar to a [lodash path](https://lodash.com/docs/4.17.5#get) (`a[0].b.c`), which follows JS-syntax, but instead uses `/` separators (e.g., `a/0/b/c`). In the end, you describe a path into the Json data to a specific point.
694
743
 
744
+ ---
745
+
695
746
  </details>
696
747
 
697
748
  ### getNodeChild
@@ -757,7 +808,7 @@ if (node) {
757
808
  }
758
809
  ```
759
810
 
760
- </details>
811
+ ---
761
812
 
762
813
  ### reduceNode
763
814
 
@@ -789,7 +840,8 @@ expect(reducedNode.schema).to.deep.eq({
789
840
  });
790
841
  ```
791
842
 
792
- > ⚠️ Please be aware that certain schema-definitions are lost when resolving or merging sub-schemas.
843
+ > [!CAUTION]
844
+ > Please be aware that certain schema-definitions are lost when resolving or merging sub-schemas.
793
845
  > This mainly refers to validation-properties, but also some ambigiuous schema might get overriden.
794
846
 
795
847
  ### toDataNodes
@@ -873,12 +925,14 @@ expect(calls).to.deep.equal([
873
925
  `validate` is a complete _JSON Schema validator_ for your input data. Calling _validate_ will return a list of validation errors for the passed data.
874
926
 
875
927
  ```ts
876
- const { valid, errors } = compileSchema(myJsonSchema).validate(myData);
928
+ const { valid, errors, annotations } = compileSchema(myJsonSchema).validate(myData);
877
929
  // { valid: boolean, errors: JsonError[] }
878
930
  ```
879
931
 
880
932
  <details><summary>About type JsonError</summary>
881
933
 
934
+ ---
935
+
882
936
  In _json-schema-library_ all errors are in the format of a `JsonError`:
883
937
 
884
938
  ```ts
@@ -892,9 +946,11 @@ type JsonError = {
892
946
 
893
947
  In almost all cases, a JSON Pointer is given on _error.data.pointer_, which points to the source within data where the error occured. For more details on how to work with errors, refer to section [custom errors](#extending-a-draft).
894
948
 
949
+ ---
950
+
895
951
  </details>
896
952
 
897
- <details><summary>Example</summary>
953
+ <details><summary>JsonError Example</summary>
898
954
 
899
955
  ```ts
900
956
  const myJsonSchema: JsonSchema = { type: "object", additionalProperties: false };
@@ -913,6 +969,56 @@ expect(errors).to.deep.equal([
913
969
 
914
970
  </details>
915
971
 
972
+ <details><summary>About type JsonAnnotation</summary>
973
+
974
+ ---
975
+
976
+ In _json-schema-library_ all annotations are in the format of a `JsonAnnotation`. _Annotations_ are meta-data associated with a json-schema that are not actual errors. They can be a deprecated warning or additional resolved meta-data based on the given value. _Annotations_ do not have an affect on the `valid` property exposed by `validate()`.
977
+
978
+ ```ts
979
+ type JsonAnnotation = {
980
+ type: "annotation";
981
+ code: string;
982
+ message: string;
983
+ data?: { [p: string]: any };
984
+ };
985
+ ```
986
+
987
+ In all cases, a JSON Pointer is given on _annotation.data.pointer_, which points to the source within data where the error occured.
988
+
989
+ An included annotation is exposed for the keyword: `deprecated: true`:
990
+
991
+ ```ts
992
+ const myJsonSchema: JsonSchema = { type: "object", properties: { name: { deprecated: true } } };
993
+
994
+ const { annotations } = compileSchema(myJsonSchema).validate({ name: "my-data" });
995
+
996
+ expect(annotations).to.deep.equal([
997
+ {
998
+ type: "annotation",
999
+ code: "deprecated-warning",
1000
+ message: "Value at `#/name` is deprecated",
1001
+ data: { pointer: "#", value: "my-data", schema: { deprecated: true } }
1002
+ }
1003
+ ]);
1004
+ ```
1005
+
1006
+ To create a custom annotation you can use the `createAnnotation` helper exposed by _SchemaNode_:
1007
+
1008
+ ```ts
1009
+ const validation: JsonSchemaValidator = ({ node, pointer, data }) => {
1010
+ return node.createAnnotation("my-annotation", {
1011
+ schema: node.schema
1012
+ pointer,
1013
+ value: data
1014
+ });
1015
+ };
1016
+ ```
1017
+
1018
+ ---
1019
+
1020
+ </details>
1021
+
916
1022
  You can also use async validators to validate data with json-schema. For this, another property asyncErrors is exposed on validate:
917
1023
 
918
1024
  ```ts
@@ -925,12 +1031,13 @@ if (errorsAsync.length > 0) {
925
1031
 
926
1032
  Per default _json-schema-library_ does not contain async validators, so `errorsAsync` is always empty. If you add async validators, a list of `Promise<JsonError|undefined>` is return and you need to resolve and filter non-errors (undefined) yourself.
927
1033
 
928
- > **Note** `isValid` only refers to errors. `errorsAsync` has to be evaluated separately
1034
+ > [!NOTE]
1035
+ > `isValid` only refers to errors. `errorsAsync` has to be evaluated separately
929
1036
 
930
1037
  <details><summary>Example Async Validation</summary>
931
1038
 
932
1039
  ```ts
933
- import { JsonSchemaValidator, draft2020 } from "json-schema-library";
1040
+ import { JsonSchemaValidator, draft2020, sanitizeErrors } from "json-schema-library";
934
1041
  // return Promise<JsonError>
935
1042
  const customValidator: JsonSchemaValidator = async ({ node, pointer, data }) => {
936
1043
  return node.createError("type-error", {
@@ -951,7 +1058,7 @@ const draftList = [
951
1058
  const { isValid, errorsAsync } = compileSchema({ custom: true }).validate("data");
952
1059
  console.log(isValid, errors.length); // true, 0
953
1060
 
954
- const errors = await Promise.all(errorsAsync);
1061
+ const errors = await Promise.all(errorsAsync).then(sanitizeErrors);
955
1062
  console.log(errors); /// [{ code: "type-error", value: "data", pointer: "#", ... }]
956
1063
  ```
957
1064
 
@@ -1103,8 +1210,7 @@ const myDraft = extendDraft(draft2020, {
1103
1210
 
1104
1211
  The built-in format validators may not always align with your specific requirements. For instance, you might need to validate the output of an `<input type="time" />`, which produces values in formats like `HH:MM` or `HH:MM:SS`. In such cases, you can customize or overwrite the format validators to suit your needs using `extendDraft`
1105
1212
 
1106
- <details>
1107
- <summary>Example of overwriting a format validator</summary>
1213
+ <details><summary>Example of overwriting a format validator</summary>
1108
1214
 
1109
1215
  ```ts
1110
1216
  import { extendDraft, draft2020 } from "json-schema-library";
@@ -1358,10 +1464,18 @@ settings.REGEX_FLAGS = "v";
1358
1464
 
1359
1465
  ## Breaking Changes
1360
1466
 
1361
- ### v10.6.0
1467
+ ### v11.0.0
1362
1468
 
1363
1469
  - introduced annotations
1470
+ - added node.createAnnotation helper
1364
1471
  - changed typing to strict
1472
+ - added annotations-list to `validate()` result
1473
+ - added keyword support for `deprecated: true` which returns a `deprecated-warning` annotation
1474
+
1475
+ **breaking changes**:
1476
+
1477
+ - Return type of validators is now `ValidationReturnType` instead of `ValidationResult`
1478
+ - type `AnnotationData` replaces `ErroData`
1365
1479
 
1366
1480
  ### v10.5.0
1367
1481