json-schema-library 10.0.0-rc9 → 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/.mocharc.js +5 -0
  2. package/CHANGELOG.md +2 -0
  3. package/README.md +160 -61
  4. package/bowtie_jlib.js +140 -0
  5. package/dist/index.d.ts +3 -1
  6. package/dist/jsonSchemaLibrary.js +1 -1
  7. package/dist/module/index.js +22 -0
  8. package/dist/module/remotes/index.js +43 -0
  9. package/dist/module/src/Draft.js +51 -0
  10. package/dist/module/src/SchemaNode.js +281 -0
  11. package/dist/module/src/compileSchema.js +69 -0
  12. package/dist/module/src/draft04/keywords/$ref.js +132 -0
  13. package/dist/module/src/draft04/keywords/exclusiveMaximum.js +20 -0
  14. package/dist/module/src/draft04/keywords/exclusiveMinimum.js +20 -0
  15. package/dist/module/src/draft04.js +105 -0
  16. package/dist/module/src/draft06/keywords/$ref.js +60 -0
  17. package/dist/module/src/draft06.js +107 -0
  18. package/dist/module/src/draft07.js +99 -0
  19. package/dist/module/src/draft2019-09/keywords/$ref.js +182 -0
  20. package/dist/module/src/draft2019-09/keywords/additionalItems.js +60 -0
  21. package/dist/module/src/draft2019-09/keywords/items.js +63 -0
  22. package/dist/module/src/draft2019-09/keywords/unevaluatedItems.js +82 -0
  23. package/dist/module/src/draft2019-09/methods/getChildSelection.js +40 -0
  24. package/dist/module/src/draft2019-09/methods/getData.js +299 -0
  25. package/dist/module/src/draft2019.js +110 -0
  26. package/dist/module/src/draft2020.js +120 -0
  27. package/dist/module/src/draftEditor.js +31 -0
  28. package/dist/module/src/errors/errors.js +67 -0
  29. package/dist/module/src/errors/render.js +11 -0
  30. package/dist/module/src/formats/formats.js +294 -0
  31. package/dist/module/src/getNode.js +44 -0
  32. package/dist/module/src/getNodeChild.js +45 -0
  33. package/dist/module/src/isItemEvaluated.js +59 -0
  34. package/dist/module/src/isPropertyEvaluated.js +69 -0
  35. package/dist/module/src/keywords/$defs.js +25 -0
  36. package/dist/module/src/keywords/$ref.js +214 -0
  37. package/dist/module/src/keywords/additionalProperties.js +91 -0
  38. package/dist/module/src/keywords/allOf.js +48 -0
  39. package/dist/module/src/keywords/anyOf.js +46 -0
  40. package/dist/module/src/keywords/const.js +14 -0
  41. package/dist/module/src/keywords/contains.js +64 -0
  42. package/dist/module/src/keywords/dependencies.js +117 -0
  43. package/dist/module/src/keywords/dependentRequired.js +52 -0
  44. package/dist/module/src/keywords/dependentSchemas.js +85 -0
  45. package/dist/module/src/keywords/enum.js +27 -0
  46. package/dist/module/src/keywords/exclusiveMaximum.js +20 -0
  47. package/dist/module/src/keywords/exclusiveMinimum.js +20 -0
  48. package/dist/module/src/keywords/format.js +11 -0
  49. package/dist/module/src/keywords/ifthenelse.js +66 -0
  50. package/dist/module/src/keywords/items.js +55 -0
  51. package/dist/module/src/keywords/maxItems.js +18 -0
  52. package/dist/module/src/keywords/maxLength.js +23 -0
  53. package/dist/module/src/keywords/maxProperties.js +23 -0
  54. package/dist/module/src/keywords/maximum.js +31 -0
  55. package/dist/module/src/keywords/minItems.js +21 -0
  56. package/dist/module/src/keywords/minLength.js +24 -0
  57. package/dist/module/src/keywords/minProperties.js +22 -0
  58. package/dist/module/src/keywords/minimum.js +31 -0
  59. package/dist/module/src/keywords/multipleOf.js +38 -0
  60. package/dist/module/src/keywords/not.js +20 -0
  61. package/dist/module/src/keywords/oneOf.js +240 -0
  62. package/dist/module/src/keywords/pattern.js +24 -0
  63. package/dist/module/src/keywords/patternProperties.js +98 -0
  64. package/dist/module/src/keywords/prefixItems.js +46 -0
  65. package/dist/module/src/keywords/properties.js +42 -0
  66. package/dist/module/src/keywords/propertyNames.js +59 -0
  67. package/dist/module/src/keywords/required.js +25 -0
  68. package/dist/module/src/keywords/type.js +40 -0
  69. package/dist/module/src/keywords/unevaluatedItems.js +74 -0
  70. package/dist/module/src/keywords/unevaluatedProperties.js +61 -0
  71. package/dist/module/src/keywords/uniqueItems.js +30 -0
  72. package/dist/module/src/mergeNode.js +112 -0
  73. package/dist/module/src/methods/createSchema.js +33 -0
  74. package/dist/module/src/methods/getChildSelection.js +40 -0
  75. package/dist/module/src/methods/getData.js +295 -0
  76. package/dist/module/src/methods/toDataNodes.js +27 -0
  77. package/dist/module/src/methods/toSchemaNodes.js +38 -0
  78. package/dist/module/src/settings.js +19 -0
  79. package/dist/module/src/tests/spec/draft04.spec.js +11 -0
  80. package/dist/module/src/tests/spec/draft06.spec.js +11 -0
  81. package/dist/module/src/tests/spec/draft07.spec.js +11 -0
  82. package/dist/module/src/tests/spec/draft2019-09.spec.js +79 -0
  83. package/dist/module/src/tests/spec/draft2020-12.spec.js +63 -0
  84. package/dist/module/src/tests/types.js +13 -0
  85. package/dist/module/src/tests/utils/addRemotes.js +17 -0
  86. package/dist/module/src/tests/utils/getDraftTests.js +36 -0
  87. package/dist/module/src/tests/utils/runTestCases.js +102 -0
  88. package/dist/module/src/types.js +9 -0
  89. package/dist/module/src/utils/copyDraft.js +6 -0
  90. package/dist/module/src/utils/getDefaultValue.js +15 -0
  91. package/dist/module/src/utils/getPrecision.js +11 -0
  92. package/dist/module/src/utils/getSchemaType.js +122 -0
  93. package/dist/module/src/utils/getTypeOf.js +8 -0
  94. package/dist/module/src/utils/getValue.js +9 -0
  95. package/dist/module/src/utils/hasProperty.js +2 -0
  96. package/dist/module/src/utils/isEmpty.js +17 -0
  97. package/dist/module/src/utils/isObject.js +4 -0
  98. package/dist/module/src/utils/isType.js +1 -0
  99. package/dist/module/src/utils/joinId.js +40 -0
  100. package/dist/module/src/utils/mergeSchema.js +77 -0
  101. package/dist/module/src/utils/omit.js +19 -0
  102. package/dist/module/src/utils/pick.js +9 -0
  103. package/dist/module/src/utils/punycode.ucs2decode.js +43 -0
  104. package/dist/module/src/utils/sanitizeErrors.js +16 -0
  105. package/dist/module/src/utils/splitRef.js +18 -0
  106. package/dist/module/src/validateNode.js +28 -0
  107. package/dist/src/SchemaNode.d.ts +36 -10
  108. package/dist/src/keywords/dependencies.d.ts +1 -1
  109. package/dist/src/keywords/oneOf.d.ts +2 -2
  110. package/dist/src/types.d.ts +1 -1
  111. package/index.ts +3 -1
  112. package/package.json +1 -1
  113. package/src/SchemaNode.ts +54 -24
  114. package/src/compileSchema.getChild.test.ts +40 -37
  115. package/src/compileSchema.reduceSchema.test.ts +18 -31
  116. package/src/compileSchema.test.ts +11 -11
  117. package/src/compileSchema.ts +3 -4
  118. package/src/compileSchema.validate.test.ts +32 -1
  119. package/src/draft04/keywords/$ref.ts +14 -13
  120. package/src/draft06/keywords/$ref.ts +5 -5
  121. package/src/draft2019-09/keywords/$ref.ts +13 -13
  122. package/src/draft2019-09/keywords/additionalItems.ts +3 -3
  123. package/src/draft2019-09/keywords/items.ts +7 -4
  124. package/src/draft2019-09/keywords/unevaluatedItems.ts +2 -2
  125. package/src/draft2019-09/methods/getData.ts +2 -3
  126. package/src/getNodeChild.ts +2 -2
  127. package/src/keywords/$defs.ts +10 -12
  128. package/src/keywords/$ref.ts +18 -21
  129. package/src/keywords/additionalProperties.ts +11 -3
  130. package/src/keywords/allOf.ts +5 -5
  131. package/src/keywords/anyOf.ts +5 -5
  132. package/src/keywords/contains.ts +4 -4
  133. package/src/keywords/dependencies.ts +12 -14
  134. package/src/keywords/dependentSchemas.ts +4 -4
  135. package/src/keywords/ifthenelse.ts +16 -6
  136. package/src/keywords/items.ts +6 -2
  137. package/src/keywords/not.ts +2 -2
  138. package/src/keywords/oneOf.ts +5 -5
  139. package/src/keywords/patternProperties.ts +4 -4
  140. package/src/keywords/prefixItems.ts +6 -2
  141. package/src/keywords/properties.ts +3 -3
  142. package/src/keywords/propertyNames.ts +2 -2
  143. package/src/keywords/type.ts +1 -1
  144. package/src/keywords/unevaluatedItems.ts +2 -2
  145. package/src/keywords/unevaluatedProperties.ts +2 -2
  146. package/src/mergeNode.ts +2 -2
  147. package/src/methods/eachSchema.test.ts +16 -16
  148. package/src/methods/getData.ts +2 -2
  149. package/src/types.ts +1 -1
  150. package/src/utils/getSchemaType.ts +9 -9
  151. package/src/utils/joinId.test.ts +8 -0
  152. package/src/utils/joinId.ts +4 -0
  153. package/src/validateNode.ts +2 -2
  154. package/src/validationPath.test.ts +1 -1
  155. package/tsconfig.json +1 -0
  156. package/webpack.config.js +49 -0
  157. package/dist/src/compileSchema.getNode.test.d.ts +0 -1
  158. package/dist/src/compileSchema.reduceSchema.test.d.ts +0 -1
  159. package/dist/src/compileSchema.test.d.ts +0 -1
  160. package/dist/src/compileSchema.validate.test.d.ts +0 -1
  161. package/dist/src/draft2019-09/compileSchema.getNode.test.d.ts +0 -1
  162. package/dist/src/draft2019-09/compileSchema.validate.test.d.ts +0 -1
  163. package/dist/src/draft2019-09/keywords/$ref.test.d.ts +0 -1
  164. package/dist/src/draft2019-09/keywords/additionalItems.test.d.ts +0 -1
  165. package/dist/src/draft2019-09/keywords/items.test.d.ts +0 -1
  166. package/dist/src/draft2019-09/methods/getChildSchemaSelection.test.d.ts +0 -1
  167. package/dist/src/draft2019-09/methods/getData.test.d.ts +0 -1
  168. package/dist/src/draft2019-09/methods/toDataNodes.test.d.ts +0 -1
  169. package/dist/src/extendDraft.test.d.ts +0 -1
  170. package/dist/src/keywords/additionalProperties.test.d.ts +0 -1
  171. package/dist/src/keywords/allOf.test.d.ts +0 -1
  172. package/dist/src/keywords/const.test.d.ts +0 -1
  173. package/dist/src/keywords/ifthenelse.test.d.ts +0 -1
  174. package/dist/src/keywords/object.test.d.ts +0 -1
  175. package/dist/src/keywords/oneOf.test.d.ts +0 -1
  176. package/dist/src/keywords/patternProperties.test.d.ts +0 -1
  177. package/dist/src/keywords/properties.test.d.ts +0 -1
  178. package/dist/src/keywords/required.test.d.ts +0 -1
  179. package/dist/src/keywords/string.test.d.ts +0 -1
  180. package/dist/src/keywords/type.test.d.ts +0 -1
  181. package/dist/src/mergeNode.test.d.ts +0 -1
  182. package/dist/src/methods/createSchema.test.d.ts +0 -1
  183. package/dist/src/methods/eachSchema.test.d.ts +0 -1
  184. package/dist/src/methods/getChildSelection.test.d.ts +0 -1
  185. package/dist/src/methods/getData.test.d.ts +0 -1
  186. package/dist/src/methods/toDataNodes.test.d.ts +0 -1
  187. package/dist/src/tests/issues/issue19.get.dependencies.test.d.ts +0 -1
  188. package/dist/src/tests/issues/issue21.getTemplate.test.d.ts +0 -1
  189. package/dist/src/tests/issues/issue22.each.test.d.ts +0 -1
  190. package/dist/src/tests/issues/issue32.getTemplate.integer.test.d.ts +0 -1
  191. package/dist/src/tests/issues/issue33.rootOneOf.test.d.ts +0 -1
  192. package/dist/src/tests/issues/issue35.oneOf.remote.test.d.ts +0 -1
  193. package/dist/src/tests/issues/issue38.getTemplate.anyOf.test.d.ts +0 -1
  194. package/dist/src/tests/issues/issue43.multipleOf.float.test.d.ts +0 -1
  195. package/dist/src/tests/issues/issue44.chainedNegLogic.test.d.ts +0 -1
  196. package/dist/src/tests/issues/issue52.test.d.ts +0 -1
  197. package/dist/src/tests/issues/issue57.allOfMutatesData.test.d.ts +0 -1
  198. package/dist/src/tests/issues/issue58.oneOfType.test.d.ts +0 -1
  199. package/dist/src/tests/issues/issue64.compileSchema.test.d.ts +0 -1
  200. package/dist/src/utils/getPrecision.test.d.ts +0 -1
  201. package/dist/src/utils/getTypeOf.test.d.ts +0 -1
  202. package/dist/src/utils/joinId.test.d.ts +0 -1
  203. package/dist/src/utils/mergeSchema.test.d.ts +0 -1
  204. package/dist/src/utils/splitRef.test.d.ts +0 -1
  205. package/dist/src/validationPath.test.d.ts +0 -1
  206. /package/dist/{src/compileSchema.getChild.test.d.ts → module/src/Keyword.js} +0 -0
package/.mocharc.js ADDED
@@ -0,0 +1,5 @@
1
+ process.env.TS_NODE_PROJECT = "./tsconfig.test.json";
2
+
3
+ module.exports = {
4
+ require: "ts-node/register"
5
+ };
package/CHANGELOG.md CHANGED
@@ -1,5 +1,7 @@
1
1
  ## Changelog
2
2
 
3
+ - reference for error-format: https://json-schema.org/blog/posts/fixing-json-schema-output
4
+
3
5
  ### v9.0.0
4
6
 
5
7
  - [Breaking] error data to always contain `schema` and `value`
package/README.md CHANGED
@@ -16,7 +16,7 @@
16
16
 
17
17
  ---
18
18
 
19
- > ⚠️ This **documentation** refers to the upcoming release **version 10**, which can be installed by `npm install json-schema-library@10.0.0-rc9`. For the latest release please refer to the **[documentation of version 9.3.5](https://github.com/sagold/json-schema-library/tree/v9.3.5)**.
19
+ > ⚠️ This **documentation** refers to the upcoming release **version 10**, which can be installed by `npm install json-schema-library@10.0.0-rc13`. For the latest release please refer to the **[documentation of version 9.3.5](https://github.com/sagold/json-schema-library/tree/v9.3.5)**. If you are on v10-rc refer to [documentation of version 10.0.0-rc8 or lower](https://github.com/sagold/json-schema-library/tree/v10.0.0-rc8)
20
20
 
21
21
  **Quick start**
22
22
 
@@ -61,7 +61,16 @@ type CompileOptions = {
61
61
  // if format-validations should create errors. Defaults to true
62
62
  formatAssertion: boolean | "meta-schema";
63
63
  // default options for all calls to node.getData()
64
- getDataDefaultOptions?: TemplateOptions;
64
+ getDataDefaultOptions?: {
65
+ // Add all properties (required and optional) to the generated data
66
+ addOptionalProps?: boolean;
67
+ // Remove data that does not match input schema. Defaults to false
68
+ removeInvalidData?: boolean;
69
+ // Set to false to take default values as they are and not extend them. Defaults to true
70
+ extendDefaults?: boolean;
71
+ // Limits how often a $ref should be followed before aborting. Prevents infinite data-structure. Defaults to 1
72
+ recursionLimit?: number;
73
+ };
65
74
  };
66
75
  ```
67
76
 
@@ -103,12 +112,12 @@ const titleData = titleNode?.getData();
103
112
 
104
113
  ```ts
105
114
  const titleNode = compileSchema(mySchema).getNode("#/image/title");
106
- console.log(titleNode.spointer); // #/properties/image/properties/title
107
- console.log(titleNode.schemaId); // #/properties/image/properties/title
115
+ console.log(titleNode.evaluationPath); // #/properties/image/properties/title
116
+ console.log(titleNode.schemaLocation); // #/properties/image/properties/title
108
117
  ```
109
118
 
110
- - `spointer` refers to the path in schema and is extended by `$ref`, e.g. if image is defined on `$defs`: `#/properties/image/$ref/properties/title`
111
- - `schemaId` refers to the absolute path within the schema and will not change, e.g. `#/$defs/properties/title`
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`
120
+ - `schemaLocation` refers to the absolute path within the schema and will not change, e.g. `#/$defs/properties/title`
112
121
 
113
122
  </details>
114
123
 
@@ -172,19 +181,19 @@ Please note that these benchmarks refer to validation only. _json-schema-library
172
181
 
173
182
  ## SchemaNode methods
174
183
 
175
- [**addRemoteSchema**](#addremoteschema) ·
176
- [**compileSchema**](#compileSchema-1) ·
177
- [**createSchema**](#createSchema) ·
178
- [**getChildSelection**](#getchildselection) ·
179
- [**getData**](#getdata) ·
180
- [**getNode**](#getnode) ·
181
- [**getNodeChild**](#getnodechild) ·
182
- [**getNodeRef**](#getnoderef) ·
183
- [**getNodeRoot**](#getnoderoot) ·
184
- [**reduceNode**](#reducenode) ·
185
- [**toDataNodes**](#todatanodes) ·
186
- [**toSchemaNodes**](#toschemanodes) ·
187
- [**validate**](#validate)
184
+ [addRemoteSchema](#addremoteschema) ·
185
+ [compileSchema](#compileSchema-1) ·
186
+ [createSchema](#createSchema) ·
187
+ [getChildSelection](#getchildselection) ·
188
+ [getData](#getdata) ·
189
+ [getNode](#getnode) ·
190
+ [getNodeChild](#getnodechild) ·
191
+ [getNodeRef](#getnoderef) ·
192
+ [getNodeRoot](#getnoderoot) ·
193
+ [reduceNode](#reducenode) ·
194
+ [toDataNodes](#todatanodes) ·
195
+ [toSchemaNodes](#toschemanodes) ·
196
+ [validate](#validate)
188
197
 
189
198
  </details>
190
199
 
@@ -192,7 +201,7 @@ Please note that these benchmarks refer to validation only. _json-schema-library
192
201
 
193
202
  `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.
194
203
 
195
- Each schemas is referenced by their unique `$id` (since draft-06, previously `id`). Usually an `$id` is specified as an url, for example `https://mydomain.com/schema/schema-name` or with a file extension like `https://mydomain.com/schema/schema-name.json`.
204
+ Each schema is referenced by their unique `$id` (since draft-06, previously `id`). Usually an `$id` is specified as an url, for example `https://mydomain.com/schema/schema-name` or with a file extension like `https://mydomain.com/schema/schema-name.json`.
196
205
 
197
206
  On a compiled schema
198
207
 
@@ -383,35 +392,35 @@ const myData = compileSchema(myJsonSchema).getData(inputData, { recursionLimit:
383
392
  <details><summary>Example</summary>
384
393
 
385
394
  ```ts
386
- import { compileSchema, JsonSchema } from 'json-schema-library';
395
+ import { compileSchema, JsonSchema } from "json-schema-library";
387
396
 
388
397
  const myJsonSchema: JsonSchema = {
389
- type: 'object',
390
- required: ['name', 'option', 'list'],
391
- properties: {
392
- name: { type: 'string' },
393
- option: {
394
- type: 'string',
395
- enum: ['first-option', 'second-option']
396
- },
397
- list: {
398
- type: 'array',
399
- items: {
400
- type: 'string',
401
- default: 'new item'
402
- },
403
- minItems: 1
398
+ type: "object",
399
+ required: ["name", "option", "list"],
400
+ properties: {
401
+ name: { type: "string" },
402
+ option: {
403
+ type: "string",
404
+ enum: ["first-option", "second-option"]
405
+ },
406
+ list: {
407
+ type: "array",
408
+ items: {
409
+ type: "string",
410
+ default: "new item"
411
+ },
412
+ minItems: 1
413
+ }
404
414
  }
405
- }
406
415
  };
407
416
 
408
417
  const schemaNode = new compileSchema(myJsonSchema);
409
418
  const myData = schemaNode.getData();
410
419
 
411
420
  expect(myData).to.deep.equal({
412
- name: ',
413
- option: 'first-option',
414
- list: ['new item']
421
+ name: "",
422
+ option: "first-option",
423
+ list: ["new item"]
415
424
  });
416
425
  ```
417
426
 
@@ -743,7 +752,7 @@ expect(reducedNode.schema).to.deep.eq({
743
752
 
744
753
  ### toDataNodes
745
754
 
746
- `each` iterates over each data-item (_object_, _array_ and _value_) and emits the data-item, schema and location to a callback.
755
+ `toDataNodes` collects all data-items (_object_, _array_ and _value_) and their SchemaNode and return them as a list of **DataNodes**:
747
756
 
748
757
  ```ts
749
758
  type DataNode = { pointer: string; value: unknown; node: SchemaNode };
@@ -779,7 +788,7 @@ expect(calls).to.deep.equal([
779
788
 
780
789
  ### toSchemaNodes
781
790
 
782
- `eachSchema` emits each sub-schema definition to a callback. A sub-schema is any schema-definition like in `properties["property"]`, `anyOf[1]`, `contains`, `$defs["name"]`, etc.
791
+ `toSchemaNodes` collects all sub-schema definitions, like in `properties["property"]`, `anyOf[1]`, `contains`, `$defs["name"]`, etc. and returns them as a list of **SchemaNodes**:
783
792
 
784
793
  ```ts
785
794
  const nodes: SchemaNode[] = compileSchema(mySchema).toSchemaNodes();
@@ -846,10 +855,7 @@ In almost all cases, a JSON Pointer is given on _error.data.pointer_, which poin
846
855
  <details><summary>Example</summary>
847
856
 
848
857
  ```ts
849
- const myJsonSchema: JsonSchema = {
850
- type: "object",
851
- additionalProperties: false
852
- };
858
+ const myJsonSchema: JsonSchema = { type: "object", additionalProperties: false };
853
859
 
854
860
  const { errors } = compileSchema(myJsonSchema).validate({ name: "my-data" });
855
861
 
@@ -868,14 +874,14 @@ expect(errors).to.deep.equal([
868
874
  You can also use async validators to validate data with json-schema. For this, another property asyncErrors is exposed on validate:
869
875
 
870
876
  ```ts
871
- const { isValid, errors, errorsAsync } = compileSchema(myJsonSchema).validate(myData);
877
+ const { errorsAsync } = compileSchema(myJsonSchema).validate(myData);
872
878
 
873
879
  if (errorsAsync.length > 0) {
874
880
  const additionalErrors = (await Promise.all(errorsAsync)).filter((err) => err != null);
875
881
  }
876
882
  ```
877
883
 
878
- Per default _json-schema-library_ does not have 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.
884
+ 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.
879
885
 
880
886
  > **Note** `isValid` only refers to errors. `errorsAsync` has to be evaluated separately
881
887
 
@@ -1051,17 +1057,71 @@ const myDraft = extendDraft(draft2020, {
1051
1057
  });
1052
1058
  ```
1053
1059
 
1054
- <details><summary>About `oneOfFuzzyKeyword`</summary>
1055
1060
 
1056
- If you're working with complex schemas that use the `oneOf` keyword to validate multiple options, `oneOfFuzzyKeyword` offers an alternative approach. It scores the schemas to return the best match, even if none of the schemas fully validate the input data. This makes error messages more readable and helps identify the most appropriate schema when multiple options exist.
1061
+ ### Overwrite a format validator
1062
+ 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`
1063
+ <details>
1064
+ <summary>Example of overwriting a format validator</summary>
1057
1065
 
1058
- `oneOfFuzzyKeyword` helps when no schema fully validates the data but you want to prioritize schemas based on how well they fit the input. This makes it easier to interpret validation results for complex conditions.
1066
+ ```ts
1067
+ import { extendDraft, draft2020 } from "json-schema-library";
1068
+
1069
+ /**
1070
+ * A Regexp that extends http://tools.ietf.org/html/rfc3339#section-5.6 spec.
1071
+ * The specification requires seconds and timezones to be a valid date format.
1072
+ *
1073
+ * matchTimeSecondsAndTimeOptional matches:
1074
+ * - HH:MM:SSz
1075
+ * - HH:MM:SS(+/-)HH:MM
1076
+ * - HH:MM:SS
1077
+ * - HH:MMz
1078
+ * - HH:MM(+/-)HH:MM
1079
+ * - HH:MM
1080
+ */
1081
+ const matchTimeSecondsAndTimeOptional =
1082
+ /^(?<time>(?:([0-1]\d|2[0-3]):[0-5]\d(:(?<second>[0-5]\d|60))?))(?:\.\d+)?(?<offset>(?:z|[+-]([0-1]\d|2[0-3])(?::?[0-5]\d)?)?)$/i;
1083
+
1084
+
1085
+ const customTimeFormatDraft = extendDraft(draft2020, {
1086
+ formats: {
1087
+ // This example extends the default time formatter which validates against RFC3339
1088
+ time: ({ node, pointer, data }) => {
1089
+ const { schema } = node;
1090
+ if (typeof data !== "string" || data === "") {
1091
+ return undefined;
1092
+ }
1093
+
1094
+ // Use the Custom Regex to validate the date and time.
1095
+ const matches = data.match(matchTimeSecondsAndTimeOptional);
1096
+ if (!matches) {
1097
+ return node.createError("format-date-time-error", { value: data, pointer, schema });
1098
+ }
1099
+
1100
+ // leap second
1101
+ if (matches.groups.second === "60") {
1102
+ // Omitted the code here for brevity.
1103
+ }
1104
+
1105
+ return undefined;
1106
+ },
1107
+
1108
+ },
1109
+ });
1110
+
1111
+ const { errors, valid } = compileSchema({
1112
+ type: "string",
1113
+ format: "time",
1114
+ $schema: "https://json-schema.org/draft/2020-12/schema",
1115
+ }, { drafts: [customTimeFormatDraft]}).validate("15:31:12");
1116
+
1117
+ console.assert(valid, errors.at(0)?.message);
1118
+ ```
1059
1119
 
1060
1120
  </details>
1061
1121
 
1062
1122
  ### Keyword
1063
1123
 
1064
- `Keywords` hold the main logic for JSON Schema functionality. Each `Keyword` corresponds to a JSON Schema keyword like `properties`, `prefixItems`, `oneOf`, etc and offers implementations to `parse`, `validate`, `resolve` and `reduce`. Note that support for each implementation is optional, dependending on the feature requirements. The main properties of a `Keyword`:
1124
+ **Keywords** hold the main logic for JSON Schema functionality. Each `Keyword` corresponds to a JSON Schema keyword like `properties`, `prefixItems`, `oneOf`, etc and offers implementations to `parse`, `validate`, `resolve` and `reduce`. Note that support for each implementation is optional, dependending on the feature requirements. The main properties of a `Keyword`:
1065
1125
 
1066
1126
  - a `Keyword` is only processed if the specified `keyword` is available as property on the JSON Schema
1067
1127
  - an optional `order` property may be added as order of keyword execution is sometimes important (`additionalItems` last, `$ref` evaluation first)
@@ -1099,9 +1159,9 @@ export const notKeyword: Keyword = {
1099
1159
  };
1100
1160
 
1101
1161
  export function parseNot(node: SchemaNode) {
1102
- const { schema, spointer, schemaId } = node;
1162
+ const { schema, evaluationPath, schemaLocation } = node;
1103
1163
  if (schema.not != null) {
1104
- node.not = node.compileSchema(schema.not, `${spointer}/not`, `${schemaId}/not`);
1164
+ node.not = node.compileSchema(schema.not, `${evaluationPath}/not`, `${schemaLocation}/not`);
1105
1165
  }
1106
1166
  }
1107
1167
  ```
@@ -1149,7 +1209,7 @@ export const typeKeyword: Keyword = {
1149
1209
  function reduceType({ node, pointer, data }: JsonSchemaReducerParams): undefined | SchemaNode {
1150
1210
  const dataType = getJsonSchemaType(data, node.schema.type);
1151
1211
  if (dataType !== "undefined" && Array.isArray(node.schema.type) && node.schema.type.includes(dataType)) {
1152
- return node.compileSchema({ ...node.schema, pointer, type: dataType }, node.spointer);
1212
+ return node.compileSchema({ ...node.schema, pointer, type: dataType }, node.evaluationPath);
1153
1213
  }
1154
1214
  return undefined;
1155
1215
  }
@@ -1157,6 +1217,13 @@ function reduceType({ node, pointer, data }: JsonSchemaReducerParams): undefined
1157
1217
 
1158
1218
  </details>
1159
1219
 
1220
+ Currently **keywords** are not exposed per default. You can still access any keyword implementation by retrieving them from a draft:
1221
+
1222
+ ```ts
1223
+ import { draft07 } from "json-schema-library";
1224
+ const dependentSchemasKeyword = draft2020.keywords.find((f) => f.keyword === "dependentSchemas");
1225
+ ```
1226
+
1160
1227
  ## Keyword extensions
1161
1228
 
1162
1229
  ### oneOfProperty
@@ -1193,6 +1260,38 @@ expect(resolvedNode?.schema).to.deep.eq({
1193
1260
  });
1194
1261
  ```
1195
1262
 
1263
+ ### oneOfFuzzyKeyword
1264
+
1265
+ If you're working with complex schemas that use the `oneOf` keyword to validate multiple options, `oneOfFuzzyKeyword` offers an alternative approach. It scores the schemas to return the best match, even if none of the schemas fully validate the input data. This makes error messages more readable and helps identify the most appropriate schema when multiple options exist.
1266
+
1267
+ `oneOfFuzzyKeyword` helps when no schema fully validates the data but you want to prioritize schemas based on how well they fit the input. This makes it easier to interpret validation results for complex conditions.
1268
+
1269
+ `oneOfFuzzyKeyword` is exposed by _json-schema-library_ and can be used to extend any draft.
1270
+
1271
+ ```ts
1272
+ import { extendDraft, oneOfFuzzyKeyword, draft2020 } from "json-schema-library";
1273
+
1274
+ const myDraft = extendDraft(draft2020, {
1275
+ keywords: [oneOfFuzzyKeyword]
1276
+ });
1277
+ ```
1278
+
1279
+ ### errorMessages
1280
+
1281
+ You can set custom errors messages locally by using the errors-keyword:
1282
+
1283
+ ```ts
1284
+ const { errors } = compileSchema({
1285
+ type: "array",
1286
+ minItems: 2,
1287
+ errorMessages: {
1288
+ "min-items-error": "Custom error {{minItems}}"
1289
+ }
1290
+ }).validate([1]);
1291
+
1292
+ assert.deepEqual(errors[0].message, "Custom error 2");
1293
+ ```
1294
+
1196
1295
  ## Breaking Changes
1197
1296
 
1198
1297
  ### v10.0.0
@@ -1212,13 +1311,13 @@ The new implementation revolves around compiling schemas into a **SchemaNode** t
1212
1311
 
1213
1312
  **`compileSchema`** is now a standalone function and replaces the `Draft` class. All return values for JSON Schema are now `SchemaNode` objects that contain a `schema` property.
1214
1313
 
1215
- ```ts
1216
- // PREVIOUSLY
1217
- const draft = new Draft(schema);
1314
+ ```ts
1315
+ // PREVIOUSLY
1316
+ const draft = new Draft(schema);
1218
1317
 
1219
- // NOW
1220
- const node = compileSchema(schema);
1221
- ```
1318
+ // NOW
1319
+ const node = compileSchema(schema);
1320
+ ```
1222
1321
 
1223
1322
  **Changed Methods**:
1224
1323
 
package/bowtie_jlib.js ADDED
@@ -0,0 +1,140 @@
1
+ /**
2
+ * test file for bowtie integration
3
+ *
4
+ * - Tutorial: https://docs.bowtie.report/en/stable/implementers/
5
+ *
6
+ * Build Dockerfile:
7
+ *
8
+ * ```
9
+ * docker build -t localhost/jlib .
10
+ * ````
11
+ *
12
+ * Test setup:
13
+ *
14
+ * ```
15
+ bowtie run -i localhost/jlib -V <<EOF
16
+ {"description": "test case 1", "schema": {}, "tests": [{"description": "a test", "instance": {}}] }
17
+ {"description": "test case 2", "schema": {"const": 37}, "tests": [{"description": "not 37", "instance": {}}, {"description": "is 37", "instance": 37}] }
18
+ EOF
19
+ *
20
+ * Test draft
21
+ *
22
+ * ```
23
+ * bowtie suite -i localhost/jlib draft7 | bowtie summary --show failures
24
+ * ```
25
+ *
26
+ */
27
+ const readline = require("readline/promises");
28
+ const process = require("process");
29
+ const os = require("os");
30
+ const packageJson = require("./package.json");
31
+ const jlib = require("./dist/jsonSchemaLibrary.js");
32
+
33
+ const compileSchema = jlib.compileSchema;
34
+
35
+ const stdio = readline.createInterface({
36
+ input: process.stdin,
37
+ output: process.stdout,
38
+ terminal: false
39
+ });
40
+
41
+ // const schemaIds: { [id: string]: SchemaDraft } = {
42
+ // "https://json-schema.org/draft/2020-12/schema": SchemaDraft.v2020_12,
43
+ // "https://json-schema.org/draft/2019-09/schema": SchemaDraft.v2019_09,
44
+ // "http://json-schema.org/draft-07/schema#": SchemaDraft.v7,
45
+ // "http://json-schema.org/draft-06/schema#": SchemaDraft.v6,
46
+ // "http://json-schema.org/draft-04/schema#": SchemaDraft.v4
47
+ // };
48
+
49
+ function send(data) {
50
+ console.log(JSON.stringify(data));
51
+ }
52
+
53
+ let started = false;
54
+ // let dialect;
55
+
56
+ const cmds = {
57
+ start: async (args) => {
58
+ console.assert(args.version === 1, { args });
59
+ started = true;
60
+ return {
61
+ version: 1,
62
+ implementation: {
63
+ language: "javascript",
64
+ name: "json-schema-library",
65
+ version: packageJson.version,
66
+ homepage: "https://github.com/sagold/json-schema-library",
67
+ issues: "https://github.com/sagold/json-schema-library/issues",
68
+ source: "https://github.com/sagold/json-schema-library",
69
+
70
+ dialects: [
71
+ "https://json-schema.org/draft/2020-12/schema",
72
+ "https://json-schema.org/draft/2019-09/schema",
73
+ "http://json-schema.org/draft-07/schema#",
74
+ "http://json-schema.org/draft-06/schema#",
75
+ "http://json-schema.org/draft-04/schema#"
76
+ ],
77
+ os: os.platform(),
78
+ os_version: os.release(),
79
+ language_version: process.version
80
+ }
81
+ };
82
+ },
83
+
84
+ dialect: async (args) => {
85
+ console.assert(started, "Not started!");
86
+ // dialect = schemaIds[args.dialect];
87
+ return { ok: true };
88
+ },
89
+
90
+ run: async (args) => {
91
+ console.assert(started, "Not started!");
92
+
93
+ // for (const id in testCase.registry) {
94
+ // ajv.addSchema(testCase.registry[id], id);
95
+ // }
96
+
97
+ const testCase = args.case;
98
+ // as {
99
+ // registry: Recors<sring, string>;
100
+ // schema: Record<string, any>;
101
+ // tests: {
102
+ // /** testdata */
103
+ // instance: unknown;
104
+ // }[];
105
+ // };
106
+
107
+ const node = compileSchema(testCase.schema);
108
+ const results = testCase.tests.map((test) => {
109
+ try {
110
+ const errors = node.validate(test.instance);
111
+ return { valid: errors.length === 0 };
112
+ } catch (error) {
113
+ return {
114
+ errored: true,
115
+ context: {
116
+ traceback: error.stack,
117
+ message: error.message
118
+ }
119
+ };
120
+ }
121
+ });
122
+
123
+ return { seq: args.seq, results: results };
124
+ },
125
+
126
+ stop: async (_) => {
127
+ console.assert(started, "Not started!");
128
+ process.exit(0);
129
+ }
130
+ };
131
+
132
+ async function main() {
133
+ for await (const line of stdio) {
134
+ const request = JSON.parse(line);
135
+ const response = await cmds[request.cmd](request);
136
+ send(response);
137
+ }
138
+ }
139
+
140
+ main();
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { compileSchema } from "./src/compileSchema";
2
2
  export type { CompileOptions } from "./src/compileSchema";
3
- export type { Context, SchemaNode, GetNodeOptions } from "./src/SchemaNode";
3
+ export type { Context, SchemaNode, GetNodeOptions, ValidateReturnType } from "./src/SchemaNode";
4
4
  export type { DataNode } from "./src/methods/toDataNodes";
5
5
  export type { Draft, DraftVersion } from "./src/Draft";
6
6
  export type { JsonError, JsonPointer, JsonSchema, OptionalNodeOrError, NodeOrError } from "./src/types";
@@ -9,6 +9,7 @@ export { draft04 } from "./src/draft04";
9
9
  export { draft06 } from "./src/draft06";
10
10
  export { draft07 } from "./src/draft07";
11
11
  export { draft2019 } from "./src/draft2019";
12
+ export { draft2020 } from "./src/draft2020";
12
13
  export { draftEditor } from "./src/draftEditor";
13
14
  export { oneOfFuzzyKeyword, oneOfKeyword } from "./src/keywords/oneOf";
14
15
  export { render } from "./src/errors/render";
@@ -19,4 +20,5 @@ export { isJsonError, isSchemaNode } from "./src/types";
19
20
  export { extendDraft, addKeywords } from "./src/Draft";
20
21
  export { mergeNode } from "./src/mergeNode";
21
22
  export { mergeSchema } from "./src/utils/mergeSchema";
23
+ export { getSchemaType } from "./src/utils/getSchemaType";
22
24
  export { remotes } from "./remotes";