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.
- package/.mocharc.js +5 -0
- package/CHANGELOG.md +2 -0
- package/README.md +160 -61
- package/bowtie_jlib.js +140 -0
- package/dist/index.d.ts +3 -1
- package/dist/jsonSchemaLibrary.js +1 -1
- package/dist/module/index.js +22 -0
- package/dist/module/remotes/index.js +43 -0
- package/dist/module/src/Draft.js +51 -0
- package/dist/module/src/SchemaNode.js +281 -0
- package/dist/module/src/compileSchema.js +69 -0
- package/dist/module/src/draft04/keywords/$ref.js +132 -0
- package/dist/module/src/draft04/keywords/exclusiveMaximum.js +20 -0
- package/dist/module/src/draft04/keywords/exclusiveMinimum.js +20 -0
- package/dist/module/src/draft04.js +105 -0
- package/dist/module/src/draft06/keywords/$ref.js +60 -0
- package/dist/module/src/draft06.js +107 -0
- package/dist/module/src/draft07.js +99 -0
- package/dist/module/src/draft2019-09/keywords/$ref.js +182 -0
- package/dist/module/src/draft2019-09/keywords/additionalItems.js +60 -0
- package/dist/module/src/draft2019-09/keywords/items.js +63 -0
- package/dist/module/src/draft2019-09/keywords/unevaluatedItems.js +82 -0
- package/dist/module/src/draft2019-09/methods/getChildSelection.js +40 -0
- package/dist/module/src/draft2019-09/methods/getData.js +299 -0
- package/dist/module/src/draft2019.js +110 -0
- package/dist/module/src/draft2020.js +120 -0
- package/dist/module/src/draftEditor.js +31 -0
- package/dist/module/src/errors/errors.js +67 -0
- package/dist/module/src/errors/render.js +11 -0
- package/dist/module/src/formats/formats.js +294 -0
- package/dist/module/src/getNode.js +44 -0
- package/dist/module/src/getNodeChild.js +45 -0
- package/dist/module/src/isItemEvaluated.js +59 -0
- package/dist/module/src/isPropertyEvaluated.js +69 -0
- package/dist/module/src/keywords/$defs.js +25 -0
- package/dist/module/src/keywords/$ref.js +214 -0
- package/dist/module/src/keywords/additionalProperties.js +91 -0
- package/dist/module/src/keywords/allOf.js +48 -0
- package/dist/module/src/keywords/anyOf.js +46 -0
- package/dist/module/src/keywords/const.js +14 -0
- package/dist/module/src/keywords/contains.js +64 -0
- package/dist/module/src/keywords/dependencies.js +117 -0
- package/dist/module/src/keywords/dependentRequired.js +52 -0
- package/dist/module/src/keywords/dependentSchemas.js +85 -0
- package/dist/module/src/keywords/enum.js +27 -0
- package/dist/module/src/keywords/exclusiveMaximum.js +20 -0
- package/dist/module/src/keywords/exclusiveMinimum.js +20 -0
- package/dist/module/src/keywords/format.js +11 -0
- package/dist/module/src/keywords/ifthenelse.js +66 -0
- package/dist/module/src/keywords/items.js +55 -0
- package/dist/module/src/keywords/maxItems.js +18 -0
- package/dist/module/src/keywords/maxLength.js +23 -0
- package/dist/module/src/keywords/maxProperties.js +23 -0
- package/dist/module/src/keywords/maximum.js +31 -0
- package/dist/module/src/keywords/minItems.js +21 -0
- package/dist/module/src/keywords/minLength.js +24 -0
- package/dist/module/src/keywords/minProperties.js +22 -0
- package/dist/module/src/keywords/minimum.js +31 -0
- package/dist/module/src/keywords/multipleOf.js +38 -0
- package/dist/module/src/keywords/not.js +20 -0
- package/dist/module/src/keywords/oneOf.js +240 -0
- package/dist/module/src/keywords/pattern.js +24 -0
- package/dist/module/src/keywords/patternProperties.js +98 -0
- package/dist/module/src/keywords/prefixItems.js +46 -0
- package/dist/module/src/keywords/properties.js +42 -0
- package/dist/module/src/keywords/propertyNames.js +59 -0
- package/dist/module/src/keywords/required.js +25 -0
- package/dist/module/src/keywords/type.js +40 -0
- package/dist/module/src/keywords/unevaluatedItems.js +74 -0
- package/dist/module/src/keywords/unevaluatedProperties.js +61 -0
- package/dist/module/src/keywords/uniqueItems.js +30 -0
- package/dist/module/src/mergeNode.js +112 -0
- package/dist/module/src/methods/createSchema.js +33 -0
- package/dist/module/src/methods/getChildSelection.js +40 -0
- package/dist/module/src/methods/getData.js +295 -0
- package/dist/module/src/methods/toDataNodes.js +27 -0
- package/dist/module/src/methods/toSchemaNodes.js +38 -0
- package/dist/module/src/settings.js +19 -0
- package/dist/module/src/tests/spec/draft04.spec.js +11 -0
- package/dist/module/src/tests/spec/draft06.spec.js +11 -0
- package/dist/module/src/tests/spec/draft07.spec.js +11 -0
- package/dist/module/src/tests/spec/draft2019-09.spec.js +79 -0
- package/dist/module/src/tests/spec/draft2020-12.spec.js +63 -0
- package/dist/module/src/tests/types.js +13 -0
- package/dist/module/src/tests/utils/addRemotes.js +17 -0
- package/dist/module/src/tests/utils/getDraftTests.js +36 -0
- package/dist/module/src/tests/utils/runTestCases.js +102 -0
- package/dist/module/src/types.js +9 -0
- package/dist/module/src/utils/copyDraft.js +6 -0
- package/dist/module/src/utils/getDefaultValue.js +15 -0
- package/dist/module/src/utils/getPrecision.js +11 -0
- package/dist/module/src/utils/getSchemaType.js +122 -0
- package/dist/module/src/utils/getTypeOf.js +8 -0
- package/dist/module/src/utils/getValue.js +9 -0
- package/dist/module/src/utils/hasProperty.js +2 -0
- package/dist/module/src/utils/isEmpty.js +17 -0
- package/dist/module/src/utils/isObject.js +4 -0
- package/dist/module/src/utils/isType.js +1 -0
- package/dist/module/src/utils/joinId.js +40 -0
- package/dist/module/src/utils/mergeSchema.js +77 -0
- package/dist/module/src/utils/omit.js +19 -0
- package/dist/module/src/utils/pick.js +9 -0
- package/dist/module/src/utils/punycode.ucs2decode.js +43 -0
- package/dist/module/src/utils/sanitizeErrors.js +16 -0
- package/dist/module/src/utils/splitRef.js +18 -0
- package/dist/module/src/validateNode.js +28 -0
- package/dist/src/SchemaNode.d.ts +36 -10
- package/dist/src/keywords/dependencies.d.ts +1 -1
- package/dist/src/keywords/oneOf.d.ts +2 -2
- package/dist/src/types.d.ts +1 -1
- package/index.ts +3 -1
- package/package.json +1 -1
- package/src/SchemaNode.ts +54 -24
- package/src/compileSchema.getChild.test.ts +40 -37
- package/src/compileSchema.reduceSchema.test.ts +18 -31
- package/src/compileSchema.test.ts +11 -11
- package/src/compileSchema.ts +3 -4
- package/src/compileSchema.validate.test.ts +32 -1
- package/src/draft04/keywords/$ref.ts +14 -13
- package/src/draft06/keywords/$ref.ts +5 -5
- package/src/draft2019-09/keywords/$ref.ts +13 -13
- package/src/draft2019-09/keywords/additionalItems.ts +3 -3
- package/src/draft2019-09/keywords/items.ts +7 -4
- package/src/draft2019-09/keywords/unevaluatedItems.ts +2 -2
- package/src/draft2019-09/methods/getData.ts +2 -3
- package/src/getNodeChild.ts +2 -2
- package/src/keywords/$defs.ts +10 -12
- package/src/keywords/$ref.ts +18 -21
- package/src/keywords/additionalProperties.ts +11 -3
- package/src/keywords/allOf.ts +5 -5
- package/src/keywords/anyOf.ts +5 -5
- package/src/keywords/contains.ts +4 -4
- package/src/keywords/dependencies.ts +12 -14
- package/src/keywords/dependentSchemas.ts +4 -4
- package/src/keywords/ifthenelse.ts +16 -6
- package/src/keywords/items.ts +6 -2
- package/src/keywords/not.ts +2 -2
- package/src/keywords/oneOf.ts +5 -5
- package/src/keywords/patternProperties.ts +4 -4
- package/src/keywords/prefixItems.ts +6 -2
- package/src/keywords/properties.ts +3 -3
- package/src/keywords/propertyNames.ts +2 -2
- package/src/keywords/type.ts +1 -1
- package/src/keywords/unevaluatedItems.ts +2 -2
- package/src/keywords/unevaluatedProperties.ts +2 -2
- package/src/mergeNode.ts +2 -2
- package/src/methods/eachSchema.test.ts +16 -16
- package/src/methods/getData.ts +2 -2
- package/src/types.ts +1 -1
- package/src/utils/getSchemaType.ts +9 -9
- package/src/utils/joinId.test.ts +8 -0
- package/src/utils/joinId.ts +4 -0
- package/src/validateNode.ts +2 -2
- package/src/validationPath.test.ts +1 -1
- package/tsconfig.json +1 -0
- package/webpack.config.js +49 -0
- package/dist/src/compileSchema.getNode.test.d.ts +0 -1
- package/dist/src/compileSchema.reduceSchema.test.d.ts +0 -1
- package/dist/src/compileSchema.test.d.ts +0 -1
- package/dist/src/compileSchema.validate.test.d.ts +0 -1
- package/dist/src/draft2019-09/compileSchema.getNode.test.d.ts +0 -1
- package/dist/src/draft2019-09/compileSchema.validate.test.d.ts +0 -1
- package/dist/src/draft2019-09/keywords/$ref.test.d.ts +0 -1
- package/dist/src/draft2019-09/keywords/additionalItems.test.d.ts +0 -1
- package/dist/src/draft2019-09/keywords/items.test.d.ts +0 -1
- package/dist/src/draft2019-09/methods/getChildSchemaSelection.test.d.ts +0 -1
- package/dist/src/draft2019-09/methods/getData.test.d.ts +0 -1
- package/dist/src/draft2019-09/methods/toDataNodes.test.d.ts +0 -1
- package/dist/src/extendDraft.test.d.ts +0 -1
- package/dist/src/keywords/additionalProperties.test.d.ts +0 -1
- package/dist/src/keywords/allOf.test.d.ts +0 -1
- package/dist/src/keywords/const.test.d.ts +0 -1
- package/dist/src/keywords/ifthenelse.test.d.ts +0 -1
- package/dist/src/keywords/object.test.d.ts +0 -1
- package/dist/src/keywords/oneOf.test.d.ts +0 -1
- package/dist/src/keywords/patternProperties.test.d.ts +0 -1
- package/dist/src/keywords/properties.test.d.ts +0 -1
- package/dist/src/keywords/required.test.d.ts +0 -1
- package/dist/src/keywords/string.test.d.ts +0 -1
- package/dist/src/keywords/type.test.d.ts +0 -1
- package/dist/src/mergeNode.test.d.ts +0 -1
- package/dist/src/methods/createSchema.test.d.ts +0 -1
- package/dist/src/methods/eachSchema.test.d.ts +0 -1
- package/dist/src/methods/getChildSelection.test.d.ts +0 -1
- package/dist/src/methods/getData.test.d.ts +0 -1
- package/dist/src/methods/toDataNodes.test.d.ts +0 -1
- package/dist/src/tests/issues/issue19.get.dependencies.test.d.ts +0 -1
- package/dist/src/tests/issues/issue21.getTemplate.test.d.ts +0 -1
- package/dist/src/tests/issues/issue22.each.test.d.ts +0 -1
- package/dist/src/tests/issues/issue32.getTemplate.integer.test.d.ts +0 -1
- package/dist/src/tests/issues/issue33.rootOneOf.test.d.ts +0 -1
- package/dist/src/tests/issues/issue35.oneOf.remote.test.d.ts +0 -1
- package/dist/src/tests/issues/issue38.getTemplate.anyOf.test.d.ts +0 -1
- package/dist/src/tests/issues/issue43.multipleOf.float.test.d.ts +0 -1
- package/dist/src/tests/issues/issue44.chainedNegLogic.test.d.ts +0 -1
- package/dist/src/tests/issues/issue52.test.d.ts +0 -1
- package/dist/src/tests/issues/issue57.allOfMutatesData.test.d.ts +0 -1
- package/dist/src/tests/issues/issue58.oneOfType.test.d.ts +0 -1
- package/dist/src/tests/issues/issue64.compileSchema.test.d.ts +0 -1
- package/dist/src/utils/getPrecision.test.d.ts +0 -1
- package/dist/src/utils/getTypeOf.test.d.ts +0 -1
- package/dist/src/utils/joinId.test.d.ts +0 -1
- package/dist/src/utils/mergeSchema.test.d.ts +0 -1
- package/dist/src/utils/splitRef.test.d.ts +0 -1
- package/dist/src/validationPath.test.d.ts +0 -1
- /package/dist/{src/compileSchema.getChild.test.d.ts → module/src/Keyword.js} +0 -0
package/.mocharc.js
ADDED
package/CHANGELOG.md
CHANGED
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-
|
|
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?:
|
|
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.
|
|
107
|
-
console.log(titleNode.
|
|
115
|
+
console.log(titleNode.evaluationPath); // #/properties/image/properties/title
|
|
116
|
+
console.log(titleNode.schemaLocation); // #/properties/image/properties/title
|
|
108
117
|
```
|
|
109
118
|
|
|
110
|
-
- `
|
|
111
|
-
- `
|
|
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
|
-
[
|
|
176
|
-
[
|
|
177
|
-
[
|
|
178
|
-
[
|
|
179
|
-
[
|
|
180
|
-
[
|
|
181
|
-
[
|
|
182
|
-
[
|
|
183
|
-
[
|
|
184
|
-
[
|
|
185
|
-
[
|
|
186
|
-
[
|
|
187
|
-
[
|
|
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
|
|
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
|
|
395
|
+
import { compileSchema, JsonSchema } from "json-schema-library";
|
|
387
396
|
|
|
388
397
|
const myJsonSchema: JsonSchema = {
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
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
|
-
|
|
413
|
-
|
|
414
|
-
|
|
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
|
-
`
|
|
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
|
-
`
|
|
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 {
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
1162
|
+
const { schema, evaluationPath, schemaLocation } = node;
|
|
1103
1163
|
if (schema.not != null) {
|
|
1104
|
-
node.not = node.compileSchema(schema.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.
|
|
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
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1314
|
+
```ts
|
|
1315
|
+
// PREVIOUSLY
|
|
1316
|
+
const draft = new Draft(schema);
|
|
1218
1317
|
|
|
1219
|
-
|
|
1220
|
-
|
|
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";
|