z-schema 7.0.0 → 7.0.6
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/README.md +7 -11
- package/bin/z-schema +0 -0
- package/cjs/index.d.ts +192 -117
- package/cjs/index.js +949 -998
- package/{src/FormatValidators.ts → dist/format-validators.js} +97 -65
- package/dist/index.js +1 -1
- package/dist/json-schema.js +40 -0
- package/dist/{JsonValidation.js → json-validation.js} +75 -69
- package/dist/{Report.js → report.js} +35 -45
- package/dist/schema-cache.js +109 -0
- package/dist/schema-compiler.js +255 -0
- package/dist/{SchemaValidation.js → schema-validator.js} +153 -149
- package/dist/types/{Errors.d.ts → errors.d.ts} +2 -0
- package/dist/types/format-validators.d.ts +10 -0
- package/dist/types/index.d.ts +10 -1
- package/dist/types/json-schema.d.ts +50 -0
- package/dist/types/json-validation.d.ts +7 -0
- package/dist/types/{Report.d.ts → report.d.ts} +22 -23
- package/dist/types/schema-cache.d.ts +17 -0
- package/dist/types/schema-compiler.d.ts +16 -0
- package/dist/types/schema-validator.d.ts +10 -0
- package/dist/types/utils/array.d.ts +2 -0
- package/dist/types/utils/clone.d.ts +2 -0
- package/dist/types/utils/json.d.ts +7 -0
- package/dist/types/utils/symbols.d.ts +2 -0
- package/dist/types/utils/unicode.d.ts +14 -0
- package/dist/types/utils/uri.d.ts +4 -0
- package/dist/types/utils/what-is.d.ts +3 -0
- package/dist/types/z-schema.d.ts +75 -0
- package/dist/utils/array.js +27 -0
- package/dist/utils/clone.js +61 -0
- package/dist/utils/json.js +59 -0
- package/dist/utils/symbols.js +2 -0
- package/dist/utils/unicode.js +45 -0
- package/dist/utils/uri.js +15 -0
- package/dist/utils/what-is.js +29 -0
- package/dist/{ZSchema.js → z-schema.js} +66 -77
- package/package.json +8 -4
- package/src/{Errors.ts → errors.ts} +4 -0
- package/src/format-validators.ts +191 -0
- package/src/index.ts +12 -1
- package/src/json-schema.ts +97 -0
- package/src/{JsonValidation.ts → json-validation.ts} +137 -127
- package/src/{Report.ts → report.ts} +60 -70
- package/src/schema-cache.ts +122 -0
- package/src/schema-compiler.ts +300 -0
- package/src/{SchemaValidation.ts → schema-validator.ts} +213 -215
- package/src/utils/array.ts +29 -0
- package/src/utils/clone.ts +63 -0
- package/src/utils/json.ts +74 -0
- package/src/utils/symbols.ts +3 -0
- package/src/utils/unicode.ts +43 -0
- package/src/utils/uri.ts +18 -0
- package/src/utils/what-is.ts +46 -0
- package/src/{ZSchema.ts → z-schema.ts} +108 -113
- package/umd/ZSchema.js +949 -998
- package/umd/ZSchema.min.js +1 -1
- package/dist/FormatValidators.js +0 -136
- package/dist/SchemaCache.js +0 -173
- package/dist/SchemaCompilation.js +0 -259
- package/dist/Utils.js +0 -266
- package/dist/types/FormatValidators.d.ts +0 -12
- package/dist/types/JsonValidation.d.ts +0 -37
- package/dist/types/SchemaCache.d.ts +0 -26
- package/dist/types/SchemaCompilation.d.ts +0 -1
- package/dist/types/SchemaValidation.d.ts +0 -6
- package/dist/types/Utils.d.ts +0 -64
- package/dist/types/ZSchema.d.ts +0 -97
- package/src/SchemaCache.ts +0 -189
- package/src/SchemaCompilation.ts +0 -293
- package/src/Utils.ts +0 -286
- /package/dist/{Errors.js → errors.js} +0 -0
- /package/dist/schemas/{hyper-schema.json → draft-04-hyper-schema.json} +0 -0
- /package/dist/schemas/{schema.json → draft-04-schema.json} +0 -0
- /package/src/schemas/{hyper-schema.json → draft-04-hyper-schema.json} +0 -0
- /package/src/schemas/{schema.json → draft-04-schema.json} +0 -0
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
1
|
+
import { Report } from './report.js';
|
|
2
|
+
import { isObject, whatIs } from './utils/what-is.js';
|
|
3
|
+
import { ucs2decode } from './utils/unicode.js';
|
|
4
|
+
import { difference, isUniqueArray } from './utils/array.js';
|
|
5
|
+
import { areEqual } from './utils/json.js';
|
|
6
|
+
import { shallowClone } from './utils/clone.js';
|
|
7
|
+
import { getFormatValidators } from './format-validators.js';
|
|
4
8
|
const shouldSkipValidate = function (options, errors) {
|
|
5
9
|
return (options &&
|
|
6
10
|
Array.isArray(options.includeErrors) &&
|
|
@@ -10,6 +14,12 @@ const shouldSkipValidate = function (options, errors) {
|
|
|
10
14
|
}));
|
|
11
15
|
};
|
|
12
16
|
export const JsonValidators = {
|
|
17
|
+
id: () => { },
|
|
18
|
+
$ref: () => { },
|
|
19
|
+
$schema: () => { },
|
|
20
|
+
title: () => { },
|
|
21
|
+
description: () => { },
|
|
22
|
+
default: () => { },
|
|
13
23
|
multipleOf: function (report, schema, json) {
|
|
14
24
|
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.1.1.2
|
|
15
25
|
if (shouldSkipValidate(this.validateOptions, ['MULTIPLE_OF'])) {
|
|
@@ -20,8 +30,8 @@ export const JsonValidators = {
|
|
|
20
30
|
}
|
|
21
31
|
const stringMultipleOf = String(schema.multipleOf);
|
|
22
32
|
const scale = Math.pow(10, stringMultipleOf.length - stringMultipleOf.indexOf('.') - 1);
|
|
23
|
-
if (
|
|
24
|
-
report.addError('MULTIPLE_OF', [json, schema.multipleOf],
|
|
33
|
+
if (whatIs((json * scale) / (schema.multipleOf * scale)) !== 'integer') {
|
|
34
|
+
report.addError('MULTIPLE_OF', [json, schema.multipleOf], undefined, schema);
|
|
25
35
|
}
|
|
26
36
|
},
|
|
27
37
|
maximum: function (report, schema, json) {
|
|
@@ -34,12 +44,12 @@ export const JsonValidators = {
|
|
|
34
44
|
}
|
|
35
45
|
if (schema.exclusiveMaximum !== true) {
|
|
36
46
|
if (json > schema.maximum) {
|
|
37
|
-
report.addError('MAXIMUM', [json, schema.maximum],
|
|
47
|
+
report.addError('MAXIMUM', [json, schema.maximum], undefined, schema);
|
|
38
48
|
}
|
|
39
49
|
}
|
|
40
50
|
else {
|
|
41
51
|
if (json >= schema.maximum) {
|
|
42
|
-
report.addError('MAXIMUM_EXCLUSIVE', [json, schema.maximum],
|
|
52
|
+
report.addError('MAXIMUM_EXCLUSIVE', [json, schema.maximum], undefined, schema);
|
|
43
53
|
}
|
|
44
54
|
}
|
|
45
55
|
},
|
|
@@ -56,12 +66,12 @@ export const JsonValidators = {
|
|
|
56
66
|
}
|
|
57
67
|
if (schema.exclusiveMinimum !== true) {
|
|
58
68
|
if (json < schema.minimum) {
|
|
59
|
-
report.addError('MINIMUM', [json, schema.minimum],
|
|
69
|
+
report.addError('MINIMUM', [json, schema.minimum], undefined, schema);
|
|
60
70
|
}
|
|
61
71
|
}
|
|
62
72
|
else {
|
|
63
73
|
if (json <= schema.minimum) {
|
|
64
|
-
report.addError('MINIMUM_EXCLUSIVE', [json, schema.minimum],
|
|
74
|
+
report.addError('MINIMUM_EXCLUSIVE', [json, schema.minimum], undefined, schema);
|
|
65
75
|
}
|
|
66
76
|
}
|
|
67
77
|
},
|
|
@@ -76,8 +86,8 @@ export const JsonValidators = {
|
|
|
76
86
|
if (typeof json !== 'string') {
|
|
77
87
|
return;
|
|
78
88
|
}
|
|
79
|
-
if (
|
|
80
|
-
report.addError('MAX_LENGTH', [json.length, schema.maxLength],
|
|
89
|
+
if (ucs2decode(json).length > schema.maxLength) {
|
|
90
|
+
report.addError('MAX_LENGTH', [json.length, schema.maxLength], undefined, schema);
|
|
81
91
|
}
|
|
82
92
|
},
|
|
83
93
|
minLength: function (report, schema, json) {
|
|
@@ -88,8 +98,8 @@ export const JsonValidators = {
|
|
|
88
98
|
if (typeof json !== 'string') {
|
|
89
99
|
return;
|
|
90
100
|
}
|
|
91
|
-
if (
|
|
92
|
-
report.addError('MIN_LENGTH', [json.length, schema.minLength],
|
|
101
|
+
if (ucs2decode(json).length < schema.minLength) {
|
|
102
|
+
report.addError('MIN_LENGTH', [json.length, schema.minLength], undefined, schema);
|
|
93
103
|
}
|
|
94
104
|
},
|
|
95
105
|
pattern: function (report, schema, json) {
|
|
@@ -101,7 +111,7 @@ export const JsonValidators = {
|
|
|
101
111
|
return;
|
|
102
112
|
}
|
|
103
113
|
if (RegExp(schema.pattern).test(json) === false) {
|
|
104
|
-
report.addError('PATTERN', [schema.pattern, json],
|
|
114
|
+
report.addError('PATTERN', [schema.pattern, json], undefined, schema);
|
|
105
115
|
}
|
|
106
116
|
},
|
|
107
117
|
additionalItems: function (report, schema, json) {
|
|
@@ -116,12 +126,12 @@ export const JsonValidators = {
|
|
|
116
126
|
// the json is valid if its size is less than, or equal to, the size of "items".
|
|
117
127
|
if (schema.additionalItems === false && Array.isArray(schema.items)) {
|
|
118
128
|
if (json.length > schema.items.length) {
|
|
119
|
-
report.addError('ARRAY_ADDITIONAL_ITEMS',
|
|
129
|
+
report.addError('ARRAY_ADDITIONAL_ITEMS', undefined, undefined, schema);
|
|
120
130
|
}
|
|
121
131
|
}
|
|
122
132
|
},
|
|
123
133
|
items: function () {
|
|
124
|
-
/*report, schema, json*/
|
|
134
|
+
/*report: Report, schema: JsonSchemaInternal, json: unknown*/
|
|
125
135
|
// covered in additionalItems
|
|
126
136
|
},
|
|
127
137
|
maxItems: function (report, schema, json) {
|
|
@@ -133,7 +143,7 @@ export const JsonValidators = {
|
|
|
133
143
|
return;
|
|
134
144
|
}
|
|
135
145
|
if (json.length > schema.maxItems) {
|
|
136
|
-
report.addError('ARRAY_LENGTH_LONG', [json.length, schema.maxItems],
|
|
146
|
+
report.addError('ARRAY_LENGTH_LONG', [json.length, schema.maxItems], undefined, schema);
|
|
137
147
|
}
|
|
138
148
|
},
|
|
139
149
|
minItems: function (report, schema, json) {
|
|
@@ -145,7 +155,7 @@ export const JsonValidators = {
|
|
|
145
155
|
return;
|
|
146
156
|
}
|
|
147
157
|
if (json.length < schema.minItems) {
|
|
148
|
-
report.addError('ARRAY_LENGTH_SHORT', [json.length, schema.minItems],
|
|
158
|
+
report.addError('ARRAY_LENGTH_SHORT', [json.length, schema.minItems], undefined, schema);
|
|
149
159
|
}
|
|
150
160
|
},
|
|
151
161
|
uniqueItems: function (report, schema, json) {
|
|
@@ -158,8 +168,8 @@ export const JsonValidators = {
|
|
|
158
168
|
}
|
|
159
169
|
if (schema.uniqueItems === true) {
|
|
160
170
|
const matches = [];
|
|
161
|
-
if (
|
|
162
|
-
report.addError('ARRAY_UNIQUE', matches,
|
|
171
|
+
if (isUniqueArray(json, matches) === false) {
|
|
172
|
+
report.addError('ARRAY_UNIQUE', matches, undefined, schema);
|
|
163
173
|
}
|
|
164
174
|
}
|
|
165
175
|
},
|
|
@@ -168,12 +178,12 @@ export const JsonValidators = {
|
|
|
168
178
|
if (shouldSkipValidate(this.validateOptions, ['OBJECT_PROPERTIES_MAXIMUM'])) {
|
|
169
179
|
return;
|
|
170
180
|
}
|
|
171
|
-
if (
|
|
181
|
+
if (!isObject(json)) {
|
|
172
182
|
return;
|
|
173
183
|
}
|
|
174
184
|
const keysCount = Object.keys(json).length;
|
|
175
185
|
if (keysCount > schema.maxProperties) {
|
|
176
|
-
report.addError('OBJECT_PROPERTIES_MAXIMUM', [keysCount, schema.maxProperties],
|
|
186
|
+
report.addError('OBJECT_PROPERTIES_MAXIMUM', [keysCount, schema.maxProperties], undefined, schema);
|
|
177
187
|
}
|
|
178
188
|
},
|
|
179
189
|
minProperties: function (report, schema, json) {
|
|
@@ -181,12 +191,12 @@ export const JsonValidators = {
|
|
|
181
191
|
if (shouldSkipValidate(this.validateOptions, ['OBJECT_PROPERTIES_MINIMUM'])) {
|
|
182
192
|
return;
|
|
183
193
|
}
|
|
184
|
-
if (
|
|
194
|
+
if (!isObject(json)) {
|
|
185
195
|
return;
|
|
186
196
|
}
|
|
187
197
|
const keysCount = Object.keys(json).length;
|
|
188
198
|
if (keysCount < schema.minProperties) {
|
|
189
|
-
report.addError('OBJECT_PROPERTIES_MINIMUM', [keysCount, schema.minProperties],
|
|
199
|
+
report.addError('OBJECT_PROPERTIES_MINIMUM', [keysCount, schema.minProperties], undefined, schema);
|
|
190
200
|
}
|
|
191
201
|
},
|
|
192
202
|
required: function (report, schema, json) {
|
|
@@ -194,14 +204,14 @@ export const JsonValidators = {
|
|
|
194
204
|
if (shouldSkipValidate(this.validateOptions, ['OBJECT_MISSING_REQUIRED_PROPERTY'])) {
|
|
195
205
|
return;
|
|
196
206
|
}
|
|
197
|
-
if (
|
|
207
|
+
if (!isObject(json)) {
|
|
198
208
|
return;
|
|
199
209
|
}
|
|
200
210
|
let idx = schema.required.length;
|
|
201
211
|
while (idx--) {
|
|
202
212
|
const requiredPropertyName = schema.required[idx];
|
|
203
213
|
if (json[requiredPropertyName] === undefined) {
|
|
204
|
-
report.addError('OBJECT_MISSING_REQUIRED_PROPERTY', [requiredPropertyName],
|
|
214
|
+
report.addError('OBJECT_MISSING_REQUIRED_PROPERTY', [requiredPropertyName], undefined, schema);
|
|
205
215
|
}
|
|
206
216
|
}
|
|
207
217
|
},
|
|
@@ -222,7 +232,7 @@ export const JsonValidators = {
|
|
|
222
232
|
if (shouldSkipValidate(this.validateOptions, ['OBJECT_ADDITIONAL_PROPERTIES'])) {
|
|
223
233
|
return;
|
|
224
234
|
}
|
|
225
|
-
if (
|
|
235
|
+
if (!isObject(json)) {
|
|
226
236
|
return;
|
|
227
237
|
}
|
|
228
238
|
const properties = schema.properties !== undefined ? schema.properties : {};
|
|
@@ -235,7 +245,7 @@ export const JsonValidators = {
|
|
|
235
245
|
// The property set from "patternProperties".
|
|
236
246
|
const pp = Object.keys(patternProperties);
|
|
237
247
|
// remove from "s" all elements of "p", if any;
|
|
238
|
-
s =
|
|
248
|
+
s = difference(s, p);
|
|
239
249
|
// for each regex in "pp", remove all elements of "s" which this regex matches.
|
|
240
250
|
let idx = pp.length;
|
|
241
251
|
while (idx--) {
|
|
@@ -250,19 +260,21 @@ export const JsonValidators = {
|
|
|
250
260
|
// Validation of the json succeeds if, after these two steps, set "s" is empty.
|
|
251
261
|
if (s.length > 0) {
|
|
252
262
|
// assumeAdditional can be an array of allowed properties
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
263
|
+
if (Array.isArray(this.options.assumeAdditional)) {
|
|
264
|
+
let idx3 = this.options.assumeAdditional.length;
|
|
265
|
+
if (idx3) {
|
|
266
|
+
while (idx3--) {
|
|
267
|
+
const io = s.indexOf(this.options.assumeAdditional[idx3]);
|
|
268
|
+
if (io !== -1) {
|
|
269
|
+
s.splice(io, 1);
|
|
270
|
+
}
|
|
259
271
|
}
|
|
260
272
|
}
|
|
261
273
|
}
|
|
262
274
|
let idx4 = s.length;
|
|
263
275
|
if (idx4) {
|
|
264
276
|
while (idx4--) {
|
|
265
|
-
report.addError('OBJECT_ADDITIONAL_PROPERTIES', [s[idx4]],
|
|
277
|
+
report.addError('OBJECT_ADDITIONAL_PROPERTIES', [s[idx4]], undefined, schema);
|
|
266
278
|
}
|
|
267
279
|
}
|
|
268
280
|
}
|
|
@@ -273,7 +285,7 @@ export const JsonValidators = {
|
|
|
273
285
|
if (shouldSkipValidate(this.validateOptions, ['OBJECT_DEPENDENCY_KEY'])) {
|
|
274
286
|
return;
|
|
275
287
|
}
|
|
276
|
-
if (
|
|
288
|
+
if (!isObject(json)) {
|
|
277
289
|
return;
|
|
278
290
|
}
|
|
279
291
|
const keys = Object.keys(schema.dependencies);
|
|
@@ -283,21 +295,21 @@ export const JsonValidators = {
|
|
|
283
295
|
const dependencyName = keys[idx];
|
|
284
296
|
if (json[dependencyName]) {
|
|
285
297
|
const dependencyDefinition = schema.dependencies[dependencyName];
|
|
286
|
-
if (
|
|
287
|
-
// if dependency is a schema, validate against this schema
|
|
288
|
-
validate.call(this, report, dependencyDefinition, json);
|
|
289
|
-
}
|
|
290
|
-
else {
|
|
298
|
+
if (Array.isArray(dependencyDefinition)) {
|
|
291
299
|
// Array
|
|
292
300
|
// if dependency is an array, object needs to have all properties in this array
|
|
293
301
|
let idx2 = dependencyDefinition.length;
|
|
294
302
|
while (idx2--) {
|
|
295
303
|
const requiredPropertyName = dependencyDefinition[idx2];
|
|
296
304
|
if (json[requiredPropertyName] === undefined) {
|
|
297
|
-
report.addError('OBJECT_DEPENDENCY_KEY', [requiredPropertyName, dependencyName],
|
|
305
|
+
report.addError('OBJECT_DEPENDENCY_KEY', [requiredPropertyName, dependencyName], undefined, schema);
|
|
298
306
|
}
|
|
299
307
|
}
|
|
300
308
|
}
|
|
309
|
+
else {
|
|
310
|
+
// if dependency is a schema, validate against this schema
|
|
311
|
+
validate.call(this, report, dependencyDefinition, json);
|
|
312
|
+
}
|
|
301
313
|
}
|
|
302
314
|
}
|
|
303
315
|
},
|
|
@@ -308,17 +320,17 @@ export const JsonValidators = {
|
|
|
308
320
|
}
|
|
309
321
|
let match = false, caseInsensitiveMatch = false, idx = schema.enum.length;
|
|
310
322
|
while (idx--) {
|
|
311
|
-
if (
|
|
323
|
+
if (areEqual(json, schema.enum[idx])) {
|
|
312
324
|
match = true;
|
|
313
325
|
break;
|
|
314
326
|
}
|
|
315
|
-
else if (
|
|
327
|
+
else if (areEqual(json, schema.enum[idx], { caseInsensitiveComparison: true })) {
|
|
316
328
|
caseInsensitiveMatch = true;
|
|
317
329
|
}
|
|
318
330
|
}
|
|
319
331
|
if (match === false) {
|
|
320
332
|
const error = caseInsensitiveMatch && this.options.enumCaseInsensitiveComparison ? 'ENUM_CASE_MISMATCH' : 'ENUM_MISMATCH';
|
|
321
|
-
report.addError(error, [json],
|
|
333
|
+
report.addError(error, [JSON.stringify(json)], undefined, schema);
|
|
322
334
|
}
|
|
323
335
|
},
|
|
324
336
|
type: function (report, schema, json) {
|
|
@@ -326,15 +338,15 @@ export const JsonValidators = {
|
|
|
326
338
|
if (shouldSkipValidate(this.validateOptions, ['INVALID_TYPE'])) {
|
|
327
339
|
return;
|
|
328
340
|
}
|
|
329
|
-
const jsonType =
|
|
341
|
+
const jsonType = whatIs(json);
|
|
330
342
|
if (typeof schema.type === 'string') {
|
|
331
343
|
if (jsonType !== schema.type && (jsonType !== 'integer' || schema.type !== 'number')) {
|
|
332
|
-
report.addError('INVALID_TYPE', [schema.type, jsonType],
|
|
344
|
+
report.addError('INVALID_TYPE', [schema.type, jsonType], undefined, schema);
|
|
333
345
|
}
|
|
334
346
|
}
|
|
335
347
|
else {
|
|
336
348
|
if (schema.type.indexOf(jsonType) === -1 && (jsonType !== 'integer' || schema.type.indexOf('number') === -1)) {
|
|
337
|
-
report.addError('INVALID_TYPE', [schema.type, jsonType],
|
|
349
|
+
report.addError('INVALID_TYPE', [JSON.stringify(schema.type), jsonType], undefined, schema);
|
|
338
350
|
}
|
|
339
351
|
}
|
|
340
352
|
},
|
|
@@ -378,39 +390,40 @@ export const JsonValidators = {
|
|
|
378
390
|
report.addError('ONE_OF_MISSING', undefined, subReports, schema);
|
|
379
391
|
}
|
|
380
392
|
else if (passes > 1) {
|
|
381
|
-
report.addError('ONE_OF_MULTIPLE',
|
|
393
|
+
report.addError('ONE_OF_MULTIPLE', undefined, undefined, schema);
|
|
382
394
|
}
|
|
383
395
|
},
|
|
384
396
|
not: function (report, schema, json) {
|
|
385
397
|
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.5.6.2
|
|
386
398
|
const subReport = new Report(report);
|
|
387
399
|
if (validate.call(this, subReport, schema.not, json) === true) {
|
|
388
|
-
report.addError('NOT_PASSED',
|
|
400
|
+
report.addError('NOT_PASSED', undefined, undefined, schema);
|
|
389
401
|
}
|
|
390
402
|
},
|
|
391
403
|
definitions: function () {
|
|
392
|
-
/*report, schema, json*/
|
|
404
|
+
/*report: Report, schema: JsonSchemaInternal, json: unknown*/
|
|
393
405
|
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.5.7.2
|
|
394
406
|
// nothing to do here
|
|
395
407
|
},
|
|
396
408
|
format: function (report, schema, json) {
|
|
397
409
|
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.7.2
|
|
398
|
-
const
|
|
410
|
+
const formatValidators = getFormatValidators(this.options);
|
|
411
|
+
const formatValidatorFn = formatValidators[schema.format];
|
|
399
412
|
if (typeof formatValidatorFn === 'function') {
|
|
400
413
|
if (shouldSkipValidate(this.validateOptions, ['INVALID_FORMAT'])) {
|
|
401
414
|
return;
|
|
402
415
|
}
|
|
403
|
-
if (report.hasError('INVALID_TYPE', [schema.type,
|
|
416
|
+
if (report.hasError('INVALID_TYPE', [schema.type, whatIs(json)])) {
|
|
404
417
|
return;
|
|
405
418
|
}
|
|
406
419
|
if (formatValidatorFn.length === 2) {
|
|
407
420
|
// async - need to clone the path here, because it will change by the time async function reports back
|
|
408
|
-
const pathBeforeAsync =
|
|
421
|
+
const pathBeforeAsync = shallowClone(report.path);
|
|
409
422
|
report.addAsyncTask(formatValidatorFn, [json], function (result) {
|
|
410
423
|
if (result !== true) {
|
|
411
424
|
const backup = report.path;
|
|
412
425
|
report.path = pathBeforeAsync;
|
|
413
|
-
report.addError('INVALID_FORMAT', [schema.format, json],
|
|
426
|
+
report.addError('INVALID_FORMAT', [schema.format, JSON.stringify(json)], undefined, schema);
|
|
414
427
|
report.path = backup;
|
|
415
428
|
}
|
|
416
429
|
});
|
|
@@ -418,12 +431,12 @@ export const JsonValidators = {
|
|
|
418
431
|
else {
|
|
419
432
|
// sync
|
|
420
433
|
if (formatValidatorFn.call(this, json) !== true) {
|
|
421
|
-
report.addError('INVALID_FORMAT', [schema.format, json],
|
|
434
|
+
report.addError('INVALID_FORMAT', [schema.format, JSON.stringify(json)], undefined, schema);
|
|
422
435
|
}
|
|
423
436
|
}
|
|
424
437
|
}
|
|
425
438
|
else if (this.options.ignoreUnknownFormats !== true) {
|
|
426
|
-
report.addError('UNKNOWN_FORMAT', [schema.format],
|
|
439
|
+
report.addError('UNKNOWN_FORMAT', [schema.format], undefined, schema);
|
|
427
440
|
}
|
|
428
441
|
},
|
|
429
442
|
};
|
|
@@ -509,18 +522,12 @@ const recurseObject = function (report, schema, json) {
|
|
|
509
522
|
}
|
|
510
523
|
}
|
|
511
524
|
};
|
|
512
|
-
/**
|
|
513
|
-
*
|
|
514
|
-
* @param {Report} report
|
|
515
|
-
* @param {*} schema
|
|
516
|
-
* @param {*} json
|
|
517
|
-
*/
|
|
518
525
|
export function validate(report, schema, json) {
|
|
519
526
|
report.commonErrorMessage = 'JSON_OBJECT_VALIDATION_FAILED';
|
|
520
527
|
// check if schema is an object
|
|
521
|
-
const to =
|
|
528
|
+
const to = whatIs(schema);
|
|
522
529
|
if (to !== 'object') {
|
|
523
|
-
report.addError('SCHEMA_NOT_AN_OBJECT', [to],
|
|
530
|
+
report.addError('SCHEMA_NOT_AN_OBJECT', [to], undefined, schema);
|
|
524
531
|
return false;
|
|
525
532
|
}
|
|
526
533
|
// check if schema is empty, everything is valid against empty schema
|
|
@@ -540,7 +547,7 @@ export function validate(report, schema, json) {
|
|
|
540
547
|
let maxRefs = 99;
|
|
541
548
|
while (schema.$ref && maxRefs > 0) {
|
|
542
549
|
if (!schema.__$refResolved) {
|
|
543
|
-
report.addError('REF_UNRESOLVED', [schema.$ref],
|
|
550
|
+
report.addError('REF_UNRESOLVED', [schema.$ref], undefined, schema);
|
|
544
551
|
break;
|
|
545
552
|
}
|
|
546
553
|
else if (schema.__$refResolved === schema) {
|
|
@@ -557,7 +564,6 @@ export function validate(report, schema, json) {
|
|
|
557
564
|
}
|
|
558
565
|
}
|
|
559
566
|
// type checking first
|
|
560
|
-
const jsonType = Utils.whatIs(json);
|
|
561
567
|
if (schema.type) {
|
|
562
568
|
keys.splice(keys.indexOf('type'), 1);
|
|
563
569
|
JsonValidators.type.call(this, report, schema, json);
|
|
@@ -576,10 +582,10 @@ export function validate(report, schema, json) {
|
|
|
576
582
|
}
|
|
577
583
|
}
|
|
578
584
|
if (report.errors.length === 0 || this.options.breakOnFirstError === false) {
|
|
579
|
-
if (
|
|
585
|
+
if (Array.isArray(json)) {
|
|
580
586
|
recurseArray.call(this, report, schema, json);
|
|
581
587
|
}
|
|
582
|
-
else if (
|
|
588
|
+
else if (isObject(json)) {
|
|
583
589
|
recurseObject.call(this, report, schema, json);
|
|
584
590
|
}
|
|
585
591
|
}
|
|
@@ -1,29 +1,22 @@
|
|
|
1
1
|
import get from 'lodash.get';
|
|
2
|
-
import { Errors } from './
|
|
3
|
-
import
|
|
2
|
+
import { Errors } from './errors.js';
|
|
3
|
+
import { whatIs } from './utils/what-is.js';
|
|
4
|
+
import { schemaSymbol, jsonSymbol } from './utils/symbols.js';
|
|
5
|
+
import { isAbsoluteUri } from './utils/uri.js';
|
|
4
6
|
export class Report {
|
|
5
|
-
|
|
7
|
+
asyncTasks = [];
|
|
8
|
+
commonErrorMessage;
|
|
9
|
+
errors = [];
|
|
10
|
+
json;
|
|
11
|
+
path = [];
|
|
12
|
+
rootSchema;
|
|
6
13
|
parentReport;
|
|
7
14
|
options;
|
|
8
15
|
reportOptions;
|
|
9
|
-
path;
|
|
10
|
-
asyncTasks;
|
|
11
|
-
rootSchema;
|
|
12
|
-
commonErrorMessage;
|
|
13
|
-
json;
|
|
14
16
|
constructor(parentOrOptions, reportOptions) {
|
|
15
17
|
this.parentReport = parentOrOptions instanceof Report ? parentOrOptions : undefined;
|
|
16
18
|
this.options = parentOrOptions instanceof Report ? parentOrOptions.options : parentOrOptions || {};
|
|
17
19
|
this.reportOptions = reportOptions || {};
|
|
18
|
-
this.errors = [];
|
|
19
|
-
/**
|
|
20
|
-
* @type {string[]}
|
|
21
|
-
*/
|
|
22
|
-
this.path = [];
|
|
23
|
-
this.asyncTasks = [];
|
|
24
|
-
this.rootSchema = undefined;
|
|
25
|
-
this.commonErrorMessage = undefined;
|
|
26
|
-
this.json = undefined;
|
|
27
20
|
}
|
|
28
21
|
isValid() {
|
|
29
22
|
if (this.asyncTasks.length > 0) {
|
|
@@ -54,17 +47,15 @@ export class Report {
|
|
|
54
47
|
callback(err, valid);
|
|
55
48
|
}, 0);
|
|
56
49
|
};
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
};
|
|
67
|
-
}
|
|
50
|
+
const respond = (asyncTaskResultProcessFn) => (asyncTaskResult) => {
|
|
51
|
+
if (timedOut) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
asyncTaskResultProcessFn(asyncTaskResult);
|
|
55
|
+
if (--tasksCount === 0) {
|
|
56
|
+
finish();
|
|
57
|
+
}
|
|
58
|
+
};
|
|
68
59
|
// finish if tasks are completed or there are any errors and breaking on first error was requested
|
|
69
60
|
if (tasksCount === 0 || (this.errors.length > 0 && this.options.breakOnFirstError)) {
|
|
70
61
|
finish();
|
|
@@ -84,9 +75,6 @@ export class Report {
|
|
|
84
75
|
}, validationTimeout);
|
|
85
76
|
}
|
|
86
77
|
getPath(returnPathAsString) {
|
|
87
|
-
/**
|
|
88
|
-
* @type {string[]|string}
|
|
89
|
-
*/
|
|
90
78
|
let path = [];
|
|
91
79
|
if (this.parentReport) {
|
|
92
80
|
path = path.concat(this.parentReport.path);
|
|
@@ -98,7 +86,7 @@ export class Report {
|
|
|
98
86
|
path
|
|
99
87
|
.map(function (segment) {
|
|
100
88
|
segment = segment.toString();
|
|
101
|
-
if (
|
|
89
|
+
if (isAbsoluteUri(segment)) {
|
|
102
90
|
return 'uri(' + segment + ')';
|
|
103
91
|
}
|
|
104
92
|
return segment.replace(/~/g, '~0').replace(/\//g, '~1');
|
|
@@ -109,7 +97,7 @@ export class Report {
|
|
|
109
97
|
}
|
|
110
98
|
getSchemaId() {
|
|
111
99
|
if (!this.rootSchema) {
|
|
112
|
-
return
|
|
100
|
+
return undefined;
|
|
113
101
|
}
|
|
114
102
|
// get the error path as an array
|
|
115
103
|
let path = [];
|
|
@@ -128,16 +116,16 @@ export class Report {
|
|
|
128
116
|
// return id of the root
|
|
129
117
|
return this.rootSchema.id;
|
|
130
118
|
}
|
|
131
|
-
hasError(
|
|
119
|
+
hasError(errCode, errParams) {
|
|
132
120
|
let idx = this.errors.length;
|
|
133
121
|
while (idx--) {
|
|
134
|
-
if (this.errors[idx].code ===
|
|
122
|
+
if (this.errors[idx].code === errCode) {
|
|
135
123
|
// assume match
|
|
136
124
|
let match = true;
|
|
137
125
|
// check the params too
|
|
138
126
|
let idx2 = this.errors[idx].params.length;
|
|
139
127
|
while (idx2--) {
|
|
140
|
-
if (this.errors[idx].params[idx2] !==
|
|
128
|
+
if (this.errors[idx].params[idx2] !== errParams[idx2]) {
|
|
141
129
|
match = false;
|
|
142
130
|
}
|
|
143
131
|
}
|
|
@@ -149,12 +137,13 @@ export class Report {
|
|
|
149
137
|
}
|
|
150
138
|
return false;
|
|
151
139
|
}
|
|
152
|
-
addError(
|
|
153
|
-
if (!
|
|
140
|
+
addError(errCode, errParams, subReports, schema) {
|
|
141
|
+
if (!errCode) {
|
|
154
142
|
throw new Error('No errorCode passed into addError()');
|
|
155
143
|
}
|
|
156
|
-
this.addCustomError(
|
|
144
|
+
this.addCustomError(errCode, Errors[errCode], errParams, subReports, schema);
|
|
157
145
|
}
|
|
146
|
+
// this returns the root object being validated (the one passed into validator.validate)
|
|
158
147
|
getJson() {
|
|
159
148
|
if (this.json) {
|
|
160
149
|
return this.json;
|
|
@@ -165,7 +154,7 @@ export class Report {
|
|
|
165
154
|
return undefined;
|
|
166
155
|
}
|
|
167
156
|
addCustomError(errorCode, errorMessage, params, subReports, schema) {
|
|
168
|
-
if (this.errors.length >= this.reportOptions.maxErrors) {
|
|
157
|
+
if (typeof this.reportOptions.maxErrors === 'number' && this.errors.length >= this.reportOptions.maxErrors) {
|
|
169
158
|
return;
|
|
170
159
|
}
|
|
171
160
|
if (!errorMessage) {
|
|
@@ -174,9 +163,9 @@ export class Report {
|
|
|
174
163
|
params = params || [];
|
|
175
164
|
let idx = params.length;
|
|
176
165
|
while (idx--) {
|
|
177
|
-
const
|
|
178
|
-
const param =
|
|
179
|
-
errorMessage = errorMessage.replace('{' + idx + '}', param);
|
|
166
|
+
const paramType = whatIs(params[idx]);
|
|
167
|
+
const param = paramType === 'object' || paramType === 'null' ? JSON.stringify(params[idx]) : params[idx];
|
|
168
|
+
errorMessage = errorMessage.replace('{' + idx + '}', param.toString());
|
|
180
169
|
}
|
|
181
170
|
const err = {
|
|
182
171
|
code: errorCode,
|
|
@@ -185,8 +174,9 @@ export class Report {
|
|
|
185
174
|
path: this.getPath(this.options.reportPathAsArray),
|
|
186
175
|
schemaId: this.getSchemaId(),
|
|
187
176
|
};
|
|
188
|
-
|
|
189
|
-
err[
|
|
177
|
+
// TODO v8: remove Symbol usage
|
|
178
|
+
err[schemaSymbol] = schema;
|
|
179
|
+
err[jsonSymbol] = this.getJson();
|
|
190
180
|
if (schema && typeof schema === 'string') {
|
|
191
181
|
err.description = schema;
|
|
192
182
|
}
|