schema-shield 1.0.5 → 1.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.
- package/README.md +400 -1050
- package/dist/formats.d.ts.map +1 -1
- package/dist/index.d.ts +33 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1247 -392
- package/dist/index.min.js +2 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.mjs +1247 -392
- package/dist/keywords/array-keywords.d.ts.map +1 -1
- package/dist/keywords/number-keywords.d.ts.map +1 -1
- package/dist/keywords/object-keywords.d.ts +7 -1
- package/dist/keywords/object-keywords.d.ts.map +1 -1
- package/dist/keywords/other-keywords.d.ts +17 -1
- package/dist/keywords/other-keywords.d.ts.map +1 -1
- package/dist/keywords/string-keywords.d.ts.map +1 -1
- package/dist/utils/deep-freeze.d.ts.map +1 -1
- package/dist/utils/main-utils.d.ts +7 -4
- package/dist/utils/main-utils.d.ts.map +1 -1
- package/lib/formats.ts +36 -10
- package/lib/index.ts +1157 -155
- package/lib/keywords/array-keywords.ts +18 -3
- package/lib/keywords/number-keywords.ts +19 -5
- package/lib/keywords/object-keywords.ts +59 -61
- package/lib/keywords/other-keywords.ts +205 -192
- package/lib/keywords/string-keywords.ts +51 -8
- package/lib/types.ts +2 -2
- package/lib/utils/deep-freeze.ts +6 -4
- package/lib/utils/main-utils.ts +91 -47
- package/package.json +8 -10
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
// lib/utils/main-utils.ts
|
|
2
|
+
var hasOwnPropertyIntrinsic = Object.prototype.hasOwnProperty;
|
|
3
|
+
var hasOwnPropertyCall = Function.prototype.call.bind(
|
|
4
|
+
hasOwnPropertyIntrinsic
|
|
5
|
+
);
|
|
6
|
+
function definePropertyOrThrow(target, key, descriptor) {
|
|
7
|
+
if (!Reflect.defineProperty(target, key, descriptor)) {
|
|
8
|
+
throw new TypeError(`Cannot define property "${String(key)}"`);
|
|
9
|
+
}
|
|
10
|
+
return target;
|
|
11
|
+
}
|
|
12
|
+
function hasOwn(target, key) {
|
|
13
|
+
return hasOwnPropertyCall(target, key);
|
|
14
|
+
}
|
|
2
15
|
var ValidationError = class extends Error {
|
|
16
|
+
code;
|
|
3
17
|
message;
|
|
4
18
|
item;
|
|
5
19
|
keyword;
|
|
@@ -12,42 +26,57 @@ var ValidationError = class extends Error {
|
|
|
12
26
|
super(message);
|
|
13
27
|
this.message = message;
|
|
14
28
|
}
|
|
15
|
-
_getCause(pointer = "#", instancePointer = "#") {
|
|
16
|
-
let schemaPath = `${pointer}/${this.keyword}`;
|
|
17
|
-
let instancePath = `${instancePointer}`;
|
|
18
|
-
if (typeof this.item !== "undefined") {
|
|
19
|
-
if (typeof this.item === "string" && this.schema && typeof this.schema === "object" && this.item in this.schema) {
|
|
20
|
-
schemaPath += `/${this.item}`;
|
|
21
|
-
}
|
|
22
|
-
instancePath += `/${this.item}`;
|
|
23
|
-
}
|
|
24
|
-
this.instancePath = instancePath;
|
|
25
|
-
this.schemaPath = schemaPath;
|
|
26
|
-
if (!this.cause || !(this.cause instanceof ValidationError)) {
|
|
27
|
-
return this;
|
|
28
|
-
}
|
|
29
|
-
return this.cause._getCause(schemaPath, instancePath);
|
|
30
|
-
}
|
|
31
29
|
getCause() {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
30
|
+
let current = this;
|
|
31
|
+
let schemaPointer = "#";
|
|
32
|
+
let instancePointer = "#";
|
|
33
|
+
const seen = /* @__PURE__ */ new Set();
|
|
34
|
+
while (!seen.has(current)) {
|
|
35
|
+
seen.add(current);
|
|
36
|
+
let schemaPath = `${schemaPointer}/${current.keyword}`;
|
|
37
|
+
let instancePath = instancePointer;
|
|
38
|
+
if (typeof current.item !== "undefined") {
|
|
39
|
+
if (typeof current.item === "string" && current.schema && typeof current.schema === "object" && current.item in current.schema) {
|
|
40
|
+
schemaPath += `/${escapeJsonPointerToken(current.item)}`;
|
|
41
|
+
}
|
|
42
|
+
instancePath += `/${escapeJsonPointerToken(current.item)}`;
|
|
43
|
+
}
|
|
44
|
+
current.schemaPath = schemaPath;
|
|
45
|
+
current.instancePath = instancePath;
|
|
46
|
+
if (!(current.cause instanceof ValidationError) || seen.has(current.cause)) {
|
|
47
|
+
return current;
|
|
48
|
+
}
|
|
49
|
+
schemaPointer = schemaPath;
|
|
50
|
+
instancePointer = instancePath;
|
|
51
|
+
current = current.cause;
|
|
45
52
|
}
|
|
46
|
-
return
|
|
53
|
+
return current;
|
|
47
54
|
}
|
|
48
55
|
getTree() {
|
|
49
56
|
this.getCause();
|
|
50
|
-
|
|
57
|
+
let current = this;
|
|
58
|
+
let root;
|
|
59
|
+
let target;
|
|
60
|
+
const seen = /* @__PURE__ */ new Set();
|
|
61
|
+
while (current && !seen.has(current)) {
|
|
62
|
+
seen.add(current);
|
|
63
|
+
const node = {
|
|
64
|
+
message: current.message,
|
|
65
|
+
keyword: current.keyword,
|
|
66
|
+
item: current.item,
|
|
67
|
+
schemaPath: current.schemaPath,
|
|
68
|
+
instancePath: current.instancePath,
|
|
69
|
+
data: current.data
|
|
70
|
+
};
|
|
71
|
+
if (!root) {
|
|
72
|
+
root = node;
|
|
73
|
+
} else if (target) {
|
|
74
|
+
target.cause = node;
|
|
75
|
+
}
|
|
76
|
+
target = node;
|
|
77
|
+
current = current.cause instanceof ValidationError ? current.cause : void 0;
|
|
78
|
+
}
|
|
79
|
+
return root;
|
|
51
80
|
}
|
|
52
81
|
getPath() {
|
|
53
82
|
const cause = this.getCause();
|
|
@@ -67,8 +96,11 @@ function getDefinedErrorFunctionForKey(key, schema, failFast) {
|
|
|
67
96
|
KeywordError.schema = schema;
|
|
68
97
|
const defineError = (message, options = {}) => {
|
|
69
98
|
KeywordError.message = message;
|
|
99
|
+
KeywordError.code = options.code;
|
|
70
100
|
KeywordError.item = options.item;
|
|
71
|
-
|
|
101
|
+
if (options.cause !== KeywordError) {
|
|
102
|
+
KeywordError.cause = options.cause && options.cause !== true ? options.cause : void 0;
|
|
103
|
+
}
|
|
72
104
|
KeywordError.data = options.data;
|
|
73
105
|
return KeywordError;
|
|
74
106
|
};
|
|
@@ -77,11 +109,14 @@ function getDefinedErrorFunctionForKey(key, schema, failFast) {
|
|
|
77
109
|
defineError
|
|
78
110
|
);
|
|
79
111
|
}
|
|
112
|
+
function escapeJsonPointerToken(value) {
|
|
113
|
+
return String(value).replace(/~/g, "~0").replace(/\//g, "~1");
|
|
114
|
+
}
|
|
80
115
|
function isCompiledSchema(subSchema) {
|
|
81
116
|
return !!subSchema && typeof subSchema === "object" && !Array.isArray(subSchema) && "$validate" in subSchema;
|
|
82
117
|
}
|
|
83
118
|
function getNamedFunction(name, fn) {
|
|
84
|
-
return
|
|
119
|
+
return definePropertyOrThrow(fn, "name", { value: name });
|
|
85
120
|
}
|
|
86
121
|
function resolvePath(root, path) {
|
|
87
122
|
if (!path || path === "#") {
|
|
@@ -126,7 +161,6 @@ var DURATION_REGEX = /^P(?!$)((\d+Y)?(\d+M)?(\d+W)?(\d+D)?)(T(?=\d)(\d+H)?(\d+M)
|
|
|
126
161
|
var URI_REGEX = /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/;
|
|
127
162
|
var EMAIL_REGEX = /^(?!\.)(?!.*\.$)[a-z0-9!#$%&'*+/=?^_`{|}~-]{1,20}(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]{1,21}){0,2}@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,60}[a-z0-9])?){0,3}$/i;
|
|
128
163
|
var HOSTNAME_REGEX = /^[a-z0-9][a-z0-9-]{0,62}(?:\.[a-z0-9][a-z0-9-]{0,62})*[a-z0-9]$/i;
|
|
129
|
-
var DATE_REGEX = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
130
164
|
var TIME_REGEX = /^([01]\d|2[0-3]):([0-5]\d):([0-5]\d)(\.\d+)?(Z|([+-])([01]\d|2[0-3]):([0-5]\d))$/;
|
|
131
165
|
var URI_REFERENCE_REGEX = /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#((?![^#]*\\)[^#]*))?/i;
|
|
132
166
|
var IRI_REGEX = /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/;
|
|
@@ -191,6 +225,22 @@ function isValidIpv4(data) {
|
|
|
191
225
|
function isHexCharCode(code) {
|
|
192
226
|
return code >= 48 && code <= 57 || code >= 65 && code <= 70 || code >= 97 && code <= 102;
|
|
193
227
|
}
|
|
228
|
+
function hasValidPercentEncoding(data) {
|
|
229
|
+
for (let index = 0; index < data.length; index++) {
|
|
230
|
+
const code = data.charCodeAt(index);
|
|
231
|
+
if (code === 92) {
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
if (code !== 37) {
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
if (index + 2 >= data.length || !isHexCharCode(data.charCodeAt(index + 1)) || !isHexCharCode(data.charCodeAt(index + 2))) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
index += 2;
|
|
241
|
+
}
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
194
244
|
function isValidIpv6(data) {
|
|
195
245
|
const length = data.length;
|
|
196
246
|
if (length === 0) {
|
|
@@ -295,7 +345,7 @@ function isValidJsonPointer(data) {
|
|
|
295
345
|
}
|
|
296
346
|
function isValidRelativeJsonPointer(data) {
|
|
297
347
|
if (data.length === 0) {
|
|
298
|
-
return
|
|
348
|
+
return false;
|
|
299
349
|
}
|
|
300
350
|
let i = 0;
|
|
301
351
|
while (i < data.length) {
|
|
@@ -308,6 +358,9 @@ function isValidRelativeJsonPointer(data) {
|
|
|
308
358
|
if (i === 0) {
|
|
309
359
|
return false;
|
|
310
360
|
}
|
|
361
|
+
if (i > 1 && data.charCodeAt(0) === 48) {
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
311
364
|
if (i === data.length) {
|
|
312
365
|
return true;
|
|
313
366
|
}
|
|
@@ -434,7 +487,7 @@ var Formats = {
|
|
|
434
487
|
return true;
|
|
435
488
|
},
|
|
436
489
|
uri(data) {
|
|
437
|
-
return URI_REGEX.test(data);
|
|
490
|
+
return URI_REGEX.test(data) && hasValidPercentEncoding(data);
|
|
438
491
|
},
|
|
439
492
|
email(data) {
|
|
440
493
|
return EMAIL_REGEX.test(data);
|
|
@@ -449,15 +502,13 @@ var Formats = {
|
|
|
449
502
|
return HOSTNAME_REGEX.test(data);
|
|
450
503
|
},
|
|
451
504
|
date(data) {
|
|
452
|
-
|
|
453
|
-
if (!match) {
|
|
505
|
+
if (data.length !== 10 || data.charCodeAt(4) !== 45 || data.charCodeAt(7) !== 45) {
|
|
454
506
|
return false;
|
|
455
507
|
}
|
|
456
|
-
const
|
|
457
|
-
const
|
|
458
|
-
const
|
|
459
|
-
|
|
460
|
-
if (month < 1 || month > 12) {
|
|
508
|
+
const year = parseFourDigits(data, 0);
|
|
509
|
+
const month = parseTwoDigits(data, 5);
|
|
510
|
+
const day = parseTwoDigits(data, 8);
|
|
511
|
+
if (year < 0 || month < 1 || month > 12) {
|
|
461
512
|
return false;
|
|
462
513
|
}
|
|
463
514
|
if (day < 1) {
|
|
@@ -529,10 +580,10 @@ var Types = {
|
|
|
529
580
|
return typeof data === "string";
|
|
530
581
|
},
|
|
531
582
|
number(data) {
|
|
532
|
-
return typeof data === "number";
|
|
583
|
+
return typeof data === "number" && Number.isFinite(data);
|
|
533
584
|
},
|
|
534
585
|
integer(data) {
|
|
535
|
-
return typeof data === "number" && data % 1 === 0;
|
|
586
|
+
return typeof data === "number" && Number.isFinite(data) && data % 1 === 0;
|
|
536
587
|
},
|
|
537
588
|
boolean(data) {
|
|
538
589
|
return typeof data === "boolean";
|
|
@@ -757,7 +808,7 @@ var ArrayKeywords = {
|
|
|
757
808
|
let tupleLength = schema._tupleItemsLength;
|
|
758
809
|
if (tupleLength === void 0) {
|
|
759
810
|
tupleLength = schema.items.length;
|
|
760
|
-
|
|
811
|
+
definePropertyOrThrow(schema, "_tupleItemsLength", {
|
|
761
812
|
value: tupleLength,
|
|
762
813
|
enumerable: false,
|
|
763
814
|
configurable: false,
|
|
@@ -814,13 +865,23 @@ var ArrayKeywords = {
|
|
|
814
865
|
}
|
|
815
866
|
return;
|
|
816
867
|
}
|
|
817
|
-
|
|
868
|
+
let hasFirstPrimitive = false;
|
|
869
|
+
let firstPrimitive;
|
|
870
|
+
let primitiveSeen;
|
|
818
871
|
let primitiveArraySignatures;
|
|
819
872
|
let arrayBuckets;
|
|
820
873
|
let objectBuckets;
|
|
821
874
|
for (let i = 0; i < len; i++) {
|
|
822
875
|
const item = data[i];
|
|
823
876
|
if (isUniquePrimitive(item)) {
|
|
877
|
+
if (!hasFirstPrimitive) {
|
|
878
|
+
hasFirstPrimitive = true;
|
|
879
|
+
firstPrimitive = item;
|
|
880
|
+
continue;
|
|
881
|
+
}
|
|
882
|
+
if (!primitiveSeen) {
|
|
883
|
+
primitiveSeen = /* @__PURE__ */ new Set([firstPrimitive]);
|
|
884
|
+
}
|
|
824
885
|
if (primitiveSeen.has(item)) {
|
|
825
886
|
return defineError("Array items are not unique", { data: item });
|
|
826
887
|
}
|
|
@@ -906,7 +967,7 @@ function isPlainObject(value) {
|
|
|
906
967
|
if (!value || typeof value !== "object") {
|
|
907
968
|
return false;
|
|
908
969
|
}
|
|
909
|
-
const proto =
|
|
970
|
+
const proto = Reflect.getPrototypeOf(value);
|
|
910
971
|
return proto === Object.prototype || proto === null;
|
|
911
972
|
}
|
|
912
973
|
function canUseStructuredClone(value) {
|
|
@@ -1001,7 +1062,7 @@ function deepCloneUnfreeze(obj, cloneClassInstances = false, seen = /* @__PURE__
|
|
|
1001
1062
|
seen.set(source, clone);
|
|
1002
1063
|
return clone;
|
|
1003
1064
|
}
|
|
1004
|
-
clone = Object.create(
|
|
1065
|
+
clone = Object.create(Reflect.getPrototypeOf(source));
|
|
1005
1066
|
seen.set(source, clone);
|
|
1006
1067
|
break;
|
|
1007
1068
|
}
|
|
@@ -1030,7 +1091,7 @@ function deepCloneUnfreeze(obj, cloneClassInstances = false, seen = /* @__PURE__
|
|
|
1030
1091
|
seen
|
|
1031
1092
|
);
|
|
1032
1093
|
}
|
|
1033
|
-
|
|
1094
|
+
definePropertyOrThrow(clone, key, descriptor);
|
|
1034
1095
|
}
|
|
1035
1096
|
return clone;
|
|
1036
1097
|
}
|
|
@@ -1041,6 +1102,9 @@ var NumberKeywords = {
|
|
|
1041
1102
|
if (typeof data !== "number") {
|
|
1042
1103
|
return;
|
|
1043
1104
|
}
|
|
1105
|
+
if (!Number.isFinite(data)) {
|
|
1106
|
+
return defineError("Value must be finite", { data });
|
|
1107
|
+
}
|
|
1044
1108
|
let min = schema.minimum;
|
|
1045
1109
|
if (typeof schema.exclusiveMinimum === "number") {
|
|
1046
1110
|
min = schema.exclusiveMinimum + 1e-15;
|
|
@@ -1056,6 +1120,9 @@ var NumberKeywords = {
|
|
|
1056
1120
|
if (typeof data !== "number") {
|
|
1057
1121
|
return;
|
|
1058
1122
|
}
|
|
1123
|
+
if (!Number.isFinite(data)) {
|
|
1124
|
+
return defineError("Value must be finite", { data });
|
|
1125
|
+
}
|
|
1059
1126
|
let max = schema.maximum;
|
|
1060
1127
|
if (typeof schema.exclusiveMaximum === "number") {
|
|
1061
1128
|
max = schema.exclusiveMaximum - 1e-15;
|
|
@@ -1071,11 +1138,14 @@ var NumberKeywords = {
|
|
|
1071
1138
|
if (typeof data !== "number") {
|
|
1072
1139
|
return;
|
|
1073
1140
|
}
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1141
|
+
if (!Number.isFinite(data) || !Number.isFinite(schema.multipleOf) || schema.multipleOf <= 0) {
|
|
1142
|
+
return defineError("Value must use a finite positive multipleOf", {
|
|
1143
|
+
data
|
|
1144
|
+
});
|
|
1077
1145
|
}
|
|
1078
|
-
|
|
1146
|
+
const quotient = data / schema.multipleOf;
|
|
1147
|
+
const valid = Number.isFinite(quotient) ? areCloseEnough(quotient, Math.round(quotient)) : data % schema.multipleOf === 0;
|
|
1148
|
+
if (!valid) {
|
|
1079
1149
|
return defineError("Value is not a multiple of the multipleOf", { data });
|
|
1080
1150
|
}
|
|
1081
1151
|
return;
|
|
@@ -1164,6 +1234,29 @@ function compilePatternMatcher(pattern) {
|
|
|
1164
1234
|
|
|
1165
1235
|
// lib/keywords/object-keywords.ts
|
|
1166
1236
|
var PATTERN_KEY_CACHE_LIMIT = 512;
|
|
1237
|
+
function createApplyPropertyDefaults(replaceEmpty) {
|
|
1238
|
+
return function applyPropertyDefaults2(schema, data, instance) {
|
|
1239
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
1240
|
+
return;
|
|
1241
|
+
}
|
|
1242
|
+
const defaultKeys = schema._defaultKeys;
|
|
1243
|
+
for (let i = 0; i < defaultKeys.length; i++) {
|
|
1244
|
+
const key = defaultKeys[i];
|
|
1245
|
+
const hasOwnValue = hasOwn(data, key);
|
|
1246
|
+
const value = hasOwnValue ? data[key] : void 0;
|
|
1247
|
+
if (hasOwnValue && value !== void 0 && (!replaceEmpty || value !== null && value !== "")) {
|
|
1248
|
+
continue;
|
|
1249
|
+
}
|
|
1250
|
+
instance.setDefault(
|
|
1251
|
+
data,
|
|
1252
|
+
key,
|
|
1253
|
+
deepCloneUnfreeze(schema.properties[key].default)
|
|
1254
|
+
);
|
|
1255
|
+
}
|
|
1256
|
+
};
|
|
1257
|
+
}
|
|
1258
|
+
var applyPropertyDefaults = createApplyPropertyDefaults(false);
|
|
1259
|
+
var applyEmptyPropertyDefaults = createApplyPropertyDefaults(true);
|
|
1167
1260
|
function getPatternPropertyEntries(schema) {
|
|
1168
1261
|
let entries = schema._patternPropertyEntries;
|
|
1169
1262
|
if (entries) {
|
|
@@ -1183,7 +1276,7 @@ function getPatternPropertyEntries(schema) {
|
|
|
1183
1276
|
match
|
|
1184
1277
|
};
|
|
1185
1278
|
}
|
|
1186
|
-
|
|
1279
|
+
definePropertyOrThrow(schema, "_patternPropertyEntries", {
|
|
1187
1280
|
value: entries,
|
|
1188
1281
|
enumerable: false,
|
|
1189
1282
|
configurable: false,
|
|
@@ -1200,7 +1293,7 @@ function getPatternKeyMatchIndexes(schema, key, entries) {
|
|
|
1200
1293
|
}
|
|
1201
1294
|
} else {
|
|
1202
1295
|
cache = /* @__PURE__ */ new Map();
|
|
1203
|
-
|
|
1296
|
+
definePropertyOrThrow(schema, "_patternKeyMatchIndexCache", {
|
|
1204
1297
|
value: cache,
|
|
1205
1298
|
enumerable: false,
|
|
1206
1299
|
configurable: false,
|
|
@@ -1225,7 +1318,7 @@ var ObjectKeywords = {
|
|
|
1225
1318
|
}
|
|
1226
1319
|
for (let i = 0; i < schema.required.length; i++) {
|
|
1227
1320
|
const key = schema.required[i];
|
|
1228
|
-
if (!
|
|
1321
|
+
if (!hasOwn(data, key)) {
|
|
1229
1322
|
return defineError("Required property is missing", {
|
|
1230
1323
|
item: key,
|
|
1231
1324
|
data: data[key]
|
|
@@ -1234,45 +1327,15 @@ var ObjectKeywords = {
|
|
|
1234
1327
|
}
|
|
1235
1328
|
return;
|
|
1236
1329
|
},
|
|
1237
|
-
properties(schema, data, defineError) {
|
|
1330
|
+
properties(schema, data, defineError, instance) {
|
|
1238
1331
|
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
1239
1332
|
return;
|
|
1240
1333
|
}
|
|
1241
|
-
|
|
1242
|
-
if (!propKeys) {
|
|
1243
|
-
propKeys = Object.keys(schema.properties || {});
|
|
1244
|
-
Object.defineProperty(schema, "_propKeys", {
|
|
1245
|
-
value: propKeys,
|
|
1246
|
-
enumerable: false,
|
|
1247
|
-
configurable: false,
|
|
1248
|
-
writable: false
|
|
1249
|
-
});
|
|
1250
|
-
}
|
|
1251
|
-
let requiredSet = schema._requiredSet;
|
|
1252
|
-
if (requiredSet === void 0) {
|
|
1253
|
-
requiredSet = Array.isArray(schema.required) ? new Set(schema.required) : null;
|
|
1254
|
-
Object.defineProperty(schema, "_requiredSet", {
|
|
1255
|
-
value: requiredSet,
|
|
1256
|
-
enumerable: false,
|
|
1257
|
-
configurable: false,
|
|
1258
|
-
writable: false
|
|
1259
|
-
});
|
|
1260
|
-
}
|
|
1334
|
+
const propKeys = schema._propKeys;
|
|
1261
1335
|
for (let i = 0; i < propKeys.length; i++) {
|
|
1262
1336
|
const key = propKeys[i];
|
|
1263
1337
|
const schemaProp = schema.properties[key];
|
|
1264
|
-
if (!
|
|
1265
|
-
if (requiredSet && requiredSet.has(key) && schemaProp && typeof schemaProp === "object" && !Array.isArray(schemaProp) && "default" in schemaProp) {
|
|
1266
|
-
const error = schemaProp.$validate(schemaProp.default);
|
|
1267
|
-
if (error) {
|
|
1268
|
-
return defineError("Default property is invalid", {
|
|
1269
|
-
item: key,
|
|
1270
|
-
cause: error,
|
|
1271
|
-
data: schemaProp.default
|
|
1272
|
-
});
|
|
1273
|
-
}
|
|
1274
|
-
data[key] = deepCloneUnfreeze(schemaProp.default);
|
|
1275
|
-
}
|
|
1338
|
+
if (!hasOwn(data, key)) {
|
|
1276
1339
|
continue;
|
|
1277
1340
|
}
|
|
1278
1341
|
if (typeof schemaProp === "boolean") {
|
|
@@ -1307,7 +1370,7 @@ var ObjectKeywords = {
|
|
|
1307
1370
|
return;
|
|
1308
1371
|
}
|
|
1309
1372
|
for (const key in data) {
|
|
1310
|
-
if (!
|
|
1373
|
+
if (!hasOwn(data, key)) {
|
|
1311
1374
|
continue;
|
|
1312
1375
|
}
|
|
1313
1376
|
const error = validate(data[key]);
|
|
@@ -1326,7 +1389,7 @@ var ObjectKeywords = {
|
|
|
1326
1389
|
}
|
|
1327
1390
|
let count = 0;
|
|
1328
1391
|
for (const key in data) {
|
|
1329
|
-
if (!
|
|
1392
|
+
if (!hasOwn(data, key)) {
|
|
1330
1393
|
continue;
|
|
1331
1394
|
}
|
|
1332
1395
|
count++;
|
|
@@ -1342,7 +1405,7 @@ var ObjectKeywords = {
|
|
|
1342
1405
|
}
|
|
1343
1406
|
let count = 0;
|
|
1344
1407
|
for (const key in data) {
|
|
1345
|
-
if (!
|
|
1408
|
+
if (!hasOwn(data, key)) {
|
|
1346
1409
|
continue;
|
|
1347
1410
|
}
|
|
1348
1411
|
count++;
|
|
@@ -1359,7 +1422,7 @@ var ObjectKeywords = {
|
|
|
1359
1422
|
let apValidate = schema._apValidate;
|
|
1360
1423
|
if (apValidate === void 0) {
|
|
1361
1424
|
apValidate = isCompiledSchema(schema.additionalProperties) ? schema.additionalProperties.$validate : null;
|
|
1362
|
-
|
|
1425
|
+
definePropertyOrThrow(schema, "_apValidate", {
|
|
1363
1426
|
value: apValidate,
|
|
1364
1427
|
enumerable: false,
|
|
1365
1428
|
configurable: false,
|
|
@@ -1368,10 +1431,10 @@ var ObjectKeywords = {
|
|
|
1368
1431
|
}
|
|
1369
1432
|
const patternEntries = getPatternPropertyEntries(schema);
|
|
1370
1433
|
for (const key in data) {
|
|
1371
|
-
if (!
|
|
1434
|
+
if (!hasOwn(data, key)) {
|
|
1372
1435
|
continue;
|
|
1373
1436
|
}
|
|
1374
|
-
if (schema.properties &&
|
|
1437
|
+
if (schema.properties && hasOwn(schema.properties, key)) {
|
|
1375
1438
|
continue;
|
|
1376
1439
|
}
|
|
1377
1440
|
if (patternEntries && patternEntries.length) {
|
|
@@ -1407,12 +1470,12 @@ var ObjectKeywords = {
|
|
|
1407
1470
|
return;
|
|
1408
1471
|
}
|
|
1409
1472
|
for (const key in data) {
|
|
1410
|
-
if (!
|
|
1473
|
+
if (!hasOwn(data, key)) {
|
|
1411
1474
|
continue;
|
|
1412
1475
|
}
|
|
1413
1476
|
const matchingIndexes = getPatternKeyMatchIndexes(schema, key, patternEntries);
|
|
1414
1477
|
if (matchingIndexes.length === 0) {
|
|
1415
|
-
if (schema.additionalProperties === false && !(schema.properties &&
|
|
1478
|
+
if (schema.additionalProperties === false && !(schema.properties && hasOwn(schema.properties, key))) {
|
|
1416
1479
|
return defineError("Additional properties are not allowed", {
|
|
1417
1480
|
item: key,
|
|
1418
1481
|
data: data[key]
|
|
@@ -1453,7 +1516,7 @@ var ObjectKeywords = {
|
|
|
1453
1516
|
if (typeof pn === "boolean") {
|
|
1454
1517
|
if (pn === false) {
|
|
1455
1518
|
for (const key in data) {
|
|
1456
|
-
if (
|
|
1519
|
+
if (hasOwn(data, key)) {
|
|
1457
1520
|
return defineError("Properties are not allowed", { data });
|
|
1458
1521
|
}
|
|
1459
1522
|
}
|
|
@@ -1465,7 +1528,7 @@ var ObjectKeywords = {
|
|
|
1465
1528
|
return;
|
|
1466
1529
|
}
|
|
1467
1530
|
for (const key in data) {
|
|
1468
|
-
if (!
|
|
1531
|
+
if (!hasOwn(data, key)) {
|
|
1469
1532
|
continue;
|
|
1470
1533
|
}
|
|
1471
1534
|
const error = validate(key);
|
|
@@ -1564,7 +1627,7 @@ function getBranchEntries(schema, key) {
|
|
|
1564
1627
|
for (let i = 0; i < source.length; i++) {
|
|
1565
1628
|
entries.push(toBranchEntry(source[i]));
|
|
1566
1629
|
}
|
|
1567
|
-
|
|
1630
|
+
definePropertyOrThrow(schema, cacheKey, {
|
|
1568
1631
|
value: entries,
|
|
1569
1632
|
enumerable: false,
|
|
1570
1633
|
configurable: false,
|
|
@@ -1572,6 +1635,147 @@ function getBranchEntries(schema, key) {
|
|
|
1572
1635
|
});
|
|
1573
1636
|
return entries;
|
|
1574
1637
|
}
|
|
1638
|
+
function evaluateAllOf(branches, data, defineError) {
|
|
1639
|
+
for (let i = 0; i < branches.length; i++) {
|
|
1640
|
+
const branch = branches[i];
|
|
1641
|
+
if (branch.kind === "validate") {
|
|
1642
|
+
const error = branch.validate(data);
|
|
1643
|
+
if (error) {
|
|
1644
|
+
return defineError("Value is not valid", { cause: error, data });
|
|
1645
|
+
}
|
|
1646
|
+
continue;
|
|
1647
|
+
}
|
|
1648
|
+
if (branch.kind === "alwaysValid") {
|
|
1649
|
+
continue;
|
|
1650
|
+
}
|
|
1651
|
+
if (branch.kind === "alwaysInvalid" || data !== branch.value) {
|
|
1652
|
+
return defineError("Value is not valid", { data });
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
function evaluateAnyOf(branches, data, defineError) {
|
|
1657
|
+
for (let i = 0; i < branches.length; i++) {
|
|
1658
|
+
const branch = branches[i];
|
|
1659
|
+
if (branch.kind === "validate") {
|
|
1660
|
+
if (!branch.validate(data)) {
|
|
1661
|
+
return;
|
|
1662
|
+
}
|
|
1663
|
+
continue;
|
|
1664
|
+
}
|
|
1665
|
+
if (branch.kind === "alwaysValid") {
|
|
1666
|
+
return;
|
|
1667
|
+
}
|
|
1668
|
+
if (branch.kind === "literal" && data === branch.value) {
|
|
1669
|
+
return;
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
return defineError("Value is not valid", { data });
|
|
1673
|
+
}
|
|
1674
|
+
function evaluateOneOf(branches, data, defineError) {
|
|
1675
|
+
let validCount = 0;
|
|
1676
|
+
let winnerIndex = -1;
|
|
1677
|
+
for (let i = 0; i < branches.length; i++) {
|
|
1678
|
+
const branch = branches[i];
|
|
1679
|
+
let isValid = false;
|
|
1680
|
+
if (branch.kind === "validate") {
|
|
1681
|
+
isValid = !branch.validate(data);
|
|
1682
|
+
} else if (branch.kind === "alwaysValid") {
|
|
1683
|
+
isValid = true;
|
|
1684
|
+
} else if (branch.kind === "literal") {
|
|
1685
|
+
isValid = data === branch.value;
|
|
1686
|
+
}
|
|
1687
|
+
if (isValid) {
|
|
1688
|
+
validCount++;
|
|
1689
|
+
winnerIndex = i;
|
|
1690
|
+
if (validCount > 1) {
|
|
1691
|
+
return {
|
|
1692
|
+
error: defineError("Value is not valid", { data }),
|
|
1693
|
+
winnerIndex: -1
|
|
1694
|
+
};
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
return {
|
|
1699
|
+
error: validCount === 1 ? void 0 : defineError("Value is not valid", { data }),
|
|
1700
|
+
winnerIndex: validCount === 1 ? winnerIndex : -1
|
|
1701
|
+
};
|
|
1702
|
+
}
|
|
1703
|
+
function createCombinatorValidator(key, schema, defineError, validateSubschema, transactions) {
|
|
1704
|
+
const sourceBranches = getBranchEntries(schema, key);
|
|
1705
|
+
const branches = validateSubschema ? sourceBranches.map(
|
|
1706
|
+
(branch, index) => branch.kind === "validate" ? {
|
|
1707
|
+
kind: "validate",
|
|
1708
|
+
validate: (data) => validateSubschema(schema[key][index], data)
|
|
1709
|
+
} : branch
|
|
1710
|
+
) : sourceBranches;
|
|
1711
|
+
if (!transactions) {
|
|
1712
|
+
if (key === "allOf") {
|
|
1713
|
+
return (data) => evaluateAllOf(branches, data, defineError);
|
|
1714
|
+
}
|
|
1715
|
+
if (key === "anyOf") {
|
|
1716
|
+
return (data) => evaluateAnyOf(branches, data, defineError);
|
|
1717
|
+
}
|
|
1718
|
+
return (data) => evaluateOneOf(branches, data, defineError).error;
|
|
1719
|
+
}
|
|
1720
|
+
if (key === "allOf") {
|
|
1721
|
+
return (data) => {
|
|
1722
|
+
const savepoint = transactions.savepoint();
|
|
1723
|
+
try {
|
|
1724
|
+
const error = evaluateAllOf(branches, data, defineError);
|
|
1725
|
+
if (error) {
|
|
1726
|
+
transactions.rollback(savepoint);
|
|
1727
|
+
}
|
|
1728
|
+
return error;
|
|
1729
|
+
} catch (error) {
|
|
1730
|
+
transactions.rollback(savepoint);
|
|
1731
|
+
throw error;
|
|
1732
|
+
}
|
|
1733
|
+
};
|
|
1734
|
+
}
|
|
1735
|
+
if (key === "anyOf") {
|
|
1736
|
+
return (data) => evaluateAnyOf(branches, data, defineError);
|
|
1737
|
+
}
|
|
1738
|
+
return (data) => {
|
|
1739
|
+
const savepoint = transactions.savepoint();
|
|
1740
|
+
const defaultsByBranch = [];
|
|
1741
|
+
const isolatedBranches = branches.map(
|
|
1742
|
+
(branch, index) => branch.kind === "validate" ? {
|
|
1743
|
+
kind: "validate",
|
|
1744
|
+
validate: (value) => {
|
|
1745
|
+
const branchSavepoint = transactions.savepoint();
|
|
1746
|
+
const error = branch.validate(value);
|
|
1747
|
+
if (!error) {
|
|
1748
|
+
defaultsByBranch[index] = transactions.capture(branchSavepoint);
|
|
1749
|
+
}
|
|
1750
|
+
return error;
|
|
1751
|
+
}
|
|
1752
|
+
} : branch
|
|
1753
|
+
);
|
|
1754
|
+
try {
|
|
1755
|
+
const result = evaluateOneOf(isolatedBranches, data, defineError);
|
|
1756
|
+
if (result.error) {
|
|
1757
|
+
transactions.rollback(savepoint);
|
|
1758
|
+
return result.error;
|
|
1759
|
+
}
|
|
1760
|
+
transactions.restore(defaultsByBranch[result.winnerIndex] || []);
|
|
1761
|
+
return;
|
|
1762
|
+
} catch (error) {
|
|
1763
|
+
transactions.rollback(savepoint);
|
|
1764
|
+
throw error;
|
|
1765
|
+
}
|
|
1766
|
+
};
|
|
1767
|
+
}
|
|
1768
|
+
function prepareCombinatorEntries(schema) {
|
|
1769
|
+
if (Array.isArray(schema.allOf)) {
|
|
1770
|
+
getBranchEntries(schema, "allOf");
|
|
1771
|
+
}
|
|
1772
|
+
if (Array.isArray(schema.anyOf)) {
|
|
1773
|
+
getBranchEntries(schema, "anyOf");
|
|
1774
|
+
}
|
|
1775
|
+
if (Array.isArray(schema.oneOf)) {
|
|
1776
|
+
getBranchEntries(schema, "oneOf");
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1575
1779
|
var OtherKeywords = {
|
|
1576
1780
|
enum(schema, data, defineError) {
|
|
1577
1781
|
let enumCache = schema._enumCache;
|
|
@@ -1588,7 +1792,7 @@ var OtherKeywords = {
|
|
|
1588
1792
|
}
|
|
1589
1793
|
}
|
|
1590
1794
|
enumCache = { primitiveSet, objectValues };
|
|
1591
|
-
|
|
1795
|
+
definePropertyOrThrow(schema, "_enumCache", {
|
|
1592
1796
|
value: enumCache,
|
|
1593
1797
|
enumerable: false,
|
|
1594
1798
|
configurable: false,
|
|
@@ -1608,137 +1812,13 @@ var OtherKeywords = {
|
|
|
1608
1812
|
return defineError("Value is not one of the allowed values", { data });
|
|
1609
1813
|
},
|
|
1610
1814
|
allOf(schema, data, defineError) {
|
|
1611
|
-
|
|
1612
|
-
if (branches.length === 1) {
|
|
1613
|
-
const onlyBranch = branches[0];
|
|
1614
|
-
if (onlyBranch.kind === "validate") {
|
|
1615
|
-
const error = onlyBranch.validate(data);
|
|
1616
|
-
if (error) {
|
|
1617
|
-
return defineError("Value is not valid", { cause: error, data });
|
|
1618
|
-
}
|
|
1619
|
-
return;
|
|
1620
|
-
}
|
|
1621
|
-
if (onlyBranch.kind === "alwaysValid") {
|
|
1622
|
-
return;
|
|
1623
|
-
}
|
|
1624
|
-
if (onlyBranch.kind === "alwaysInvalid") {
|
|
1625
|
-
return defineError("Value is not valid", { data });
|
|
1626
|
-
}
|
|
1627
|
-
if (data !== onlyBranch.value) {
|
|
1628
|
-
return defineError("Value is not valid", { data });
|
|
1629
|
-
}
|
|
1630
|
-
return;
|
|
1631
|
-
}
|
|
1632
|
-
for (let i = 0; i < branches.length; i++) {
|
|
1633
|
-
const branch = branches[i];
|
|
1634
|
-
if (branch.kind === "validate") {
|
|
1635
|
-
const error = branch.validate(data);
|
|
1636
|
-
if (error) {
|
|
1637
|
-
return defineError("Value is not valid", { cause: error, data });
|
|
1638
|
-
}
|
|
1639
|
-
continue;
|
|
1640
|
-
}
|
|
1641
|
-
if (branch.kind === "alwaysValid") {
|
|
1642
|
-
continue;
|
|
1643
|
-
}
|
|
1644
|
-
if (branch.kind === "alwaysInvalid") {
|
|
1645
|
-
return defineError("Value is not valid", { data });
|
|
1646
|
-
}
|
|
1647
|
-
if (data !== branch.value) {
|
|
1648
|
-
return defineError("Value is not valid", { data });
|
|
1649
|
-
}
|
|
1650
|
-
}
|
|
1651
|
-
return;
|
|
1815
|
+
return createCombinatorValidator("allOf", schema, defineError)(data);
|
|
1652
1816
|
},
|
|
1653
1817
|
anyOf(schema, data, defineError) {
|
|
1654
|
-
|
|
1655
|
-
if (branches.length === 1) {
|
|
1656
|
-
const onlyBranch = branches[0];
|
|
1657
|
-
if (onlyBranch.kind === "validate") {
|
|
1658
|
-
const error = onlyBranch.validate(data);
|
|
1659
|
-
if (!error) {
|
|
1660
|
-
return;
|
|
1661
|
-
}
|
|
1662
|
-
return defineError("Value is not valid", { data });
|
|
1663
|
-
}
|
|
1664
|
-
if (onlyBranch.kind === "alwaysValid") {
|
|
1665
|
-
return;
|
|
1666
|
-
}
|
|
1667
|
-
if (onlyBranch.kind === "alwaysInvalid") {
|
|
1668
|
-
return defineError("Value is not valid", { data });
|
|
1669
|
-
}
|
|
1670
|
-
if (data === onlyBranch.value) {
|
|
1671
|
-
return;
|
|
1672
|
-
}
|
|
1673
|
-
return defineError("Value is not valid", { data });
|
|
1674
|
-
}
|
|
1675
|
-
for (let i = 0; i < branches.length; i++) {
|
|
1676
|
-
const branch = branches[i];
|
|
1677
|
-
if (branch.kind === "validate") {
|
|
1678
|
-
const error = branch.validate(data);
|
|
1679
|
-
if (!error) {
|
|
1680
|
-
return;
|
|
1681
|
-
}
|
|
1682
|
-
continue;
|
|
1683
|
-
}
|
|
1684
|
-
if (branch.kind === "alwaysValid") {
|
|
1685
|
-
return;
|
|
1686
|
-
}
|
|
1687
|
-
if (branch.kind === "alwaysInvalid") {
|
|
1688
|
-
continue;
|
|
1689
|
-
}
|
|
1690
|
-
if (data === branch.value) {
|
|
1691
|
-
return;
|
|
1692
|
-
}
|
|
1693
|
-
}
|
|
1694
|
-
return defineError("Value is not valid", { data });
|
|
1818
|
+
return createCombinatorValidator("anyOf", schema, defineError)(data);
|
|
1695
1819
|
},
|
|
1696
1820
|
oneOf(schema, data, defineError) {
|
|
1697
|
-
|
|
1698
|
-
if (branches.length === 1) {
|
|
1699
|
-
const onlyBranch = branches[0];
|
|
1700
|
-
if (onlyBranch.kind === "validate") {
|
|
1701
|
-
const error = onlyBranch.validate(data);
|
|
1702
|
-
if (!error) {
|
|
1703
|
-
return;
|
|
1704
|
-
}
|
|
1705
|
-
return defineError("Value is not valid", { data });
|
|
1706
|
-
}
|
|
1707
|
-
if (onlyBranch.kind === "alwaysValid") {
|
|
1708
|
-
return;
|
|
1709
|
-
}
|
|
1710
|
-
if (onlyBranch.kind === "alwaysInvalid") {
|
|
1711
|
-
return defineError("Value is not valid", { data });
|
|
1712
|
-
}
|
|
1713
|
-
if (data === onlyBranch.value) {
|
|
1714
|
-
return;
|
|
1715
|
-
}
|
|
1716
|
-
return defineError("Value is not valid", { data });
|
|
1717
|
-
}
|
|
1718
|
-
let validCount = 0;
|
|
1719
|
-
for (let i = 0; i < branches.length; i++) {
|
|
1720
|
-
const branch = branches[i];
|
|
1721
|
-
let isValid = false;
|
|
1722
|
-
if (branch.kind === "validate") {
|
|
1723
|
-
isValid = !branch.validate(data);
|
|
1724
|
-
} else if (branch.kind === "alwaysValid") {
|
|
1725
|
-
isValid = true;
|
|
1726
|
-
} else if (branch.kind === "alwaysInvalid") {
|
|
1727
|
-
isValid = false;
|
|
1728
|
-
} else {
|
|
1729
|
-
isValid = data === branch.value;
|
|
1730
|
-
}
|
|
1731
|
-
if (isValid) {
|
|
1732
|
-
validCount++;
|
|
1733
|
-
if (validCount > 1) {
|
|
1734
|
-
return defineError("Value is not valid", { data });
|
|
1735
|
-
}
|
|
1736
|
-
}
|
|
1737
|
-
}
|
|
1738
|
-
if (validCount === 1) {
|
|
1739
|
-
return;
|
|
1740
|
-
}
|
|
1741
|
-
return defineError("Value is not valid", { data });
|
|
1821
|
+
return createCombinatorValidator("oneOf", schema, defineError)(data);
|
|
1742
1822
|
},
|
|
1743
1823
|
const(schema, data, defineError) {
|
|
1744
1824
|
if (data === schema.const) {
|
|
@@ -1798,45 +1878,62 @@ var OtherKeywords = {
|
|
|
1798
1878
|
}
|
|
1799
1879
|
return defineError("Value is not valid", { data });
|
|
1800
1880
|
},
|
|
1801
|
-
$ref(schema, data, defineError
|
|
1802
|
-
if (schema._resolvedRef) {
|
|
1803
|
-
if (schema.$validate !== schema._resolvedRef) {
|
|
1804
|
-
schema.$validate = schema._resolvedRef;
|
|
1805
|
-
}
|
|
1881
|
+
$ref(schema, data, defineError) {
|
|
1882
|
+
if (typeof schema._resolvedRef === "function") {
|
|
1806
1883
|
return schema._resolvedRef(data);
|
|
1807
1884
|
}
|
|
1808
|
-
|
|
1809
|
-
let targetSchema = instance.getSchemaRef(refPath);
|
|
1810
|
-
if (!targetSchema) {
|
|
1811
|
-
targetSchema = instance.getSchemaById(refPath);
|
|
1812
|
-
}
|
|
1813
|
-
if (!targetSchema) {
|
|
1814
|
-
return defineError(`Missing reference: ${refPath}`);
|
|
1815
|
-
}
|
|
1816
|
-
if (!targetSchema.$validate) {
|
|
1817
|
-
return;
|
|
1818
|
-
}
|
|
1819
|
-
schema._resolvedRef = targetSchema.$validate;
|
|
1820
|
-
schema.$validate = schema._resolvedRef;
|
|
1821
|
-
return schema._resolvedRef(data);
|
|
1885
|
+
return defineError(`Missing reference: ${schema.$ref}`);
|
|
1822
1886
|
}
|
|
1823
1887
|
};
|
|
1824
1888
|
|
|
1825
1889
|
// lib/keywords/string-keywords.ts
|
|
1826
1890
|
var PATTERN_MATCH_CACHE_LIMIT = 512;
|
|
1827
1891
|
var FORMAT_RESULT_CACHE_LIMIT = 512;
|
|
1892
|
+
function hasAtLeastCodePoints(value, limit) {
|
|
1893
|
+
let count = 0;
|
|
1894
|
+
for (let index = 0; index < value.length; index++) {
|
|
1895
|
+
const unit = value.charCodeAt(index);
|
|
1896
|
+
if (unit >= 55296 && unit <= 56319 && index + 1 < value.length) {
|
|
1897
|
+
const nextUnit = value.charCodeAt(index + 1);
|
|
1898
|
+
if (nextUnit >= 56320 && nextUnit <= 57343) {
|
|
1899
|
+
index++;
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
count++;
|
|
1903
|
+
if (count >= limit) {
|
|
1904
|
+
return true;
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
return count >= limit;
|
|
1908
|
+
}
|
|
1828
1909
|
var StringKeywords = {
|
|
1829
1910
|
minLength(schema, data, defineError) {
|
|
1830
|
-
if (typeof data !== "string"
|
|
1911
|
+
if (typeof data !== "string") {
|
|
1912
|
+
return;
|
|
1913
|
+
}
|
|
1914
|
+
const units = data.length;
|
|
1915
|
+
const limit = schema.minLength;
|
|
1916
|
+
if (units < limit) {
|
|
1917
|
+
return defineError("Value is shorter than the minimum length", { data });
|
|
1918
|
+
}
|
|
1919
|
+
if (units - limit >= limit || hasAtLeastCodePoints(data, limit)) {
|
|
1831
1920
|
return;
|
|
1832
1921
|
}
|
|
1833
1922
|
return defineError("Value is shorter than the minimum length", { data });
|
|
1834
1923
|
},
|
|
1835
1924
|
maxLength(schema, data, defineError) {
|
|
1836
|
-
if (typeof data !== "string"
|
|
1925
|
+
if (typeof data !== "string") {
|
|
1926
|
+
return;
|
|
1927
|
+
}
|
|
1928
|
+
const units = data.length;
|
|
1929
|
+
const limit = schema.maxLength;
|
|
1930
|
+
if (units <= limit) {
|
|
1837
1931
|
return;
|
|
1838
1932
|
}
|
|
1839
|
-
|
|
1933
|
+
if (units - limit > limit || hasAtLeastCodePoints(data, limit + 1)) {
|
|
1934
|
+
return defineError("Value is longer than the maximum length", { data });
|
|
1935
|
+
}
|
|
1936
|
+
return;
|
|
1840
1937
|
},
|
|
1841
1938
|
pattern(schema, data, defineError) {
|
|
1842
1939
|
if (typeof data !== "string") {
|
|
@@ -1848,7 +1945,7 @@ var StringKeywords = {
|
|
|
1848
1945
|
try {
|
|
1849
1946
|
const compiled = compilePatternMatcher(schema.pattern);
|
|
1850
1947
|
patternMatch = compiled instanceof RegExp ? (value) => compiled.test(value) : compiled;
|
|
1851
|
-
|
|
1948
|
+
definePropertyOrThrow(schema, "_patternMatch", {
|
|
1852
1949
|
value: patternMatch,
|
|
1853
1950
|
enumerable: false,
|
|
1854
1951
|
configurable: false,
|
|
@@ -1863,7 +1960,7 @@ var StringKeywords = {
|
|
|
1863
1960
|
}
|
|
1864
1961
|
if (!patternMatchCache) {
|
|
1865
1962
|
patternMatchCache = /* @__PURE__ */ new Map();
|
|
1866
|
-
|
|
1963
|
+
definePropertyOrThrow(schema, "_patternMatchCache", {
|
|
1867
1964
|
value: patternMatchCache,
|
|
1868
1965
|
enumerable: false,
|
|
1869
1966
|
configurable: false,
|
|
@@ -1895,7 +1992,7 @@ var StringKeywords = {
|
|
|
1895
1992
|
let formatResultCache = schema._formatResultCache;
|
|
1896
1993
|
if (formatValidate === void 0) {
|
|
1897
1994
|
formatValidate = instance.getFormat(schema.format);
|
|
1898
|
-
|
|
1995
|
+
definePropertyOrThrow(schema, "_formatValidate", {
|
|
1899
1996
|
value: formatValidate,
|
|
1900
1997
|
enumerable: false,
|
|
1901
1998
|
configurable: false,
|
|
@@ -1910,7 +2007,7 @@ var StringKeywords = {
|
|
|
1910
2007
|
schema.format,
|
|
1911
2008
|
formatValidate
|
|
1912
2009
|
);
|
|
1913
|
-
|
|
2010
|
+
definePropertyOrThrow(schema, "_formatResultCacheEnabled", {
|
|
1914
2011
|
value: formatResultCacheEnabled,
|
|
1915
2012
|
enumerable: false,
|
|
1916
2013
|
configurable: false,
|
|
@@ -1925,7 +2022,7 @@ var StringKeywords = {
|
|
|
1925
2022
|
}
|
|
1926
2023
|
if (!formatResultCache) {
|
|
1927
2024
|
formatResultCache = /* @__PURE__ */ new Map();
|
|
1928
|
-
|
|
2025
|
+
definePropertyOrThrow(schema, "_formatResultCache", {
|
|
1929
2026
|
value: formatResultCache,
|
|
1930
2027
|
enumerable: false,
|
|
1931
2028
|
configurable: false,
|
|
@@ -1958,20 +2055,61 @@ var keywords = {
|
|
|
1958
2055
|
};
|
|
1959
2056
|
|
|
1960
2057
|
// lib/index.ts
|
|
2058
|
+
var MAX_COMPILE_DEPTH = 128;
|
|
2059
|
+
var LOCAL_SCHEMA_BASE = "schema-shield://local/root";
|
|
2060
|
+
var FAIL_FAST_TYPE_VALIDATORS = {
|
|
2061
|
+
object: (data) => data !== null && typeof data === "object" && !Array.isArray(data) ? void 0 : true,
|
|
2062
|
+
array: (data) => Array.isArray(data) ? void 0 : true,
|
|
2063
|
+
string: (data) => typeof data === "string" ? void 0 : true,
|
|
2064
|
+
number: (data) => typeof data === "number" && Number.isFinite(data) ? void 0 : true,
|
|
2065
|
+
integer: (data) => typeof data === "number" && Number.isFinite(data) && Number.isInteger(data) ? void 0 : true,
|
|
2066
|
+
boolean: (data) => typeof data === "boolean" ? void 0 : true,
|
|
2067
|
+
null: (data) => data === null ? void 0 : true
|
|
2068
|
+
};
|
|
2069
|
+
function createBuiltinTypeValidator(_type, defineError, fallback) {
|
|
2070
|
+
return (data) => {
|
|
2071
|
+
if (!fallback(data)) {
|
|
2072
|
+
return defineError("Invalid type", { data });
|
|
2073
|
+
}
|
|
2074
|
+
};
|
|
2075
|
+
}
|
|
1961
2076
|
var SchemaShield = class {
|
|
1962
2077
|
types = {};
|
|
1963
2078
|
formats = {};
|
|
1964
2079
|
keywords = {};
|
|
1965
2080
|
immutable = false;
|
|
2081
|
+
useDefaults = false;
|
|
1966
2082
|
rootSchema = null;
|
|
1967
|
-
idRegistry = /* @__PURE__ */ new Map();
|
|
1968
2083
|
failFast = true;
|
|
2084
|
+
maxDepth;
|
|
2085
|
+
validationContexts = [];
|
|
2086
|
+
compileCache = /* @__PURE__ */ new WeakMap();
|
|
2087
|
+
compilingRequiresContext = false;
|
|
2088
|
+
compilingMutableSchemas = /* @__PURE__ */ new WeakSet();
|
|
1969
2089
|
constructor({
|
|
1970
2090
|
immutable = false,
|
|
1971
|
-
failFast = true
|
|
2091
|
+
failFast = true,
|
|
2092
|
+
maxDepth = 128,
|
|
2093
|
+
useDefaults = false
|
|
1972
2094
|
} = {}) {
|
|
2095
|
+
if (!Number.isInteger(maxDepth) || maxDepth < 1 || maxDepth > 256) {
|
|
2096
|
+
const error = new ValidationError("maxDepth must be an integer from 1 to 256");
|
|
2097
|
+
error.code = "INVALID_MAX_DEPTH";
|
|
2098
|
+
error.keyword = "maxDepth";
|
|
2099
|
+
throw error;
|
|
2100
|
+
}
|
|
2101
|
+
if (useDefaults !== false && useDefaults !== true && useDefaults !== "empty") {
|
|
2102
|
+
const error = new ValidationError(
|
|
2103
|
+
'useDefaults must be false, true, or "empty"'
|
|
2104
|
+
);
|
|
2105
|
+
error.code = "INVALID_USE_DEFAULTS";
|
|
2106
|
+
error.keyword = "useDefaults";
|
|
2107
|
+
throw error;
|
|
2108
|
+
}
|
|
1973
2109
|
this.immutable = immutable;
|
|
1974
2110
|
this.failFast = failFast;
|
|
2111
|
+
this.maxDepth = maxDepth;
|
|
2112
|
+
this.useDefaults = useDefaults;
|
|
1975
2113
|
for (const [type, validator] of Object.entries(Types)) {
|
|
1976
2114
|
if (validator) {
|
|
1977
2115
|
this.addType(type, validator);
|
|
@@ -1986,6 +2124,50 @@ var SchemaShield = class {
|
|
|
1986
2124
|
}
|
|
1987
2125
|
}
|
|
1988
2126
|
}
|
|
2127
|
+
setDefault(target, key, value) {
|
|
2128
|
+
const context = this.validationContexts[this.validationContexts.length - 1];
|
|
2129
|
+
if (context) {
|
|
2130
|
+
context.defaults.push({
|
|
2131
|
+
target,
|
|
2132
|
+
key,
|
|
2133
|
+
descriptor: Reflect.getOwnPropertyDescriptor(target, key)
|
|
2134
|
+
});
|
|
2135
|
+
}
|
|
2136
|
+
definePropertyOrThrow(target, key, {
|
|
2137
|
+
value,
|
|
2138
|
+
enumerable: true,
|
|
2139
|
+
configurable: true,
|
|
2140
|
+
writable: true
|
|
2141
|
+
});
|
|
2142
|
+
}
|
|
2143
|
+
#defaultSavepoint() {
|
|
2144
|
+
const context = this.validationContexts[this.validationContexts.length - 1];
|
|
2145
|
+
return context ? context.defaults.length : 0;
|
|
2146
|
+
}
|
|
2147
|
+
#rollbackDefaultSavepoint(savepoint) {
|
|
2148
|
+
const context = this.validationContexts[this.validationContexts.length - 1];
|
|
2149
|
+
if (context) {
|
|
2150
|
+
this.rollbackDefaults(context, savepoint);
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
#captureDefaultSavepoint(savepoint) {
|
|
2154
|
+
const context = this.validationContexts[this.validationContexts.length - 1];
|
|
2155
|
+
if (!context || context.defaults.length === savepoint) {
|
|
2156
|
+
return [];
|
|
2157
|
+
}
|
|
2158
|
+
const mutations = context.defaults.slice(savepoint).map((entry) => ({
|
|
2159
|
+
...entry,
|
|
2160
|
+
value: entry.target[entry.key]
|
|
2161
|
+
}));
|
|
2162
|
+
this.rollbackDefaults(context, savepoint);
|
|
2163
|
+
return mutations;
|
|
2164
|
+
}
|
|
2165
|
+
#restoreDefaults(mutations) {
|
|
2166
|
+
for (let index = 0; index < mutations.length; index++) {
|
|
2167
|
+
const mutation = mutations[index];
|
|
2168
|
+
this.setDefault(mutation.target, mutation.key, mutation.value);
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
1989
2171
|
addType(name, validator, overwrite = false) {
|
|
1990
2172
|
if (this.types[name] && !overwrite) {
|
|
1991
2173
|
throw new ValidationError(`Type "${name}" already exists`);
|
|
@@ -2023,14 +2205,465 @@ var SchemaShield = class {
|
|
|
2023
2205
|
return resolvePath(this.rootSchema, path);
|
|
2024
2206
|
}
|
|
2025
2207
|
getSchemaById(id) {
|
|
2026
|
-
|
|
2208
|
+
if (!this.rootSchema) {
|
|
2209
|
+
return;
|
|
2210
|
+
}
|
|
2211
|
+
const stack = [this.rootSchema];
|
|
2212
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
2213
|
+
while (stack.length > 0) {
|
|
2214
|
+
const node = stack.pop();
|
|
2215
|
+
if (seen.has(node)) {
|
|
2216
|
+
continue;
|
|
2217
|
+
}
|
|
2218
|
+
seen.add(node);
|
|
2219
|
+
if (node.$id === id) {
|
|
2220
|
+
return node;
|
|
2221
|
+
}
|
|
2222
|
+
const children = this.schemaChildren(node);
|
|
2223
|
+
for (let index = 0; index < children.length; index++) {
|
|
2224
|
+
stack.push(children[index]);
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
return;
|
|
2228
|
+
}
|
|
2229
|
+
depthError(message = "Maximum schema depth exceeded") {
|
|
2230
|
+
if (this.failFast) {
|
|
2231
|
+
return true;
|
|
2232
|
+
}
|
|
2233
|
+
const error = new ValidationError(message);
|
|
2234
|
+
error.code = "MAX_DEPTH_EXCEEDED";
|
|
2235
|
+
error.keyword = "maxDepth";
|
|
2236
|
+
return error;
|
|
2237
|
+
}
|
|
2238
|
+
schemaChildEntries(schema) {
|
|
2239
|
+
const children = [];
|
|
2240
|
+
const mapKeys = [
|
|
2241
|
+
"properties",
|
|
2242
|
+
"patternProperties",
|
|
2243
|
+
"definitions",
|
|
2244
|
+
"$defs",
|
|
2245
|
+
"dependencies"
|
|
2246
|
+
];
|
|
2247
|
+
const arrayKeys = ["allOf", "anyOf", "oneOf", "items"];
|
|
2248
|
+
const singleKeys = [
|
|
2249
|
+
"items",
|
|
2250
|
+
"additionalItems",
|
|
2251
|
+
"additionalProperties",
|
|
2252
|
+
"contains",
|
|
2253
|
+
"propertyNames",
|
|
2254
|
+
"values",
|
|
2255
|
+
"elements",
|
|
2256
|
+
"not",
|
|
2257
|
+
"if",
|
|
2258
|
+
"then",
|
|
2259
|
+
"else"
|
|
2260
|
+
];
|
|
2261
|
+
for (const key of mapKeys) {
|
|
2262
|
+
const value = schema[key];
|
|
2263
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
2264
|
+
continue;
|
|
2265
|
+
}
|
|
2266
|
+
for (const childKey of Object.keys(value)) {
|
|
2267
|
+
const child = value[childKey];
|
|
2268
|
+
if (child && typeof child === "object") {
|
|
2269
|
+
children.push({
|
|
2270
|
+
value: child,
|
|
2271
|
+
pointer: `/${this.escapePointerToken(key)}/${this.escapePointerToken(
|
|
2272
|
+
childKey
|
|
2273
|
+
)}`
|
|
2274
|
+
});
|
|
2275
|
+
}
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
for (const key of arrayKeys) {
|
|
2279
|
+
const value = schema[key];
|
|
2280
|
+
if (!Array.isArray(value)) {
|
|
2281
|
+
continue;
|
|
2282
|
+
}
|
|
2283
|
+
for (let index = 0; index < value.length; index++) {
|
|
2284
|
+
const child = value[index];
|
|
2285
|
+
if (child && typeof child === "object") {
|
|
2286
|
+
children.push({
|
|
2287
|
+
value: child,
|
|
2288
|
+
pointer: `/${this.escapePointerToken(key)}/${index}`
|
|
2289
|
+
});
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
for (const key of singleKeys) {
|
|
2294
|
+
const value = schema[key];
|
|
2295
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
2296
|
+
children.push({
|
|
2297
|
+
value,
|
|
2298
|
+
pointer: `/${this.escapePointerToken(key)}`
|
|
2299
|
+
});
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2302
|
+
for (const key of Object.keys(schema)) {
|
|
2303
|
+
if (key === "enum" || key === "const" || key === "default" || key === "examples" || mapKeys.includes(key) || arrayKeys.includes(key) || singleKeys.includes(key)) {
|
|
2304
|
+
continue;
|
|
2305
|
+
}
|
|
2306
|
+
const keyword = this.getKeyword(key);
|
|
2307
|
+
const value = schema[key];
|
|
2308
|
+
if (keyword && keyword !== keywords[key] && value && typeof value === "object") {
|
|
2309
|
+
children.push({
|
|
2310
|
+
value,
|
|
2311
|
+
pointer: `/${this.escapePointerToken(key)}`
|
|
2312
|
+
});
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
return children;
|
|
2316
|
+
}
|
|
2317
|
+
schemaChildren(schema) {
|
|
2318
|
+
return this.schemaChildEntries(schema).map((entry) => entry.value);
|
|
2319
|
+
}
|
|
2320
|
+
registrySubschemaEntries(schema) {
|
|
2321
|
+
const children = [];
|
|
2322
|
+
const mapKeys = ["properties", "patternProperties", "definitions"];
|
|
2323
|
+
const arrayKeys = ["allOf", "anyOf", "oneOf", "items"];
|
|
2324
|
+
const singleKeys = [
|
|
2325
|
+
"items",
|
|
2326
|
+
"additionalItems",
|
|
2327
|
+
"additionalProperties",
|
|
2328
|
+
"contains",
|
|
2329
|
+
"propertyNames",
|
|
2330
|
+
"not",
|
|
2331
|
+
"if",
|
|
2332
|
+
"then",
|
|
2333
|
+
"else"
|
|
2334
|
+
];
|
|
2335
|
+
for (const key of mapKeys) {
|
|
2336
|
+
const value = schema[key];
|
|
2337
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
2338
|
+
continue;
|
|
2339
|
+
}
|
|
2340
|
+
for (const childKey of Object.keys(value)) {
|
|
2341
|
+
const child = value[childKey];
|
|
2342
|
+
if (child && typeof child === "object" && !Array.isArray(child)) {
|
|
2343
|
+
children.push({
|
|
2344
|
+
value: child,
|
|
2345
|
+
pointer: `/${this.escapePointerToken(key)}/${this.escapePointerToken(
|
|
2346
|
+
childKey
|
|
2347
|
+
)}`
|
|
2348
|
+
});
|
|
2349
|
+
}
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2352
|
+
const dependencies = schema.dependencies;
|
|
2353
|
+
if (dependencies && typeof dependencies === "object" && !Array.isArray(dependencies)) {
|
|
2354
|
+
for (const dependencyKey of Object.keys(dependencies)) {
|
|
2355
|
+
const child = dependencies[dependencyKey];
|
|
2356
|
+
if (child && typeof child === "object" && !Array.isArray(child)) {
|
|
2357
|
+
children.push({
|
|
2358
|
+
value: child,
|
|
2359
|
+
pointer: `/dependencies/${this.escapePointerToken(dependencyKey)}`
|
|
2360
|
+
});
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
for (const key of arrayKeys) {
|
|
2365
|
+
const value = schema[key];
|
|
2366
|
+
if (!Array.isArray(value)) {
|
|
2367
|
+
continue;
|
|
2368
|
+
}
|
|
2369
|
+
for (let index = 0; index < value.length; index++) {
|
|
2370
|
+
const child = value[index];
|
|
2371
|
+
if (child && typeof child === "object" && !Array.isArray(child)) {
|
|
2372
|
+
children.push({
|
|
2373
|
+
value: child,
|
|
2374
|
+
pointer: `/${this.escapePointerToken(key)}/${index}`
|
|
2375
|
+
});
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
for (const key of singleKeys) {
|
|
2380
|
+
const value = schema[key];
|
|
2381
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
2382
|
+
children.push({
|
|
2383
|
+
value,
|
|
2384
|
+
pointer: `/${this.escapePointerToken(key)}`
|
|
2385
|
+
});
|
|
2386
|
+
}
|
|
2387
|
+
}
|
|
2388
|
+
return children;
|
|
2389
|
+
}
|
|
2390
|
+
escapePointerToken(value) {
|
|
2391
|
+
return value.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
2392
|
+
}
|
|
2393
|
+
resolveUri(reference, baseUri, keyword) {
|
|
2394
|
+
try {
|
|
2395
|
+
return new URL(reference, baseUri).href;
|
|
2396
|
+
} catch {
|
|
2397
|
+
const error = new ValidationError(`Invalid ${keyword} URI: ${reference}`);
|
|
2398
|
+
error.code = keyword === "$id" ? "INVALID_SCHEMA_ID" : "REFERENCE_NOT_FOUND";
|
|
2399
|
+
error.keyword = keyword;
|
|
2400
|
+
throw error;
|
|
2401
|
+
}
|
|
2402
|
+
}
|
|
2403
|
+
resourceUri(uri) {
|
|
2404
|
+
const hashIndex = uri.indexOf("#");
|
|
2405
|
+
return hashIndex === -1 ? uri : uri.slice(0, hashIndex);
|
|
2406
|
+
}
|
|
2407
|
+
buildReferenceRegistry(schema) {
|
|
2408
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
2409
|
+
const positions = [];
|
|
2410
|
+
const positionsByNode = /* @__PURE__ */ new WeakMap();
|
|
2411
|
+
if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
|
|
2412
|
+
return Object.freeze({
|
|
2413
|
+
aliases,
|
|
2414
|
+
positions: Object.freeze(positions),
|
|
2415
|
+
positionsByNode
|
|
2416
|
+
});
|
|
2417
|
+
}
|
|
2418
|
+
const register = (uri, node) => {
|
|
2419
|
+
const existing = aliases.get(uri);
|
|
2420
|
+
if (existing && existing !== node) {
|
|
2421
|
+
const error = new ValidationError(`Duplicate schema identity: ${uri}`);
|
|
2422
|
+
error.code = "DUPLICATE_SCHEMA_ID";
|
|
2423
|
+
error.keyword = "$id";
|
|
2424
|
+
throw error;
|
|
2425
|
+
}
|
|
2426
|
+
aliases.set(uri, node);
|
|
2427
|
+
};
|
|
2428
|
+
register(LOCAL_SCHEMA_BASE, schema);
|
|
2429
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
2430
|
+
const stack = [
|
|
2431
|
+
{
|
|
2432
|
+
node: schema,
|
|
2433
|
+
inheritedBase: LOCAL_SCHEMA_BASE,
|
|
2434
|
+
resourceRoot: schema,
|
|
2435
|
+
pointer: "#"
|
|
2436
|
+
}
|
|
2437
|
+
];
|
|
2438
|
+
while (stack.length > 0) {
|
|
2439
|
+
const entry = stack.pop();
|
|
2440
|
+
if (visited.has(entry.node)) {
|
|
2441
|
+
continue;
|
|
2442
|
+
}
|
|
2443
|
+
visited.add(entry.node);
|
|
2444
|
+
let baseUri = entry.inheritedBase;
|
|
2445
|
+
let resourceRoot = entry.resourceRoot;
|
|
2446
|
+
if (typeof entry.node.$id === "string" && !("$ref" in entry.node)) {
|
|
2447
|
+
baseUri = this.resolveUri(entry.node.$id, entry.inheritedBase, "$id");
|
|
2448
|
+
register(baseUri, entry.node);
|
|
2449
|
+
if (baseUri.indexOf("#") === -1 || baseUri.endsWith("#")) {
|
|
2450
|
+
resourceRoot = entry.node;
|
|
2451
|
+
register(this.resourceUri(baseUri), entry.node);
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2454
|
+
const position = {
|
|
2455
|
+
source: entry.node,
|
|
2456
|
+
baseUri,
|
|
2457
|
+
resourceRoot,
|
|
2458
|
+
pointer: entry.pointer
|
|
2459
|
+
};
|
|
2460
|
+
positions.push(position);
|
|
2461
|
+
positionsByNode.set(entry.node, position);
|
|
2462
|
+
const children = this.registrySubschemaEntries(entry.node);
|
|
2463
|
+
for (let index = children.length - 1; index >= 0; index--) {
|
|
2464
|
+
const child = children[index];
|
|
2465
|
+
if (Array.isArray(child.value)) {
|
|
2466
|
+
continue;
|
|
2467
|
+
}
|
|
2468
|
+
stack.push({
|
|
2469
|
+
node: child.value,
|
|
2470
|
+
inheritedBase: baseUri,
|
|
2471
|
+
resourceRoot,
|
|
2472
|
+
pointer: `${entry.pointer}${child.pointer}`
|
|
2473
|
+
});
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
return Object.freeze({
|
|
2477
|
+
aliases,
|
|
2478
|
+
positions: Object.freeze(positions),
|
|
2479
|
+
positionsByNode
|
|
2480
|
+
});
|
|
2481
|
+
}
|
|
2482
|
+
resolveReferenceSource(ref, position, registry) {
|
|
2483
|
+
const resolvedUri = this.resolveUri(ref, position.baseUri, "$ref");
|
|
2484
|
+
const exactTarget = registry.aliases.get(resolvedUri);
|
|
2485
|
+
if (exactTarget) {
|
|
2486
|
+
return exactTarget;
|
|
2487
|
+
}
|
|
2488
|
+
const resourceRoot = registry.aliases.get(this.resourceUri(resolvedUri));
|
|
2489
|
+
if (!resourceRoot) {
|
|
2490
|
+
return;
|
|
2491
|
+
}
|
|
2492
|
+
const hashIndex = resolvedUri.indexOf("#");
|
|
2493
|
+
const fragment = hashIndex === -1 ? "" : resolvedUri.slice(hashIndex + 1);
|
|
2494
|
+
if (fragment.length === 0) {
|
|
2495
|
+
return resourceRoot;
|
|
2496
|
+
}
|
|
2497
|
+
if (fragment.startsWith("/")) {
|
|
2498
|
+
return resolvePath(resourceRoot, `#${fragment}`);
|
|
2499
|
+
}
|
|
2500
|
+
return;
|
|
2501
|
+
}
|
|
2502
|
+
analyzeSchema(schema, registry) {
|
|
2503
|
+
if (!schema || typeof schema !== "object") {
|
|
2504
|
+
return {
|
|
2505
|
+
requiresDepthGuard: false,
|
|
2506
|
+
requiresMutationJournal: false,
|
|
2507
|
+
mutableSchemas: /* @__PURE__ */ new WeakSet()
|
|
2508
|
+
};
|
|
2509
|
+
}
|
|
2510
|
+
const visiting = /* @__PURE__ */ new WeakSet();
|
|
2511
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
2512
|
+
const stack = [{ value: schema, depth: 0, exit: false }];
|
|
2513
|
+
let requiresDepthGuard = false;
|
|
2514
|
+
let requiresMutationJournal = false;
|
|
2515
|
+
while (stack.length > 0) {
|
|
2516
|
+
const entry = stack.pop();
|
|
2517
|
+
if (entry.exit) {
|
|
2518
|
+
visiting.delete(entry.value);
|
|
2519
|
+
visited.add(entry.value);
|
|
2520
|
+
continue;
|
|
2521
|
+
}
|
|
2522
|
+
if (visited.has(entry.value)) {
|
|
2523
|
+
continue;
|
|
2524
|
+
}
|
|
2525
|
+
if (visiting.has(entry.value)) {
|
|
2526
|
+
const error = new ValidationError("Cyclic schema graph is not supported");
|
|
2527
|
+
error.code = "CYCLIC_SCHEMA_GRAPH";
|
|
2528
|
+
error.keyword = "compile";
|
|
2529
|
+
throw error;
|
|
2530
|
+
}
|
|
2531
|
+
if (entry.depth > MAX_COMPILE_DEPTH) {
|
|
2532
|
+
const error = new ValidationError("Maximum compile depth exceeded");
|
|
2533
|
+
error.code = "MAX_COMPILE_DEPTH_EXCEEDED";
|
|
2534
|
+
error.keyword = "compile";
|
|
2535
|
+
throw error;
|
|
2536
|
+
}
|
|
2537
|
+
if (entry.depth > this.maxDepth) {
|
|
2538
|
+
requiresDepthGuard = true;
|
|
2539
|
+
}
|
|
2540
|
+
visiting.add(entry.value);
|
|
2541
|
+
stack.push({ ...entry, exit: true });
|
|
2542
|
+
if (this.useDefaults !== false && this.hasPropertyDefaults(entry.value)) {
|
|
2543
|
+
requiresMutationJournal = true;
|
|
2544
|
+
}
|
|
2545
|
+
for (const key of Object.keys(entry.value)) {
|
|
2546
|
+
const keyword = this.getKeyword(key);
|
|
2547
|
+
if (keyword && keyword !== keywords[key]) {
|
|
2548
|
+
requiresDepthGuard = true;
|
|
2549
|
+
requiresMutationJournal = true;
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
const children = this.schemaChildren(entry.value);
|
|
2553
|
+
for (let index = children.length - 1; index >= 0; index--) {
|
|
2554
|
+
stack.push({
|
|
2555
|
+
value: children[index],
|
|
2556
|
+
depth: entry.depth + 1,
|
|
2557
|
+
exit: false
|
|
2558
|
+
});
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
2561
|
+
const semanticState = /* @__PURE__ */ new WeakMap();
|
|
2562
|
+
const semanticStack = [{ value: schema, exit: false }];
|
|
2563
|
+
while (semanticStack.length > 0 && !requiresDepthGuard) {
|
|
2564
|
+
const entry = semanticStack.pop();
|
|
2565
|
+
if (entry.exit) {
|
|
2566
|
+
semanticState.set(entry.value, 2);
|
|
2567
|
+
continue;
|
|
2568
|
+
}
|
|
2569
|
+
const state = semanticState.get(entry.value);
|
|
2570
|
+
if (state === 1) {
|
|
2571
|
+
requiresDepthGuard = true;
|
|
2572
|
+
break;
|
|
2573
|
+
}
|
|
2574
|
+
if (state === 2) {
|
|
2575
|
+
continue;
|
|
2576
|
+
}
|
|
2577
|
+
semanticState.set(entry.value, 1);
|
|
2578
|
+
semanticStack.push({ value: entry.value, exit: true });
|
|
2579
|
+
const children = this.schemaChildren(entry.value);
|
|
2580
|
+
if (typeof entry.value.$ref === "string" && this.getKeyword("$ref") === keywords.$ref) {
|
|
2581
|
+
const position = registry.positionsByNode.get(entry.value);
|
|
2582
|
+
const target = position ? this.resolveReferenceSource(entry.value.$ref, position, registry) : void 0;
|
|
2583
|
+
if (target && typeof target === "object") {
|
|
2584
|
+
children.push(target);
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2587
|
+
for (let index = children.length - 1; index >= 0; index--) {
|
|
2588
|
+
semanticStack.push({
|
|
2589
|
+
value: children[index],
|
|
2590
|
+
exit: false
|
|
2591
|
+
});
|
|
2592
|
+
}
|
|
2593
|
+
}
|
|
2594
|
+
const mutableSchemas = /* @__PURE__ */ new WeakSet();
|
|
2595
|
+
if (requiresMutationJournal) {
|
|
2596
|
+
const mutationStack = [{ value: schema, exit: false }];
|
|
2597
|
+
const mutationVisited = /* @__PURE__ */ new WeakSet();
|
|
2598
|
+
while (mutationStack.length > 0) {
|
|
2599
|
+
const entry = mutationStack.pop();
|
|
2600
|
+
if (entry.exit) {
|
|
2601
|
+
const children2 = this.schemaChildren(entry.value);
|
|
2602
|
+
const hasCustomKeyword = Object.keys(entry.value).some((key) => {
|
|
2603
|
+
const keyword = this.getKeyword(key);
|
|
2604
|
+
return !!keyword && keyword !== keywords[key];
|
|
2605
|
+
});
|
|
2606
|
+
if (this.useDefaults !== false && this.hasPropertyDefaults(entry.value) || hasCustomKeyword || typeof entry.value.$ref === "string" || children2.some((child) => mutableSchemas.has(child))) {
|
|
2607
|
+
mutableSchemas.add(entry.value);
|
|
2608
|
+
}
|
|
2609
|
+
continue;
|
|
2610
|
+
}
|
|
2611
|
+
if (mutationVisited.has(entry.value)) {
|
|
2612
|
+
continue;
|
|
2613
|
+
}
|
|
2614
|
+
mutationVisited.add(entry.value);
|
|
2615
|
+
mutationStack.push({ value: entry.value, exit: true });
|
|
2616
|
+
const children = this.schemaChildren(entry.value);
|
|
2617
|
+
for (let index = children.length - 1; index >= 0; index--) {
|
|
2618
|
+
mutationStack.push({
|
|
2619
|
+
value: children[index],
|
|
2620
|
+
exit: false
|
|
2621
|
+
});
|
|
2622
|
+
}
|
|
2623
|
+
}
|
|
2624
|
+
}
|
|
2625
|
+
return { requiresDepthGuard, requiresMutationJournal, mutableSchemas };
|
|
2027
2626
|
}
|
|
2028
2627
|
compile(schema) {
|
|
2029
|
-
this.
|
|
2628
|
+
const prepared = this.prepareSchema(schema);
|
|
2629
|
+
const compiledSchema = prepared.compiledSchema;
|
|
2630
|
+
if (!prepared.requiresDepthGuard && !prepared.requiresMutationJournal) {
|
|
2631
|
+
const directValidate = compiledSchema.$validate;
|
|
2632
|
+
const validate = this.immutable ? (data) => {
|
|
2633
|
+
const clonedData = deepCloneUnfreeze(data);
|
|
2634
|
+
const error = directValidate(clonedData);
|
|
2635
|
+
return error ? { data: clonedData, error, valid: false } : { data: clonedData, error: null, valid: true };
|
|
2636
|
+
} : (data) => {
|
|
2637
|
+
const error = directValidate(data);
|
|
2638
|
+
return error ? { data, error, valid: false } : { data, error: null, valid: true };
|
|
2639
|
+
};
|
|
2640
|
+
validate.compiledSchema = compiledSchema;
|
|
2641
|
+
return validate;
|
|
2642
|
+
}
|
|
2643
|
+
return this.createGuardedValidator(compiledSchema, prepared.depthGuardState);
|
|
2644
|
+
}
|
|
2645
|
+
prepareSchema(schema) {
|
|
2646
|
+
const referenceRegistry = this.buildReferenceRegistry(schema);
|
|
2647
|
+
const analysis = this.analyzeSchema(schema, referenceRegistry);
|
|
2648
|
+
this.compileCache = /* @__PURE__ */ new WeakMap();
|
|
2649
|
+
this.compilingRequiresContext = analysis.requiresDepthGuard || analysis.requiresMutationJournal;
|
|
2650
|
+
this.compilingMutableSchemas = analysis.mutableSchemas;
|
|
2030
2651
|
const compiledSchema = this.compileSchema(schema);
|
|
2031
2652
|
this.rootSchema = compiledSchema;
|
|
2653
|
+
let depthGuardState = null;
|
|
2654
|
+
if (analysis.requiresDepthGuard) {
|
|
2655
|
+
depthGuardState = this.installDepthGuards(compiledSchema);
|
|
2656
|
+
definePropertyOrThrow(compiledSchema, "_requiresDepthGuard", {
|
|
2657
|
+
value: true,
|
|
2658
|
+
enumerable: false,
|
|
2659
|
+
configurable: false,
|
|
2660
|
+
writable: false
|
|
2661
|
+
});
|
|
2662
|
+
} else if (analysis.requiresMutationJournal) {
|
|
2663
|
+
depthGuardState = { context: null };
|
|
2664
|
+
}
|
|
2032
2665
|
if (compiledSchema._hasRef === true) {
|
|
2033
|
-
this.linkReferences(
|
|
2666
|
+
this.linkReferences(referenceRegistry);
|
|
2034
2667
|
}
|
|
2035
2668
|
if (!compiledSchema.$validate) {
|
|
2036
2669
|
if (schema === false) {
|
|
@@ -2059,14 +2692,53 @@ var SchemaShield = class {
|
|
|
2059
2692
|
);
|
|
2060
2693
|
}
|
|
2061
2694
|
}
|
|
2695
|
+
return {
|
|
2696
|
+
compiledSchema,
|
|
2697
|
+
requiresDepthGuard: analysis.requiresDepthGuard,
|
|
2698
|
+
requiresMutationJournal: analysis.requiresMutationJournal,
|
|
2699
|
+
depthGuardState
|
|
2700
|
+
};
|
|
2701
|
+
}
|
|
2702
|
+
createGuardedValidator(compiledSchema, depthGuardState) {
|
|
2703
|
+
const reusableContext = {
|
|
2704
|
+
active: false,
|
|
2705
|
+
depth: -1,
|
|
2706
|
+
depthExceeded: false,
|
|
2707
|
+
defaults: []
|
|
2708
|
+
};
|
|
2062
2709
|
const validate = (data) => {
|
|
2063
2710
|
this.rootSchema = compiledSchema;
|
|
2064
|
-
const
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2711
|
+
const context = reusableContext.active ? {
|
|
2712
|
+
active: false,
|
|
2713
|
+
depth: -1,
|
|
2714
|
+
depthExceeded: false,
|
|
2715
|
+
defaults: []
|
|
2716
|
+
} : reusableContext;
|
|
2717
|
+
context.active = true;
|
|
2718
|
+
context.depth = -1;
|
|
2719
|
+
context.depthExceeded = false;
|
|
2720
|
+
delete context.depthError;
|
|
2721
|
+
context.defaults.length = 0;
|
|
2722
|
+
this.validationContexts.push(context);
|
|
2723
|
+
const priorContext = depthGuardState.context;
|
|
2724
|
+
depthGuardState.context = context;
|
|
2725
|
+
let clonedData = data;
|
|
2726
|
+
try {
|
|
2727
|
+
clonedData = this.immutable ? deepCloneUnfreeze(data) : data;
|
|
2728
|
+
let error = compiledSchema.$validate(clonedData);
|
|
2729
|
+
if (this.isDepthError(error)) {
|
|
2730
|
+
this.rollbackDefaults(context, 0);
|
|
2731
|
+
error = context.depthError || this.depthError();
|
|
2732
|
+
}
|
|
2733
|
+
return error ? { data: clonedData, error, valid: false } : { data: clonedData, error: null, valid: true };
|
|
2734
|
+
} catch (error) {
|
|
2735
|
+
this.rollbackDefaults(context, 0);
|
|
2736
|
+
throw error;
|
|
2737
|
+
} finally {
|
|
2738
|
+
depthGuardState.context = priorContext;
|
|
2739
|
+
this.validationContexts.pop();
|
|
2740
|
+
context.active = false;
|
|
2068
2741
|
}
|
|
2069
|
-
return { data: clonedData, error: null, valid: true };
|
|
2070
2742
|
};
|
|
2071
2743
|
validate.compiledSchema = compiledSchema;
|
|
2072
2744
|
return validate;
|
|
@@ -2169,7 +2841,7 @@ var SchemaShield = class {
|
|
|
2169
2841
|
if (schema._hasRef === true) {
|
|
2170
2842
|
return;
|
|
2171
2843
|
}
|
|
2172
|
-
|
|
2844
|
+
definePropertyOrThrow(schema, "_hasRef", {
|
|
2173
2845
|
value: true,
|
|
2174
2846
|
enumerable: false,
|
|
2175
2847
|
configurable: false,
|
|
@@ -2227,15 +2899,15 @@ var SchemaShield = class {
|
|
|
2227
2899
|
return false;
|
|
2228
2900
|
}
|
|
2229
2901
|
}
|
|
2230
|
-
|
|
2902
|
+
hasPropertyDefaults(schema) {
|
|
2231
2903
|
const properties = schema.properties;
|
|
2232
2904
|
if (!this.isPlainObject(properties)) {
|
|
2233
2905
|
return false;
|
|
2234
2906
|
}
|
|
2235
|
-
const
|
|
2236
|
-
for (let i = 0; i <
|
|
2237
|
-
const subSchema = properties[
|
|
2238
|
-
if (this.isPlainObject(subSchema) && "default"
|
|
2907
|
+
const propertyKeys = Object.keys(properties);
|
|
2908
|
+
for (let i = 0; i < propertyKeys.length; i++) {
|
|
2909
|
+
const subSchema = properties[propertyKeys[i]];
|
|
2910
|
+
if (this.isPlainObject(subSchema) && hasOwn(subSchema, "default")) {
|
|
2239
2911
|
return true;
|
|
2240
2912
|
}
|
|
2241
2913
|
}
|
|
@@ -2244,24 +2916,134 @@ var SchemaShield = class {
|
|
|
2244
2916
|
isDefaultTypeValidator(type, validator) {
|
|
2245
2917
|
return Types[type] === validator;
|
|
2246
2918
|
}
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
schema = { oneOf: [] };
|
|
2919
|
+
rollbackDefaults(context, start) {
|
|
2920
|
+
for (let index = context.defaults.length - 1; index >= start; index--) {
|
|
2921
|
+
const entry = context.defaults[index];
|
|
2922
|
+
if (entry.descriptor) {
|
|
2923
|
+
definePropertyOrThrow(entry.target, entry.key, entry.descriptor);
|
|
2253
2924
|
} else {
|
|
2254
|
-
|
|
2925
|
+
delete entry.target[entry.key];
|
|
2255
2926
|
}
|
|
2256
2927
|
}
|
|
2928
|
+
context.defaults.length = start;
|
|
2929
|
+
}
|
|
2930
|
+
isDepthError(error) {
|
|
2931
|
+
const context = this.validationContexts[this.validationContexts.length - 1];
|
|
2932
|
+
if (context?.depthExceeded) {
|
|
2933
|
+
return true;
|
|
2934
|
+
}
|
|
2935
|
+
if (!(error instanceof ValidationError)) {
|
|
2936
|
+
return false;
|
|
2937
|
+
}
|
|
2938
|
+
return error.getCause().code === "MAX_DEPTH_EXCEEDED";
|
|
2939
|
+
}
|
|
2940
|
+
validateSubschema(schema, data) {
|
|
2941
|
+
if (!schema || typeof schema.$validate !== "function") {
|
|
2942
|
+
return;
|
|
2943
|
+
}
|
|
2944
|
+
const context = this.validationContexts[this.validationContexts.length - 1];
|
|
2945
|
+
const savepoint = context?.defaults.length || 0;
|
|
2946
|
+
try {
|
|
2947
|
+
const error = schema.$validate(data);
|
|
2948
|
+
if (error && context) {
|
|
2949
|
+
this.rollbackDefaults(context, savepoint);
|
|
2950
|
+
}
|
|
2951
|
+
return error;
|
|
2952
|
+
} catch (error) {
|
|
2953
|
+
if (context) {
|
|
2954
|
+
this.rollbackDefaults(context, savepoint);
|
|
2955
|
+
}
|
|
2956
|
+
throw error;
|
|
2957
|
+
}
|
|
2958
|
+
}
|
|
2959
|
+
installDepthGuards(root) {
|
|
2960
|
+
const state = { context: null };
|
|
2961
|
+
const stack = [root];
|
|
2962
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
2963
|
+
while (stack.length > 0) {
|
|
2964
|
+
const schema = stack.pop();
|
|
2965
|
+
if (!schema || typeof schema !== "object" || seen.has(schema)) {
|
|
2966
|
+
continue;
|
|
2967
|
+
}
|
|
2968
|
+
seen.add(schema);
|
|
2969
|
+
if (typeof schema.$validate === "function") {
|
|
2970
|
+
const directValidate = schema.$validate;
|
|
2971
|
+
schema.$validate = getNamedFunction(directValidate.name, (data) => {
|
|
2972
|
+
const context = state.context;
|
|
2973
|
+
if (!context) {
|
|
2974
|
+
return directValidate(data);
|
|
2975
|
+
}
|
|
2976
|
+
const nextDepth = context.depth + 1;
|
|
2977
|
+
if (nextDepth > this.maxDepth) {
|
|
2978
|
+
context.depthExceeded = true;
|
|
2979
|
+
if (!context.depthError) {
|
|
2980
|
+
context.depthError = this.depthError();
|
|
2981
|
+
}
|
|
2982
|
+
return context.depthError;
|
|
2983
|
+
}
|
|
2984
|
+
context.depth = nextDepth;
|
|
2985
|
+
try {
|
|
2986
|
+
return directValidate(data);
|
|
2987
|
+
} finally {
|
|
2988
|
+
context.depth--;
|
|
2989
|
+
}
|
|
2990
|
+
});
|
|
2991
|
+
}
|
|
2992
|
+
const children = this.schemaChildren(schema);
|
|
2993
|
+
for (const child of children) {
|
|
2994
|
+
stack.push(child);
|
|
2995
|
+
}
|
|
2996
|
+
}
|
|
2997
|
+
return state;
|
|
2998
|
+
}
|
|
2999
|
+
compileSchema(schema) {
|
|
3000
|
+
if (schema === true) {
|
|
3001
|
+
return {
|
|
3002
|
+
$validate: getNamedFunction("Validate_True", () => {
|
|
3003
|
+
})
|
|
3004
|
+
};
|
|
3005
|
+
}
|
|
3006
|
+
if (schema === false) {
|
|
3007
|
+
const compiledFalse = {};
|
|
3008
|
+
const defineError = getDefinedErrorFunctionForKey(
|
|
3009
|
+
"oneOf",
|
|
3010
|
+
compiledFalse,
|
|
3011
|
+
this.failFast
|
|
3012
|
+
);
|
|
3013
|
+
compiledFalse.$validate = getNamedFunction(
|
|
3014
|
+
"Validate_False",
|
|
3015
|
+
(data) => defineError("Value is not valid", { data })
|
|
3016
|
+
);
|
|
3017
|
+
return compiledFalse;
|
|
3018
|
+
}
|
|
3019
|
+
const sourceSchema = schema && typeof schema === "object" && !Array.isArray(schema) ? schema : null;
|
|
3020
|
+
const schemaCanApplyDefaults = sourceSchema !== null && this.compilingMutableSchemas.has(sourceSchema);
|
|
3021
|
+
if (sourceSchema) {
|
|
3022
|
+
const cached = this.compileCache.get(sourceSchema);
|
|
3023
|
+
if (cached) {
|
|
3024
|
+
return cached;
|
|
3025
|
+
}
|
|
3026
|
+
}
|
|
3027
|
+
if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
|
|
3028
|
+
schema = { oneOf: [schema] };
|
|
3029
|
+
}
|
|
2257
3030
|
schema = this.normalizeSchemaForCompile(schema);
|
|
2258
3031
|
const compiledSchema = deepCloneUnfreeze(
|
|
2259
3032
|
schema
|
|
2260
3033
|
);
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
this.idRegistry.set(schema.$id, compiledSchema);
|
|
3034
|
+
if (sourceSchema) {
|
|
3035
|
+
this.compileCache.set(sourceSchema, compiledSchema);
|
|
2264
3036
|
}
|
|
3037
|
+
if (schemaCanApplyDefaults) {
|
|
3038
|
+
definePropertyOrThrow(compiledSchema, "_canApplyDefaults", {
|
|
3039
|
+
value: true,
|
|
3040
|
+
enumerable: false,
|
|
3041
|
+
configurable: false,
|
|
3042
|
+
writable: false
|
|
3043
|
+
});
|
|
3044
|
+
}
|
|
3045
|
+
const validateSubschema = this.compilingRequiresContext ? this.validateSubschema.bind(this) : void 0;
|
|
3046
|
+
let schemaHasRef = false;
|
|
2265
3047
|
if ("$ref" in schema) {
|
|
2266
3048
|
schemaHasRef = true;
|
|
2267
3049
|
const refValidator = this.getKeyword("$ref");
|
|
@@ -2271,21 +3053,53 @@ var SchemaShield = class {
|
|
|
2271
3053
|
schema["$ref"],
|
|
2272
3054
|
this.failFast
|
|
2273
3055
|
);
|
|
3056
|
+
const isBuiltinRef = refValidator === keywords.$ref;
|
|
2274
3057
|
compiledSchema.$validate = getNamedFunction(
|
|
2275
|
-
"Validate_Reference",
|
|
3058
|
+
isBuiltinRef ? "Validate_Reference" : refValidator.name || "$ref",
|
|
2276
3059
|
(data) => refValidator(
|
|
2277
3060
|
compiledSchema,
|
|
2278
3061
|
data,
|
|
2279
3062
|
defineError,
|
|
2280
|
-
this
|
|
3063
|
+
this,
|
|
3064
|
+
validateSubschema
|
|
2281
3065
|
)
|
|
2282
3066
|
);
|
|
3067
|
+
if (!isBuiltinRef) {
|
|
3068
|
+
schemaHasRef = false;
|
|
3069
|
+
}
|
|
3070
|
+
}
|
|
3071
|
+
for (const key of ["definitions", "$defs"]) {
|
|
3072
|
+
const definitions = schema[key];
|
|
3073
|
+
if (!definitions || typeof definitions !== "object") {
|
|
3074
|
+
continue;
|
|
3075
|
+
}
|
|
3076
|
+
const compiledDefinitions = {};
|
|
3077
|
+
for (const definitionKey of Object.keys(definitions)) {
|
|
3078
|
+
compiledDefinitions[definitionKey] = this.compileSchema(
|
|
3079
|
+
definitions[definitionKey]
|
|
3080
|
+
);
|
|
3081
|
+
}
|
|
3082
|
+
compiledSchema[key] = compiledDefinitions;
|
|
3083
|
+
}
|
|
3084
|
+
if (schemaHasRef) {
|
|
3085
|
+
this.markSchemaHasRef(compiledSchema);
|
|
2283
3086
|
}
|
|
2284
|
-
this.markSchemaHasRef(compiledSchema);
|
|
2285
3087
|
return compiledSchema;
|
|
2286
3088
|
}
|
|
2287
3089
|
const validators = [];
|
|
2288
3090
|
const activeNames = [];
|
|
3091
|
+
const pendingCombinators = [];
|
|
3092
|
+
if (this.useDefaults !== false && this.getKeyword("properties") === keywords.properties && this.hasPropertyDefaults(schema)) {
|
|
3093
|
+
const applyDefaults = this.useDefaults === "empty" ? applyEmptyPropertyDefaults : applyPropertyDefaults;
|
|
3094
|
+
validators.push({
|
|
3095
|
+
name: applyDefaults.name,
|
|
3096
|
+
validate: getNamedFunction(
|
|
3097
|
+
applyDefaults.name,
|
|
3098
|
+
(data) => applyDefaults(compiledSchema, data, this)
|
|
3099
|
+
)
|
|
3100
|
+
});
|
|
3101
|
+
activeNames.push(applyDefaults.name);
|
|
3102
|
+
}
|
|
2289
3103
|
if ("type" in schema) {
|
|
2290
3104
|
const defineTypeError = getDefinedErrorFunctionForKey(
|
|
2291
3105
|
"type",
|
|
@@ -2321,65 +3135,11 @@ var SchemaShield = class {
|
|
|
2321
3135
|
if (typeFunctions.length === 1 && allTypesDefault) {
|
|
2322
3136
|
const singleTypeName = defaultTypeNames[0];
|
|
2323
3137
|
typeMethodName = singleTypeName;
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
}
|
|
2330
|
-
};
|
|
2331
|
-
break;
|
|
2332
|
-
case "array":
|
|
2333
|
-
combinedTypeValidator = (data) => {
|
|
2334
|
-
if (!Array.isArray(data)) {
|
|
2335
|
-
return defineTypeError("Invalid type", { data });
|
|
2336
|
-
}
|
|
2337
|
-
};
|
|
2338
|
-
break;
|
|
2339
|
-
case "string":
|
|
2340
|
-
combinedTypeValidator = (data) => {
|
|
2341
|
-
if (typeof data !== "string") {
|
|
2342
|
-
return defineTypeError("Invalid type", { data });
|
|
2343
|
-
}
|
|
2344
|
-
};
|
|
2345
|
-
break;
|
|
2346
|
-
case "number":
|
|
2347
|
-
combinedTypeValidator = (data) => {
|
|
2348
|
-
if (typeof data !== "number") {
|
|
2349
|
-
return defineTypeError("Invalid type", { data });
|
|
2350
|
-
}
|
|
2351
|
-
};
|
|
2352
|
-
break;
|
|
2353
|
-
case "integer":
|
|
2354
|
-
combinedTypeValidator = (data) => {
|
|
2355
|
-
if (typeof data !== "number" || !Number.isInteger(data)) {
|
|
2356
|
-
return defineTypeError("Invalid type", { data });
|
|
2357
|
-
}
|
|
2358
|
-
};
|
|
2359
|
-
break;
|
|
2360
|
-
case "boolean":
|
|
2361
|
-
combinedTypeValidator = (data) => {
|
|
2362
|
-
if (typeof data !== "boolean") {
|
|
2363
|
-
return defineTypeError("Invalid type", { data });
|
|
2364
|
-
}
|
|
2365
|
-
};
|
|
2366
|
-
break;
|
|
2367
|
-
case "null":
|
|
2368
|
-
combinedTypeValidator = (data) => {
|
|
2369
|
-
if (data !== null) {
|
|
2370
|
-
return defineTypeError("Invalid type", { data });
|
|
2371
|
-
}
|
|
2372
|
-
};
|
|
2373
|
-
break;
|
|
2374
|
-
default: {
|
|
2375
|
-
const singleTypeFn = typeFunctions[0];
|
|
2376
|
-
combinedTypeValidator = (data) => {
|
|
2377
|
-
if (!singleTypeFn(data)) {
|
|
2378
|
-
return defineTypeError("Invalid type", { data });
|
|
2379
|
-
}
|
|
2380
|
-
};
|
|
2381
|
-
}
|
|
2382
|
-
}
|
|
3138
|
+
combinedTypeValidator = this.failFast && FAIL_FAST_TYPE_VALIDATORS[singleTypeName] ? FAIL_FAST_TYPE_VALIDATORS[singleTypeName] : createBuiltinTypeValidator(
|
|
3139
|
+
singleTypeName,
|
|
3140
|
+
defineTypeError,
|
|
3141
|
+
typeFunctions[0]
|
|
3142
|
+
);
|
|
2383
3143
|
} else if (typeFunctions.length > 1 && allTypesDefault) {
|
|
2384
3144
|
typeMethodName = defaultTypeNames.join("_OR_");
|
|
2385
3145
|
const allowsObject = defaultTypeNames.includes("object");
|
|
@@ -2392,6 +3152,9 @@ var SchemaShield = class {
|
|
|
2392
3152
|
combinedTypeValidator = (data) => {
|
|
2393
3153
|
const dataType = typeof data;
|
|
2394
3154
|
if (dataType === "number") {
|
|
3155
|
+
if (!Number.isFinite(data)) {
|
|
3156
|
+
return defineTypeError("Invalid type", { data });
|
|
3157
|
+
}
|
|
2395
3158
|
if (allowsNumber || allowsInteger && Number.isInteger(data)) {
|
|
2396
3159
|
return;
|
|
2397
3160
|
}
|
|
@@ -2455,7 +3218,8 @@ var SchemaShield = class {
|
|
|
2455
3218
|
activeNames.push(typeMethodName);
|
|
2456
3219
|
}
|
|
2457
3220
|
const { type, $id, $ref, $validate, required, ...otherKeys } = schema;
|
|
2458
|
-
const
|
|
3221
|
+
const otherKeyNames = Object.keys(otherKeys);
|
|
3222
|
+
const keyOrder = required ? ["required", ...otherKeyNames] : otherKeyNames;
|
|
2459
3223
|
for (const key of keyOrder) {
|
|
2460
3224
|
const keywordFn = this.getKeyword(key);
|
|
2461
3225
|
if (!keywordFn) {
|
|
@@ -2470,12 +3234,33 @@ var SchemaShield = class {
|
|
|
2470
3234
|
this.failFast
|
|
2471
3235
|
);
|
|
2472
3236
|
const fnName = keywordFn.name || key;
|
|
3237
|
+
if ((key === "allOf" || key === "anyOf" || key === "oneOf") && keywordFn === keywords[key]) {
|
|
3238
|
+
const item = {
|
|
3239
|
+
name: fnName,
|
|
3240
|
+
validate: () => {
|
|
3241
|
+
throw new ValidationError("Combinator validator was not prepared");
|
|
3242
|
+
}
|
|
3243
|
+
};
|
|
3244
|
+
validators.push(item);
|
|
3245
|
+
pendingCombinators.push({ item, key, defineError });
|
|
3246
|
+
activeNames.push(fnName);
|
|
3247
|
+
continue;
|
|
3248
|
+
}
|
|
3249
|
+
const keywordValidate = validateSubschema ? (data) => keywordFn(
|
|
3250
|
+
compiledSchema,
|
|
3251
|
+
data,
|
|
3252
|
+
defineError,
|
|
3253
|
+
this,
|
|
3254
|
+
validateSubschema
|
|
3255
|
+
) : (data) => keywordFn(
|
|
3256
|
+
compiledSchema,
|
|
3257
|
+
data,
|
|
3258
|
+
defineError,
|
|
3259
|
+
this
|
|
3260
|
+
);
|
|
2473
3261
|
validators.push({
|
|
2474
3262
|
name: fnName,
|
|
2475
|
-
validate: getNamedFunction(
|
|
2476
|
-
fnName,
|
|
2477
|
-
(data) => keywordFn(compiledSchema, data, defineError, this)
|
|
2478
|
-
)
|
|
3263
|
+
validate: getNamedFunction(fnName, keywordValidate)
|
|
2479
3264
|
});
|
|
2480
3265
|
activeNames.push(fnName);
|
|
2481
3266
|
}
|
|
@@ -2517,6 +3302,50 @@ var SchemaShield = class {
|
|
|
2517
3302
|
continue;
|
|
2518
3303
|
}
|
|
2519
3304
|
}
|
|
3305
|
+
if (this.isPlainObject(schema.properties)) {
|
|
3306
|
+
definePropertyOrThrow(compiledSchema, "_propKeys", {
|
|
3307
|
+
value: Object.keys(schema.properties),
|
|
3308
|
+
enumerable: false,
|
|
3309
|
+
configurable: false,
|
|
3310
|
+
writable: false
|
|
3311
|
+
});
|
|
3312
|
+
}
|
|
3313
|
+
if (this.useDefaults !== false && this.isPlainObject(schema.properties) && this.hasPropertyDefaults(schema)) {
|
|
3314
|
+
const defaultKeys = Object.keys(schema.properties).filter(
|
|
3315
|
+
(key) => {
|
|
3316
|
+
const property = schema.properties[key];
|
|
3317
|
+
return property && typeof property === "object" && !Array.isArray(property) && hasOwn(property, "default");
|
|
3318
|
+
}
|
|
3319
|
+
);
|
|
3320
|
+
if (defaultKeys.length > 0) {
|
|
3321
|
+
definePropertyOrThrow(compiledSchema, "_defaultKeys", {
|
|
3322
|
+
value: defaultKeys,
|
|
3323
|
+
enumerable: false,
|
|
3324
|
+
configurable: false,
|
|
3325
|
+
writable: false
|
|
3326
|
+
});
|
|
3327
|
+
}
|
|
3328
|
+
}
|
|
3329
|
+
prepareCombinatorEntries(compiledSchema);
|
|
3330
|
+
for (let index = 0; index < pendingCombinators.length; index++) {
|
|
3331
|
+
const pending = pendingCombinators[index];
|
|
3332
|
+
const transactions = compiledSchema._canApplyDefaults === true ? {
|
|
3333
|
+
savepoint: () => this.#defaultSavepoint(),
|
|
3334
|
+
rollback: (savepoint) => this.#rollbackDefaultSavepoint(savepoint),
|
|
3335
|
+
capture: (savepoint) => this.#captureDefaultSavepoint(savepoint),
|
|
3336
|
+
restore: (mutations) => this.#restoreDefaults(mutations)
|
|
3337
|
+
} : void 0;
|
|
3338
|
+
pending.item.validate = getNamedFunction(
|
|
3339
|
+
pending.item.name,
|
|
3340
|
+
createCombinatorValidator(
|
|
3341
|
+
pending.key,
|
|
3342
|
+
compiledSchema,
|
|
3343
|
+
pending.defineError,
|
|
3344
|
+
validateSubschema,
|
|
3345
|
+
transactions
|
|
3346
|
+
)
|
|
3347
|
+
);
|
|
3348
|
+
}
|
|
2520
3349
|
if (schemaHasRef) {
|
|
2521
3350
|
this.markSchemaHasRef(compiledSchema);
|
|
2522
3351
|
}
|
|
@@ -2558,54 +3387,80 @@ var SchemaShield = class {
|
|
|
2558
3387
|
}
|
|
2559
3388
|
return false;
|
|
2560
3389
|
}
|
|
2561
|
-
|
|
2562
|
-
const
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
3390
|
+
getCompiledReferenceTarget(ref, position, registry) {
|
|
3391
|
+
const resolvedUri = this.resolveUri(ref, position.baseUri, "$ref");
|
|
3392
|
+
const exactTarget = registry.aliases.get(resolvedUri);
|
|
3393
|
+
if (exactTarget) {
|
|
3394
|
+
return this.compileCache.get(exactTarget);
|
|
3395
|
+
}
|
|
3396
|
+
const resourceRoot = registry.aliases.get(this.resourceUri(resolvedUri));
|
|
3397
|
+
if (!resourceRoot) {
|
|
3398
|
+
return;
|
|
3399
|
+
}
|
|
3400
|
+
const compiledResource = this.compileCache.get(resourceRoot);
|
|
3401
|
+
if (!compiledResource) {
|
|
3402
|
+
return;
|
|
3403
|
+
}
|
|
3404
|
+
const hashIndex = resolvedUri.indexOf("#");
|
|
3405
|
+
const fragment = hashIndex === -1 ? "" : resolvedUri.slice(hashIndex + 1);
|
|
3406
|
+
if (fragment.length === 0) {
|
|
3407
|
+
return compiledResource;
|
|
3408
|
+
}
|
|
3409
|
+
if (fragment.startsWith("/")) {
|
|
3410
|
+
return resolvePath(compiledResource, `#${fragment}`);
|
|
3411
|
+
}
|
|
3412
|
+
return;
|
|
3413
|
+
}
|
|
3414
|
+
linkReferences(registry) {
|
|
3415
|
+
for (let index = 0; index < registry.positions.length; index++) {
|
|
3416
|
+
const position = registry.positions[index];
|
|
3417
|
+
if (typeof position.source.$ref !== "string" || this.getKeyword("$ref") !== keywords.$ref) {
|
|
2566
3418
|
continue;
|
|
2567
|
-
if (typeof node.$ref === "string" && typeof node.$validate === "function" && node.$validate.name === "Validate_Reference") {
|
|
2568
|
-
const refPath = node.$ref;
|
|
2569
|
-
let target = this.getSchemaRef(refPath);
|
|
2570
|
-
if (typeof target === "undefined") {
|
|
2571
|
-
target = this.getSchemaById(refPath);
|
|
2572
|
-
}
|
|
2573
|
-
if (typeof target === "boolean") {
|
|
2574
|
-
if (target === true) {
|
|
2575
|
-
node.$validate = getNamedFunction("Validate_Ref_True", () => {
|
|
2576
|
-
});
|
|
2577
|
-
} else {
|
|
2578
|
-
const defineError = getDefinedErrorFunctionForKey(
|
|
2579
|
-
"$ref",
|
|
2580
|
-
node,
|
|
2581
|
-
this.failFast
|
|
2582
|
-
);
|
|
2583
|
-
node.$validate = getNamedFunction(
|
|
2584
|
-
"Validate_Ref_False",
|
|
2585
|
-
(_data) => defineError("Value is not valid")
|
|
2586
|
-
);
|
|
2587
|
-
}
|
|
2588
|
-
continue;
|
|
2589
|
-
}
|
|
2590
|
-
if (target && typeof target.$validate === "function") {
|
|
2591
|
-
node.$validate = target.$validate;
|
|
2592
|
-
}
|
|
2593
3419
|
}
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
3420
|
+
const node = this.compileCache.get(position.source);
|
|
3421
|
+
const target = this.getCompiledReferenceTarget(
|
|
3422
|
+
position.source.$ref,
|
|
3423
|
+
position,
|
|
3424
|
+
registry
|
|
3425
|
+
);
|
|
3426
|
+
if (!node || typeof target === "undefined") {
|
|
3427
|
+
const error = new ValidationError(
|
|
3428
|
+
`Reference not found: ${position.source.$ref}`
|
|
3429
|
+
);
|
|
3430
|
+
error.code = "REFERENCE_NOT_FOUND";
|
|
3431
|
+
error.keyword = "$ref";
|
|
3432
|
+
throw error;
|
|
3433
|
+
}
|
|
3434
|
+
let targetValidate;
|
|
3435
|
+
if (target === true) {
|
|
3436
|
+
targetValidate = getNamedFunction("Validate_Ref_True", () => {
|
|
3437
|
+
});
|
|
3438
|
+
} else if (target === false) {
|
|
3439
|
+
const defineError = getDefinedErrorFunctionForKey(
|
|
3440
|
+
"$ref",
|
|
3441
|
+
node,
|
|
3442
|
+
this.failFast
|
|
3443
|
+
);
|
|
3444
|
+
targetValidate = getNamedFunction(
|
|
3445
|
+
"Validate_Ref_False",
|
|
3446
|
+
(data) => defineError("Value is not valid", { data })
|
|
3447
|
+
);
|
|
3448
|
+
} else {
|
|
3449
|
+
if (typeof target.$validate !== "function") {
|
|
3450
|
+
target.$validate = getNamedFunction(
|
|
3451
|
+
"Validate_Ref_Any",
|
|
3452
|
+
() => {
|
|
2603
3453
|
}
|
|
2604
|
-
|
|
2605
|
-
} else if (typeof value === "object") {
|
|
2606
|
-
stack.push(value);
|
|
3454
|
+
);
|
|
2607
3455
|
}
|
|
3456
|
+
targetValidate = target.$validate;
|
|
2608
3457
|
}
|
|
3458
|
+
definePropertyOrThrow(node, "_resolvedRef", {
|
|
3459
|
+
value: targetValidate,
|
|
3460
|
+
enumerable: false,
|
|
3461
|
+
configurable: false,
|
|
3462
|
+
writable: false
|
|
3463
|
+
});
|
|
2609
3464
|
}
|
|
2610
3465
|
}
|
|
2611
3466
|
};
|