json-schema-library 11.0.5 → 11.2.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 +1 -0
- package/CHANGELOG.md +17 -0
- package/README.md +120 -0
- package/bowtie/.editorconfig +21 -0
- package/bowtie/.prettierrc +6 -0
- package/bowtie/BOWTIE.md +54 -0
- package/bowtie/Dockerfile +6 -0
- package/bowtie/bowtie-api.ts +101 -0
- package/bowtie/bowtie.test.ts +76 -0
- package/bowtie/bowtie.ts +156 -0
- package/bowtie/package.json +11 -0
- package/bowtie/tsconfig.json +12 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +39 -470
- package/dist/index.d.mts +39 -470
- package/dist/index.mjs +1 -1
- package/dist/jlib.js +2 -13
- package/dist/remotes/index.cjs +1 -0
- package/dist/remotes/index.d.cts +7 -0
- package/dist/remotes/index.d.mts +7 -0
- package/dist/remotes/index.mjs +1 -0
- package/dist/types-B2wwNWyo.d.cts +513 -0
- package/dist/types-BhTU1l2h.d.mts +513 -0
- package/index.ts +10 -4
- package/package.json +14 -8
- package/src/Keyword.ts +37 -12
- package/src/SchemaNode.ts +84 -16
- package/src/compileSchema.ts +56 -4
- package/src/draft04/keywords/$ref.ts +22 -14
- package/src/draft04/keywords/exclusiveMaximum.ts +14 -0
- package/src/draft04/keywords/exclusiveMinimum.ts +14 -0
- package/src/draft04/validateSchema.test.ts +20 -0
- package/src/draft06/keywords/$ref.ts +15 -5
- package/src/draft2019-09/keywords/$ref.test.ts +3 -1
- package/src/draft2019-09/keywords/$ref.ts +40 -16
- package/src/draft2019-09/keywords/additionalItems.ts +33 -10
- package/src/draft2019-09/keywords/items.ts +32 -10
- package/src/draft2019-09/keywords/unevaluatedItems.ts +19 -6
- package/src/draft2019-09/methods/getData.ts +1 -1
- package/src/draft2019-09/validateSchema.test.ts +28 -0
- package/src/errors/errors.ts +8 -1
- package/src/formats/formats.ts +35 -28
- package/src/formats/hyperjump.d.ts +172 -0
- package/src/keywords/$defs.ts +34 -8
- package/src/keywords/$ref.ts +59 -13
- package/src/keywords/additionalProperties.ts +19 -8
- package/src/keywords/allOf.ts +44 -18
- package/src/keywords/anyOf.ts +38 -19
- package/src/keywords/contains.ts +21 -9
- package/src/keywords/dependencies.ts +37 -17
- package/src/keywords/dependentRequired.ts +56 -38
- package/src/keywords/dependentSchemas.ts +37 -13
- package/src/keywords/deprecated.ts +32 -8
- package/src/keywords/enum.ts +30 -8
- package/src/keywords/exclusiveMaximum.ts +21 -2
- package/src/keywords/exclusiveMinimum.ts +22 -3
- package/src/keywords/format.ts +21 -2
- package/src/keywords/ifthenelse.ts +49 -5
- package/src/keywords/items.ts +27 -13
- package/src/keywords/maxItems.ts +22 -2
- package/src/keywords/maxLength.ts +30 -9
- package/src/keywords/maxProperties.ts +30 -9
- package/src/keywords/maximum.ts +28 -8
- package/src/keywords/minItems.ts +30 -9
- package/src/keywords/minLength.ts +30 -9
- package/src/keywords/minProperties.ts +26 -5
- package/src/keywords/minimum.ts +32 -13
- package/src/keywords/multipleOf.ts +33 -12
- package/src/keywords/not.ts +23 -10
- package/src/keywords/oneOf.ts +29 -9
- package/src/keywords/pattern.ts +35 -9
- package/src/keywords/properties.ts +34 -11
- package/src/keywords/propertyDependencies.test.ts +180 -0
- package/src/keywords/propertyDependencies.ts +173 -0
- package/src/keywords/propertyNames.ts +26 -14
- package/src/keywords/required.ts +31 -8
- package/src/keywords/type.ts +53 -16
- package/src/keywords/unevaluatedItems.ts +24 -8
- package/src/keywords/unevaluatedProperties.ts +24 -7
- package/src/keywords/uniqueItems.ts +23 -4
- package/src/mergeNode.ts +9 -4
- package/src/methods/getData.ts +1 -1
- package/src/settings.ts +2 -1
- package/src/types.ts +1 -1
- package/src/utils/isListOfStrings.ts +3 -0
- package/src/validate.test.ts +0 -2
- package/src/validateNode.ts +6 -3
- package/src/validateSchema.test.ts +312 -0
- package/tsconfig.json +11 -4
- package/tsconfig.test.json +9 -2
- package/tsdown.config.ts +1 -1
- package/Dockerfile +0 -6
- package/bowtie_jlib.js +0 -140
- package/remotes/draft04.json +0 -150
- package/remotes/draft06.json +0 -155
- package/remotes/draft07.json +0 -155
- package/remotes/draft2019-09.json +0 -42
- package/remotes/draft2019-09_meta_applicator.json +0 -53
- package/remotes/draft2019-09_meta_content.json +0 -14
- package/remotes/draft2019-09_meta_core.json +0 -54
- package/remotes/draft2019-09_meta_format.json +0 -11
- package/remotes/draft2019-09_meta_meta-data.json +0 -34
- package/remotes/draft2019-09_meta_validation.json +0 -95
- package/remotes/draft2020-12.json +0 -55
- package/remotes/draft2020-12_meta_applicator.json +0 -45
- package/remotes/draft2020-12_meta_content.json +0 -14
- package/remotes/draft2020-12_meta_core.json +0 -48
- package/remotes/draft2020-12_meta_format_annotation.json +0 -11
- package/remotes/draft2020-12_meta_format_assertion.json +0 -11
- package/remotes/draft2020-12_meta_meta_data.json +0 -34
- package/remotes/draft2020-12_meta_unevaluated.json +0 -12
- package/remotes/draft2020-12_meta_validation.json +0 -87
- package/remotes/index.ts +0 -48
|
@@ -1,25 +1,46 @@
|
|
|
1
1
|
import { isObject } from "../utils/isObject";
|
|
2
2
|
import { Keyword, JsonSchemaValidatorParams } from "../Keyword";
|
|
3
|
+
import { SchemaNode } from "../SchemaNode";
|
|
4
|
+
import { isNumber } from "../types";
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
const KEYWORD = "maxProperties";
|
|
7
|
+
|
|
8
|
+
export const maxPropertiesKeyword: Keyword<typeof KEYWORD> = {
|
|
9
|
+
id: KEYWORD,
|
|
10
|
+
keyword: KEYWORD,
|
|
11
|
+
parse: parseMaxProperties,
|
|
12
|
+
addValidate: (node) => node[KEYWORD] != null,
|
|
8
13
|
validate: validateMaxProperties
|
|
9
14
|
};
|
|
10
15
|
|
|
11
|
-
function
|
|
16
|
+
function parseMaxProperties(node: SchemaNode) {
|
|
17
|
+
const max = node.schema[KEYWORD];
|
|
18
|
+
if (max == null) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (!isNumber(max)) {
|
|
22
|
+
return node.createError("schema-error", {
|
|
23
|
+
pointer: `${node.schemaLocation}/${KEYWORD}`,
|
|
24
|
+
schema: node.schema,
|
|
25
|
+
value: max,
|
|
26
|
+
message: `Keyword '${KEYWORD}' must be a number - received '${typeof max}'`
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
node[KEYWORD] = max;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function validateMaxProperties({ node, data, pointer = "#" }: JsonSchemaValidatorParams<typeof KEYWORD>) {
|
|
12
33
|
if (!isObject(data)) {
|
|
13
34
|
return;
|
|
14
35
|
}
|
|
15
|
-
const
|
|
36
|
+
const maxProperties = node[KEYWORD];
|
|
16
37
|
const propertyCount = Object.keys(data).length;
|
|
17
|
-
if (
|
|
38
|
+
if (maxProperties < propertyCount) {
|
|
18
39
|
return node.createError("max-properties-error", {
|
|
19
|
-
maxProperties:
|
|
40
|
+
maxProperties: maxProperties,
|
|
20
41
|
length: propertyCount,
|
|
21
42
|
pointer,
|
|
22
|
-
schema,
|
|
43
|
+
schema: node.schema,
|
|
23
44
|
value: data
|
|
24
45
|
});
|
|
25
46
|
}
|
package/src/keywords/maximum.ts
CHANGED
|
@@ -1,31 +1,51 @@
|
|
|
1
1
|
import { Keyword, JsonSchemaValidatorParams } from "../Keyword";
|
|
2
|
-
import { isNumber } from "../types";
|
|
2
|
+
import { isNumber, SchemaNode } from "../types";
|
|
3
|
+
|
|
4
|
+
const KEYWORD = "maximum";
|
|
3
5
|
|
|
4
6
|
export const maximumKeyword: Keyword = {
|
|
5
|
-
id:
|
|
6
|
-
keyword:
|
|
7
|
-
|
|
7
|
+
id: KEYWORD,
|
|
8
|
+
keyword: KEYWORD,
|
|
9
|
+
parse: parseMaximum,
|
|
10
|
+
addValidate: (node) => node.maximum != null,
|
|
8
11
|
validate: validateMaximum
|
|
9
12
|
};
|
|
10
13
|
|
|
14
|
+
function parseMaximum(node: SchemaNode) {
|
|
15
|
+
const max = node.schema[KEYWORD];
|
|
16
|
+
if (max == null) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (!isNumber(max)) {
|
|
20
|
+
return node.createError("schema-error", {
|
|
21
|
+
pointer: `${node.schemaLocation}/${KEYWORD}`,
|
|
22
|
+
schema: node.schema,
|
|
23
|
+
value: max,
|
|
24
|
+
message: `Keyword '${KEYWORD}' must be a number - received '${typeof max}'`
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
node[KEYWORD] = max;
|
|
28
|
+
}
|
|
29
|
+
|
|
11
30
|
function validateMaximum({ node, data, pointer }: JsonSchemaValidatorParams) {
|
|
12
31
|
if (!isNumber(data)) {
|
|
13
32
|
return undefined;
|
|
14
33
|
}
|
|
15
34
|
|
|
35
|
+
const max = node[KEYWORD];
|
|
16
36
|
const { schema } = node;
|
|
17
|
-
if (
|
|
37
|
+
if (max && max < data) {
|
|
18
38
|
return node.createError("maximum-error", {
|
|
19
|
-
maximum:
|
|
39
|
+
maximum: max,
|
|
20
40
|
length: data,
|
|
21
41
|
value: data,
|
|
22
42
|
pointer,
|
|
23
43
|
schema
|
|
24
44
|
});
|
|
25
45
|
}
|
|
26
|
-
if (
|
|
46
|
+
if (max && schema.exclusiveMaximum === true && max === data) {
|
|
27
47
|
return node.createError("maximum-error", {
|
|
28
|
-
maximum:
|
|
48
|
+
maximum: max,
|
|
29
49
|
length: data,
|
|
30
50
|
pointer,
|
|
31
51
|
schema,
|
package/src/keywords/minItems.ts
CHANGED
|
@@ -1,23 +1,44 @@
|
|
|
1
1
|
import { JsonSchemaValidatorParams, Keyword } from "../Keyword";
|
|
2
|
+
import { SchemaNode } from "../SchemaNode";
|
|
3
|
+
import { isNumber } from "../types";
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
const KEYWORD = "minItems";
|
|
6
|
+
|
|
7
|
+
export const minItemsKeyword: Keyword<"minItems"> = {
|
|
8
|
+
id: KEYWORD,
|
|
9
|
+
keyword: KEYWORD,
|
|
10
|
+
parse: parseMinItems,
|
|
11
|
+
addValidate: (node) => node[KEYWORD] != null,
|
|
7
12
|
validate: validateMinItems
|
|
8
13
|
};
|
|
9
14
|
|
|
10
|
-
function
|
|
15
|
+
function parseMinItems(node: SchemaNode) {
|
|
16
|
+
const min = node.schema[KEYWORD];
|
|
17
|
+
if (min == null) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (!isNumber(min)) {
|
|
21
|
+
return node.createError("schema-error", {
|
|
22
|
+
pointer: `${node.schemaLocation}/${KEYWORD}`,
|
|
23
|
+
schema: node.schema,
|
|
24
|
+
value: min,
|
|
25
|
+
message: `Keyword '${KEYWORD}' must be a number - received '${typeof min}'`
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
node[KEYWORD] = min;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function validateMinItems({ node, data, pointer }: JsonSchemaValidatorParams<"minItems">) {
|
|
11
32
|
if (!Array.isArray(data)) {
|
|
12
33
|
return;
|
|
13
34
|
}
|
|
14
|
-
const
|
|
15
|
-
if (
|
|
35
|
+
const minItems = node[KEYWORD];
|
|
36
|
+
if (minItems > data.length) {
|
|
16
37
|
return node.createError("min-items-error", {
|
|
17
|
-
minItems:
|
|
38
|
+
minItems: minItems,
|
|
18
39
|
length: data.length,
|
|
19
40
|
pointer,
|
|
20
|
-
schema,
|
|
41
|
+
schema: node.schema,
|
|
21
42
|
value: data
|
|
22
43
|
});
|
|
23
44
|
}
|
|
@@ -1,27 +1,48 @@
|
|
|
1
1
|
import ucs2decode from "../utils/punycode.ucs2decode";
|
|
2
2
|
import { Keyword, JsonSchemaValidatorParams } from "../Keyword";
|
|
3
|
+
import { SchemaNode } from "../SchemaNode";
|
|
4
|
+
import { isNumber } from "../types";
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
const KEYWORD = "minLength";
|
|
7
|
+
|
|
8
|
+
export const minLengthKeyword: Keyword<"minLength"> = {
|
|
9
|
+
id: KEYWORD,
|
|
10
|
+
keyword: KEYWORD,
|
|
11
|
+
parse: parseMinLength,
|
|
12
|
+
addValidate: (node) => node[KEYWORD] != null,
|
|
8
13
|
validate: validateMinLength
|
|
9
14
|
};
|
|
10
15
|
|
|
11
|
-
function
|
|
16
|
+
function parseMinLength(node: SchemaNode) {
|
|
17
|
+
const min = node.schema[KEYWORD];
|
|
18
|
+
if (min == null) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (!isNumber(min)) {
|
|
22
|
+
return node.createError("schema-error", {
|
|
23
|
+
pointer: `${node.schemaLocation}/${KEYWORD}`,
|
|
24
|
+
schema: node.schema,
|
|
25
|
+
value: min,
|
|
26
|
+
message: `Keyword '${KEYWORD}' must be a number - received '${typeof min}'`
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
node[KEYWORD] = min;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function validateMinLength({ node, data, pointer = "#" }: JsonSchemaValidatorParams<"minLength">) {
|
|
12
33
|
if (typeof data !== "string") {
|
|
13
34
|
return;
|
|
14
35
|
}
|
|
15
|
-
const { schema } = node;
|
|
16
36
|
const length = ucs2decode(data).length;
|
|
17
|
-
|
|
37
|
+
const minLength = node[KEYWORD];
|
|
38
|
+
if (minLength <= length) {
|
|
18
39
|
return;
|
|
19
40
|
}
|
|
20
41
|
return node.createError("min-length-error", {
|
|
21
|
-
minLength
|
|
42
|
+
minLength,
|
|
22
43
|
length,
|
|
23
44
|
pointer,
|
|
24
|
-
schema,
|
|
45
|
+
schema: node.schema,
|
|
25
46
|
value: data
|
|
26
47
|
});
|
|
27
48
|
}
|
|
@@ -1,14 +1,35 @@
|
|
|
1
1
|
import { isObject } from "../utils/isObject";
|
|
2
2
|
import { Keyword, JsonSchemaValidatorParams } from "../Keyword";
|
|
3
|
+
import { SchemaNode } from "../SchemaNode";
|
|
4
|
+
import { isNumber } from "../types";
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
const KEYWORD = "minProperties";
|
|
7
|
+
|
|
8
|
+
export const minPropertiesKeyword: Keyword<"minProperties"> = {
|
|
9
|
+
id: KEYWORD,
|
|
10
|
+
keyword: KEYWORD,
|
|
11
|
+
parse: parseMinItems,
|
|
12
|
+
addValidate: (node) => node[KEYWORD] != null,
|
|
8
13
|
validate: validateMinProperties
|
|
9
14
|
};
|
|
10
15
|
|
|
11
|
-
function
|
|
16
|
+
function parseMinItems(node: SchemaNode) {
|
|
17
|
+
const min = node.schema[KEYWORD];
|
|
18
|
+
if (min == null) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (!isNumber(min)) {
|
|
22
|
+
return node.createError("schema-error", {
|
|
23
|
+
pointer: `${node.schemaLocation}/${KEYWORD}`,
|
|
24
|
+
schema: node.schema,
|
|
25
|
+
value: min,
|
|
26
|
+
message: `Keyword '${KEYWORD}' must be a number - received '${typeof min}'`
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
node[KEYWORD] = min;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function validateMinProperties({ node, data, pointer = "#" }: JsonSchemaValidatorParams<"minProperties">) {
|
|
12
33
|
if (!isObject(data)) {
|
|
13
34
|
return;
|
|
14
35
|
}
|
package/src/keywords/minimum.ts
CHANGED
|
@@ -1,33 +1,52 @@
|
|
|
1
1
|
import { Keyword, JsonSchemaValidatorParams } from "../Keyword";
|
|
2
|
-
import { isNumber } from "../types";
|
|
2
|
+
import { isNumber, SchemaNode } from "../types";
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
const KEYWORD = "minimum";
|
|
5
|
+
|
|
6
|
+
export const minimumKeyword: Keyword<"minimum"> = {
|
|
7
|
+
id: KEYWORD,
|
|
8
|
+
keyword: KEYWORD,
|
|
9
|
+
parse: parseMinimum,
|
|
10
|
+
addValidate: (node) => node[KEYWORD] != null,
|
|
8
11
|
validate: validateMinimum
|
|
9
12
|
};
|
|
10
13
|
|
|
11
|
-
function
|
|
14
|
+
function parseMinimum(node: SchemaNode) {
|
|
15
|
+
const min = node.schema[KEYWORD];
|
|
16
|
+
if (min == null) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (!isNumber(min)) {
|
|
20
|
+
return node.createError("schema-error", {
|
|
21
|
+
pointer: `${node.schemaLocation}/${KEYWORD}`,
|
|
22
|
+
schema: node.schema,
|
|
23
|
+
value: min,
|
|
24
|
+
message: `Keyword '${KEYWORD}' must be a number - received '${typeof min}'`
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
node[KEYWORD] = min;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function validateMinimum({ node, data, pointer }: JsonSchemaValidatorParams<"minimum">) {
|
|
12
31
|
if (!isNumber(data)) {
|
|
13
32
|
return undefined;
|
|
14
33
|
}
|
|
15
|
-
const
|
|
16
|
-
if (
|
|
34
|
+
const min = node[KEYWORD];
|
|
35
|
+
if (min > data) {
|
|
17
36
|
return node.createError("minimum-error", {
|
|
18
|
-
minimum:
|
|
37
|
+
minimum: min,
|
|
19
38
|
length: data,
|
|
20
39
|
pointer,
|
|
21
|
-
schema,
|
|
40
|
+
schema: node.schema,
|
|
22
41
|
value: data
|
|
23
42
|
});
|
|
24
43
|
}
|
|
25
|
-
if (schema.exclusiveMinimum === true && schema.minimum === data) {
|
|
44
|
+
if (node.schema.exclusiveMinimum === true && node.schema.minimum === data) {
|
|
26
45
|
return node.createError("minimum-error", {
|
|
27
|
-
minimum:
|
|
46
|
+
minimum: min,
|
|
28
47
|
length: data,
|
|
29
48
|
pointer,
|
|
30
|
-
schema,
|
|
49
|
+
schema: node.schema,
|
|
31
50
|
value: data
|
|
32
51
|
});
|
|
33
52
|
}
|
|
@@ -1,39 +1,60 @@
|
|
|
1
1
|
import { getPrecision } from "../utils/getPrecision";
|
|
2
2
|
import { Keyword, JsonSchemaValidatorParams } from "../Keyword";
|
|
3
|
+
import { SchemaNode } from "../SchemaNode";
|
|
4
|
+
import { isNumber } from "../types";
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
const KEYWORD = "multipleOf";
|
|
7
|
+
|
|
8
|
+
export const multipleOfKeyword: Keyword<"multipleOf"> = {
|
|
9
|
+
id: KEYWORD,
|
|
10
|
+
keyword: KEYWORD,
|
|
11
|
+
parse: parseMultipleOf,
|
|
12
|
+
addValidate: (node) => node[KEYWORD] != null,
|
|
8
13
|
validate: validateMultipleOf
|
|
9
14
|
};
|
|
10
15
|
|
|
11
|
-
function
|
|
16
|
+
function parseMultipleOf(node: SchemaNode) {
|
|
17
|
+
const multipleOf = node.schema[KEYWORD];
|
|
18
|
+
if (multipleOf == null) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (!isNumber(multipleOf)) {
|
|
22
|
+
return node.createError("schema-error", {
|
|
23
|
+
pointer: `${node.schemaLocation}/${KEYWORD}`,
|
|
24
|
+
schema: node.schema,
|
|
25
|
+
value: multipleOf,
|
|
26
|
+
message: `Keyword '${KEYWORD}' must be a number - received '${typeof multipleOf}'`
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
node[KEYWORD] = multipleOf;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function validateMultipleOf({ node, data, pointer }: JsonSchemaValidatorParams<"multipleOf">) {
|
|
12
33
|
if (typeof data !== "number") {
|
|
13
34
|
return undefined;
|
|
14
35
|
}
|
|
15
|
-
const
|
|
36
|
+
const multipleOf = node[KEYWORD];
|
|
16
37
|
const valuePrecision = getPrecision(data);
|
|
17
|
-
const multiplePrecision = getPrecision(
|
|
38
|
+
const multiplePrecision = getPrecision(multipleOf);
|
|
18
39
|
if (valuePrecision > multiplePrecision) {
|
|
19
40
|
// value with higher precision then multipleOf-precision can never be multiple
|
|
20
41
|
return node.createError("multiple-of-error", {
|
|
21
|
-
multipleOf
|
|
42
|
+
multipleOf,
|
|
22
43
|
value: data,
|
|
23
44
|
pointer,
|
|
24
|
-
schema
|
|
45
|
+
schema: node.schema
|
|
25
46
|
});
|
|
26
47
|
}
|
|
27
48
|
|
|
28
49
|
const precision = Math.pow(10, multiplePrecision);
|
|
29
50
|
const val = Math.round(data * precision);
|
|
30
|
-
const multiple = Math.round(
|
|
51
|
+
const multiple = Math.round(multipleOf * precision);
|
|
31
52
|
if ((val % multiple) / precision !== 0) {
|
|
32
53
|
return node.createError("multiple-of-error", {
|
|
33
|
-
multipleOf:
|
|
54
|
+
multipleOf: multipleOf,
|
|
34
55
|
value: data,
|
|
35
56
|
pointer,
|
|
36
|
-
schema
|
|
57
|
+
schema: node.schema
|
|
37
58
|
});
|
|
38
59
|
}
|
|
39
60
|
|
package/src/keywords/not.ts
CHANGED
|
@@ -1,26 +1,39 @@
|
|
|
1
1
|
import { Keyword, JsonSchemaValidatorParams } from "../Keyword";
|
|
2
|
-
import { SchemaNode } from "../types";
|
|
2
|
+
import { isBooleanSchema, isJsonSchema, SchemaNode } from "../types";
|
|
3
3
|
import { validateNode } from "../validateNode";
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
const KEYWORD = "not";
|
|
6
|
+
|
|
7
|
+
export const notKeyword: Keyword<"not"> = {
|
|
8
|
+
id: KEYWORD,
|
|
9
|
+
keyword: KEYWORD,
|
|
8
10
|
parse: parseNot,
|
|
9
|
-
addValidate: (node) => node
|
|
11
|
+
addValidate: (node) => node[KEYWORD] != null,
|
|
10
12
|
validate: validateNot
|
|
11
13
|
};
|
|
12
14
|
|
|
13
15
|
export function parseNot(node: SchemaNode) {
|
|
14
16
|
const { schema, evaluationPath, schemaLocation } = node;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
const not = schema[KEYWORD];
|
|
18
|
+
if (not == null) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (!isJsonSchema(not) && !isBooleanSchema(not)) {
|
|
22
|
+
return node.createError("schema-error", {
|
|
23
|
+
pointer: `${schemaLocation}/${KEYWORD}`,
|
|
24
|
+
schema,
|
|
25
|
+
value: not,
|
|
26
|
+
message: `Keyword '${KEYWORD}' must be a valid JSON Schema - received '${typeof not}'`
|
|
27
|
+
});
|
|
17
28
|
}
|
|
29
|
+
node[KEYWORD] = node.compileSchema(schema[KEYWORD], `${evaluationPath}/not`, `${schemaLocation}/not`);
|
|
30
|
+
return node[KEYWORD].schemaValidation;
|
|
18
31
|
}
|
|
19
32
|
|
|
20
|
-
function validateNot({ node, data, pointer, path }: JsonSchemaValidatorParams) {
|
|
33
|
+
function validateNot({ node, data, pointer, path }: JsonSchemaValidatorParams<"not">) {
|
|
21
34
|
const { schema } = node;
|
|
22
35
|
// not has been tested in addValidate
|
|
23
|
-
if (validateNode(node
|
|
24
|
-
return node.createError("not-error", { value: data, not: schema
|
|
36
|
+
if (validateNode(node[KEYWORD]!, data, pointer, path).length === 0) {
|
|
37
|
+
return node.createError("not-error", { value: data, not: schema[KEYWORD], pointer, schema });
|
|
25
38
|
}
|
|
26
39
|
}
|
package/src/keywords/oneOf.ts
CHANGED
|
@@ -3,7 +3,8 @@ import {
|
|
|
3
3
|
JsonSchemaReducerParams,
|
|
4
4
|
JsonSchemaValidatorParams,
|
|
5
5
|
ValidationPath,
|
|
6
|
-
ValidationReturnType
|
|
6
|
+
ValidationReturnType,
|
|
7
|
+
ValidationAnnotation
|
|
7
8
|
} from "../Keyword";
|
|
8
9
|
import { isSchemaNode, SchemaNode } from "../types";
|
|
9
10
|
import settings from "../settings";
|
|
@@ -13,15 +14,16 @@ import { isObject } from "../utils/isObject";
|
|
|
13
14
|
import { validateNode } from "../validateNode";
|
|
14
15
|
import { joinDynamicId } from "../SchemaNode";
|
|
15
16
|
|
|
17
|
+
const KEYWORD = "oneOf";
|
|
16
18
|
const { DECLARATOR_ONEOF } = settings;
|
|
17
19
|
|
|
18
20
|
export const oneOfKeyword: Keyword = {
|
|
19
|
-
id:
|
|
20
|
-
keyword:
|
|
21
|
+
id: KEYWORD,
|
|
22
|
+
keyword: KEYWORD,
|
|
21
23
|
parse: parseOneOf,
|
|
22
|
-
addReduce: (node) => node
|
|
24
|
+
addReduce: (node) => node[KEYWORD] != null,
|
|
23
25
|
reduce: reduceOneOf,
|
|
24
|
-
addValidate: (node) => node
|
|
26
|
+
addValidate: (node) => node[KEYWORD] != null,
|
|
25
27
|
validate: oneOfValidator
|
|
26
28
|
};
|
|
27
29
|
|
|
@@ -37,11 +39,29 @@ export const oneOfFuzzyKeyword: Keyword = {
|
|
|
37
39
|
|
|
38
40
|
export function parseOneOf(node: SchemaNode) {
|
|
39
41
|
const { schema, evaluationPath, schemaLocation } = node;
|
|
40
|
-
if (
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
if (schema[KEYWORD] == null) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (!Array.isArray(schema[KEYWORD])) {
|
|
46
|
+
return node.createError("schema-error", {
|
|
47
|
+
pointer: schemaLocation,
|
|
48
|
+
schema,
|
|
49
|
+
value: schema[KEYWORD],
|
|
50
|
+
message: `Keyword '${KEYWORD}' must be an array - received '${typeof schema[KEYWORD]}'`
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
if (schema[KEYWORD].length === 0) {
|
|
54
|
+
return;
|
|
44
55
|
}
|
|
56
|
+
|
|
57
|
+
node[KEYWORD] = schema[KEYWORD].map((s, index) =>
|
|
58
|
+
node.compileSchema(s, `${evaluationPath}/${KEYWORD}/${index}`, `${schemaLocation}/${KEYWORD}/${index}`)
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
return node[KEYWORD].reduce((errors, node) => {
|
|
62
|
+
if (node.schemaValidation) errors.push(...node.schemaValidation);
|
|
63
|
+
return errors;
|
|
64
|
+
}, [] as ValidationAnnotation[]);
|
|
45
65
|
}
|
|
46
66
|
|
|
47
67
|
function reduceOneOf({ node, data, pointer, path }: Omit<JsonSchemaReducerParams, "key">) {
|
package/src/keywords/pattern.ts
CHANGED
|
@@ -1,22 +1,49 @@
|
|
|
1
1
|
import { Keyword, JsonSchemaValidatorParams } from "../Keyword";
|
|
2
|
+
import { SchemaNode } from "../SchemaNode";
|
|
2
3
|
import settings from "../settings";
|
|
3
4
|
|
|
5
|
+
const KEYWORD = "pattern";
|
|
4
6
|
const { REGEX_FLAGS } = settings;
|
|
5
7
|
|
|
6
|
-
export const patternKeyword: Keyword = {
|
|
7
|
-
id:
|
|
8
|
-
keyword:
|
|
9
|
-
|
|
8
|
+
export const patternKeyword: Keyword<"pattern"> = {
|
|
9
|
+
id: KEYWORD,
|
|
10
|
+
keyword: KEYWORD,
|
|
11
|
+
parse: parsePattern,
|
|
12
|
+
addValidate: (node) => node[KEYWORD] != null,
|
|
10
13
|
validate: validatePattern
|
|
11
14
|
};
|
|
12
15
|
|
|
13
|
-
function
|
|
14
|
-
const
|
|
16
|
+
function parsePattern(node: SchemaNode) {
|
|
17
|
+
const pattern = node.schema[KEYWORD];
|
|
18
|
+
if (pattern == null) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (typeof pattern !== "string") {
|
|
22
|
+
return node.createError("schema-error", {
|
|
23
|
+
pointer: node.schemaLocation,
|
|
24
|
+
schema: node.schema,
|
|
25
|
+
value: pattern,
|
|
26
|
+
message: `Keyword 'pattern' must be a string - received '${typeof pattern}'`
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
node[KEYWORD] = new RegExp(pattern, node.schema.regexFlags ?? REGEX_FLAGS);
|
|
31
|
+
} catch (e) {
|
|
32
|
+
return node.createError("schema-error", {
|
|
33
|
+
pointer: node.schemaLocation,
|
|
34
|
+
schema: node.schema,
|
|
35
|
+
value: pattern,
|
|
36
|
+
message: (e as Error).message
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function validatePattern({ node, data, pointer = "#" }: JsonSchemaValidatorParams<"pattern">) {
|
|
15
42
|
if (typeof data !== "string") {
|
|
16
43
|
return;
|
|
17
44
|
}
|
|
18
|
-
|
|
19
|
-
|
|
45
|
+
if (node.pattern.test(data) === false) {
|
|
46
|
+
const { schema } = node;
|
|
20
47
|
return node.createError("pattern-error", {
|
|
21
48
|
pattern: schema.pattern,
|
|
22
49
|
description: schema.patternExample || schema.pattern,
|
|
@@ -26,5 +53,4 @@ function validatePattern({ node, data, pointer = "#" }: JsonSchemaValidatorParam
|
|
|
26
53
|
pointer
|
|
27
54
|
});
|
|
28
55
|
}
|
|
29
|
-
return undefined;
|
|
30
56
|
}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { getValue } from "../utils/getValue";
|
|
2
2
|
import { SchemaNode } from "../types";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
Keyword,
|
|
5
|
+
JsonSchemaResolverParams,
|
|
6
|
+
JsonSchemaValidatorParams,
|
|
7
|
+
ValidationReturnType,
|
|
8
|
+
ValidationAnnotation
|
|
9
|
+
} from "../Keyword";
|
|
4
10
|
import { isObject } from "../utils/isObject";
|
|
5
11
|
import { validateNode } from "../validateNode";
|
|
6
12
|
|
|
@@ -20,18 +26,35 @@ function propertyResolver({ node, key }: JsonSchemaResolverParams) {
|
|
|
20
26
|
|
|
21
27
|
export function parseProperties(node: SchemaNode) {
|
|
22
28
|
const { schema, evaluationPath, schemaLocation } = node;
|
|
23
|
-
if (schema.properties) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
if (schema.properties == null) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (schema.properties && !isObject(schema.properties)) {
|
|
34
|
+
return node.createError("schema-error", {
|
|
35
|
+
pointer: schemaLocation,
|
|
36
|
+
schema,
|
|
37
|
+
value: undefined,
|
|
38
|
+
message: "keyword `properties` must be of type `object`"
|
|
32
39
|
});
|
|
33
|
-
node.properties = parsedProperties;
|
|
34
40
|
}
|
|
41
|
+
|
|
42
|
+
const errors: ValidationAnnotation[] = [];
|
|
43
|
+
const parsedProperties: Record<string, SchemaNode> = {};
|
|
44
|
+
Object.keys(schema.properties).forEach((propertyName) => {
|
|
45
|
+
const propertyNode = node.compileSchema(
|
|
46
|
+
schema.properties[propertyName],
|
|
47
|
+
`${evaluationPath}/properties/${propertyName}`,
|
|
48
|
+
`${schemaLocation}/properties/${propertyName}`
|
|
49
|
+
);
|
|
50
|
+
parsedProperties[propertyName] = propertyNode;
|
|
51
|
+
if (parsedProperties[propertyName].schemaValidation) {
|
|
52
|
+
errors.push(...parsedProperties[propertyName].schemaValidation);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
node.properties = parsedProperties;
|
|
56
|
+
|
|
57
|
+
return errors;
|
|
35
58
|
}
|
|
36
59
|
|
|
37
60
|
function validateProperties({ node, data, pointer, path }: JsonSchemaValidatorParams) {
|