json-schema-library 10.0.0-rc9 → 10.1.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 +166 -62
- 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 +57 -0
- package/dist/module/src/draft2019-09/keywords/items.js +64 -0
- package/dist/module/src/draft2019-09/keywords/unevaluatedItems.js +82 -0
- package/dist/module/src/draft2019-09/methods/getChildSelection.js +39 -0
- package/dist/module/src/draft2019-09/methods/getData.js +298 -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 +111 -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 +37 -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 +69 -12
- 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 +87 -26
- 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 +10 -13
- package/src/draft2019-09/keywords/items.ts +10 -7
- package/src/draft2019-09/keywords/unevaluatedItems.ts +2 -2
- package/src/draft2019-09/methods/getChildSchemaSelection.test.ts +2 -0
- package/src/draft2019-09/methods/getChildSelection.ts +3 -4
- package/src/draft2019-09/methods/getData.test.ts +1 -0
- package/src/draft2019-09/methods/getData.ts +6 -8
- 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 -3
- package/src/methods/eachSchema.test.ts +16 -16
- package/src/methods/getData.ts +2 -2
- package/src/methods/toSchemaNodes.ts +0 -1
- 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,8 +16,6 @@
|
|
|
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)**.
|
|
20
|
-
|
|
21
19
|
**Quick start**
|
|
22
20
|
|
|
23
21
|
`npm install json-schema-library`
|
|
@@ -61,7 +59,16 @@ type CompileOptions = {
|
|
|
61
59
|
// if format-validations should create errors. Defaults to true
|
|
62
60
|
formatAssertion: boolean | "meta-schema";
|
|
63
61
|
// default options for all calls to node.getData()
|
|
64
|
-
getDataDefaultOptions?:
|
|
62
|
+
getDataDefaultOptions?: {
|
|
63
|
+
// Add all properties (required and optional) to the generated data
|
|
64
|
+
addOptionalProps?: boolean;
|
|
65
|
+
// Remove data that does not match input schema. Defaults to false
|
|
66
|
+
removeInvalidData?: boolean;
|
|
67
|
+
// Set to false to take default values as they are and not extend them. Defaults to true
|
|
68
|
+
extendDefaults?: boolean;
|
|
69
|
+
// Limits how often a $ref should be followed before aborting. Prevents infinite data-structure. Defaults to 1
|
|
70
|
+
recursionLimit?: number;
|
|
71
|
+
};
|
|
65
72
|
};
|
|
66
73
|
```
|
|
67
74
|
|
|
@@ -103,12 +110,12 @@ const titleData = titleNode?.getData();
|
|
|
103
110
|
|
|
104
111
|
```ts
|
|
105
112
|
const titleNode = compileSchema(mySchema).getNode("#/image/title");
|
|
106
|
-
console.log(titleNode.
|
|
107
|
-
console.log(titleNode.
|
|
113
|
+
console.log(titleNode.evaluationPath); // #/properties/image/properties/title
|
|
114
|
+
console.log(titleNode.schemaLocation); // #/properties/image/properties/title
|
|
108
115
|
```
|
|
109
116
|
|
|
110
|
-
- `
|
|
111
|
-
- `
|
|
117
|
+
- `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
|
+
- `schemaLocation` refers to the absolute path within the schema and will not change, e.g. `#/$defs/properties/title`
|
|
112
119
|
|
|
113
120
|
</details>
|
|
114
121
|
|
|
@@ -172,19 +179,19 @@ Please note that these benchmarks refer to validation only. _json-schema-library
|
|
|
172
179
|
|
|
173
180
|
## SchemaNode methods
|
|
174
181
|
|
|
175
|
-
[
|
|
176
|
-
[
|
|
177
|
-
[
|
|
178
|
-
[
|
|
179
|
-
[
|
|
180
|
-
[
|
|
181
|
-
[
|
|
182
|
-
[
|
|
183
|
-
[
|
|
184
|
-
[
|
|
185
|
-
[
|
|
186
|
-
[
|
|
187
|
-
[
|
|
182
|
+
[addRemoteSchema](#addremoteschema) ·
|
|
183
|
+
[compileSchema](#compileSchema-1) ·
|
|
184
|
+
[createSchema](#createSchema) ·
|
|
185
|
+
[getChildSelection](#getchildselection) ·
|
|
186
|
+
[getData](#getdata) ·
|
|
187
|
+
[getNode](#getnode) ·
|
|
188
|
+
[getNodeChild](#getnodechild) ·
|
|
189
|
+
[getNodeRef](#getnoderef) ·
|
|
190
|
+
[getNodeRoot](#getnoderoot) ·
|
|
191
|
+
[reduceNode](#reducenode) ·
|
|
192
|
+
[toDataNodes](#todatanodes) ·
|
|
193
|
+
[toSchemaNodes](#toschemanodes) ·
|
|
194
|
+
[validate](#validate)
|
|
188
195
|
|
|
189
196
|
</details>
|
|
190
197
|
|
|
@@ -192,7 +199,7 @@ Please note that these benchmarks refer to validation only. _json-schema-library
|
|
|
192
199
|
|
|
193
200
|
`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
201
|
|
|
195
|
-
Each
|
|
202
|
+
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
203
|
|
|
197
204
|
On a compiled schema
|
|
198
205
|
|
|
@@ -383,35 +390,35 @@ const myData = compileSchema(myJsonSchema).getData(inputData, { recursionLimit:
|
|
|
383
390
|
<details><summary>Example</summary>
|
|
384
391
|
|
|
385
392
|
```ts
|
|
386
|
-
import { compileSchema, JsonSchema } from
|
|
393
|
+
import { compileSchema, JsonSchema } from "json-schema-library";
|
|
387
394
|
|
|
388
395
|
const myJsonSchema: JsonSchema = {
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
396
|
+
type: "object",
|
|
397
|
+
required: ["name", "option", "list"],
|
|
398
|
+
properties: {
|
|
399
|
+
name: { type: "string" },
|
|
400
|
+
option: {
|
|
401
|
+
type: "string",
|
|
402
|
+
enum: ["first-option", "second-option"]
|
|
403
|
+
},
|
|
404
|
+
list: {
|
|
405
|
+
type: "array",
|
|
406
|
+
items: {
|
|
407
|
+
type: "string",
|
|
408
|
+
default: "new item"
|
|
409
|
+
},
|
|
410
|
+
minItems: 1
|
|
411
|
+
}
|
|
404
412
|
}
|
|
405
|
-
}
|
|
406
413
|
};
|
|
407
414
|
|
|
408
415
|
const schemaNode = new compileSchema(myJsonSchema);
|
|
409
416
|
const myData = schemaNode.getData();
|
|
410
417
|
|
|
411
418
|
expect(myData).to.deep.equal({
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
419
|
+
name: "",
|
|
420
|
+
option: "first-option",
|
|
421
|
+
list: ["new item"]
|
|
415
422
|
});
|
|
416
423
|
```
|
|
417
424
|
|
|
@@ -743,7 +750,7 @@ expect(reducedNode.schema).to.deep.eq({
|
|
|
743
750
|
|
|
744
751
|
### toDataNodes
|
|
745
752
|
|
|
746
|
-
`
|
|
753
|
+
`toDataNodes` collects all data-items (_object_, _array_ and _value_) and their SchemaNode and return them as a list of **DataNodes**:
|
|
747
754
|
|
|
748
755
|
```ts
|
|
749
756
|
type DataNode = { pointer: string; value: unknown; node: SchemaNode };
|
|
@@ -779,7 +786,7 @@ expect(calls).to.deep.equal([
|
|
|
779
786
|
|
|
780
787
|
### toSchemaNodes
|
|
781
788
|
|
|
782
|
-
`
|
|
789
|
+
`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
790
|
|
|
784
791
|
```ts
|
|
785
792
|
const nodes: SchemaNode[] = compileSchema(mySchema).toSchemaNodes();
|
|
@@ -846,10 +853,7 @@ In almost all cases, a JSON Pointer is given on _error.data.pointer_, which poin
|
|
|
846
853
|
<details><summary>Example</summary>
|
|
847
854
|
|
|
848
855
|
```ts
|
|
849
|
-
const myJsonSchema: JsonSchema = {
|
|
850
|
-
type: "object",
|
|
851
|
-
additionalProperties: false
|
|
852
|
-
};
|
|
856
|
+
const myJsonSchema: JsonSchema = { type: "object", additionalProperties: false };
|
|
853
857
|
|
|
854
858
|
const { errors } = compileSchema(myJsonSchema).validate({ name: "my-data" });
|
|
855
859
|
|
|
@@ -868,14 +872,14 @@ expect(errors).to.deep.equal([
|
|
|
868
872
|
You can also use async validators to validate data with json-schema. For this, another property asyncErrors is exposed on validate:
|
|
869
873
|
|
|
870
874
|
```ts
|
|
871
|
-
const {
|
|
875
|
+
const { errorsAsync } = compileSchema(myJsonSchema).validate(myData);
|
|
872
876
|
|
|
873
877
|
if (errorsAsync.length > 0) {
|
|
874
878
|
const additionalErrors = (await Promise.all(errorsAsync)).filter((err) => err != null);
|
|
875
879
|
}
|
|
876
880
|
```
|
|
877
881
|
|
|
878
|
-
Per default _json-schema-library_ does not
|
|
882
|
+
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
883
|
|
|
880
884
|
> **Note** `isValid` only refers to errors. `errorsAsync` has to be evaluated separately
|
|
881
885
|
|
|
@@ -1051,17 +1055,73 @@ const myDraft = extendDraft(draft2020, {
|
|
|
1051
1055
|
});
|
|
1052
1056
|
```
|
|
1053
1057
|
|
|
1054
|
-
|
|
1058
|
+
### Overwrite a format validator
|
|
1055
1059
|
|
|
1056
|
-
|
|
1060
|
+
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`
|
|
1057
1061
|
|
|
1058
|
-
|
|
1062
|
+
<details>
|
|
1063
|
+
<summary>Example of overwriting a format validator</summary>
|
|
1064
|
+
|
|
1065
|
+
```ts
|
|
1066
|
+
import { extendDraft, draft2020 } from "json-schema-library";
|
|
1067
|
+
|
|
1068
|
+
/**
|
|
1069
|
+
* A Regexp that extends http://tools.ietf.org/html/rfc3339#section-5.6 spec.
|
|
1070
|
+
* The specification requires seconds and timezones to be a valid date format.
|
|
1071
|
+
*
|
|
1072
|
+
* matchTimeSecondsAndTimeOptional matches:
|
|
1073
|
+
* - HH:MM:SSz
|
|
1074
|
+
* - HH:MM:SS(+/-)HH:MM
|
|
1075
|
+
* - HH:MM:SS
|
|
1076
|
+
* - HH:MMz
|
|
1077
|
+
* - HH:MM(+/-)HH:MM
|
|
1078
|
+
* - HH:MM
|
|
1079
|
+
*/
|
|
1080
|
+
const matchTimeSecondsAndTimeOptional =
|
|
1081
|
+
/^(?<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;
|
|
1082
|
+
|
|
1083
|
+
const customTimeFormatDraft = extendDraft(draft2020, {
|
|
1084
|
+
formats: {
|
|
1085
|
+
// This example extends the default time formatter which validates against RFC3339
|
|
1086
|
+
time: ({ node, pointer, data }) => {
|
|
1087
|
+
const { schema } = node;
|
|
1088
|
+
if (typeof data !== "string" || data === "") {
|
|
1089
|
+
return undefined;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
// Use the Custom Regex to validate the date and time.
|
|
1093
|
+
const matches = data.match(matchTimeSecondsAndTimeOptional);
|
|
1094
|
+
if (!matches) {
|
|
1095
|
+
return node.createError("format-date-time-error", { value: data, pointer, schema });
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
// leap second
|
|
1099
|
+
if (matches.groups.second === "60") {
|
|
1100
|
+
// Omitted the code here for brevity.
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
return undefined;
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
});
|
|
1107
|
+
|
|
1108
|
+
const { errors, valid } = compileSchema(
|
|
1109
|
+
{
|
|
1110
|
+
type: "string",
|
|
1111
|
+
format: "time",
|
|
1112
|
+
$schema: "https://json-schema.org/draft/2020-12/schema"
|
|
1113
|
+
},
|
|
1114
|
+
{ drafts: [customTimeFormatDraft] }
|
|
1115
|
+
).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,8 +1260,45 @@ 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
|
|
|
1297
|
+
### v10.1.0
|
|
1298
|
+
|
|
1299
|
+
- replaced `node.additionalItems` by `node.items` for drafts below 2020-12
|
|
1300
|
+
- fixed `additionalItems` behaviour to be ignored when `schema.items` is not an array
|
|
1301
|
+
|
|
1198
1302
|
### v10.0.0
|
|
1199
1303
|
|
|
1200
1304
|
> This update involves some significant changes in how you work with the library, so please carefully review the migration guide and adjust your implementation accordingly.
|
|
@@ -1212,13 +1316,13 @@ The new implementation revolves around compiling schemas into a **SchemaNode** t
|
|
|
1212
1316
|
|
|
1213
1317
|
**`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
1318
|
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1319
|
+
```ts
|
|
1320
|
+
// PREVIOUSLY
|
|
1321
|
+
const draft = new Draft(schema);
|
|
1218
1322
|
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1323
|
+
// NOW
|
|
1324
|
+
const node = compileSchema(schema);
|
|
1325
|
+
```
|
|
1222
1326
|
|
|
1223
1327
|
**Changed Methods**:
|
|
1224
1328
|
|
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";
|