schema-shield 0.0.2
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 +11 -0
- package/dist/formats.d.ts +3 -0
- package/dist/formats.d.ts.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1289 -0
- package/dist/index.min.js +1 -0
- package/dist/index.min.js.map +1 -0
- package/dist/index.mjs +1267 -0
- package/dist/keywords/array-keywords.d.ts +3 -0
- package/dist/keywords/array-keywords.d.ts.map +1 -0
- package/dist/keywords/number-keywords.d.ts +3 -0
- package/dist/keywords/number-keywords.d.ts.map +1 -0
- package/dist/keywords/object-keywords.d.ts +3 -0
- package/dist/keywords/object-keywords.d.ts.map +1 -0
- package/dist/keywords/other-keywords.d.ts +3 -0
- package/dist/keywords/other-keywords.d.ts.map +1 -0
- package/dist/keywords/string-keywords.d.ts +3 -0
- package/dist/keywords/string-keywords.d.ts.map +1 -0
- package/dist/keywords.d.ts +3 -0
- package/dist/keywords.d.ts.map +1 -0
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils.d.ts +13 -0
- package/dist/utils.d.ts.map +1 -0
- package/lib/formats.ts +56 -0
- package/lib/index.ts +308 -0
- package/lib/keywords/array-keywords.ts +204 -0
- package/lib/keywords/number-keywords.ts +79 -0
- package/lib/keywords/object-keywords.ts +230 -0
- package/lib/keywords/other-keywords.ts +248 -0
- package/lib/keywords/string-keywords.ts +165 -0
- package/lib/keywords.ts +14 -0
- package/lib/types.ts +176 -0
- package/lib/utils.ts +79 -0
- package/package.json +189 -0
- package/tsconfig.json +16 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1289 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// lib/index.ts
|
|
20
|
+
var lib_exports = {};
|
|
21
|
+
__export(lib_exports, {
|
|
22
|
+
SchemaShield: () => SchemaShield
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(lib_exports);
|
|
25
|
+
|
|
26
|
+
// lib/utils.ts
|
|
27
|
+
var ValidationError = class extends Error {
|
|
28
|
+
name;
|
|
29
|
+
pointer;
|
|
30
|
+
message;
|
|
31
|
+
value;
|
|
32
|
+
code;
|
|
33
|
+
constructor(message, options = {
|
|
34
|
+
pointer: "",
|
|
35
|
+
value: null,
|
|
36
|
+
code: ""
|
|
37
|
+
}) {
|
|
38
|
+
super(message);
|
|
39
|
+
this.name = "ValidationError";
|
|
40
|
+
this.pointer = options.pointer;
|
|
41
|
+
this.message = message;
|
|
42
|
+
this.value = options.value;
|
|
43
|
+
this.code = options.code;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
function deepEqual(obj, other) {
|
|
47
|
+
if (Array.isArray(obj) && Array.isArray(other)) {
|
|
48
|
+
if (obj.length !== other.length) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
for (let i = 0; i < obj.length; i++) {
|
|
52
|
+
if (!deepEqual(obj[i], other[i])) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
if (typeof obj === "object" && typeof other === "object") {
|
|
59
|
+
if (obj === null || other === null) {
|
|
60
|
+
return obj === other;
|
|
61
|
+
}
|
|
62
|
+
const keys = Object.keys(obj);
|
|
63
|
+
if (keys.length !== Object.keys(other).length) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
for (const key of keys) {
|
|
67
|
+
if (!deepEqual(obj[key], other[key])) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
return obj === other;
|
|
74
|
+
}
|
|
75
|
+
function isObject(data) {
|
|
76
|
+
return typeof data === "object" && data !== null && !Array.isArray(data);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// lib/formats.ts
|
|
80
|
+
var RegExps = {
|
|
81
|
+
"date-time": /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/,
|
|
82
|
+
uri: /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/,
|
|
83
|
+
email: /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,
|
|
84
|
+
ipv4: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/,
|
|
85
|
+
ipv6: /^(?:(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|(?=(?:[0-9a-fA-F]{0,4}:){0,7}[0-9a-fA-F]{0,4}(?![:.\w]))(([0-9a-fA-F]{1,4}:){1,7}|:)((:[0-9a-fA-F]{1,4}){1,7}|:))$/,
|
|
86
|
+
hostname: /^[a-zA-Z0-9][a-zA-Z0-9-]{0,62}(\.[a-zA-Z0-9][a-zA-Z0-9-]{0,62})*$/
|
|
87
|
+
};
|
|
88
|
+
function notImplementedFormat(data) {
|
|
89
|
+
throw new ValidationError(
|
|
90
|
+
`Format "${data}" is not implemented yet. Please open an issue on GitHub.`
|
|
91
|
+
);
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
var Formats = {
|
|
95
|
+
["date-time"](data) {
|
|
96
|
+
return RegExps["date-time"].test(data);
|
|
97
|
+
},
|
|
98
|
+
uri(data) {
|
|
99
|
+
return RegExps.uri.test(data);
|
|
100
|
+
},
|
|
101
|
+
email(data) {
|
|
102
|
+
return RegExps.email.test(data);
|
|
103
|
+
},
|
|
104
|
+
ipv4(data) {
|
|
105
|
+
return RegExps.ipv4.test(data);
|
|
106
|
+
},
|
|
107
|
+
ipv6(data) {
|
|
108
|
+
return RegExps.ipv6.test(data);
|
|
109
|
+
},
|
|
110
|
+
hostname(data) {
|
|
111
|
+
return RegExps.hostname.test(data);
|
|
112
|
+
},
|
|
113
|
+
// Not supported yet
|
|
114
|
+
time: notImplementedFormat,
|
|
115
|
+
date: notImplementedFormat,
|
|
116
|
+
duration: notImplementedFormat,
|
|
117
|
+
"idn-email": notImplementedFormat,
|
|
118
|
+
"idn-hostname": notImplementedFormat,
|
|
119
|
+
uuid: notImplementedFormat,
|
|
120
|
+
"uri-reference": notImplementedFormat,
|
|
121
|
+
iri: notImplementedFormat,
|
|
122
|
+
"iri-reference": notImplementedFormat,
|
|
123
|
+
"uri-template": notImplementedFormat,
|
|
124
|
+
"json-pointer": notImplementedFormat,
|
|
125
|
+
"relative-json-pointer": notImplementedFormat,
|
|
126
|
+
regex: notImplementedFormat
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// lib/types.ts
|
|
130
|
+
var Types = {
|
|
131
|
+
object(schema, data, pointer) {
|
|
132
|
+
if (typeof data === "object" && data !== null && !Array.isArray(data)) {
|
|
133
|
+
return {
|
|
134
|
+
valid: true,
|
|
135
|
+
errors: [],
|
|
136
|
+
data
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
valid: false,
|
|
141
|
+
errors: [
|
|
142
|
+
new ValidationError("Data is not an object", {
|
|
143
|
+
pointer,
|
|
144
|
+
value: data,
|
|
145
|
+
code: "NOT_AN_OBJECT"
|
|
146
|
+
})
|
|
147
|
+
],
|
|
148
|
+
data
|
|
149
|
+
};
|
|
150
|
+
},
|
|
151
|
+
array(schema, data, pointer) {
|
|
152
|
+
if (Array.isArray(data)) {
|
|
153
|
+
return {
|
|
154
|
+
valid: true,
|
|
155
|
+
errors: [],
|
|
156
|
+
data
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
if (typeof data === "object" && data !== null && "length" in data) {
|
|
160
|
+
const keys = Object.keys(data);
|
|
161
|
+
if (keys.length > 0 && (keys[0] !== "0" || keys.length !== data.length)) {
|
|
162
|
+
return {
|
|
163
|
+
valid: false,
|
|
164
|
+
errors: [
|
|
165
|
+
new ValidationError("Data is not an array", {
|
|
166
|
+
pointer,
|
|
167
|
+
value: data,
|
|
168
|
+
code: "NOT_AN_ARRAY"
|
|
169
|
+
})
|
|
170
|
+
],
|
|
171
|
+
data
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
return {
|
|
175
|
+
valid: true,
|
|
176
|
+
errors: [],
|
|
177
|
+
data
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
valid: false,
|
|
182
|
+
errors: [
|
|
183
|
+
new ValidationError("Data is not an array", {
|
|
184
|
+
pointer,
|
|
185
|
+
value: data,
|
|
186
|
+
code: "NOT_AN_ARRAY"
|
|
187
|
+
})
|
|
188
|
+
],
|
|
189
|
+
data
|
|
190
|
+
};
|
|
191
|
+
},
|
|
192
|
+
string(schema, data, pointer) {
|
|
193
|
+
if (typeof data === "string") {
|
|
194
|
+
return {
|
|
195
|
+
valid: true,
|
|
196
|
+
errors: [],
|
|
197
|
+
data
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
valid: false,
|
|
202
|
+
errors: [
|
|
203
|
+
new ValidationError("Data is not a string", {
|
|
204
|
+
pointer,
|
|
205
|
+
value: data,
|
|
206
|
+
code: "NOT_A_STRING"
|
|
207
|
+
})
|
|
208
|
+
],
|
|
209
|
+
data
|
|
210
|
+
};
|
|
211
|
+
},
|
|
212
|
+
number(schema, data, pointer) {
|
|
213
|
+
if (typeof data === "number") {
|
|
214
|
+
return {
|
|
215
|
+
valid: true,
|
|
216
|
+
errors: [],
|
|
217
|
+
data
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
valid: false,
|
|
222
|
+
errors: [
|
|
223
|
+
new ValidationError("Data is not a number", {
|
|
224
|
+
pointer,
|
|
225
|
+
value: data,
|
|
226
|
+
code: "NOT_A_NUMBER"
|
|
227
|
+
})
|
|
228
|
+
],
|
|
229
|
+
data
|
|
230
|
+
};
|
|
231
|
+
},
|
|
232
|
+
integer(schema, data, pointer) {
|
|
233
|
+
if (typeof data === "number" && Number.isInteger(data)) {
|
|
234
|
+
return {
|
|
235
|
+
valid: true,
|
|
236
|
+
errors: [],
|
|
237
|
+
data
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
return {
|
|
241
|
+
valid: false,
|
|
242
|
+
errors: [
|
|
243
|
+
new ValidationError("Data is not an integer", {
|
|
244
|
+
pointer,
|
|
245
|
+
value: data,
|
|
246
|
+
code: "NOT_AN_INTEGER"
|
|
247
|
+
})
|
|
248
|
+
],
|
|
249
|
+
data
|
|
250
|
+
};
|
|
251
|
+
},
|
|
252
|
+
boolean(schema, data, pointer) {
|
|
253
|
+
if (typeof data === "boolean") {
|
|
254
|
+
return {
|
|
255
|
+
valid: true,
|
|
256
|
+
errors: [],
|
|
257
|
+
data
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
return {
|
|
261
|
+
valid: false,
|
|
262
|
+
errors: [
|
|
263
|
+
new ValidationError("Data is not a boolean", {
|
|
264
|
+
pointer,
|
|
265
|
+
value: data,
|
|
266
|
+
code: "NOT_A_BOOLEAN"
|
|
267
|
+
})
|
|
268
|
+
],
|
|
269
|
+
data
|
|
270
|
+
};
|
|
271
|
+
},
|
|
272
|
+
null(schema, data, pointer) {
|
|
273
|
+
if (data === null) {
|
|
274
|
+
return {
|
|
275
|
+
valid: true,
|
|
276
|
+
errors: [],
|
|
277
|
+
data
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
return {
|
|
281
|
+
valid: false,
|
|
282
|
+
errors: [
|
|
283
|
+
new ValidationError("Data is not null", {
|
|
284
|
+
pointer,
|
|
285
|
+
value: data,
|
|
286
|
+
code: "NOT_NULL"
|
|
287
|
+
})
|
|
288
|
+
],
|
|
289
|
+
data
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
// lib/keywords/array-keywords.ts
|
|
295
|
+
var ArrayKeywords = {
|
|
296
|
+
items(schema, data, pointer, schemaShieldInstance) {
|
|
297
|
+
if (!Array.isArray(data)) {
|
|
298
|
+
return { valid: true, errors: [], data };
|
|
299
|
+
}
|
|
300
|
+
const errors = [];
|
|
301
|
+
let finalData = [...data];
|
|
302
|
+
if (Array.isArray(schema.items)) {
|
|
303
|
+
for (let i = 0; i < schema.items.length; i++) {
|
|
304
|
+
if (typeof schema.items[i] === "boolean") {
|
|
305
|
+
if (schema.items[i] === false && typeof data[i] !== "undefined") {
|
|
306
|
+
errors.push(
|
|
307
|
+
new ValidationError("Array item is not allowed", {
|
|
308
|
+
pointer: `${pointer}/${i}`,
|
|
309
|
+
value: data[i],
|
|
310
|
+
code: "ARRAY_ITEM_NOT_ALLOWED"
|
|
311
|
+
})
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
const { validator } = schema.items[i];
|
|
317
|
+
if (!validator) {
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
const validatorResult = validator(
|
|
321
|
+
schema.items[i],
|
|
322
|
+
finalData[i],
|
|
323
|
+
`${pointer}/${i}`,
|
|
324
|
+
schemaShieldInstance
|
|
325
|
+
);
|
|
326
|
+
finalData[i] = validatorResult.data;
|
|
327
|
+
if (!validatorResult.valid) {
|
|
328
|
+
errors.push(...validatorResult.errors);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
} else if (typeof schema.items === "boolean") {
|
|
332
|
+
if (schema.items === false && data.length > 0) {
|
|
333
|
+
errors.push(
|
|
334
|
+
new ValidationError("Array is not allowed", {
|
|
335
|
+
pointer,
|
|
336
|
+
value: data,
|
|
337
|
+
code: "ARRAY_NOT_ALLOWED"
|
|
338
|
+
})
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
} else {
|
|
342
|
+
const { validator } = schema.items;
|
|
343
|
+
if (!validator) {
|
|
344
|
+
return { valid: true, errors: [], data };
|
|
345
|
+
}
|
|
346
|
+
for (let i = 0; i < finalData.length; i++) {
|
|
347
|
+
const validatorErrors = validator(
|
|
348
|
+
schema.items,
|
|
349
|
+
finalData[i],
|
|
350
|
+
`${pointer}/${i}`,
|
|
351
|
+
schemaShieldInstance
|
|
352
|
+
);
|
|
353
|
+
finalData[i] = validatorErrors.data;
|
|
354
|
+
if (!validatorErrors.valid) {
|
|
355
|
+
errors.push(...validatorErrors.errors);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return { valid: errors.length === 0, errors, data: finalData };
|
|
360
|
+
},
|
|
361
|
+
minItems(schema, data, pointer) {
|
|
362
|
+
if (!Array.isArray(data) || data.length >= schema.minItems) {
|
|
363
|
+
return { valid: true, errors: [], data };
|
|
364
|
+
}
|
|
365
|
+
return {
|
|
366
|
+
valid: false,
|
|
367
|
+
errors: [
|
|
368
|
+
new ValidationError("Array is too short", {
|
|
369
|
+
pointer,
|
|
370
|
+
value: data,
|
|
371
|
+
code: "ARRAY_TOO_SHORT"
|
|
372
|
+
})
|
|
373
|
+
],
|
|
374
|
+
data
|
|
375
|
+
};
|
|
376
|
+
},
|
|
377
|
+
maxItems(schema, data, pointer) {
|
|
378
|
+
if (!Array.isArray(data) || data.length <= schema.maxItems) {
|
|
379
|
+
return { valid: true, errors: [], data };
|
|
380
|
+
}
|
|
381
|
+
return {
|
|
382
|
+
valid: false,
|
|
383
|
+
errors: [
|
|
384
|
+
new ValidationError("Array is too long", {
|
|
385
|
+
pointer,
|
|
386
|
+
value: data,
|
|
387
|
+
code: "ARRAY_TOO_LONG"
|
|
388
|
+
})
|
|
389
|
+
],
|
|
390
|
+
data
|
|
391
|
+
};
|
|
392
|
+
},
|
|
393
|
+
additionalItems(schema, data, pointer, schemaShieldInstance) {
|
|
394
|
+
if (!Array.isArray(data) || !schema.items || !Array.isArray(schema.items)) {
|
|
395
|
+
return { valid: true, errors: [], data };
|
|
396
|
+
}
|
|
397
|
+
if (schema.additionalItems === false) {
|
|
398
|
+
if (data.length > schema.items.length) {
|
|
399
|
+
return {
|
|
400
|
+
valid: false,
|
|
401
|
+
errors: [
|
|
402
|
+
new ValidationError("Array has too many items", {
|
|
403
|
+
pointer,
|
|
404
|
+
value: data,
|
|
405
|
+
code: "ARRAY_TOO_MANY_ITEMS"
|
|
406
|
+
})
|
|
407
|
+
],
|
|
408
|
+
data
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
return { valid: true, errors: [], data };
|
|
412
|
+
}
|
|
413
|
+
const errors = [];
|
|
414
|
+
let finalData = [...data];
|
|
415
|
+
if (typeof schema.additionalItems === "object") {
|
|
416
|
+
for (let i = schema.items.length; i < finalData.length; i++) {
|
|
417
|
+
const { validator } = schema.additionalItems;
|
|
418
|
+
const validatorResult = validator(
|
|
419
|
+
schema.additionalItems,
|
|
420
|
+
finalData[i],
|
|
421
|
+
`${pointer}/${i}`,
|
|
422
|
+
schemaShieldInstance
|
|
423
|
+
);
|
|
424
|
+
if (!validatorResult.valid) {
|
|
425
|
+
errors.push(...validatorResult.errors);
|
|
426
|
+
}
|
|
427
|
+
finalData[i] = validatorResult.data;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
return { valid: errors.length === 0, errors, data: finalData };
|
|
431
|
+
},
|
|
432
|
+
uniqueItems(schema, data, pointer) {
|
|
433
|
+
if (!Array.isArray(data) || !schema.uniqueItems) {
|
|
434
|
+
return { valid: true, errors: [], data };
|
|
435
|
+
}
|
|
436
|
+
const unique = /* @__PURE__ */ new Set();
|
|
437
|
+
for (const item of data) {
|
|
438
|
+
let itemStr = item;
|
|
439
|
+
if (typeof item === "string") {
|
|
440
|
+
itemStr = `"${item}"`;
|
|
441
|
+
} else if (isObject(item)) {
|
|
442
|
+
const keys = Object.keys(item).sort();
|
|
443
|
+
const sorted = {};
|
|
444
|
+
for (let i = 0; i < keys.length; i++) {
|
|
445
|
+
sorted[keys[i]] = item[keys[i]];
|
|
446
|
+
}
|
|
447
|
+
itemStr = JSON.stringify(sorted);
|
|
448
|
+
} else if (Array.isArray(item)) {
|
|
449
|
+
itemStr = JSON.stringify(item);
|
|
450
|
+
}
|
|
451
|
+
if (unique.has(itemStr)) {
|
|
452
|
+
return {
|
|
453
|
+
valid: false,
|
|
454
|
+
errors: [
|
|
455
|
+
new ValidationError("Array items are not unique", {
|
|
456
|
+
pointer,
|
|
457
|
+
value: data,
|
|
458
|
+
code: "ARRAY_ITEMS_NOT_UNIQUE"
|
|
459
|
+
})
|
|
460
|
+
],
|
|
461
|
+
data
|
|
462
|
+
};
|
|
463
|
+
} else {
|
|
464
|
+
unique.add(itemStr);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
return { valid: true, errors: [], data };
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
// lib/keywords/number-keywords.ts
|
|
472
|
+
var NumberKeywords = {
|
|
473
|
+
minimum(schema, data, pointer) {
|
|
474
|
+
if (typeof data !== "number") {
|
|
475
|
+
return { valid: true, errors: [], data };
|
|
476
|
+
}
|
|
477
|
+
const min = schema.exclusiveMinimum ? schema.minimum + 1e-15 : schema.minimum;
|
|
478
|
+
const valid = data >= min;
|
|
479
|
+
return {
|
|
480
|
+
valid,
|
|
481
|
+
errors: valid ? [] : [
|
|
482
|
+
new ValidationError("Number is too small", {
|
|
483
|
+
pointer,
|
|
484
|
+
value: data,
|
|
485
|
+
code: "NUMBER_TOO_SMALL"
|
|
486
|
+
})
|
|
487
|
+
],
|
|
488
|
+
data
|
|
489
|
+
};
|
|
490
|
+
},
|
|
491
|
+
maximum(schema, data, pointer) {
|
|
492
|
+
if (typeof data !== "number") {
|
|
493
|
+
return { valid: true, errors: [], data };
|
|
494
|
+
}
|
|
495
|
+
const max = schema.exclusiveMaximum ? schema.maximum - 1e-15 : schema.maximum;
|
|
496
|
+
const valid = data <= max;
|
|
497
|
+
return {
|
|
498
|
+
valid,
|
|
499
|
+
errors: valid ? [] : [
|
|
500
|
+
new ValidationError("Number is too large", {
|
|
501
|
+
pointer,
|
|
502
|
+
value: data,
|
|
503
|
+
code: "NUMBER_TOO_LARGE"
|
|
504
|
+
})
|
|
505
|
+
],
|
|
506
|
+
data
|
|
507
|
+
};
|
|
508
|
+
},
|
|
509
|
+
multipleOf(schema, data, pointer) {
|
|
510
|
+
if (typeof data !== "number") {
|
|
511
|
+
return { valid: true, errors: [], data };
|
|
512
|
+
}
|
|
513
|
+
const quotient = data / schema.multipleOf;
|
|
514
|
+
const areMultiples = Math.abs(quotient - Math.round(quotient)) < 1e-15;
|
|
515
|
+
return {
|
|
516
|
+
valid: areMultiples,
|
|
517
|
+
errors: areMultiples ? [] : [
|
|
518
|
+
new ValidationError("Number is not a multiple of", {
|
|
519
|
+
pointer,
|
|
520
|
+
value: data,
|
|
521
|
+
code: "NUMBER_NOT_MULTIPLE_OF"
|
|
522
|
+
})
|
|
523
|
+
],
|
|
524
|
+
data
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
// lib/keywords/object-keywords.ts
|
|
530
|
+
var ObjectKeywords = {
|
|
531
|
+
// Object
|
|
532
|
+
required(schema, data, pointer) {
|
|
533
|
+
if (!isObject(data)) {
|
|
534
|
+
return {
|
|
535
|
+
valid: true,
|
|
536
|
+
errors: [],
|
|
537
|
+
data
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
const errors = [];
|
|
541
|
+
for (let i = 0; i < schema.required.length; i++) {
|
|
542
|
+
const key = schema.required[i];
|
|
543
|
+
if (!data.hasOwnProperty(key)) {
|
|
544
|
+
errors.push(
|
|
545
|
+
new ValidationError("Missing required property", {
|
|
546
|
+
pointer: `${pointer}/${key}`,
|
|
547
|
+
value: data,
|
|
548
|
+
code: "MISSING_REQUIRED_PROPERTY"
|
|
549
|
+
})
|
|
550
|
+
);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return { valid: errors.length === 0, errors, data };
|
|
554
|
+
},
|
|
555
|
+
properties(schema, data, pointer, schemaShieldInstance) {
|
|
556
|
+
if (!isObject(data)) {
|
|
557
|
+
return { valid: true, errors: [], data };
|
|
558
|
+
}
|
|
559
|
+
const errors = [];
|
|
560
|
+
let finalData = { ...data };
|
|
561
|
+
for (let key in schema.properties) {
|
|
562
|
+
if (!data.hasOwnProperty(key) || typeof data[key] === "undefined") {
|
|
563
|
+
if (isObject(schema.properties[key]) && "default" in schema.properties[key]) {
|
|
564
|
+
finalData[key] = schema.properties[key].default;
|
|
565
|
+
}
|
|
566
|
+
continue;
|
|
567
|
+
}
|
|
568
|
+
if (typeof schema.properties[key] === "boolean") {
|
|
569
|
+
if (schema.properties[key] === false) {
|
|
570
|
+
errors.push(
|
|
571
|
+
new ValidationError("Property is not allowed", {
|
|
572
|
+
pointer: `${pointer}/${key}`,
|
|
573
|
+
value: data[key],
|
|
574
|
+
code: "PROPERTY_NOT_ALLOWED"
|
|
575
|
+
})
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
continue;
|
|
579
|
+
}
|
|
580
|
+
const { validator } = schema.properties[key];
|
|
581
|
+
if (!validator) {
|
|
582
|
+
continue;
|
|
583
|
+
}
|
|
584
|
+
const validatorResult = validator(
|
|
585
|
+
schema.properties[key],
|
|
586
|
+
finalData[key],
|
|
587
|
+
`${pointer}/${key}`,
|
|
588
|
+
schemaShieldInstance
|
|
589
|
+
);
|
|
590
|
+
finalData[key] = validatorResult.data;
|
|
591
|
+
if (!validatorResult.valid) {
|
|
592
|
+
errors.push(...validatorResult.errors);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
return { valid: errors.length === 0, errors, data: finalData };
|
|
596
|
+
},
|
|
597
|
+
maxProperties(schema, data, pointer) {
|
|
598
|
+
if (!isObject(data) || Object.keys(data).length <= schema.maxProperties) {
|
|
599
|
+
return { valid: true, errors: [], data };
|
|
600
|
+
}
|
|
601
|
+
return {
|
|
602
|
+
valid: false,
|
|
603
|
+
errors: [
|
|
604
|
+
new ValidationError("Object has too many properties", {
|
|
605
|
+
pointer,
|
|
606
|
+
value: data,
|
|
607
|
+
code: "OBJECT_TOO_MANY_PROPERTIES"
|
|
608
|
+
})
|
|
609
|
+
],
|
|
610
|
+
data
|
|
611
|
+
};
|
|
612
|
+
},
|
|
613
|
+
minProperties(schema, data, pointer) {
|
|
614
|
+
if (!isObject(data) || Object.keys(data).length >= schema.minProperties) {
|
|
615
|
+
return { valid: true, errors: [], data };
|
|
616
|
+
}
|
|
617
|
+
return {
|
|
618
|
+
valid: false,
|
|
619
|
+
errors: [
|
|
620
|
+
new ValidationError("Object has too few properties", {
|
|
621
|
+
pointer,
|
|
622
|
+
value: data,
|
|
623
|
+
code: "OBJECT_TOO_FEW_PROPERTIES"
|
|
624
|
+
})
|
|
625
|
+
],
|
|
626
|
+
data
|
|
627
|
+
};
|
|
628
|
+
},
|
|
629
|
+
additionalProperties(schema, data, pointer, schemaShieldInstance) {
|
|
630
|
+
if (!isObject(data)) {
|
|
631
|
+
return { valid: true, errors: [], data };
|
|
632
|
+
}
|
|
633
|
+
const errors = [];
|
|
634
|
+
let finalData = { ...data };
|
|
635
|
+
for (let key in data) {
|
|
636
|
+
if (schema.properties && schema.properties.hasOwnProperty(key)) {
|
|
637
|
+
continue;
|
|
638
|
+
}
|
|
639
|
+
if (schema.patternProperties) {
|
|
640
|
+
let match = false;
|
|
641
|
+
for (let pattern in schema.patternProperties) {
|
|
642
|
+
if (new RegExp(pattern).test(key)) {
|
|
643
|
+
match = true;
|
|
644
|
+
break;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
if (match) {
|
|
648
|
+
continue;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
if (schema.additionalProperties === false) {
|
|
652
|
+
errors.push(
|
|
653
|
+
new ValidationError("Additional property not allowed", {
|
|
654
|
+
pointer: `${pointer}/${key}`,
|
|
655
|
+
value: data,
|
|
656
|
+
code: "ADDITIONAL_PROPERTY_NOT_ALLOWED"
|
|
657
|
+
})
|
|
658
|
+
);
|
|
659
|
+
continue;
|
|
660
|
+
}
|
|
661
|
+
const { validator } = schema.additionalProperties;
|
|
662
|
+
if (!validator) {
|
|
663
|
+
continue;
|
|
664
|
+
}
|
|
665
|
+
const validatorResult = validator(
|
|
666
|
+
schema.additionalProperties,
|
|
667
|
+
finalData[key],
|
|
668
|
+
`${pointer}/${key}`,
|
|
669
|
+
schemaShieldInstance
|
|
670
|
+
);
|
|
671
|
+
finalData[key] = validatorResult.data;
|
|
672
|
+
if (!validatorResult.valid) {
|
|
673
|
+
errors.push(...validatorResult.errors);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
return { valid: errors.length === 0, errors, data: finalData };
|
|
677
|
+
},
|
|
678
|
+
patternProperties(schema, data, pointer, schemaShieldInstance) {
|
|
679
|
+
if (!isObject(data)) {
|
|
680
|
+
return { valid: true, errors: [], data };
|
|
681
|
+
}
|
|
682
|
+
const errors = [];
|
|
683
|
+
let finalData = { ...data };
|
|
684
|
+
for (let pattern in schema.patternProperties) {
|
|
685
|
+
if (typeof schema.patternProperties[pattern] === "boolean") {
|
|
686
|
+
if (schema.patternProperties[pattern] === false) {
|
|
687
|
+
for (let key in finalData) {
|
|
688
|
+
if (new RegExp(pattern).test(key)) {
|
|
689
|
+
errors.push(
|
|
690
|
+
new ValidationError("Property is not allowed", {
|
|
691
|
+
pointer: `${pointer}/${key}`,
|
|
692
|
+
value: data[key],
|
|
693
|
+
code: "PROPERTY_NOT_ALLOWED"
|
|
694
|
+
})
|
|
695
|
+
);
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
continue;
|
|
700
|
+
}
|
|
701
|
+
const { validator } = schema.patternProperties[pattern];
|
|
702
|
+
if (!validator) {
|
|
703
|
+
continue;
|
|
704
|
+
}
|
|
705
|
+
for (let key in finalData) {
|
|
706
|
+
if (new RegExp(pattern).test(key)) {
|
|
707
|
+
const validatorResult = validator(
|
|
708
|
+
schema.patternProperties[pattern],
|
|
709
|
+
finalData[key],
|
|
710
|
+
`${pointer}/${key}`,
|
|
711
|
+
schemaShieldInstance
|
|
712
|
+
);
|
|
713
|
+
finalData[key] = validatorResult.data;
|
|
714
|
+
if (!validatorResult.valid) {
|
|
715
|
+
errors.push(...validatorResult.errors);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
return { valid: errors.length === 0, errors, data: finalData };
|
|
721
|
+
}
|
|
722
|
+
};
|
|
723
|
+
|
|
724
|
+
// lib/keywords/other-keywords.ts
|
|
725
|
+
var OtherKeywords = {
|
|
726
|
+
nullable(schema, data, pointer) {
|
|
727
|
+
if (schema.nullable && data !== null) {
|
|
728
|
+
return {
|
|
729
|
+
valid: false,
|
|
730
|
+
errors: [
|
|
731
|
+
new ValidationError("Value must be null to be empty", {
|
|
732
|
+
pointer,
|
|
733
|
+
value: data,
|
|
734
|
+
code: "VALUE_NOT_NULL"
|
|
735
|
+
})
|
|
736
|
+
],
|
|
737
|
+
data
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
return { valid: true, errors: [], data };
|
|
741
|
+
},
|
|
742
|
+
oneOf(schema, data, pointer, schemaShieldInstance) {
|
|
743
|
+
const errors = [];
|
|
744
|
+
let validCount = 0;
|
|
745
|
+
let finalData = data;
|
|
746
|
+
for (let i = 0; i < schema.oneOf.length; i++) {
|
|
747
|
+
if (isObject(schema.oneOf[i])) {
|
|
748
|
+
const { validator } = schema.oneOf[i];
|
|
749
|
+
if (!validator) {
|
|
750
|
+
validCount++;
|
|
751
|
+
continue;
|
|
752
|
+
}
|
|
753
|
+
const validationResult = validator(
|
|
754
|
+
schema.oneOf[i],
|
|
755
|
+
finalData,
|
|
756
|
+
pointer,
|
|
757
|
+
schemaShieldInstance
|
|
758
|
+
);
|
|
759
|
+
if (validationResult.valid) {
|
|
760
|
+
validCount++;
|
|
761
|
+
} else {
|
|
762
|
+
errors.push(...validationResult.errors);
|
|
763
|
+
}
|
|
764
|
+
finalData = validationResult.data;
|
|
765
|
+
} else {
|
|
766
|
+
if (typeof schema.oneOf[i] === "boolean") {
|
|
767
|
+
if (Boolean(data) === schema.oneOf[i]) {
|
|
768
|
+
validCount++;
|
|
769
|
+
}
|
|
770
|
+
continue;
|
|
771
|
+
}
|
|
772
|
+
if (data === schema.oneOf[i]) {
|
|
773
|
+
validCount++;
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
if (validCount === 1) {
|
|
778
|
+
return { valid: true, errors: [], data: finalData };
|
|
779
|
+
}
|
|
780
|
+
return {
|
|
781
|
+
valid: false,
|
|
782
|
+
errors: [
|
|
783
|
+
new ValidationError(`Value must match exactly one schema in oneOf`, {
|
|
784
|
+
pointer,
|
|
785
|
+
value: data,
|
|
786
|
+
code: "VALUE_DOES_NOT_MATCH_ONE_OF"
|
|
787
|
+
})
|
|
788
|
+
],
|
|
789
|
+
data: finalData
|
|
790
|
+
};
|
|
791
|
+
},
|
|
792
|
+
allOf(schema, data, pointer, schemaShieldInstance) {
|
|
793
|
+
const errors = [];
|
|
794
|
+
let finalData = data;
|
|
795
|
+
for (let i = 0; i < schema.allOf.length; i++) {
|
|
796
|
+
if (isObject(schema.allOf[i])) {
|
|
797
|
+
const { validator } = schema.allOf[i];
|
|
798
|
+
if (!validator) {
|
|
799
|
+
continue;
|
|
800
|
+
}
|
|
801
|
+
const validatorResult = validator(
|
|
802
|
+
schema.allOf[i],
|
|
803
|
+
finalData,
|
|
804
|
+
pointer,
|
|
805
|
+
schemaShieldInstance
|
|
806
|
+
);
|
|
807
|
+
if (!validatorResult.valid) {
|
|
808
|
+
errors.push(...validatorResult.errors);
|
|
809
|
+
}
|
|
810
|
+
finalData = validatorResult.data;
|
|
811
|
+
} else {
|
|
812
|
+
if (typeof schema.allOf[i] === "boolean") {
|
|
813
|
+
if (Boolean(data) !== schema.allOf[i]) {
|
|
814
|
+
errors.push(
|
|
815
|
+
new ValidationError(`Value must match all schemas in allOf`, {
|
|
816
|
+
pointer,
|
|
817
|
+
value: data,
|
|
818
|
+
code: "VALUE_DOES_NOT_MATCH_ALL_OF"
|
|
819
|
+
})
|
|
820
|
+
);
|
|
821
|
+
}
|
|
822
|
+
continue;
|
|
823
|
+
}
|
|
824
|
+
if (data !== schema.allOf[i]) {
|
|
825
|
+
errors.push(
|
|
826
|
+
new ValidationError(`Value must match all schemas in allOf`, {
|
|
827
|
+
pointer,
|
|
828
|
+
value: data,
|
|
829
|
+
code: "VALUE_DOES_NOT_MATCH_ALL_OF"
|
|
830
|
+
})
|
|
831
|
+
);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
return { valid: errors.length === 0, errors, data: finalData };
|
|
836
|
+
},
|
|
837
|
+
anyOf(schema, data, pointer, schemaShieldInstance) {
|
|
838
|
+
let finalData = data;
|
|
839
|
+
for (let i = 0; i < schema.anyOf.length; i++) {
|
|
840
|
+
if (isObject(schema.anyOf[i])) {
|
|
841
|
+
const { validator } = schema.anyOf[i];
|
|
842
|
+
if (!validator) {
|
|
843
|
+
return { valid: true, errors: [], data };
|
|
844
|
+
}
|
|
845
|
+
const validationResult = validator(
|
|
846
|
+
schema.anyOf[i],
|
|
847
|
+
finalData,
|
|
848
|
+
pointer,
|
|
849
|
+
schemaShieldInstance
|
|
850
|
+
);
|
|
851
|
+
finalData = validationResult.data;
|
|
852
|
+
if (validationResult.valid) {
|
|
853
|
+
return { valid: true, errors: [], data: finalData };
|
|
854
|
+
}
|
|
855
|
+
} else {
|
|
856
|
+
if (typeof schema.anyOf[i] === "boolean") {
|
|
857
|
+
if (Boolean(data) === schema.anyOf[i]) {
|
|
858
|
+
return { valid: true, errors: [], data: finalData };
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
if (data === schema.anyOf[i]) {
|
|
862
|
+
return { valid: true, errors: [], data: finalData };
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
return {
|
|
867
|
+
valid: false,
|
|
868
|
+
errors: [
|
|
869
|
+
new ValidationError(`Value must match at least one schema in anyOf`, {
|
|
870
|
+
pointer,
|
|
871
|
+
value: data,
|
|
872
|
+
code: "VALUE_DOES_NOT_MATCH_ANY_OF"
|
|
873
|
+
})
|
|
874
|
+
],
|
|
875
|
+
data
|
|
876
|
+
};
|
|
877
|
+
},
|
|
878
|
+
dependencies(schema, data, pointer, schemaShieldInstance) {
|
|
879
|
+
if (!isObject(data)) {
|
|
880
|
+
return { valid: true, errors: [], data };
|
|
881
|
+
}
|
|
882
|
+
const errors = [];
|
|
883
|
+
let finalData = data;
|
|
884
|
+
for (const key in schema.dependencies) {
|
|
885
|
+
if (key in data === false) {
|
|
886
|
+
continue;
|
|
887
|
+
}
|
|
888
|
+
const dependency = schema.dependencies[key];
|
|
889
|
+
if (Array.isArray(dependency)) {
|
|
890
|
+
for (let i = 0; i < dependency.length; i++) {
|
|
891
|
+
if (!(dependency[i] in data)) {
|
|
892
|
+
errors.push(
|
|
893
|
+
new ValidationError(`Dependency ${dependency[i]} is missing`, {
|
|
894
|
+
pointer,
|
|
895
|
+
value: data,
|
|
896
|
+
code: "DEPENDENCY_MISSING"
|
|
897
|
+
})
|
|
898
|
+
);
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
continue;
|
|
902
|
+
}
|
|
903
|
+
if (typeof dependency === "boolean") {
|
|
904
|
+
if (dependency) {
|
|
905
|
+
continue;
|
|
906
|
+
}
|
|
907
|
+
errors.push(
|
|
908
|
+
new ValidationError(`Dependency ${key} is missing`, {
|
|
909
|
+
pointer,
|
|
910
|
+
value: data,
|
|
911
|
+
code: "DEPENDENCY_MISSING"
|
|
912
|
+
})
|
|
913
|
+
);
|
|
914
|
+
continue;
|
|
915
|
+
}
|
|
916
|
+
if (typeof dependency === "string") {
|
|
917
|
+
if (dependency in data) {
|
|
918
|
+
continue;
|
|
919
|
+
}
|
|
920
|
+
errors.push(
|
|
921
|
+
new ValidationError(`Dependency ${dependency} is missing`, {
|
|
922
|
+
pointer,
|
|
923
|
+
value: data,
|
|
924
|
+
code: "DEPENDENCY_MISSING"
|
|
925
|
+
})
|
|
926
|
+
);
|
|
927
|
+
continue;
|
|
928
|
+
}
|
|
929
|
+
const { validator } = dependency;
|
|
930
|
+
if (!validator) {
|
|
931
|
+
continue;
|
|
932
|
+
}
|
|
933
|
+
const validatorResult = validator(
|
|
934
|
+
dependency,
|
|
935
|
+
finalData,
|
|
936
|
+
pointer,
|
|
937
|
+
schemaShieldInstance
|
|
938
|
+
);
|
|
939
|
+
if (!validatorResult.valid) {
|
|
940
|
+
errors.push(...validatorResult.errors);
|
|
941
|
+
}
|
|
942
|
+
finalData = validatorResult.data;
|
|
943
|
+
}
|
|
944
|
+
return { valid: errors.length === 0, errors, data: finalData };
|
|
945
|
+
}
|
|
946
|
+
};
|
|
947
|
+
|
|
948
|
+
// lib/keywords/string-keywords.ts
|
|
949
|
+
var StringKeywords = {
|
|
950
|
+
minLength(schema, data, pointer) {
|
|
951
|
+
if (typeof data !== "string" || data.length >= schema.minLength) {
|
|
952
|
+
return { valid: true, errors: [], data };
|
|
953
|
+
}
|
|
954
|
+
return {
|
|
955
|
+
valid: false,
|
|
956
|
+
errors: [
|
|
957
|
+
new ValidationError("String is too short", {
|
|
958
|
+
pointer,
|
|
959
|
+
value: data,
|
|
960
|
+
code: "STRING_TOO_SHORT"
|
|
961
|
+
})
|
|
962
|
+
],
|
|
963
|
+
data
|
|
964
|
+
};
|
|
965
|
+
},
|
|
966
|
+
maxLength(schema, data, pointer) {
|
|
967
|
+
if (typeof data !== "string" || data.length <= schema.maxLength) {
|
|
968
|
+
return { valid: true, errors: [], data };
|
|
969
|
+
}
|
|
970
|
+
return {
|
|
971
|
+
valid: false,
|
|
972
|
+
errors: [
|
|
973
|
+
new ValidationError("String is too long", {
|
|
974
|
+
pointer,
|
|
975
|
+
value: data,
|
|
976
|
+
code: "STRING_TOO_LONG"
|
|
977
|
+
})
|
|
978
|
+
],
|
|
979
|
+
data
|
|
980
|
+
};
|
|
981
|
+
},
|
|
982
|
+
pattern(schema, data, pointer) {
|
|
983
|
+
if (typeof data !== "string") {
|
|
984
|
+
return { valid: true, errors: [], data };
|
|
985
|
+
}
|
|
986
|
+
const patternRegexp = typeof schema.pattern === "string" ? new RegExp(schema.pattern) : schema.pattern;
|
|
987
|
+
if (patternRegexp instanceof RegExp === false) {
|
|
988
|
+
return {
|
|
989
|
+
valid: false,
|
|
990
|
+
errors: [
|
|
991
|
+
new ValidationError("Pattern is not a valid regular expression", {
|
|
992
|
+
pointer,
|
|
993
|
+
value: data,
|
|
994
|
+
code: "PATTERN_IS_NOT_REGEXP"
|
|
995
|
+
})
|
|
996
|
+
],
|
|
997
|
+
data
|
|
998
|
+
};
|
|
999
|
+
}
|
|
1000
|
+
const valid = patternRegexp.test(data);
|
|
1001
|
+
return {
|
|
1002
|
+
valid,
|
|
1003
|
+
errors: valid ? [] : [
|
|
1004
|
+
new ValidationError("String does not match pattern", {
|
|
1005
|
+
pointer,
|
|
1006
|
+
value: data,
|
|
1007
|
+
code: "STRING_DOES_NOT_MATCH_PATTERN"
|
|
1008
|
+
})
|
|
1009
|
+
],
|
|
1010
|
+
data
|
|
1011
|
+
};
|
|
1012
|
+
},
|
|
1013
|
+
format(schema, data, pointer, formatInstance) {
|
|
1014
|
+
if (typeof data !== "string") {
|
|
1015
|
+
return { valid: true, errors: [], data };
|
|
1016
|
+
}
|
|
1017
|
+
const formatValidate = formatInstance.formats.get(schema.format);
|
|
1018
|
+
if (!formatValidate) {
|
|
1019
|
+
return {
|
|
1020
|
+
valid: false,
|
|
1021
|
+
errors: [
|
|
1022
|
+
new ValidationError(`Unknown format ${schema.format}`, {
|
|
1023
|
+
pointer,
|
|
1024
|
+
value: data,
|
|
1025
|
+
code: "UNKNOWN_FORMAT"
|
|
1026
|
+
})
|
|
1027
|
+
],
|
|
1028
|
+
data
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
1031
|
+
const valid = formatValidate(data);
|
|
1032
|
+
return {
|
|
1033
|
+
valid,
|
|
1034
|
+
errors: valid ? [] : [
|
|
1035
|
+
new ValidationError(
|
|
1036
|
+
`String does not match format ${schema.format}`,
|
|
1037
|
+
{
|
|
1038
|
+
pointer,
|
|
1039
|
+
value: data,
|
|
1040
|
+
code: "STRING_DOES_NOT_MATCH_FORMAT"
|
|
1041
|
+
}
|
|
1042
|
+
)
|
|
1043
|
+
],
|
|
1044
|
+
data
|
|
1045
|
+
};
|
|
1046
|
+
},
|
|
1047
|
+
enum(schema, data, pointer) {
|
|
1048
|
+
for (let i = 0; i < schema.enum.length; i++) {
|
|
1049
|
+
if (schema.enum[i] === data) {
|
|
1050
|
+
return { valid: true, errors: [], data };
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
if (Array.isArray(data)) {
|
|
1054
|
+
for (let i = 0; i < schema.enum.length; i++) {
|
|
1055
|
+
if (Array.isArray(schema.enum[i])) {
|
|
1056
|
+
if (deepEqual(schema.enum[i], data)) {
|
|
1057
|
+
return { valid: true, errors: [], data };
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
if (typeof data === "object" && data !== null) {
|
|
1063
|
+
for (let i = 0; i < schema.enum.length; i++) {
|
|
1064
|
+
if (typeof schema.enum[i] === "object" && schema.enum[i] !== null) {
|
|
1065
|
+
if (deepEqual(schema.enum[i], data)) {
|
|
1066
|
+
return { valid: true, errors: [], data };
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
return {
|
|
1072
|
+
valid: false,
|
|
1073
|
+
errors: [
|
|
1074
|
+
new ValidationError(`Value must be one of ${schema.enum.join(", ")}`, {
|
|
1075
|
+
pointer,
|
|
1076
|
+
value: data,
|
|
1077
|
+
code: "VALUE_NOT_IN_ENUM"
|
|
1078
|
+
})
|
|
1079
|
+
],
|
|
1080
|
+
data
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1083
|
+
};
|
|
1084
|
+
|
|
1085
|
+
// lib/keywords.ts
|
|
1086
|
+
var keywords = {
|
|
1087
|
+
...ObjectKeywords,
|
|
1088
|
+
...ArrayKeywords,
|
|
1089
|
+
...StringKeywords,
|
|
1090
|
+
...NumberKeywords,
|
|
1091
|
+
...OtherKeywords
|
|
1092
|
+
};
|
|
1093
|
+
|
|
1094
|
+
// lib/index.ts
|
|
1095
|
+
var SchemaShield = class {
|
|
1096
|
+
types = /* @__PURE__ */ new Map();
|
|
1097
|
+
formats = /* @__PURE__ */ new Map();
|
|
1098
|
+
keywords = /* @__PURE__ */ new Map();
|
|
1099
|
+
constructor() {
|
|
1100
|
+
for (const type in Types) {
|
|
1101
|
+
this.addType(type, Types[type]);
|
|
1102
|
+
}
|
|
1103
|
+
for (const keyword in keywords) {
|
|
1104
|
+
this.addKeyword(keyword, keywords[keyword]);
|
|
1105
|
+
}
|
|
1106
|
+
for (const format in Formats) {
|
|
1107
|
+
this.addFormat(format, Formats[format]);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
addType(name, validator) {
|
|
1111
|
+
this.types.set(name, validator);
|
|
1112
|
+
}
|
|
1113
|
+
addFormat(name, validator) {
|
|
1114
|
+
this.formats.set(name, validator);
|
|
1115
|
+
}
|
|
1116
|
+
addKeyword(name, validator) {
|
|
1117
|
+
this.keywords.set(name, validator);
|
|
1118
|
+
}
|
|
1119
|
+
compile(schema) {
|
|
1120
|
+
const compiledSchema = this.compileSchema(schema, "#");
|
|
1121
|
+
const schemaShield = this;
|
|
1122
|
+
function validate(data) {
|
|
1123
|
+
return compiledSchema.validator(compiledSchema, data, "#", schemaShield);
|
|
1124
|
+
}
|
|
1125
|
+
validate.compiledSchema = compiledSchema;
|
|
1126
|
+
return validate;
|
|
1127
|
+
}
|
|
1128
|
+
compileSchema(schema, pointer) {
|
|
1129
|
+
if (typeof schema !== "object" || schema === null) {
|
|
1130
|
+
throw new ValidationError("Schema is not an object", {
|
|
1131
|
+
pointer,
|
|
1132
|
+
value: schema,
|
|
1133
|
+
code: "SCHEMA_NOT_OBJECT"
|
|
1134
|
+
});
|
|
1135
|
+
}
|
|
1136
|
+
const compiledSchema = {
|
|
1137
|
+
...schema,
|
|
1138
|
+
pointer
|
|
1139
|
+
};
|
|
1140
|
+
if ("type" in compiledSchema) {
|
|
1141
|
+
const types = Array.isArray(compiledSchema.type) ? compiledSchema.type : compiledSchema.type.split(",").map((t) => t.trim());
|
|
1142
|
+
compiledSchema.validators = types.filter((type) => this.types.has(type)).map((type) => this.types.get(type));
|
|
1143
|
+
}
|
|
1144
|
+
const validator = (schema2, data, pointer2) => {
|
|
1145
|
+
if (typeof data === "undefined") {
|
|
1146
|
+
if (pointer2 === "#") {
|
|
1147
|
+
return {
|
|
1148
|
+
valid: false,
|
|
1149
|
+
errors: [
|
|
1150
|
+
new ValidationError("Data is undefined", {
|
|
1151
|
+
pointer: pointer2,
|
|
1152
|
+
value: data,
|
|
1153
|
+
code: "DATA_UNDEFINED"
|
|
1154
|
+
})
|
|
1155
|
+
],
|
|
1156
|
+
data
|
|
1157
|
+
};
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
let finalData = data;
|
|
1161
|
+
const typeErrorsResult = this.validateTypes(schema2, finalData, pointer2);
|
|
1162
|
+
if (typeErrorsResult.valid === false) {
|
|
1163
|
+
return typeErrorsResult;
|
|
1164
|
+
}
|
|
1165
|
+
finalData = typeErrorsResult.data;
|
|
1166
|
+
return this.validateKeywords(schema2, finalData, pointer2);
|
|
1167
|
+
};
|
|
1168
|
+
compiledSchema.validator = validator;
|
|
1169
|
+
for (let key in schema) {
|
|
1170
|
+
if (key === "type") {
|
|
1171
|
+
continue;
|
|
1172
|
+
}
|
|
1173
|
+
if (this.keywords.has(key)) {
|
|
1174
|
+
const validator2 = this.keywords.get(key);
|
|
1175
|
+
compiledSchema.keywords = compiledSchema.keywords || {};
|
|
1176
|
+
compiledSchema.keywords[key] = validator2;
|
|
1177
|
+
}
|
|
1178
|
+
if (Array.isArray(schema[key])) {
|
|
1179
|
+
this.handleArraySchema(key, schema, pointer, compiledSchema);
|
|
1180
|
+
continue;
|
|
1181
|
+
}
|
|
1182
|
+
if (isObject(schema[key])) {
|
|
1183
|
+
this.handleObjectSchema(key, schema, pointer, compiledSchema);
|
|
1184
|
+
continue;
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
return compiledSchema;
|
|
1188
|
+
}
|
|
1189
|
+
handleArraySchema(key, schema, pointer, compiledSchema) {
|
|
1190
|
+
compiledSchema[key] = schema[key].map((subSchema, index) => {
|
|
1191
|
+
if (typeof subSchema === "object" && subSchema !== null) {
|
|
1192
|
+
if ("type" in subSchema) {
|
|
1193
|
+
return this.compileSchema(subSchema, `${pointer}/${key}/${index}`);
|
|
1194
|
+
}
|
|
1195
|
+
for (let subKey in subSchema) {
|
|
1196
|
+
if (this.keywords.has(subKey)) {
|
|
1197
|
+
return this.compileSchema(subSchema, `${pointer}/${key}/${index}`);
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
return subSchema;
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
handleObjectSchema(key, schema, pointer, compiledSchema) {
|
|
1205
|
+
if ("type" in schema[key]) {
|
|
1206
|
+
compiledSchema[key] = this.compileSchema(
|
|
1207
|
+
schema[key],
|
|
1208
|
+
`${pointer}/${key}`
|
|
1209
|
+
);
|
|
1210
|
+
return;
|
|
1211
|
+
}
|
|
1212
|
+
for (let subKey in schema[key]) {
|
|
1213
|
+
compiledSchema[key] = compiledSchema[key] || {};
|
|
1214
|
+
if (this.keywords.has(subKey)) {
|
|
1215
|
+
compiledSchema[key][subKey] = this.compileSchema(
|
|
1216
|
+
schema[key][subKey],
|
|
1217
|
+
`${pointer}/${subKey}`
|
|
1218
|
+
);
|
|
1219
|
+
continue;
|
|
1220
|
+
}
|
|
1221
|
+
if (typeof schema[key][subKey] === "object") {
|
|
1222
|
+
if ("type" in schema[key][subKey]) {
|
|
1223
|
+
compiledSchema[key][subKey] = this.compileSchema(
|
|
1224
|
+
schema[key][subKey],
|
|
1225
|
+
`${pointer}/${key}/${subKey}`
|
|
1226
|
+
);
|
|
1227
|
+
continue;
|
|
1228
|
+
}
|
|
1229
|
+
for (let subSubKey in schema[key][subKey]) {
|
|
1230
|
+
if (this.keywords.has(subSubKey)) {
|
|
1231
|
+
compiledSchema[key][subKey] = this.compileSchema(
|
|
1232
|
+
schema[key][subKey],
|
|
1233
|
+
`${pointer}/${key}/${subKey}`
|
|
1234
|
+
);
|
|
1235
|
+
continue;
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
validateTypes(schema, data, pointer) {
|
|
1242
|
+
if (typeof data === "undefined" || !Array.isArray(schema.validators) || schema.validators.length === 0) {
|
|
1243
|
+
return {
|
|
1244
|
+
valid: true,
|
|
1245
|
+
errors: [],
|
|
1246
|
+
data
|
|
1247
|
+
};
|
|
1248
|
+
}
|
|
1249
|
+
let errors = [];
|
|
1250
|
+
let finalData = data;
|
|
1251
|
+
for (let schemaValidator of schema.validators) {
|
|
1252
|
+
const schemaResult = schemaValidator(schema, data, pointer, this);
|
|
1253
|
+
finalData = schemaResult.data;
|
|
1254
|
+
if (schemaResult.valid) {
|
|
1255
|
+
return schemaResult;
|
|
1256
|
+
}
|
|
1257
|
+
errors = schemaResult.errors;
|
|
1258
|
+
}
|
|
1259
|
+
return {
|
|
1260
|
+
valid: errors.length === 0,
|
|
1261
|
+
errors,
|
|
1262
|
+
data: finalData
|
|
1263
|
+
};
|
|
1264
|
+
}
|
|
1265
|
+
validateKeywords(schema, data, pointer) {
|
|
1266
|
+
const errors = [];
|
|
1267
|
+
let finalData = data;
|
|
1268
|
+
if ("keywords" in schema) {
|
|
1269
|
+
for (let keyword in schema.keywords) {
|
|
1270
|
+
const keywordValidator = schema.keywords[keyword];
|
|
1271
|
+
const keywordResult = keywordValidator(
|
|
1272
|
+
schema,
|
|
1273
|
+
finalData,
|
|
1274
|
+
pointer,
|
|
1275
|
+
this
|
|
1276
|
+
);
|
|
1277
|
+
finalData = keywordResult.data;
|
|
1278
|
+
if (!keywordResult.valid) {
|
|
1279
|
+
errors.push(...keywordResult.errors);
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
return {
|
|
1284
|
+
valid: errors.length === 0,
|
|
1285
|
+
errors,
|
|
1286
|
+
data: finalData
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
1289
|
+
};
|