schema-shield 1.0.4 → 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 +419 -919
- 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 +1250 -391
- package/dist/index.min.js +2 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.mjs +1250 -391
- 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 +8 -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 +97 -42
- package/package.json +9 -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;
|
|
@@ -8,42 +22,61 @@ var ValidationError = class extends Error {
|
|
|
8
22
|
instancePath = "";
|
|
9
23
|
data;
|
|
10
24
|
schema;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (typeof this.item !== "undefined") {
|
|
15
|
-
if (typeof this.item === "string" && this.item in this.schema) {
|
|
16
|
-
schemaPath += `/${this.item}`;
|
|
17
|
-
}
|
|
18
|
-
instancePath += `/${this.item}`;
|
|
19
|
-
}
|
|
20
|
-
this.instancePath = instancePath;
|
|
21
|
-
this.schemaPath = schemaPath;
|
|
22
|
-
if (!this.cause || !(this.cause instanceof ValidationError)) {
|
|
23
|
-
return this;
|
|
24
|
-
}
|
|
25
|
-
return this.cause._getCause(schemaPath, instancePath);
|
|
25
|
+
constructor(message) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.message = message;
|
|
26
28
|
}
|
|
27
29
|
getCause() {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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;
|
|
41
52
|
}
|
|
42
|
-
return
|
|
53
|
+
return current;
|
|
43
54
|
}
|
|
44
55
|
getTree() {
|
|
45
56
|
this.getCause();
|
|
46
|
-
|
|
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;
|
|
47
80
|
}
|
|
48
81
|
getPath() {
|
|
49
82
|
const cause = this.getCause();
|
|
@@ -63,8 +96,11 @@ function getDefinedErrorFunctionForKey(key, schema, failFast) {
|
|
|
63
96
|
KeywordError.schema = schema;
|
|
64
97
|
const defineError = (message, options = {}) => {
|
|
65
98
|
KeywordError.message = message;
|
|
99
|
+
KeywordError.code = options.code;
|
|
66
100
|
KeywordError.item = options.item;
|
|
67
|
-
|
|
101
|
+
if (options.cause !== KeywordError) {
|
|
102
|
+
KeywordError.cause = options.cause && options.cause !== true ? options.cause : void 0;
|
|
103
|
+
}
|
|
68
104
|
KeywordError.data = options.data;
|
|
69
105
|
return KeywordError;
|
|
70
106
|
};
|
|
@@ -73,11 +109,14 @@ function getDefinedErrorFunctionForKey(key, schema, failFast) {
|
|
|
73
109
|
defineError
|
|
74
110
|
);
|
|
75
111
|
}
|
|
112
|
+
function escapeJsonPointerToken(value) {
|
|
113
|
+
return String(value).replace(/~/g, "~0").replace(/\//g, "~1");
|
|
114
|
+
}
|
|
76
115
|
function isCompiledSchema(subSchema) {
|
|
77
116
|
return !!subSchema && typeof subSchema === "object" && !Array.isArray(subSchema) && "$validate" in subSchema;
|
|
78
117
|
}
|
|
79
118
|
function getNamedFunction(name, fn) {
|
|
80
|
-
return
|
|
119
|
+
return definePropertyOrThrow(fn, "name", { value: name });
|
|
81
120
|
}
|
|
82
121
|
function resolvePath(root, path) {
|
|
83
122
|
if (!path || path === "#") {
|
|
@@ -122,7 +161,6 @@ var DURATION_REGEX = /^P(?!$)((\d+Y)?(\d+M)?(\d+W)?(\d+D)?)(T(?=\d)(\d+H)?(\d+M)
|
|
|
122
161
|
var URI_REGEX = /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/;
|
|
123
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;
|
|
124
163
|
var HOSTNAME_REGEX = /^[a-z0-9][a-z0-9-]{0,62}(?:\.[a-z0-9][a-z0-9-]{0,62})*[a-z0-9]$/i;
|
|
125
|
-
var DATE_REGEX = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
126
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))$/;
|
|
127
165
|
var URI_REFERENCE_REGEX = /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#((?![^#]*\\)[^#]*))?/i;
|
|
128
166
|
var IRI_REGEX = /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/;
|
|
@@ -187,6 +225,22 @@ function isValidIpv4(data) {
|
|
|
187
225
|
function isHexCharCode(code) {
|
|
188
226
|
return code >= 48 && code <= 57 || code >= 65 && code <= 70 || code >= 97 && code <= 102;
|
|
189
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
|
+
}
|
|
190
244
|
function isValidIpv6(data) {
|
|
191
245
|
const length = data.length;
|
|
192
246
|
if (length === 0) {
|
|
@@ -291,7 +345,7 @@ function isValidJsonPointer(data) {
|
|
|
291
345
|
}
|
|
292
346
|
function isValidRelativeJsonPointer(data) {
|
|
293
347
|
if (data.length === 0) {
|
|
294
|
-
return
|
|
348
|
+
return false;
|
|
295
349
|
}
|
|
296
350
|
let i = 0;
|
|
297
351
|
while (i < data.length) {
|
|
@@ -304,6 +358,9 @@ function isValidRelativeJsonPointer(data) {
|
|
|
304
358
|
if (i === 0) {
|
|
305
359
|
return false;
|
|
306
360
|
}
|
|
361
|
+
if (i > 1 && data.charCodeAt(0) === 48) {
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
307
364
|
if (i === data.length) {
|
|
308
365
|
return true;
|
|
309
366
|
}
|
|
@@ -430,7 +487,7 @@ var Formats = {
|
|
|
430
487
|
return true;
|
|
431
488
|
},
|
|
432
489
|
uri(data) {
|
|
433
|
-
return URI_REGEX.test(data);
|
|
490
|
+
return URI_REGEX.test(data) && hasValidPercentEncoding(data);
|
|
434
491
|
},
|
|
435
492
|
email(data) {
|
|
436
493
|
return EMAIL_REGEX.test(data);
|
|
@@ -445,15 +502,13 @@ var Formats = {
|
|
|
445
502
|
return HOSTNAME_REGEX.test(data);
|
|
446
503
|
},
|
|
447
504
|
date(data) {
|
|
448
|
-
|
|
449
|
-
if (!match) {
|
|
505
|
+
if (data.length !== 10 || data.charCodeAt(4) !== 45 || data.charCodeAt(7) !== 45) {
|
|
450
506
|
return false;
|
|
451
507
|
}
|
|
452
|
-
const
|
|
453
|
-
const
|
|
454
|
-
const
|
|
455
|
-
|
|
456
|
-
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) {
|
|
457
512
|
return false;
|
|
458
513
|
}
|
|
459
514
|
if (day < 1) {
|
|
@@ -525,10 +580,10 @@ var Types = {
|
|
|
525
580
|
return typeof data === "string";
|
|
526
581
|
},
|
|
527
582
|
number(data) {
|
|
528
|
-
return typeof data === "number";
|
|
583
|
+
return typeof data === "number" && Number.isFinite(data);
|
|
529
584
|
},
|
|
530
585
|
integer(data) {
|
|
531
|
-
return typeof data === "number" && data % 1 === 0;
|
|
586
|
+
return typeof data === "number" && Number.isFinite(data) && data % 1 === 0;
|
|
532
587
|
},
|
|
533
588
|
boolean(data) {
|
|
534
589
|
return typeof data === "boolean";
|
|
@@ -753,7 +808,7 @@ var ArrayKeywords = {
|
|
|
753
808
|
let tupleLength = schema._tupleItemsLength;
|
|
754
809
|
if (tupleLength === void 0) {
|
|
755
810
|
tupleLength = schema.items.length;
|
|
756
|
-
|
|
811
|
+
definePropertyOrThrow(schema, "_tupleItemsLength", {
|
|
757
812
|
value: tupleLength,
|
|
758
813
|
enumerable: false,
|
|
759
814
|
configurable: false,
|
|
@@ -810,13 +865,23 @@ var ArrayKeywords = {
|
|
|
810
865
|
}
|
|
811
866
|
return;
|
|
812
867
|
}
|
|
813
|
-
|
|
868
|
+
let hasFirstPrimitive = false;
|
|
869
|
+
let firstPrimitive;
|
|
870
|
+
let primitiveSeen;
|
|
814
871
|
let primitiveArraySignatures;
|
|
815
872
|
let arrayBuckets;
|
|
816
873
|
let objectBuckets;
|
|
817
874
|
for (let i = 0; i < len; i++) {
|
|
818
875
|
const item = data[i];
|
|
819
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
|
+
}
|
|
820
885
|
if (primitiveSeen.has(item)) {
|
|
821
886
|
return defineError("Array items are not unique", { data: item });
|
|
822
887
|
}
|
|
@@ -902,7 +967,7 @@ function isPlainObject(value) {
|
|
|
902
967
|
if (!value || typeof value !== "object") {
|
|
903
968
|
return false;
|
|
904
969
|
}
|
|
905
|
-
const proto =
|
|
970
|
+
const proto = Reflect.getPrototypeOf(value);
|
|
906
971
|
return proto === Object.prototype || proto === null;
|
|
907
972
|
}
|
|
908
973
|
function canUseStructuredClone(value) {
|
|
@@ -997,7 +1062,7 @@ function deepCloneUnfreeze(obj, cloneClassInstances = false, seen = /* @__PURE__
|
|
|
997
1062
|
seen.set(source, clone);
|
|
998
1063
|
return clone;
|
|
999
1064
|
}
|
|
1000
|
-
clone = Object.create(
|
|
1065
|
+
clone = Object.create(Reflect.getPrototypeOf(source));
|
|
1001
1066
|
seen.set(source, clone);
|
|
1002
1067
|
break;
|
|
1003
1068
|
}
|
|
@@ -1026,7 +1091,7 @@ function deepCloneUnfreeze(obj, cloneClassInstances = false, seen = /* @__PURE__
|
|
|
1026
1091
|
seen
|
|
1027
1092
|
);
|
|
1028
1093
|
}
|
|
1029
|
-
|
|
1094
|
+
definePropertyOrThrow(clone, key, descriptor);
|
|
1030
1095
|
}
|
|
1031
1096
|
return clone;
|
|
1032
1097
|
}
|
|
@@ -1037,6 +1102,9 @@ var NumberKeywords = {
|
|
|
1037
1102
|
if (typeof data !== "number") {
|
|
1038
1103
|
return;
|
|
1039
1104
|
}
|
|
1105
|
+
if (!Number.isFinite(data)) {
|
|
1106
|
+
return defineError("Value must be finite", { data });
|
|
1107
|
+
}
|
|
1040
1108
|
let min = schema.minimum;
|
|
1041
1109
|
if (typeof schema.exclusiveMinimum === "number") {
|
|
1042
1110
|
min = schema.exclusiveMinimum + 1e-15;
|
|
@@ -1052,6 +1120,9 @@ var NumberKeywords = {
|
|
|
1052
1120
|
if (typeof data !== "number") {
|
|
1053
1121
|
return;
|
|
1054
1122
|
}
|
|
1123
|
+
if (!Number.isFinite(data)) {
|
|
1124
|
+
return defineError("Value must be finite", { data });
|
|
1125
|
+
}
|
|
1055
1126
|
let max = schema.maximum;
|
|
1056
1127
|
if (typeof schema.exclusiveMaximum === "number") {
|
|
1057
1128
|
max = schema.exclusiveMaximum - 1e-15;
|
|
@@ -1067,11 +1138,14 @@ var NumberKeywords = {
|
|
|
1067
1138
|
if (typeof data !== "number") {
|
|
1068
1139
|
return;
|
|
1069
1140
|
}
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
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
|
+
});
|
|
1073
1145
|
}
|
|
1074
|
-
|
|
1146
|
+
const quotient = data / schema.multipleOf;
|
|
1147
|
+
const valid = Number.isFinite(quotient) ? areCloseEnough(quotient, Math.round(quotient)) : data % schema.multipleOf === 0;
|
|
1148
|
+
if (!valid) {
|
|
1075
1149
|
return defineError("Value is not a multiple of the multipleOf", { data });
|
|
1076
1150
|
}
|
|
1077
1151
|
return;
|
|
@@ -1160,6 +1234,29 @@ function compilePatternMatcher(pattern) {
|
|
|
1160
1234
|
|
|
1161
1235
|
// lib/keywords/object-keywords.ts
|
|
1162
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);
|
|
1163
1260
|
function getPatternPropertyEntries(schema) {
|
|
1164
1261
|
let entries = schema._patternPropertyEntries;
|
|
1165
1262
|
if (entries) {
|
|
@@ -1179,7 +1276,7 @@ function getPatternPropertyEntries(schema) {
|
|
|
1179
1276
|
match
|
|
1180
1277
|
};
|
|
1181
1278
|
}
|
|
1182
|
-
|
|
1279
|
+
definePropertyOrThrow(schema, "_patternPropertyEntries", {
|
|
1183
1280
|
value: entries,
|
|
1184
1281
|
enumerable: false,
|
|
1185
1282
|
configurable: false,
|
|
@@ -1196,7 +1293,7 @@ function getPatternKeyMatchIndexes(schema, key, entries) {
|
|
|
1196
1293
|
}
|
|
1197
1294
|
} else {
|
|
1198
1295
|
cache = /* @__PURE__ */ new Map();
|
|
1199
|
-
|
|
1296
|
+
definePropertyOrThrow(schema, "_patternKeyMatchIndexCache", {
|
|
1200
1297
|
value: cache,
|
|
1201
1298
|
enumerable: false,
|
|
1202
1299
|
configurable: false,
|
|
@@ -1221,7 +1318,7 @@ var ObjectKeywords = {
|
|
|
1221
1318
|
}
|
|
1222
1319
|
for (let i = 0; i < schema.required.length; i++) {
|
|
1223
1320
|
const key = schema.required[i];
|
|
1224
|
-
if (!
|
|
1321
|
+
if (!hasOwn(data, key)) {
|
|
1225
1322
|
return defineError("Required property is missing", {
|
|
1226
1323
|
item: key,
|
|
1227
1324
|
data: data[key]
|
|
@@ -1230,45 +1327,15 @@ var ObjectKeywords = {
|
|
|
1230
1327
|
}
|
|
1231
1328
|
return;
|
|
1232
1329
|
},
|
|
1233
|
-
properties(schema, data, defineError) {
|
|
1330
|
+
properties(schema, data, defineError, instance) {
|
|
1234
1331
|
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
1235
1332
|
return;
|
|
1236
1333
|
}
|
|
1237
|
-
|
|
1238
|
-
if (!propKeys) {
|
|
1239
|
-
propKeys = Object.keys(schema.properties || {});
|
|
1240
|
-
Object.defineProperty(schema, "_propKeys", {
|
|
1241
|
-
value: propKeys,
|
|
1242
|
-
enumerable: false,
|
|
1243
|
-
configurable: false,
|
|
1244
|
-
writable: false
|
|
1245
|
-
});
|
|
1246
|
-
}
|
|
1247
|
-
let requiredSet = schema._requiredSet;
|
|
1248
|
-
if (requiredSet === void 0) {
|
|
1249
|
-
requiredSet = Array.isArray(schema.required) ? new Set(schema.required) : null;
|
|
1250
|
-
Object.defineProperty(schema, "_requiredSet", {
|
|
1251
|
-
value: requiredSet,
|
|
1252
|
-
enumerable: false,
|
|
1253
|
-
configurable: false,
|
|
1254
|
-
writable: false
|
|
1255
|
-
});
|
|
1256
|
-
}
|
|
1334
|
+
const propKeys = schema._propKeys;
|
|
1257
1335
|
for (let i = 0; i < propKeys.length; i++) {
|
|
1258
1336
|
const key = propKeys[i];
|
|
1259
1337
|
const schemaProp = schema.properties[key];
|
|
1260
|
-
if (!
|
|
1261
|
-
if (requiredSet && requiredSet.has(key) && schemaProp && typeof schemaProp === "object" && !Array.isArray(schemaProp) && "default" in schemaProp) {
|
|
1262
|
-
const error = schemaProp.$validate(schemaProp.default);
|
|
1263
|
-
if (error) {
|
|
1264
|
-
return defineError("Default property is invalid", {
|
|
1265
|
-
item: key,
|
|
1266
|
-
cause: error,
|
|
1267
|
-
data: schemaProp.default
|
|
1268
|
-
});
|
|
1269
|
-
}
|
|
1270
|
-
data[key] = deepCloneUnfreeze(schemaProp.default);
|
|
1271
|
-
}
|
|
1338
|
+
if (!hasOwn(data, key)) {
|
|
1272
1339
|
continue;
|
|
1273
1340
|
}
|
|
1274
1341
|
if (typeof schemaProp === "boolean") {
|
|
@@ -1303,7 +1370,7 @@ var ObjectKeywords = {
|
|
|
1303
1370
|
return;
|
|
1304
1371
|
}
|
|
1305
1372
|
for (const key in data) {
|
|
1306
|
-
if (!
|
|
1373
|
+
if (!hasOwn(data, key)) {
|
|
1307
1374
|
continue;
|
|
1308
1375
|
}
|
|
1309
1376
|
const error = validate(data[key]);
|
|
@@ -1322,7 +1389,7 @@ var ObjectKeywords = {
|
|
|
1322
1389
|
}
|
|
1323
1390
|
let count = 0;
|
|
1324
1391
|
for (const key in data) {
|
|
1325
|
-
if (!
|
|
1392
|
+
if (!hasOwn(data, key)) {
|
|
1326
1393
|
continue;
|
|
1327
1394
|
}
|
|
1328
1395
|
count++;
|
|
@@ -1338,7 +1405,7 @@ var ObjectKeywords = {
|
|
|
1338
1405
|
}
|
|
1339
1406
|
let count = 0;
|
|
1340
1407
|
for (const key in data) {
|
|
1341
|
-
if (!
|
|
1408
|
+
if (!hasOwn(data, key)) {
|
|
1342
1409
|
continue;
|
|
1343
1410
|
}
|
|
1344
1411
|
count++;
|
|
@@ -1355,7 +1422,7 @@ var ObjectKeywords = {
|
|
|
1355
1422
|
let apValidate = schema._apValidate;
|
|
1356
1423
|
if (apValidate === void 0) {
|
|
1357
1424
|
apValidate = isCompiledSchema(schema.additionalProperties) ? schema.additionalProperties.$validate : null;
|
|
1358
|
-
|
|
1425
|
+
definePropertyOrThrow(schema, "_apValidate", {
|
|
1359
1426
|
value: apValidate,
|
|
1360
1427
|
enumerable: false,
|
|
1361
1428
|
configurable: false,
|
|
@@ -1364,10 +1431,10 @@ var ObjectKeywords = {
|
|
|
1364
1431
|
}
|
|
1365
1432
|
const patternEntries = getPatternPropertyEntries(schema);
|
|
1366
1433
|
for (const key in data) {
|
|
1367
|
-
if (!
|
|
1434
|
+
if (!hasOwn(data, key)) {
|
|
1368
1435
|
continue;
|
|
1369
1436
|
}
|
|
1370
|
-
if (schema.properties &&
|
|
1437
|
+
if (schema.properties && hasOwn(schema.properties, key)) {
|
|
1371
1438
|
continue;
|
|
1372
1439
|
}
|
|
1373
1440
|
if (patternEntries && patternEntries.length) {
|
|
@@ -1403,12 +1470,12 @@ var ObjectKeywords = {
|
|
|
1403
1470
|
return;
|
|
1404
1471
|
}
|
|
1405
1472
|
for (const key in data) {
|
|
1406
|
-
if (!
|
|
1473
|
+
if (!hasOwn(data, key)) {
|
|
1407
1474
|
continue;
|
|
1408
1475
|
}
|
|
1409
1476
|
const matchingIndexes = getPatternKeyMatchIndexes(schema, key, patternEntries);
|
|
1410
1477
|
if (matchingIndexes.length === 0) {
|
|
1411
|
-
if (schema.additionalProperties === false && !(schema.properties &&
|
|
1478
|
+
if (schema.additionalProperties === false && !(schema.properties && hasOwn(schema.properties, key))) {
|
|
1412
1479
|
return defineError("Additional properties are not allowed", {
|
|
1413
1480
|
item: key,
|
|
1414
1481
|
data: data[key]
|
|
@@ -1449,7 +1516,7 @@ var ObjectKeywords = {
|
|
|
1449
1516
|
if (typeof pn === "boolean") {
|
|
1450
1517
|
if (pn === false) {
|
|
1451
1518
|
for (const key in data) {
|
|
1452
|
-
if (
|
|
1519
|
+
if (hasOwn(data, key)) {
|
|
1453
1520
|
return defineError("Properties are not allowed", { data });
|
|
1454
1521
|
}
|
|
1455
1522
|
}
|
|
@@ -1461,7 +1528,7 @@ var ObjectKeywords = {
|
|
|
1461
1528
|
return;
|
|
1462
1529
|
}
|
|
1463
1530
|
for (const key in data) {
|
|
1464
|
-
if (!
|
|
1531
|
+
if (!hasOwn(data, key)) {
|
|
1465
1532
|
continue;
|
|
1466
1533
|
}
|
|
1467
1534
|
const error = validate(key);
|
|
@@ -1560,7 +1627,7 @@ function getBranchEntries(schema, key) {
|
|
|
1560
1627
|
for (let i = 0; i < source.length; i++) {
|
|
1561
1628
|
entries.push(toBranchEntry(source[i]));
|
|
1562
1629
|
}
|
|
1563
|
-
|
|
1630
|
+
definePropertyOrThrow(schema, cacheKey, {
|
|
1564
1631
|
value: entries,
|
|
1565
1632
|
enumerable: false,
|
|
1566
1633
|
configurable: false,
|
|
@@ -1568,6 +1635,147 @@ function getBranchEntries(schema, key) {
|
|
|
1568
1635
|
});
|
|
1569
1636
|
return entries;
|
|
1570
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
|
+
}
|
|
1571
1779
|
var OtherKeywords = {
|
|
1572
1780
|
enum(schema, data, defineError) {
|
|
1573
1781
|
let enumCache = schema._enumCache;
|
|
@@ -1584,7 +1792,7 @@ var OtherKeywords = {
|
|
|
1584
1792
|
}
|
|
1585
1793
|
}
|
|
1586
1794
|
enumCache = { primitiveSet, objectValues };
|
|
1587
|
-
|
|
1795
|
+
definePropertyOrThrow(schema, "_enumCache", {
|
|
1588
1796
|
value: enumCache,
|
|
1589
1797
|
enumerable: false,
|
|
1590
1798
|
configurable: false,
|
|
@@ -1604,137 +1812,13 @@ var OtherKeywords = {
|
|
|
1604
1812
|
return defineError("Value is not one of the allowed values", { data });
|
|
1605
1813
|
},
|
|
1606
1814
|
allOf(schema, data, defineError) {
|
|
1607
|
-
|
|
1608
|
-
if (branches.length === 1) {
|
|
1609
|
-
const onlyBranch = branches[0];
|
|
1610
|
-
if (onlyBranch.kind === "validate") {
|
|
1611
|
-
const error = onlyBranch.validate(data);
|
|
1612
|
-
if (error) {
|
|
1613
|
-
return defineError("Value is not valid", { cause: error, data });
|
|
1614
|
-
}
|
|
1615
|
-
return;
|
|
1616
|
-
}
|
|
1617
|
-
if (onlyBranch.kind === "alwaysValid") {
|
|
1618
|
-
return;
|
|
1619
|
-
}
|
|
1620
|
-
if (onlyBranch.kind === "alwaysInvalid") {
|
|
1621
|
-
return defineError("Value is not valid", { data });
|
|
1622
|
-
}
|
|
1623
|
-
if (data !== onlyBranch.value) {
|
|
1624
|
-
return defineError("Value is not valid", { data });
|
|
1625
|
-
}
|
|
1626
|
-
return;
|
|
1627
|
-
}
|
|
1628
|
-
for (let i = 0; i < branches.length; i++) {
|
|
1629
|
-
const branch = branches[i];
|
|
1630
|
-
if (branch.kind === "validate") {
|
|
1631
|
-
const error = branch.validate(data);
|
|
1632
|
-
if (error) {
|
|
1633
|
-
return defineError("Value is not valid", { cause: error, data });
|
|
1634
|
-
}
|
|
1635
|
-
continue;
|
|
1636
|
-
}
|
|
1637
|
-
if (branch.kind === "alwaysValid") {
|
|
1638
|
-
continue;
|
|
1639
|
-
}
|
|
1640
|
-
if (branch.kind === "alwaysInvalid") {
|
|
1641
|
-
return defineError("Value is not valid", { data });
|
|
1642
|
-
}
|
|
1643
|
-
if (data !== branch.value) {
|
|
1644
|
-
return defineError("Value is not valid", { data });
|
|
1645
|
-
}
|
|
1646
|
-
}
|
|
1647
|
-
return;
|
|
1815
|
+
return createCombinatorValidator("allOf", schema, defineError)(data);
|
|
1648
1816
|
},
|
|
1649
1817
|
anyOf(schema, data, defineError) {
|
|
1650
|
-
|
|
1651
|
-
if (branches.length === 1) {
|
|
1652
|
-
const onlyBranch = branches[0];
|
|
1653
|
-
if (onlyBranch.kind === "validate") {
|
|
1654
|
-
const error = onlyBranch.validate(data);
|
|
1655
|
-
if (!error) {
|
|
1656
|
-
return;
|
|
1657
|
-
}
|
|
1658
|
-
return defineError("Value is not valid", { data });
|
|
1659
|
-
}
|
|
1660
|
-
if (onlyBranch.kind === "alwaysValid") {
|
|
1661
|
-
return;
|
|
1662
|
-
}
|
|
1663
|
-
if (onlyBranch.kind === "alwaysInvalid") {
|
|
1664
|
-
return defineError("Value is not valid", { data });
|
|
1665
|
-
}
|
|
1666
|
-
if (data === onlyBranch.value) {
|
|
1667
|
-
return;
|
|
1668
|
-
}
|
|
1669
|
-
return defineError("Value is not valid", { data });
|
|
1670
|
-
}
|
|
1671
|
-
for (let i = 0; i < branches.length; i++) {
|
|
1672
|
-
const branch = branches[i];
|
|
1673
|
-
if (branch.kind === "validate") {
|
|
1674
|
-
const error = branch.validate(data);
|
|
1675
|
-
if (!error) {
|
|
1676
|
-
return;
|
|
1677
|
-
}
|
|
1678
|
-
continue;
|
|
1679
|
-
}
|
|
1680
|
-
if (branch.kind === "alwaysValid") {
|
|
1681
|
-
return;
|
|
1682
|
-
}
|
|
1683
|
-
if (branch.kind === "alwaysInvalid") {
|
|
1684
|
-
continue;
|
|
1685
|
-
}
|
|
1686
|
-
if (data === branch.value) {
|
|
1687
|
-
return;
|
|
1688
|
-
}
|
|
1689
|
-
}
|
|
1690
|
-
return defineError("Value is not valid", { data });
|
|
1818
|
+
return createCombinatorValidator("anyOf", schema, defineError)(data);
|
|
1691
1819
|
},
|
|
1692
1820
|
oneOf(schema, data, defineError) {
|
|
1693
|
-
|
|
1694
|
-
if (branches.length === 1) {
|
|
1695
|
-
const onlyBranch = branches[0];
|
|
1696
|
-
if (onlyBranch.kind === "validate") {
|
|
1697
|
-
const error = onlyBranch.validate(data);
|
|
1698
|
-
if (!error) {
|
|
1699
|
-
return;
|
|
1700
|
-
}
|
|
1701
|
-
return defineError("Value is not valid", { data });
|
|
1702
|
-
}
|
|
1703
|
-
if (onlyBranch.kind === "alwaysValid") {
|
|
1704
|
-
return;
|
|
1705
|
-
}
|
|
1706
|
-
if (onlyBranch.kind === "alwaysInvalid") {
|
|
1707
|
-
return defineError("Value is not valid", { data });
|
|
1708
|
-
}
|
|
1709
|
-
if (data === onlyBranch.value) {
|
|
1710
|
-
return;
|
|
1711
|
-
}
|
|
1712
|
-
return defineError("Value is not valid", { data });
|
|
1713
|
-
}
|
|
1714
|
-
let validCount = 0;
|
|
1715
|
-
for (let i = 0; i < branches.length; i++) {
|
|
1716
|
-
const branch = branches[i];
|
|
1717
|
-
let isValid = false;
|
|
1718
|
-
if (branch.kind === "validate") {
|
|
1719
|
-
isValid = !branch.validate(data);
|
|
1720
|
-
} else if (branch.kind === "alwaysValid") {
|
|
1721
|
-
isValid = true;
|
|
1722
|
-
} else if (branch.kind === "alwaysInvalid") {
|
|
1723
|
-
isValid = false;
|
|
1724
|
-
} else {
|
|
1725
|
-
isValid = data === branch.value;
|
|
1726
|
-
}
|
|
1727
|
-
if (isValid) {
|
|
1728
|
-
validCount++;
|
|
1729
|
-
if (validCount > 1) {
|
|
1730
|
-
return defineError("Value is not valid", { data });
|
|
1731
|
-
}
|
|
1732
|
-
}
|
|
1733
|
-
}
|
|
1734
|
-
if (validCount === 1) {
|
|
1735
|
-
return;
|
|
1736
|
-
}
|
|
1737
|
-
return defineError("Value is not valid", { data });
|
|
1821
|
+
return createCombinatorValidator("oneOf", schema, defineError)(data);
|
|
1738
1822
|
},
|
|
1739
1823
|
const(schema, data, defineError) {
|
|
1740
1824
|
if (data === schema.const) {
|
|
@@ -1794,45 +1878,62 @@ var OtherKeywords = {
|
|
|
1794
1878
|
}
|
|
1795
1879
|
return defineError("Value is not valid", { data });
|
|
1796
1880
|
},
|
|
1797
|
-
$ref(schema, data, defineError
|
|
1798
|
-
if (schema._resolvedRef) {
|
|
1799
|
-
if (schema.$validate !== schema._resolvedRef) {
|
|
1800
|
-
schema.$validate = schema._resolvedRef;
|
|
1801
|
-
}
|
|
1881
|
+
$ref(schema, data, defineError) {
|
|
1882
|
+
if (typeof schema._resolvedRef === "function") {
|
|
1802
1883
|
return schema._resolvedRef(data);
|
|
1803
1884
|
}
|
|
1804
|
-
|
|
1805
|
-
let targetSchema = instance.getSchemaRef(refPath);
|
|
1806
|
-
if (!targetSchema) {
|
|
1807
|
-
targetSchema = instance.getSchemaById(refPath);
|
|
1808
|
-
}
|
|
1809
|
-
if (!targetSchema) {
|
|
1810
|
-
return defineError(`Missing reference: ${refPath}`);
|
|
1811
|
-
}
|
|
1812
|
-
if (!targetSchema.$validate) {
|
|
1813
|
-
return;
|
|
1814
|
-
}
|
|
1815
|
-
schema._resolvedRef = targetSchema.$validate;
|
|
1816
|
-
schema.$validate = schema._resolvedRef;
|
|
1817
|
-
return schema._resolvedRef(data);
|
|
1885
|
+
return defineError(`Missing reference: ${schema.$ref}`);
|
|
1818
1886
|
}
|
|
1819
1887
|
};
|
|
1820
1888
|
|
|
1821
1889
|
// lib/keywords/string-keywords.ts
|
|
1822
1890
|
var PATTERN_MATCH_CACHE_LIMIT = 512;
|
|
1823
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
|
+
}
|
|
1824
1909
|
var StringKeywords = {
|
|
1825
1910
|
minLength(schema, data, defineError) {
|
|
1826
|
-
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)) {
|
|
1827
1920
|
return;
|
|
1828
1921
|
}
|
|
1829
1922
|
return defineError("Value is shorter than the minimum length", { data });
|
|
1830
1923
|
},
|
|
1831
1924
|
maxLength(schema, data, defineError) {
|
|
1832
|
-
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) {
|
|
1833
1931
|
return;
|
|
1834
1932
|
}
|
|
1835
|
-
|
|
1933
|
+
if (units - limit > limit || hasAtLeastCodePoints(data, limit + 1)) {
|
|
1934
|
+
return defineError("Value is longer than the maximum length", { data });
|
|
1935
|
+
}
|
|
1936
|
+
return;
|
|
1836
1937
|
},
|
|
1837
1938
|
pattern(schema, data, defineError) {
|
|
1838
1939
|
if (typeof data !== "string") {
|
|
@@ -1844,7 +1945,7 @@ var StringKeywords = {
|
|
|
1844
1945
|
try {
|
|
1845
1946
|
const compiled = compilePatternMatcher(schema.pattern);
|
|
1846
1947
|
patternMatch = compiled instanceof RegExp ? (value) => compiled.test(value) : compiled;
|
|
1847
|
-
|
|
1948
|
+
definePropertyOrThrow(schema, "_patternMatch", {
|
|
1848
1949
|
value: patternMatch,
|
|
1849
1950
|
enumerable: false,
|
|
1850
1951
|
configurable: false,
|
|
@@ -1859,7 +1960,7 @@ var StringKeywords = {
|
|
|
1859
1960
|
}
|
|
1860
1961
|
if (!patternMatchCache) {
|
|
1861
1962
|
patternMatchCache = /* @__PURE__ */ new Map();
|
|
1862
|
-
|
|
1963
|
+
definePropertyOrThrow(schema, "_patternMatchCache", {
|
|
1863
1964
|
value: patternMatchCache,
|
|
1864
1965
|
enumerable: false,
|
|
1865
1966
|
configurable: false,
|
|
@@ -1891,7 +1992,7 @@ var StringKeywords = {
|
|
|
1891
1992
|
let formatResultCache = schema._formatResultCache;
|
|
1892
1993
|
if (formatValidate === void 0) {
|
|
1893
1994
|
formatValidate = instance.getFormat(schema.format);
|
|
1894
|
-
|
|
1995
|
+
definePropertyOrThrow(schema, "_formatValidate", {
|
|
1895
1996
|
value: formatValidate,
|
|
1896
1997
|
enumerable: false,
|
|
1897
1998
|
configurable: false,
|
|
@@ -1906,7 +2007,7 @@ var StringKeywords = {
|
|
|
1906
2007
|
schema.format,
|
|
1907
2008
|
formatValidate
|
|
1908
2009
|
);
|
|
1909
|
-
|
|
2010
|
+
definePropertyOrThrow(schema, "_formatResultCacheEnabled", {
|
|
1910
2011
|
value: formatResultCacheEnabled,
|
|
1911
2012
|
enumerable: false,
|
|
1912
2013
|
configurable: false,
|
|
@@ -1921,7 +2022,7 @@ var StringKeywords = {
|
|
|
1921
2022
|
}
|
|
1922
2023
|
if (!formatResultCache) {
|
|
1923
2024
|
formatResultCache = /* @__PURE__ */ new Map();
|
|
1924
|
-
|
|
2025
|
+
definePropertyOrThrow(schema, "_formatResultCache", {
|
|
1925
2026
|
value: formatResultCache,
|
|
1926
2027
|
enumerable: false,
|
|
1927
2028
|
configurable: false,
|
|
@@ -1954,20 +2055,61 @@ var keywords = {
|
|
|
1954
2055
|
};
|
|
1955
2056
|
|
|
1956
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
|
+
}
|
|
1957
2076
|
var SchemaShield = class {
|
|
1958
2077
|
types = {};
|
|
1959
2078
|
formats = {};
|
|
1960
2079
|
keywords = {};
|
|
1961
2080
|
immutable = false;
|
|
2081
|
+
useDefaults = false;
|
|
1962
2082
|
rootSchema = null;
|
|
1963
|
-
idRegistry = /* @__PURE__ */ new Map();
|
|
1964
2083
|
failFast = true;
|
|
2084
|
+
maxDepth;
|
|
2085
|
+
validationContexts = [];
|
|
2086
|
+
compileCache = /* @__PURE__ */ new WeakMap();
|
|
2087
|
+
compilingRequiresContext = false;
|
|
2088
|
+
compilingMutableSchemas = /* @__PURE__ */ new WeakSet();
|
|
1965
2089
|
constructor({
|
|
1966
2090
|
immutable = false,
|
|
1967
|
-
failFast = true
|
|
2091
|
+
failFast = true,
|
|
2092
|
+
maxDepth = 128,
|
|
2093
|
+
useDefaults = false
|
|
1968
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
|
+
}
|
|
1969
2109
|
this.immutable = immutable;
|
|
1970
2110
|
this.failFast = failFast;
|
|
2111
|
+
this.maxDepth = maxDepth;
|
|
2112
|
+
this.useDefaults = useDefaults;
|
|
1971
2113
|
for (const [type, validator] of Object.entries(Types)) {
|
|
1972
2114
|
if (validator) {
|
|
1973
2115
|
this.addType(type, validator);
|
|
@@ -1982,6 +2124,50 @@ var SchemaShield = class {
|
|
|
1982
2124
|
}
|
|
1983
2125
|
}
|
|
1984
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
|
+
}
|
|
1985
2171
|
addType(name, validator, overwrite = false) {
|
|
1986
2172
|
if (this.types[name] && !overwrite) {
|
|
1987
2173
|
throw new ValidationError(`Type "${name}" already exists`);
|
|
@@ -2019,14 +2205,465 @@ var SchemaShield = class {
|
|
|
2019
2205
|
return resolvePath(this.rootSchema, path);
|
|
2020
2206
|
}
|
|
2021
2207
|
getSchemaById(id) {
|
|
2022
|
-
|
|
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 };
|
|
2023
2626
|
}
|
|
2024
2627
|
compile(schema) {
|
|
2025
|
-
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;
|
|
2026
2651
|
const compiledSchema = this.compileSchema(schema);
|
|
2027
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
|
+
}
|
|
2028
2665
|
if (compiledSchema._hasRef === true) {
|
|
2029
|
-
this.linkReferences(
|
|
2666
|
+
this.linkReferences(referenceRegistry);
|
|
2030
2667
|
}
|
|
2031
2668
|
if (!compiledSchema.$validate) {
|
|
2032
2669
|
if (schema === false) {
|
|
@@ -2055,14 +2692,53 @@ var SchemaShield = class {
|
|
|
2055
2692
|
);
|
|
2056
2693
|
}
|
|
2057
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
|
+
};
|
|
2058
2709
|
const validate = (data) => {
|
|
2059
2710
|
this.rootSchema = compiledSchema;
|
|
2060
|
-
const
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
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;
|
|
2064
2741
|
}
|
|
2065
|
-
return { data: clonedData, error: null, valid: true };
|
|
2066
2742
|
};
|
|
2067
2743
|
validate.compiledSchema = compiledSchema;
|
|
2068
2744
|
return validate;
|
|
@@ -2165,7 +2841,7 @@ var SchemaShield = class {
|
|
|
2165
2841
|
if (schema._hasRef === true) {
|
|
2166
2842
|
return;
|
|
2167
2843
|
}
|
|
2168
|
-
|
|
2844
|
+
definePropertyOrThrow(schema, "_hasRef", {
|
|
2169
2845
|
value: true,
|
|
2170
2846
|
enumerable: false,
|
|
2171
2847
|
configurable: false,
|
|
@@ -2223,15 +2899,15 @@ var SchemaShield = class {
|
|
|
2223
2899
|
return false;
|
|
2224
2900
|
}
|
|
2225
2901
|
}
|
|
2226
|
-
|
|
2902
|
+
hasPropertyDefaults(schema) {
|
|
2227
2903
|
const properties = schema.properties;
|
|
2228
2904
|
if (!this.isPlainObject(properties)) {
|
|
2229
2905
|
return false;
|
|
2230
2906
|
}
|
|
2231
|
-
const
|
|
2232
|
-
for (let i = 0; i <
|
|
2233
|
-
const subSchema = properties[
|
|
2234
|
-
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")) {
|
|
2235
2911
|
return true;
|
|
2236
2912
|
}
|
|
2237
2913
|
}
|
|
@@ -2240,24 +2916,134 @@ var SchemaShield = class {
|
|
|
2240
2916
|
isDefaultTypeValidator(type, validator) {
|
|
2241
2917
|
return Types[type] === validator;
|
|
2242
2918
|
}
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
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);
|
|
2249
2924
|
} else {
|
|
2250
|
-
|
|
2925
|
+
delete entry.target[entry.key];
|
|
2926
|
+
}
|
|
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);
|
|
2251
2995
|
}
|
|
2252
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
|
+
}
|
|
2253
3030
|
schema = this.normalizeSchemaForCompile(schema);
|
|
2254
3031
|
const compiledSchema = deepCloneUnfreeze(
|
|
2255
3032
|
schema
|
|
2256
3033
|
);
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
this.idRegistry.set(schema.$id, compiledSchema);
|
|
3034
|
+
if (sourceSchema) {
|
|
3035
|
+
this.compileCache.set(sourceSchema, compiledSchema);
|
|
2260
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;
|
|
2261
3047
|
if ("$ref" in schema) {
|
|
2262
3048
|
schemaHasRef = true;
|
|
2263
3049
|
const refValidator = this.getKeyword("$ref");
|
|
@@ -2267,21 +3053,53 @@ var SchemaShield = class {
|
|
|
2267
3053
|
schema["$ref"],
|
|
2268
3054
|
this.failFast
|
|
2269
3055
|
);
|
|
3056
|
+
const isBuiltinRef = refValidator === keywords.$ref;
|
|
2270
3057
|
compiledSchema.$validate = getNamedFunction(
|
|
2271
|
-
"Validate_Reference",
|
|
3058
|
+
isBuiltinRef ? "Validate_Reference" : refValidator.name || "$ref",
|
|
2272
3059
|
(data) => refValidator(
|
|
2273
3060
|
compiledSchema,
|
|
2274
3061
|
data,
|
|
2275
3062
|
defineError,
|
|
2276
|
-
this
|
|
3063
|
+
this,
|
|
3064
|
+
validateSubschema
|
|
2277
3065
|
)
|
|
2278
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);
|
|
2279
3086
|
}
|
|
2280
|
-
this.markSchemaHasRef(compiledSchema);
|
|
2281
3087
|
return compiledSchema;
|
|
2282
3088
|
}
|
|
2283
3089
|
const validators = [];
|
|
2284
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
|
+
}
|
|
2285
3103
|
if ("type" in schema) {
|
|
2286
3104
|
const defineTypeError = getDefinedErrorFunctionForKey(
|
|
2287
3105
|
"type",
|
|
@@ -2317,65 +3135,11 @@ var SchemaShield = class {
|
|
|
2317
3135
|
if (typeFunctions.length === 1 && allTypesDefault) {
|
|
2318
3136
|
const singleTypeName = defaultTypeNames[0];
|
|
2319
3137
|
typeMethodName = singleTypeName;
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
}
|
|
2326
|
-
};
|
|
2327
|
-
break;
|
|
2328
|
-
case "array":
|
|
2329
|
-
combinedTypeValidator = (data) => {
|
|
2330
|
-
if (!Array.isArray(data)) {
|
|
2331
|
-
return defineTypeError("Invalid type", { data });
|
|
2332
|
-
}
|
|
2333
|
-
};
|
|
2334
|
-
break;
|
|
2335
|
-
case "string":
|
|
2336
|
-
combinedTypeValidator = (data) => {
|
|
2337
|
-
if (typeof data !== "string") {
|
|
2338
|
-
return defineTypeError("Invalid type", { data });
|
|
2339
|
-
}
|
|
2340
|
-
};
|
|
2341
|
-
break;
|
|
2342
|
-
case "number":
|
|
2343
|
-
combinedTypeValidator = (data) => {
|
|
2344
|
-
if (typeof data !== "number") {
|
|
2345
|
-
return defineTypeError("Invalid type", { data });
|
|
2346
|
-
}
|
|
2347
|
-
};
|
|
2348
|
-
break;
|
|
2349
|
-
case "integer":
|
|
2350
|
-
combinedTypeValidator = (data) => {
|
|
2351
|
-
if (typeof data !== "number" || !Number.isInteger(data)) {
|
|
2352
|
-
return defineTypeError("Invalid type", { data });
|
|
2353
|
-
}
|
|
2354
|
-
};
|
|
2355
|
-
break;
|
|
2356
|
-
case "boolean":
|
|
2357
|
-
combinedTypeValidator = (data) => {
|
|
2358
|
-
if (typeof data !== "boolean") {
|
|
2359
|
-
return defineTypeError("Invalid type", { data });
|
|
2360
|
-
}
|
|
2361
|
-
};
|
|
2362
|
-
break;
|
|
2363
|
-
case "null":
|
|
2364
|
-
combinedTypeValidator = (data) => {
|
|
2365
|
-
if (data !== null) {
|
|
2366
|
-
return defineTypeError("Invalid type", { data });
|
|
2367
|
-
}
|
|
2368
|
-
};
|
|
2369
|
-
break;
|
|
2370
|
-
default: {
|
|
2371
|
-
const singleTypeFn = typeFunctions[0];
|
|
2372
|
-
combinedTypeValidator = (data) => {
|
|
2373
|
-
if (!singleTypeFn(data)) {
|
|
2374
|
-
return defineTypeError("Invalid type", { data });
|
|
2375
|
-
}
|
|
2376
|
-
};
|
|
2377
|
-
}
|
|
2378
|
-
}
|
|
3138
|
+
combinedTypeValidator = this.failFast && FAIL_FAST_TYPE_VALIDATORS[singleTypeName] ? FAIL_FAST_TYPE_VALIDATORS[singleTypeName] : createBuiltinTypeValidator(
|
|
3139
|
+
singleTypeName,
|
|
3140
|
+
defineTypeError,
|
|
3141
|
+
typeFunctions[0]
|
|
3142
|
+
);
|
|
2379
3143
|
} else if (typeFunctions.length > 1 && allTypesDefault) {
|
|
2380
3144
|
typeMethodName = defaultTypeNames.join("_OR_");
|
|
2381
3145
|
const allowsObject = defaultTypeNames.includes("object");
|
|
@@ -2388,6 +3152,9 @@ var SchemaShield = class {
|
|
|
2388
3152
|
combinedTypeValidator = (data) => {
|
|
2389
3153
|
const dataType = typeof data;
|
|
2390
3154
|
if (dataType === "number") {
|
|
3155
|
+
if (!Number.isFinite(data)) {
|
|
3156
|
+
return defineTypeError("Invalid type", { data });
|
|
3157
|
+
}
|
|
2391
3158
|
if (allowsNumber || allowsInteger && Number.isInteger(data)) {
|
|
2392
3159
|
return;
|
|
2393
3160
|
}
|
|
@@ -2451,7 +3218,8 @@ var SchemaShield = class {
|
|
|
2451
3218
|
activeNames.push(typeMethodName);
|
|
2452
3219
|
}
|
|
2453
3220
|
const { type, $id, $ref, $validate, required, ...otherKeys } = schema;
|
|
2454
|
-
const
|
|
3221
|
+
const otherKeyNames = Object.keys(otherKeys);
|
|
3222
|
+
const keyOrder = required ? ["required", ...otherKeyNames] : otherKeyNames;
|
|
2455
3223
|
for (const key of keyOrder) {
|
|
2456
3224
|
const keywordFn = this.getKeyword(key);
|
|
2457
3225
|
if (!keywordFn) {
|
|
@@ -2466,12 +3234,33 @@ var SchemaShield = class {
|
|
|
2466
3234
|
this.failFast
|
|
2467
3235
|
);
|
|
2468
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
|
+
);
|
|
2469
3261
|
validators.push({
|
|
2470
3262
|
name: fnName,
|
|
2471
|
-
validate: getNamedFunction(
|
|
2472
|
-
fnName,
|
|
2473
|
-
(data) => keywordFn(compiledSchema, data, defineError, this)
|
|
2474
|
-
)
|
|
3263
|
+
validate: getNamedFunction(fnName, keywordValidate)
|
|
2475
3264
|
});
|
|
2476
3265
|
activeNames.push(fnName);
|
|
2477
3266
|
}
|
|
@@ -2513,6 +3302,50 @@ var SchemaShield = class {
|
|
|
2513
3302
|
continue;
|
|
2514
3303
|
}
|
|
2515
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
|
+
}
|
|
2516
3349
|
if (schemaHasRef) {
|
|
2517
3350
|
this.markSchemaHasRef(compiledSchema);
|
|
2518
3351
|
}
|
|
@@ -2554,54 +3387,80 @@ var SchemaShield = class {
|
|
|
2554
3387
|
}
|
|
2555
3388
|
return false;
|
|
2556
3389
|
}
|
|
2557
|
-
|
|
2558
|
-
const
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
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) {
|
|
2562
3418
|
continue;
|
|
2563
|
-
if (typeof node.$ref === "string" && typeof node.$validate === "function" && node.$validate.name === "Validate_Reference") {
|
|
2564
|
-
const refPath = node.$ref;
|
|
2565
|
-
let target = this.getSchemaRef(refPath);
|
|
2566
|
-
if (typeof target === "undefined") {
|
|
2567
|
-
target = this.getSchemaById(refPath);
|
|
2568
|
-
}
|
|
2569
|
-
if (typeof target === "boolean") {
|
|
2570
|
-
if (target === true) {
|
|
2571
|
-
node.$validate = getNamedFunction("Validate_Ref_True", () => {
|
|
2572
|
-
});
|
|
2573
|
-
} else {
|
|
2574
|
-
const defineError = getDefinedErrorFunctionForKey(
|
|
2575
|
-
"$ref",
|
|
2576
|
-
node,
|
|
2577
|
-
this.failFast
|
|
2578
|
-
);
|
|
2579
|
-
node.$validate = getNamedFunction(
|
|
2580
|
-
"Validate_Ref_False",
|
|
2581
|
-
(_data) => defineError("Value is not valid")
|
|
2582
|
-
);
|
|
2583
|
-
}
|
|
2584
|
-
continue;
|
|
2585
|
-
}
|
|
2586
|
-
if (target && typeof target.$validate === "function") {
|
|
2587
|
-
node.$validate = target.$validate;
|
|
2588
|
-
}
|
|
2589
3419
|
}
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
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
|
+
() => {
|
|
2599
3453
|
}
|
|
2600
|
-
|
|
2601
|
-
} else if (typeof value === "object") {
|
|
2602
|
-
stack.push(value);
|
|
3454
|
+
);
|
|
2603
3455
|
}
|
|
3456
|
+
targetValidate = target.$validate;
|
|
2604
3457
|
}
|
|
3458
|
+
definePropertyOrThrow(node, "_resolvedRef", {
|
|
3459
|
+
value: targetValidate,
|
|
3460
|
+
enumerable: false,
|
|
3461
|
+
configurable: false,
|
|
3462
|
+
writable: false
|
|
3463
|
+
});
|
|
2605
3464
|
}
|
|
2606
3465
|
}
|
|
2607
3466
|
};
|