json-schema-library 11.0.4 → 11.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.
Files changed (58) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +112 -0
  3. package/dist/index.cjs +1 -1
  4. package/dist/index.d.cts +93 -16
  5. package/dist/index.d.mts +93 -16
  6. package/dist/index.mjs +1 -1
  7. package/dist/jlib.js +3 -3
  8. package/index.ts +10 -1
  9. package/package.json +11 -8
  10. package/src/Draft.ts +1 -1
  11. package/src/Keyword.ts +36 -10
  12. package/src/SchemaNode.ts +75 -16
  13. package/src/compileSchema.ts +53 -4
  14. package/src/errors/errors.ts +4 -1
  15. package/src/keywords/$defs.ts +34 -8
  16. package/src/keywords/$ref.ts +12 -0
  17. package/src/keywords/additionalProperties.ts +19 -8
  18. package/src/keywords/allOf.ts +44 -18
  19. package/src/keywords/anyOf.ts +38 -19
  20. package/src/keywords/contains.ts +21 -9
  21. package/src/keywords/dependencies.ts +37 -17
  22. package/src/keywords/dependentRequired.ts +56 -38
  23. package/src/keywords/dependentSchemas.ts +37 -13
  24. package/src/keywords/deprecated.ts +32 -8
  25. package/src/keywords/enum.ts +30 -8
  26. package/src/keywords/exclusiveMaximum.ts +21 -2
  27. package/src/keywords/exclusiveMinimum.ts +22 -3
  28. package/src/keywords/format.ts +21 -2
  29. package/src/keywords/ifthenelse.ts +49 -5
  30. package/src/keywords/items.ts +27 -13
  31. package/src/keywords/maxItems.ts +22 -2
  32. package/src/keywords/maxLength.ts +30 -9
  33. package/src/keywords/maxProperties.ts +30 -9
  34. package/src/keywords/maximum.ts +28 -8
  35. package/src/keywords/minItems.ts +30 -9
  36. package/src/keywords/minLength.ts +30 -9
  37. package/src/keywords/minProperties.ts +26 -5
  38. package/src/keywords/minimum.ts +32 -13
  39. package/src/keywords/multipleOf.ts +33 -12
  40. package/src/keywords/not.ts +23 -10
  41. package/src/keywords/oneOf.ts +29 -9
  42. package/src/keywords/pattern.ts +35 -9
  43. package/src/keywords/properties.ts +35 -12
  44. package/src/keywords/propertyDependencies.test.ts +180 -0
  45. package/src/keywords/propertyDependencies.ts +173 -0
  46. package/src/keywords/propertyNames.ts +26 -14
  47. package/src/keywords/required.ts +31 -8
  48. package/src/keywords/type.ts +53 -16
  49. package/src/keywords/unevaluatedItems.ts +24 -8
  50. package/src/keywords/unevaluatedProperties.ts +24 -7
  51. package/src/keywords/uniqueItems.ts +23 -4
  52. package/src/mergeNode.ts +9 -4
  53. package/src/settings.ts +2 -1
  54. package/src/types.ts +1 -1
  55. package/src/utils/isListOfStrings.ts +3 -0
  56. package/src/validate.test.ts +0 -2
  57. package/src/validateNode.ts +2 -2
  58. package/src/validateSchema.test.ts +312 -0
@@ -0,0 +1,312 @@
1
+ import { compileSchema } from "./compileSchema";
2
+ import { strict as assert } from "assert";
3
+ import { extendDraft } from "./Draft";
4
+ import { draft2020 } from "./draft2020";
5
+ import { propertyDependenciesKeyword } from "./keywords/propertyDependencies";
6
+ import { draft07 } from "./draft07";
7
+
8
+ const withAdditionalKeywords = {
9
+ drafts: [
10
+ extendDraft(draft2020, {
11
+ keywords: [propertyDependenciesKeyword]
12
+ })
13
+ ]
14
+ };
15
+
16
+ describe("validateSchema", () => {
17
+ it("should error if `$defs` is not an object", () => {
18
+ const { schemaErrors } = compileSchema({ $defs: true });
19
+ assert.equal(schemaErrors?.length, 1);
20
+ });
21
+ it("should throw an error if schema is invalid and option 'throwOnInvalidSchema = true'", () => {
22
+ assert.throws(() => {
23
+ compileSchema({ $defs: true }, { throwOnInvalidSchema: true });
24
+ });
25
+ });
26
+ it("should error for missing `$ref` target in $defs", () => {
27
+ const { schemaErrors } = compileSchema({
28
+ type: "object",
29
+ properties: {
30
+ invalid: { $ref: "#/$defs/invalid" }
31
+ }
32
+ });
33
+ assert.equal(schemaErrors?.length, 1);
34
+ assert.equal(schemaErrors[0].data.pointer, "#/properties/invalid/$ref");
35
+ assert.equal(schemaErrors[0].data.value, "#/$defs/invalid");
36
+ });
37
+ it("should error if `additionalProperties` is not a valid JSON Schema", () => {
38
+ const { schemaErrors } = compileSchema({ additionalProperties: 999 });
39
+ assert.equal(schemaErrors?.length, 1);
40
+ });
41
+ it("should error if `allOf` is not a an array", () => {
42
+ const { schemaErrors } = compileSchema({ allOf: {} });
43
+ assert.equal(schemaErrors?.length, 1);
44
+ });
45
+ it("should error if `allOf schema` is not a valid JSON Schema", () => {
46
+ const { schemaErrors } = compileSchema({ allOf: [999] });
47
+ assert.equal(schemaErrors?.length, 1);
48
+ });
49
+ it("should error if `anyOf` is not a an array", () => {
50
+ const { schemaErrors } = compileSchema({ anyOf: {} });
51
+ assert.equal(schemaErrors?.length, 1);
52
+ });
53
+ it("should error if `anyOf schema` is not a valid JSON Schema", () => {
54
+ const { schemaErrors } = compileSchema({ anyOf: [999] });
55
+ assert.equal(schemaErrors?.length, 1);
56
+ });
57
+ // any const is valid: https://json-schema.org/draft/2020-12/json-schema-validation#name-const
58
+ it("should error if `contains` is not a valid JSON Schema", () => {
59
+ const { schemaErrors } = compileSchema({ contains: [] });
60
+ assert.equal(schemaErrors?.length, 1);
61
+ });
62
+ it("should error if `dependencies` is not a an object", () => {
63
+ const { schemaErrors } = compileSchema({ dependencies: [] });
64
+ assert.equal(schemaErrors?.length, 1);
65
+ });
66
+ it("should error if `dependentRequired` is not a an object", () => {
67
+ const { schemaErrors } = compileSchema({ dependentRequired: [] });
68
+ assert.equal(schemaErrors?.length, 1);
69
+ });
70
+ it("should error if `dependentRequired` is not a an object with a list of strings", () => {
71
+ const { schemaErrors } = compileSchema({
72
+ dependentRequired: {
73
+ property: ["title", true]
74
+ }
75
+ });
76
+ assert.equal(schemaErrors?.length, 1);
77
+ });
78
+ it("should error if `dependentSchemas` is not a an object containing schemata", () => {
79
+ const { schemaErrors } = compileSchema({
80
+ dependentSchemas: {
81
+ valid: { type: "string" },
82
+ stillValid: true,
83
+ invalid: 999
84
+ }
85
+ });
86
+ assert.equal(schemaErrors?.length, 1);
87
+ assert.equal(schemaErrors[0].data.pointer, "#/dependentSchemas/invalid");
88
+ });
89
+ it("should error if `deprecated` is not a a boolean", () => {
90
+ const { schemaErrors } = compileSchema({ deprecated: {} });
91
+ assert.equal(schemaErrors?.length, 1);
92
+ });
93
+ it("should error if `enum` is not an array", () => {
94
+ const { schemaErrors } = compileSchema({ type: "string", enum: true });
95
+ assert.equal(schemaErrors?.length, 1);
96
+ });
97
+ it("should error if `exclusiveMaximum` is not a number", () => {
98
+ const { schemaErrors } = compileSchema({ exclusiveMaximum: true });
99
+ assert.equal(schemaErrors?.length, 1);
100
+ });
101
+ it("should error if `exclusiveMinimum` is not a number", () => {
102
+ const { schemaErrors } = compileSchema({ exclusiveMinimum: true });
103
+ assert.equal(schemaErrors?.length, 1);
104
+ });
105
+ it("should error if `format` is not a string", () => {
106
+ const { schemaErrors } = compileSchema({ format: {} });
107
+ assert.equal(schemaErrors?.length, 1);
108
+ });
109
+ it("should error if `if` is not a valid JSON Schema", () => {
110
+ const { schemaErrors } = compileSchema({ if: 999, then: false, else: true });
111
+ assert.equal(schemaErrors?.length, 1);
112
+ });
113
+ it("should error if `then` is not a valid JSON Schema", () => {
114
+ const { schemaErrors } = compileSchema({ if: {}, then: [], else: true });
115
+ assert.equal(schemaErrors?.length, 1);
116
+ });
117
+ it("should error if `else` is not a valid JSON Schema", () => {
118
+ const { schemaErrors } = compileSchema({ if: {}, then: false, else: 999 });
119
+ assert.equal(schemaErrors?.length, 1);
120
+ });
121
+ it("should error if `items` is not a valid JSON Schema", () => {
122
+ const { schemaErrors } = compileSchema({ items: [] });
123
+ assert.equal(schemaErrors?.length, 1);
124
+ });
125
+ it("should error if `maximum` is not a number", () => {
126
+ const { schemaErrors } = compileSchema({ maximum: true });
127
+ assert.equal(schemaErrors?.length, 1);
128
+ });
129
+ it("should error if `maxItems` is not a number", () => {
130
+ const { schemaErrors } = compileSchema({ maxItems: true });
131
+ assert.equal(schemaErrors?.length, 1);
132
+ });
133
+ it("should error if `maxLength` is not a number", () => {
134
+ const { schemaErrors } = compileSchema({ maxLength: true });
135
+ assert.equal(schemaErrors?.length, 1);
136
+ });
137
+ it("should error if `maxProperties` is not a number", () => {
138
+ const { schemaErrors } = compileSchema({ maxProperties: true });
139
+ assert.equal(schemaErrors?.length, 1);
140
+ });
141
+ it("should error if `minimum` is not a number", () => {
142
+ const { schemaErrors } = compileSchema({ minimum: true });
143
+ assert.equal(schemaErrors?.length, 1);
144
+ });
145
+ it("should error if `minItems` is not a number", () => {
146
+ const { schemaErrors } = compileSchema({ minItems: true });
147
+ assert.equal(schemaErrors?.length, 1);
148
+ });
149
+ it("should error if `minLength` is not a number", () => {
150
+ const { schemaErrors } = compileSchema({ minLength: true });
151
+ assert.equal(schemaErrors?.length, 1);
152
+ });
153
+ it("should error if `minProperties` is not a number", () => {
154
+ const { schemaErrors } = compileSchema({ minProperties: true });
155
+ assert.equal(schemaErrors?.length, 1);
156
+ });
157
+ it("should error if `multipleOf` is not a number", () => {
158
+ const { schemaErrors } = compileSchema({ multipleOf: true });
159
+ assert.equal(schemaErrors?.length, 1);
160
+ });
161
+ it("should error if `not` is not a JSON Schema", () => {
162
+ const { schemaErrors } = compileSchema({ not: [] });
163
+ assert.equal(schemaErrors?.length, 1);
164
+ });
165
+ it("should error if `oneOf` is not a an array", () => {
166
+ const { schemaErrors } = compileSchema({ oneOf: {} });
167
+ assert.equal(schemaErrors?.length, 1);
168
+ });
169
+ it("should error if `oneOf schema` is not a valid JSON Schema", () => {
170
+ const { schemaErrors } = compileSchema({ oneOf: [999] });
171
+ assert.equal(schemaErrors?.length, 1);
172
+ });
173
+ it("should error if `pattern` is not a string", () => {
174
+ const { schemaErrors } = compileSchema({ type: "string", pattern: true });
175
+ assert.equal(schemaErrors?.length, 1);
176
+ });
177
+ it("should error if `pattern` is an invalid regexp", () => {
178
+ const { schemaErrors } = compileSchema({ type: "string", pattern: "(" });
179
+ assert.equal(schemaErrors?.length, 1);
180
+ });
181
+ it("should error if `properties` is not an object", () => {
182
+ const { schemaErrors } = compileSchema({ type: "object", properties: 999 });
183
+ assert.equal(schemaErrors?.length, 1);
184
+ });
185
+ it("should error if `properties[string]` is not a JSON Schema", () => {
186
+ const { schemaErrors } = compileSchema({
187
+ type: "object",
188
+ properties: {
189
+ valid: { type: "string" },
190
+ alsoValid: false,
191
+ invalid: 999
192
+ }
193
+ });
194
+ assert.equal(schemaErrors?.length, 1);
195
+ assert.equal(schemaErrors[0].data.pointer, "#/properties/invalid");
196
+ });
197
+ it("should error if `propertyDependencies` is not an object", () => {
198
+ const { schemaErrors } = compileSchema({ propertyDependencies: true }, withAdditionalKeywords);
199
+ assert.equal(schemaErrors?.length, 1);
200
+ });
201
+ it("should error if `propertyDependencies[string]` is not an object", () => {
202
+ const { schemaErrors } = compileSchema({ propertyDependencies: { invalid: true } }, withAdditionalKeywords);
203
+ assert.equal(schemaErrors?.length, 1);
204
+ });
205
+ it("should error if `propertyDependencies[string][string]` is not JSON Schema", () => {
206
+ const { schemaErrors } = compileSchema(
207
+ { propertyDependencies: { valid: { invalid: 999 } } },
208
+ withAdditionalKeywords
209
+ );
210
+ assert.equal(schemaErrors?.length, 1);
211
+ });
212
+ it("should error if `propertyNames` is not a JSON Schema type", () => {
213
+ const { schemaErrors } = compileSchema({ propertyNames: "error" });
214
+ assert.equal(schemaErrors?.length, 1);
215
+ assert.equal(schemaErrors[0].data.pointer, "#/propertyNames");
216
+ });
217
+ it("should error if `required` is not a string[]", () => {
218
+ const { schemaErrors } = compileSchema({ type: "object", required: [123, "valid"] });
219
+ assert.equal(schemaErrors?.length, 1);
220
+ assert.equal(schemaErrors[0].data.pointer, "#/required");
221
+ });
222
+ it("should error if `type` is not a JSON Schema type", () => {
223
+ const { schemaErrors } = compileSchema({ type: "error" });
224
+ assert.equal(schemaErrors?.length, 1);
225
+ assert.equal(schemaErrors[0].data.pointer, "#/type");
226
+ });
227
+ it("should error if `type` is not a valid JSON Schema type format", () => {
228
+ const { schemaErrors } = compileSchema({ type: {} });
229
+ assert.equal(schemaErrors?.length, 1);
230
+ assert.equal(schemaErrors[0].data.pointer, "#/type");
231
+ });
232
+ it("should error if `type` is not a valid JSON Schema", () => {
233
+ const { schemaErrors } = compileSchema({ type: "error" });
234
+ assert.equal(schemaErrors?.length, 1);
235
+ assert.equal(schemaErrors[0].data.pointer, "#/type");
236
+ });
237
+ it("should error if `unevaluatedItems` is not a valid JSON Schema", () => {
238
+ const { schemaErrors } = compileSchema({ unevaluatedItems: [] });
239
+ assert.equal(schemaErrors?.length, 1);
240
+ assert.equal(schemaErrors[0].data.pointer, "#/unevaluatedItems");
241
+ });
242
+ it("should error if `unevaluatedProperties` is not a valid JSON Schema", () => {
243
+ const { schemaErrors } = compileSchema({ unevaluatedProperties: 999 });
244
+ assert.equal(schemaErrors?.length, 1);
245
+ assert.equal(schemaErrors[0].data.pointer, "#/unevaluatedProperties");
246
+ });
247
+ it("should error if `uniqueItems` is not a boolean", () => {
248
+ const { schemaErrors } = compileSchema({ uniqueItems: {} });
249
+ assert.equal(schemaErrors?.length, 1);
250
+ assert.equal(schemaErrors[0].data.pointer, "#/uniqueItems");
251
+ });
252
+
253
+ describe("annotations", () => {
254
+ it("should return unknown keywords as annotation", () => {
255
+ const { schemaAnnotations } = compileSchema(
256
+ {
257
+ properties: {
258
+ headline: {
259
+ options: {},
260
+ type: "string"
261
+ }
262
+ }
263
+ },
264
+ { withSchemaAnnotations: true }
265
+ );
266
+ assert.equal(schemaAnnotations.length, 1);
267
+ assert.equal(schemaAnnotations[0].data.pointer, "#/properties/headline/options");
268
+ });
269
+ it("should return not unknown keywords starting with 'x-'", () => {
270
+ const { schemaAnnotations } = compileSchema(
271
+ {
272
+ properties: {
273
+ headline: {
274
+ "x-options": {},
275
+ type: "string"
276
+ }
277
+ }
278
+ },
279
+ { withSchemaAnnotations: true }
280
+ );
281
+ assert.equal(schemaAnnotations.length, 0);
282
+ });
283
+ it("should return removed keywords from old drafts as annotation", () => {
284
+ const { schemaAnnotations } = compileSchema(
285
+ {
286
+ properties: {
287
+ headline: {
288
+ additionalItems: true
289
+ }
290
+ }
291
+ },
292
+ { withSchemaAnnotations: true }
293
+ );
294
+ assert.equal(schemaAnnotations.length, 1);
295
+ assert.equal(schemaAnnotations[0].data.pointer, "#/properties/headline/additionalItems");
296
+ });
297
+ it("should return new keywords in old drafts as annotation", () => {
298
+ const { schemaAnnotations } = compileSchema(
299
+ {
300
+ properties: {
301
+ headline: {
302
+ prefixItems: []
303
+ }
304
+ }
305
+ },
306
+ { drafts: [draft07], withSchemaAnnotations: true }
307
+ );
308
+ assert.equal(schemaAnnotations.length, 1);
309
+ assert.equal(schemaAnnotations[0].data.pointer, "#/properties/headline/prefixItems");
310
+ });
311
+ });
312
+ });