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.
Files changed (113) hide show
  1. package/.mocharc.js +1 -0
  2. package/CHANGELOG.md +17 -0
  3. package/README.md +120 -0
  4. package/bowtie/.editorconfig +21 -0
  5. package/bowtie/.prettierrc +6 -0
  6. package/bowtie/BOWTIE.md +54 -0
  7. package/bowtie/Dockerfile +6 -0
  8. package/bowtie/bowtie-api.ts +101 -0
  9. package/bowtie/bowtie.test.ts +76 -0
  10. package/bowtie/bowtie.ts +156 -0
  11. package/bowtie/package.json +11 -0
  12. package/bowtie/tsconfig.json +12 -0
  13. package/dist/index.cjs +1 -1
  14. package/dist/index.d.cts +39 -470
  15. package/dist/index.d.mts +39 -470
  16. package/dist/index.mjs +1 -1
  17. package/dist/jlib.js +2 -13
  18. package/dist/remotes/index.cjs +1 -0
  19. package/dist/remotes/index.d.cts +7 -0
  20. package/dist/remotes/index.d.mts +7 -0
  21. package/dist/remotes/index.mjs +1 -0
  22. package/dist/types-B2wwNWyo.d.cts +513 -0
  23. package/dist/types-BhTU1l2h.d.mts +513 -0
  24. package/index.ts +10 -4
  25. package/package.json +14 -8
  26. package/src/Keyword.ts +37 -12
  27. package/src/SchemaNode.ts +84 -16
  28. package/src/compileSchema.ts +56 -4
  29. package/src/draft04/keywords/$ref.ts +22 -14
  30. package/src/draft04/keywords/exclusiveMaximum.ts +14 -0
  31. package/src/draft04/keywords/exclusiveMinimum.ts +14 -0
  32. package/src/draft04/validateSchema.test.ts +20 -0
  33. package/src/draft06/keywords/$ref.ts +15 -5
  34. package/src/draft2019-09/keywords/$ref.test.ts +3 -1
  35. package/src/draft2019-09/keywords/$ref.ts +40 -16
  36. package/src/draft2019-09/keywords/additionalItems.ts +33 -10
  37. package/src/draft2019-09/keywords/items.ts +32 -10
  38. package/src/draft2019-09/keywords/unevaluatedItems.ts +19 -6
  39. package/src/draft2019-09/methods/getData.ts +1 -1
  40. package/src/draft2019-09/validateSchema.test.ts +28 -0
  41. package/src/errors/errors.ts +8 -1
  42. package/src/formats/formats.ts +35 -28
  43. package/src/formats/hyperjump.d.ts +172 -0
  44. package/src/keywords/$defs.ts +34 -8
  45. package/src/keywords/$ref.ts +59 -13
  46. package/src/keywords/additionalProperties.ts +19 -8
  47. package/src/keywords/allOf.ts +44 -18
  48. package/src/keywords/anyOf.ts +38 -19
  49. package/src/keywords/contains.ts +21 -9
  50. package/src/keywords/dependencies.ts +37 -17
  51. package/src/keywords/dependentRequired.ts +56 -38
  52. package/src/keywords/dependentSchemas.ts +37 -13
  53. package/src/keywords/deprecated.ts +32 -8
  54. package/src/keywords/enum.ts +30 -8
  55. package/src/keywords/exclusiveMaximum.ts +21 -2
  56. package/src/keywords/exclusiveMinimum.ts +22 -3
  57. package/src/keywords/format.ts +21 -2
  58. package/src/keywords/ifthenelse.ts +49 -5
  59. package/src/keywords/items.ts +27 -13
  60. package/src/keywords/maxItems.ts +22 -2
  61. package/src/keywords/maxLength.ts +30 -9
  62. package/src/keywords/maxProperties.ts +30 -9
  63. package/src/keywords/maximum.ts +28 -8
  64. package/src/keywords/minItems.ts +30 -9
  65. package/src/keywords/minLength.ts +30 -9
  66. package/src/keywords/minProperties.ts +26 -5
  67. package/src/keywords/minimum.ts +32 -13
  68. package/src/keywords/multipleOf.ts +33 -12
  69. package/src/keywords/not.ts +23 -10
  70. package/src/keywords/oneOf.ts +29 -9
  71. package/src/keywords/pattern.ts +35 -9
  72. package/src/keywords/properties.ts +34 -11
  73. package/src/keywords/propertyDependencies.test.ts +180 -0
  74. package/src/keywords/propertyDependencies.ts +173 -0
  75. package/src/keywords/propertyNames.ts +26 -14
  76. package/src/keywords/required.ts +31 -8
  77. package/src/keywords/type.ts +53 -16
  78. package/src/keywords/unevaluatedItems.ts +24 -8
  79. package/src/keywords/unevaluatedProperties.ts +24 -7
  80. package/src/keywords/uniqueItems.ts +23 -4
  81. package/src/mergeNode.ts +9 -4
  82. package/src/methods/getData.ts +1 -1
  83. package/src/settings.ts +2 -1
  84. package/src/types.ts +1 -1
  85. package/src/utils/isListOfStrings.ts +3 -0
  86. package/src/validate.test.ts +0 -2
  87. package/src/validateNode.ts +6 -3
  88. package/src/validateSchema.test.ts +312 -0
  89. package/tsconfig.json +11 -4
  90. package/tsconfig.test.json +9 -2
  91. package/tsdown.config.ts +1 -1
  92. package/Dockerfile +0 -6
  93. package/bowtie_jlib.js +0 -140
  94. package/remotes/draft04.json +0 -150
  95. package/remotes/draft06.json +0 -155
  96. package/remotes/draft07.json +0 -155
  97. package/remotes/draft2019-09.json +0 -42
  98. package/remotes/draft2019-09_meta_applicator.json +0 -53
  99. package/remotes/draft2019-09_meta_content.json +0 -14
  100. package/remotes/draft2019-09_meta_core.json +0 -54
  101. package/remotes/draft2019-09_meta_format.json +0 -11
  102. package/remotes/draft2019-09_meta_meta-data.json +0 -34
  103. package/remotes/draft2019-09_meta_validation.json +0 -95
  104. package/remotes/draft2020-12.json +0 -55
  105. package/remotes/draft2020-12_meta_applicator.json +0 -45
  106. package/remotes/draft2020-12_meta_content.json +0 -14
  107. package/remotes/draft2020-12_meta_core.json +0 -48
  108. package/remotes/draft2020-12_meta_format_annotation.json +0 -11
  109. package/remotes/draft2020-12_meta_format_assertion.json +0 -11
  110. package/remotes/draft2020-12_meta_meta_data.json +0 -34
  111. package/remotes/draft2020-12_meta_unevaluated.json +0 -12
  112. package/remotes/draft2020-12_meta_validation.json +0 -87
  113. 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
- export const maxPropertiesKeyword: Keyword = {
5
- id: "maxProperties",
6
- keyword: "maxProperties",
7
- addValidate: ({ schema }) => !isNaN(schema.maxProperties),
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 validateMaxProperties({ node, data, pointer = "#" }: JsonSchemaValidatorParams) {
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 { schema } = node;
36
+ const maxProperties = node[KEYWORD];
16
37
  const propertyCount = Object.keys(data).length;
17
- if (isNaN(schema.maxProperties) === false && schema.maxProperties < propertyCount) {
38
+ if (maxProperties < propertyCount) {
18
39
  return node.createError("max-properties-error", {
19
- maxProperties: schema.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
  }
@@ -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: "maximum",
6
- keyword: "maximum",
7
- addValidate: ({ schema }) => !isNaN(schema.maximum),
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 (schema.maximum && schema.maximum < data) {
37
+ if (max && max < data) {
18
38
  return node.createError("maximum-error", {
19
- maximum: schema.maximum,
39
+ maximum: max,
20
40
  length: data,
21
41
  value: data,
22
42
  pointer,
23
43
  schema
24
44
  });
25
45
  }
26
- if (schema.maximum && schema.exclusiveMaximum === true && schema.maximum === data) {
46
+ if (max && schema.exclusiveMaximum === true && max === data) {
27
47
  return node.createError("maximum-error", {
28
- maximum: schema.maximum,
48
+ maximum: max,
29
49
  length: data,
30
50
  pointer,
31
51
  schema,
@@ -1,23 +1,44 @@
1
1
  import { JsonSchemaValidatorParams, Keyword } from "../Keyword";
2
+ import { SchemaNode } from "../SchemaNode";
3
+ import { isNumber } from "../types";
2
4
 
3
- export const minItemsKeyword: Keyword = {
4
- id: "minItems",
5
- keyword: "minItems",
6
- addValidate: ({ schema }) => !isNaN(schema.minItems),
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 validateMinItems({ node, data, pointer }: JsonSchemaValidatorParams) {
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 { schema } = node;
15
- if (schema.minItems > data.length) {
35
+ const minItems = node[KEYWORD];
36
+ if (minItems > data.length) {
16
37
  return node.createError("min-items-error", {
17
- minItems: schema.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
- export const minLengthKeyword: Keyword = {
5
- id: "minLength",
6
- keyword: "minLength",
7
- addValidate: ({ schema }) => !isNaN(schema.minLength),
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 validateMinLength({ node, data, pointer = "#" }: JsonSchemaValidatorParams) {
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
- if (schema.minLength <= length) {
37
+ const minLength = node[KEYWORD];
38
+ if (minLength <= length) {
18
39
  return;
19
40
  }
20
41
  return node.createError("min-length-error", {
21
- minLength: schema.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
- export const minPropertiesKeyword: Keyword = {
5
- id: "minProperties",
6
- keyword: "minProperties",
7
- addValidate: ({ schema }) => !isNaN(schema.minProperties),
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 validateMinProperties({ node, data, pointer = "#" }: JsonSchemaValidatorParams) {
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
  }
@@ -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
- export const minimumKeyword: Keyword = {
5
- id: "minimum",
6
- keyword: "minimum",
7
- addValidate: ({ schema }) => !isNaN(schema.minimum),
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 validateMinimum({ node, data, pointer }: JsonSchemaValidatorParams) {
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 { schema } = node;
16
- if (schema.minimum > data) {
34
+ const min = node[KEYWORD];
35
+ if (min > data) {
17
36
  return node.createError("minimum-error", {
18
- minimum: schema.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: schema.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
- export const multipleOfKeyword: Keyword = {
5
- id: "multipleOf",
6
- keyword: "multipleOf",
7
- addValidate: ({ schema }) => !isNaN(schema.multipleOf),
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 validateMultipleOf({ node, data, pointer }: JsonSchemaValidatorParams) {
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 { schema } = node;
36
+ const multipleOf = node[KEYWORD];
16
37
  const valuePrecision = getPrecision(data);
17
- const multiplePrecision = getPrecision(schema.multipleOf);
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: schema.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(schema.multipleOf * precision);
51
+ const multiple = Math.round(multipleOf * precision);
31
52
  if ((val % multiple) / precision !== 0) {
32
53
  return node.createError("multiple-of-error", {
33
- multipleOf: schema.multipleOf,
54
+ multipleOf: multipleOf,
34
55
  value: data,
35
56
  pointer,
36
- schema
57
+ schema: node.schema
37
58
  });
38
59
  }
39
60
 
@@ -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
- export const notKeyword: Keyword = {
6
- id: "not",
7
- keyword: "not",
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.not != null,
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
- if (schema.not != null) {
16
- node.not = node.compileSchema(schema.not, `${evaluationPath}/not`, `${schemaLocation}/not`);
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.not!, data, pointer, path).length === 0) {
24
- return node.createError("not-error", { value: data, not: schema.not, pointer, 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
  }
@@ -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: "oneOf",
20
- keyword: "oneOf",
21
+ id: KEYWORD,
22
+ keyword: KEYWORD,
21
23
  parse: parseOneOf,
22
- addReduce: (node) => node.oneOf != null,
24
+ addReduce: (node) => node[KEYWORD] != null,
23
25
  reduce: reduceOneOf,
24
- addValidate: (node) => node.oneOf != null,
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 (Array.isArray(schema.oneOf) && schema.oneOf.length) {
41
- node.oneOf = schema.oneOf.map((s, index) =>
42
- node.compileSchema(s, `${evaluationPath}/oneOf/${index}`, `${schemaLocation}/oneOf/${index}`)
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">) {
@@ -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: "pattern",
8
- keyword: "pattern",
9
- addValidate: ({ schema }) => typeof schema.pattern === "string",
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 validatePattern({ node, data, pointer = "#" }: JsonSchemaValidatorParams) {
14
- const { schema } = node;
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
- const pattern = new RegExp(schema.pattern, schema.regexFlags ?? REGEX_FLAGS);
19
- if (pattern.test(data) === false) {
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 { Keyword, JsonSchemaResolverParams, JsonSchemaValidatorParams, ValidationReturnType } from "../Keyword";
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
- const parsedProperties: Record<string, SchemaNode> = {};
25
- Object.keys(schema.properties).forEach((propertyName) => {
26
- const propertyNode = node.compileSchema(
27
- schema.properties[propertyName],
28
- `${evaluationPath}/properties/${propertyName}`,
29
- `${schemaLocation}/properties/${propertyName}`
30
- );
31
- parsedProperties[propertyName] = propertyNode;
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) {