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.js
CHANGED
|
@@ -26,7 +26,21 @@ __export(lib_exports, {
|
|
|
26
26
|
module.exports = __toCommonJS(lib_exports);
|
|
27
27
|
|
|
28
28
|
// lib/utils/main-utils.ts
|
|
29
|
+
var hasOwnPropertyIntrinsic = Object.prototype.hasOwnProperty;
|
|
30
|
+
var hasOwnPropertyCall = Function.prototype.call.bind(
|
|
31
|
+
hasOwnPropertyIntrinsic
|
|
32
|
+
);
|
|
33
|
+
function definePropertyOrThrow(target, key, descriptor) {
|
|
34
|
+
if (!Reflect.defineProperty(target, key, descriptor)) {
|
|
35
|
+
throw new TypeError(`Cannot define property "${String(key)}"`);
|
|
36
|
+
}
|
|
37
|
+
return target;
|
|
38
|
+
}
|
|
39
|
+
function hasOwn(target, key) {
|
|
40
|
+
return hasOwnPropertyCall(target, key);
|
|
41
|
+
}
|
|
29
42
|
var ValidationError = class extends Error {
|
|
43
|
+
code;
|
|
30
44
|
message;
|
|
31
45
|
item;
|
|
32
46
|
keyword;
|
|
@@ -35,42 +49,61 @@ var ValidationError = class extends Error {
|
|
|
35
49
|
instancePath = "";
|
|
36
50
|
data;
|
|
37
51
|
schema;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (typeof this.item !== "undefined") {
|
|
42
|
-
if (typeof this.item === "string" && this.item in this.schema) {
|
|
43
|
-
schemaPath += `/${this.item}`;
|
|
44
|
-
}
|
|
45
|
-
instancePath += `/${this.item}`;
|
|
46
|
-
}
|
|
47
|
-
this.instancePath = instancePath;
|
|
48
|
-
this.schemaPath = schemaPath;
|
|
49
|
-
if (!this.cause || !(this.cause instanceof ValidationError)) {
|
|
50
|
-
return this;
|
|
51
|
-
}
|
|
52
|
-
return this.cause._getCause(schemaPath, instancePath);
|
|
52
|
+
constructor(message) {
|
|
53
|
+
super(message);
|
|
54
|
+
this.message = message;
|
|
53
55
|
}
|
|
54
56
|
getCause() {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
57
|
+
let current = this;
|
|
58
|
+
let schemaPointer = "#";
|
|
59
|
+
let instancePointer = "#";
|
|
60
|
+
const seen = /* @__PURE__ */ new Set();
|
|
61
|
+
while (!seen.has(current)) {
|
|
62
|
+
seen.add(current);
|
|
63
|
+
let schemaPath = `${schemaPointer}/${current.keyword}`;
|
|
64
|
+
let instancePath = instancePointer;
|
|
65
|
+
if (typeof current.item !== "undefined") {
|
|
66
|
+
if (typeof current.item === "string" && current.schema && typeof current.schema === "object" && current.item in current.schema) {
|
|
67
|
+
schemaPath += `/${escapeJsonPointerToken(current.item)}`;
|
|
68
|
+
}
|
|
69
|
+
instancePath += `/${escapeJsonPointerToken(current.item)}`;
|
|
70
|
+
}
|
|
71
|
+
current.schemaPath = schemaPath;
|
|
72
|
+
current.instancePath = instancePath;
|
|
73
|
+
if (!(current.cause instanceof ValidationError) || seen.has(current.cause)) {
|
|
74
|
+
return current;
|
|
75
|
+
}
|
|
76
|
+
schemaPointer = schemaPath;
|
|
77
|
+
instancePointer = instancePath;
|
|
78
|
+
current = current.cause;
|
|
68
79
|
}
|
|
69
|
-
return
|
|
80
|
+
return current;
|
|
70
81
|
}
|
|
71
82
|
getTree() {
|
|
72
83
|
this.getCause();
|
|
73
|
-
|
|
84
|
+
let current = this;
|
|
85
|
+
let root;
|
|
86
|
+
let target;
|
|
87
|
+
const seen = /* @__PURE__ */ new Set();
|
|
88
|
+
while (current && !seen.has(current)) {
|
|
89
|
+
seen.add(current);
|
|
90
|
+
const node = {
|
|
91
|
+
message: current.message,
|
|
92
|
+
keyword: current.keyword,
|
|
93
|
+
item: current.item,
|
|
94
|
+
schemaPath: current.schemaPath,
|
|
95
|
+
instancePath: current.instancePath,
|
|
96
|
+
data: current.data
|
|
97
|
+
};
|
|
98
|
+
if (!root) {
|
|
99
|
+
root = node;
|
|
100
|
+
} else if (target) {
|
|
101
|
+
target.cause = node;
|
|
102
|
+
}
|
|
103
|
+
target = node;
|
|
104
|
+
current = current.cause instanceof ValidationError ? current.cause : void 0;
|
|
105
|
+
}
|
|
106
|
+
return root;
|
|
74
107
|
}
|
|
75
108
|
getPath() {
|
|
76
109
|
const cause = this.getCause();
|
|
@@ -90,8 +123,11 @@ function getDefinedErrorFunctionForKey(key, schema, failFast) {
|
|
|
90
123
|
KeywordError.schema = schema;
|
|
91
124
|
const defineError = (message, options = {}) => {
|
|
92
125
|
KeywordError.message = message;
|
|
126
|
+
KeywordError.code = options.code;
|
|
93
127
|
KeywordError.item = options.item;
|
|
94
|
-
|
|
128
|
+
if (options.cause !== KeywordError) {
|
|
129
|
+
KeywordError.cause = options.cause && options.cause !== true ? options.cause : void 0;
|
|
130
|
+
}
|
|
95
131
|
KeywordError.data = options.data;
|
|
96
132
|
return KeywordError;
|
|
97
133
|
};
|
|
@@ -100,11 +136,14 @@ function getDefinedErrorFunctionForKey(key, schema, failFast) {
|
|
|
100
136
|
defineError
|
|
101
137
|
);
|
|
102
138
|
}
|
|
139
|
+
function escapeJsonPointerToken(value) {
|
|
140
|
+
return String(value).replace(/~/g, "~0").replace(/\//g, "~1");
|
|
141
|
+
}
|
|
103
142
|
function isCompiledSchema(subSchema) {
|
|
104
143
|
return !!subSchema && typeof subSchema === "object" && !Array.isArray(subSchema) && "$validate" in subSchema;
|
|
105
144
|
}
|
|
106
145
|
function getNamedFunction(name, fn) {
|
|
107
|
-
return
|
|
146
|
+
return definePropertyOrThrow(fn, "name", { value: name });
|
|
108
147
|
}
|
|
109
148
|
function resolvePath(root, path) {
|
|
110
149
|
if (!path || path === "#") {
|
|
@@ -149,7 +188,6 @@ var DURATION_REGEX = /^P(?!$)((\d+Y)?(\d+M)?(\d+W)?(\d+D)?)(T(?=\d)(\d+H)?(\d+M)
|
|
|
149
188
|
var URI_REGEX = /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/;
|
|
150
189
|
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;
|
|
151
190
|
var HOSTNAME_REGEX = /^[a-z0-9][a-z0-9-]{0,62}(?:\.[a-z0-9][a-z0-9-]{0,62})*[a-z0-9]$/i;
|
|
152
|
-
var DATE_REGEX = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
153
191
|
var TIME_REGEX = /^([01]\d|2[0-3]):([0-5]\d):([0-5]\d)(\.\d+)?(Z|([+-])([01]\d|2[0-3]):([0-5]\d))$/;
|
|
154
192
|
var URI_REFERENCE_REGEX = /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#((?![^#]*\\)[^#]*))?/i;
|
|
155
193
|
var IRI_REGEX = /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/;
|
|
@@ -214,6 +252,22 @@ function isValidIpv4(data) {
|
|
|
214
252
|
function isHexCharCode(code) {
|
|
215
253
|
return code >= 48 && code <= 57 || code >= 65 && code <= 70 || code >= 97 && code <= 102;
|
|
216
254
|
}
|
|
255
|
+
function hasValidPercentEncoding(data) {
|
|
256
|
+
for (let index = 0; index < data.length; index++) {
|
|
257
|
+
const code = data.charCodeAt(index);
|
|
258
|
+
if (code === 92) {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
if (code !== 37) {
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
if (index + 2 >= data.length || !isHexCharCode(data.charCodeAt(index + 1)) || !isHexCharCode(data.charCodeAt(index + 2))) {
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
index += 2;
|
|
268
|
+
}
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
217
271
|
function isValidIpv6(data) {
|
|
218
272
|
const length = data.length;
|
|
219
273
|
if (length === 0) {
|
|
@@ -318,7 +372,7 @@ function isValidJsonPointer(data) {
|
|
|
318
372
|
}
|
|
319
373
|
function isValidRelativeJsonPointer(data) {
|
|
320
374
|
if (data.length === 0) {
|
|
321
|
-
return
|
|
375
|
+
return false;
|
|
322
376
|
}
|
|
323
377
|
let i = 0;
|
|
324
378
|
while (i < data.length) {
|
|
@@ -331,6 +385,9 @@ function isValidRelativeJsonPointer(data) {
|
|
|
331
385
|
if (i === 0) {
|
|
332
386
|
return false;
|
|
333
387
|
}
|
|
388
|
+
if (i > 1 && data.charCodeAt(0) === 48) {
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
334
391
|
if (i === data.length) {
|
|
335
392
|
return true;
|
|
336
393
|
}
|
|
@@ -457,7 +514,7 @@ var Formats = {
|
|
|
457
514
|
return true;
|
|
458
515
|
},
|
|
459
516
|
uri(data) {
|
|
460
|
-
return URI_REGEX.test(data);
|
|
517
|
+
return URI_REGEX.test(data) && hasValidPercentEncoding(data);
|
|
461
518
|
},
|
|
462
519
|
email(data) {
|
|
463
520
|
return EMAIL_REGEX.test(data);
|
|
@@ -472,15 +529,13 @@ var Formats = {
|
|
|
472
529
|
return HOSTNAME_REGEX.test(data);
|
|
473
530
|
},
|
|
474
531
|
date(data) {
|
|
475
|
-
|
|
476
|
-
if (!match) {
|
|
532
|
+
if (data.length !== 10 || data.charCodeAt(4) !== 45 || data.charCodeAt(7) !== 45) {
|
|
477
533
|
return false;
|
|
478
534
|
}
|
|
479
|
-
const
|
|
480
|
-
const
|
|
481
|
-
const
|
|
482
|
-
|
|
483
|
-
if (month < 1 || month > 12) {
|
|
535
|
+
const year = parseFourDigits(data, 0);
|
|
536
|
+
const month = parseTwoDigits(data, 5);
|
|
537
|
+
const day = parseTwoDigits(data, 8);
|
|
538
|
+
if (year < 0 || month < 1 || month > 12) {
|
|
484
539
|
return false;
|
|
485
540
|
}
|
|
486
541
|
if (day < 1) {
|
|
@@ -552,10 +607,10 @@ var Types = {
|
|
|
552
607
|
return typeof data === "string";
|
|
553
608
|
},
|
|
554
609
|
number(data) {
|
|
555
|
-
return typeof data === "number";
|
|
610
|
+
return typeof data === "number" && Number.isFinite(data);
|
|
556
611
|
},
|
|
557
612
|
integer(data) {
|
|
558
|
-
return typeof data === "number" && data % 1 === 0;
|
|
613
|
+
return typeof data === "number" && Number.isFinite(data) && data % 1 === 0;
|
|
559
614
|
},
|
|
560
615
|
boolean(data) {
|
|
561
616
|
return typeof data === "boolean";
|
|
@@ -780,7 +835,7 @@ var ArrayKeywords = {
|
|
|
780
835
|
let tupleLength = schema._tupleItemsLength;
|
|
781
836
|
if (tupleLength === void 0) {
|
|
782
837
|
tupleLength = schema.items.length;
|
|
783
|
-
|
|
838
|
+
definePropertyOrThrow(schema, "_tupleItemsLength", {
|
|
784
839
|
value: tupleLength,
|
|
785
840
|
enumerable: false,
|
|
786
841
|
configurable: false,
|
|
@@ -837,13 +892,23 @@ var ArrayKeywords = {
|
|
|
837
892
|
}
|
|
838
893
|
return;
|
|
839
894
|
}
|
|
840
|
-
|
|
895
|
+
let hasFirstPrimitive = false;
|
|
896
|
+
let firstPrimitive;
|
|
897
|
+
let primitiveSeen;
|
|
841
898
|
let primitiveArraySignatures;
|
|
842
899
|
let arrayBuckets;
|
|
843
900
|
let objectBuckets;
|
|
844
901
|
for (let i = 0; i < len; i++) {
|
|
845
902
|
const item = data[i];
|
|
846
903
|
if (isUniquePrimitive(item)) {
|
|
904
|
+
if (!hasFirstPrimitive) {
|
|
905
|
+
hasFirstPrimitive = true;
|
|
906
|
+
firstPrimitive = item;
|
|
907
|
+
continue;
|
|
908
|
+
}
|
|
909
|
+
if (!primitiveSeen) {
|
|
910
|
+
primitiveSeen = /* @__PURE__ */ new Set([firstPrimitive]);
|
|
911
|
+
}
|
|
847
912
|
if (primitiveSeen.has(item)) {
|
|
848
913
|
return defineError("Array items are not unique", { data: item });
|
|
849
914
|
}
|
|
@@ -929,7 +994,7 @@ function isPlainObject(value) {
|
|
|
929
994
|
if (!value || typeof value !== "object") {
|
|
930
995
|
return false;
|
|
931
996
|
}
|
|
932
|
-
const proto =
|
|
997
|
+
const proto = Reflect.getPrototypeOf(value);
|
|
933
998
|
return proto === Object.prototype || proto === null;
|
|
934
999
|
}
|
|
935
1000
|
function canUseStructuredClone(value) {
|
|
@@ -1024,7 +1089,7 @@ function deepCloneUnfreeze(obj, cloneClassInstances = false, seen = /* @__PURE__
|
|
|
1024
1089
|
seen.set(source, clone);
|
|
1025
1090
|
return clone;
|
|
1026
1091
|
}
|
|
1027
|
-
clone = Object.create(
|
|
1092
|
+
clone = Object.create(Reflect.getPrototypeOf(source));
|
|
1028
1093
|
seen.set(source, clone);
|
|
1029
1094
|
break;
|
|
1030
1095
|
}
|
|
@@ -1053,7 +1118,7 @@ function deepCloneUnfreeze(obj, cloneClassInstances = false, seen = /* @__PURE__
|
|
|
1053
1118
|
seen
|
|
1054
1119
|
);
|
|
1055
1120
|
}
|
|
1056
|
-
|
|
1121
|
+
definePropertyOrThrow(clone, key, descriptor);
|
|
1057
1122
|
}
|
|
1058
1123
|
return clone;
|
|
1059
1124
|
}
|
|
@@ -1064,6 +1129,9 @@ var NumberKeywords = {
|
|
|
1064
1129
|
if (typeof data !== "number") {
|
|
1065
1130
|
return;
|
|
1066
1131
|
}
|
|
1132
|
+
if (!Number.isFinite(data)) {
|
|
1133
|
+
return defineError("Value must be finite", { data });
|
|
1134
|
+
}
|
|
1067
1135
|
let min = schema.minimum;
|
|
1068
1136
|
if (typeof schema.exclusiveMinimum === "number") {
|
|
1069
1137
|
min = schema.exclusiveMinimum + 1e-15;
|
|
@@ -1079,6 +1147,9 @@ var NumberKeywords = {
|
|
|
1079
1147
|
if (typeof data !== "number") {
|
|
1080
1148
|
return;
|
|
1081
1149
|
}
|
|
1150
|
+
if (!Number.isFinite(data)) {
|
|
1151
|
+
return defineError("Value must be finite", { data });
|
|
1152
|
+
}
|
|
1082
1153
|
let max = schema.maximum;
|
|
1083
1154
|
if (typeof schema.exclusiveMaximum === "number") {
|
|
1084
1155
|
max = schema.exclusiveMaximum - 1e-15;
|
|
@@ -1094,11 +1165,14 @@ var NumberKeywords = {
|
|
|
1094
1165
|
if (typeof data !== "number") {
|
|
1095
1166
|
return;
|
|
1096
1167
|
}
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1168
|
+
if (!Number.isFinite(data) || !Number.isFinite(schema.multipleOf) || schema.multipleOf <= 0) {
|
|
1169
|
+
return defineError("Value must use a finite positive multipleOf", {
|
|
1170
|
+
data
|
|
1171
|
+
});
|
|
1100
1172
|
}
|
|
1101
|
-
|
|
1173
|
+
const quotient = data / schema.multipleOf;
|
|
1174
|
+
const valid = Number.isFinite(quotient) ? areCloseEnough(quotient, Math.round(quotient)) : data % schema.multipleOf === 0;
|
|
1175
|
+
if (!valid) {
|
|
1102
1176
|
return defineError("Value is not a multiple of the multipleOf", { data });
|
|
1103
1177
|
}
|
|
1104
1178
|
return;
|
|
@@ -1187,6 +1261,29 @@ function compilePatternMatcher(pattern) {
|
|
|
1187
1261
|
|
|
1188
1262
|
// lib/keywords/object-keywords.ts
|
|
1189
1263
|
var PATTERN_KEY_CACHE_LIMIT = 512;
|
|
1264
|
+
function createApplyPropertyDefaults(replaceEmpty) {
|
|
1265
|
+
return function applyPropertyDefaults2(schema, data, instance) {
|
|
1266
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
1267
|
+
return;
|
|
1268
|
+
}
|
|
1269
|
+
const defaultKeys = schema._defaultKeys;
|
|
1270
|
+
for (let i = 0; i < defaultKeys.length; i++) {
|
|
1271
|
+
const key = defaultKeys[i];
|
|
1272
|
+
const hasOwnValue = hasOwn(data, key);
|
|
1273
|
+
const value = hasOwnValue ? data[key] : void 0;
|
|
1274
|
+
if (hasOwnValue && value !== void 0 && (!replaceEmpty || value !== null && value !== "")) {
|
|
1275
|
+
continue;
|
|
1276
|
+
}
|
|
1277
|
+
instance.setDefault(
|
|
1278
|
+
data,
|
|
1279
|
+
key,
|
|
1280
|
+
deepCloneUnfreeze(schema.properties[key].default)
|
|
1281
|
+
);
|
|
1282
|
+
}
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
var applyPropertyDefaults = createApplyPropertyDefaults(false);
|
|
1286
|
+
var applyEmptyPropertyDefaults = createApplyPropertyDefaults(true);
|
|
1190
1287
|
function getPatternPropertyEntries(schema) {
|
|
1191
1288
|
let entries = schema._patternPropertyEntries;
|
|
1192
1289
|
if (entries) {
|
|
@@ -1206,7 +1303,7 @@ function getPatternPropertyEntries(schema) {
|
|
|
1206
1303
|
match
|
|
1207
1304
|
};
|
|
1208
1305
|
}
|
|
1209
|
-
|
|
1306
|
+
definePropertyOrThrow(schema, "_patternPropertyEntries", {
|
|
1210
1307
|
value: entries,
|
|
1211
1308
|
enumerable: false,
|
|
1212
1309
|
configurable: false,
|
|
@@ -1223,7 +1320,7 @@ function getPatternKeyMatchIndexes(schema, key, entries) {
|
|
|
1223
1320
|
}
|
|
1224
1321
|
} else {
|
|
1225
1322
|
cache = /* @__PURE__ */ new Map();
|
|
1226
|
-
|
|
1323
|
+
definePropertyOrThrow(schema, "_patternKeyMatchIndexCache", {
|
|
1227
1324
|
value: cache,
|
|
1228
1325
|
enumerable: false,
|
|
1229
1326
|
configurable: false,
|
|
@@ -1248,7 +1345,7 @@ var ObjectKeywords = {
|
|
|
1248
1345
|
}
|
|
1249
1346
|
for (let i = 0; i < schema.required.length; i++) {
|
|
1250
1347
|
const key = schema.required[i];
|
|
1251
|
-
if (!
|
|
1348
|
+
if (!hasOwn(data, key)) {
|
|
1252
1349
|
return defineError("Required property is missing", {
|
|
1253
1350
|
item: key,
|
|
1254
1351
|
data: data[key]
|
|
@@ -1257,45 +1354,15 @@ var ObjectKeywords = {
|
|
|
1257
1354
|
}
|
|
1258
1355
|
return;
|
|
1259
1356
|
},
|
|
1260
|
-
properties(schema, data, defineError) {
|
|
1357
|
+
properties(schema, data, defineError, instance) {
|
|
1261
1358
|
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
1262
1359
|
return;
|
|
1263
1360
|
}
|
|
1264
|
-
|
|
1265
|
-
if (!propKeys) {
|
|
1266
|
-
propKeys = Object.keys(schema.properties || {});
|
|
1267
|
-
Object.defineProperty(schema, "_propKeys", {
|
|
1268
|
-
value: propKeys,
|
|
1269
|
-
enumerable: false,
|
|
1270
|
-
configurable: false,
|
|
1271
|
-
writable: false
|
|
1272
|
-
});
|
|
1273
|
-
}
|
|
1274
|
-
let requiredSet = schema._requiredSet;
|
|
1275
|
-
if (requiredSet === void 0) {
|
|
1276
|
-
requiredSet = Array.isArray(schema.required) ? new Set(schema.required) : null;
|
|
1277
|
-
Object.defineProperty(schema, "_requiredSet", {
|
|
1278
|
-
value: requiredSet,
|
|
1279
|
-
enumerable: false,
|
|
1280
|
-
configurable: false,
|
|
1281
|
-
writable: false
|
|
1282
|
-
});
|
|
1283
|
-
}
|
|
1361
|
+
const propKeys = schema._propKeys;
|
|
1284
1362
|
for (let i = 0; i < propKeys.length; i++) {
|
|
1285
1363
|
const key = propKeys[i];
|
|
1286
1364
|
const schemaProp = schema.properties[key];
|
|
1287
|
-
if (!
|
|
1288
|
-
if (requiredSet && requiredSet.has(key) && schemaProp && typeof schemaProp === "object" && !Array.isArray(schemaProp) && "default" in schemaProp) {
|
|
1289
|
-
const error = schemaProp.$validate(schemaProp.default);
|
|
1290
|
-
if (error) {
|
|
1291
|
-
return defineError("Default property is invalid", {
|
|
1292
|
-
item: key,
|
|
1293
|
-
cause: error,
|
|
1294
|
-
data: schemaProp.default
|
|
1295
|
-
});
|
|
1296
|
-
}
|
|
1297
|
-
data[key] = deepCloneUnfreeze(schemaProp.default);
|
|
1298
|
-
}
|
|
1365
|
+
if (!hasOwn(data, key)) {
|
|
1299
1366
|
continue;
|
|
1300
1367
|
}
|
|
1301
1368
|
if (typeof schemaProp === "boolean") {
|
|
@@ -1330,7 +1397,7 @@ var ObjectKeywords = {
|
|
|
1330
1397
|
return;
|
|
1331
1398
|
}
|
|
1332
1399
|
for (const key in data) {
|
|
1333
|
-
if (!
|
|
1400
|
+
if (!hasOwn(data, key)) {
|
|
1334
1401
|
continue;
|
|
1335
1402
|
}
|
|
1336
1403
|
const error = validate(data[key]);
|
|
@@ -1349,7 +1416,7 @@ var ObjectKeywords = {
|
|
|
1349
1416
|
}
|
|
1350
1417
|
let count = 0;
|
|
1351
1418
|
for (const key in data) {
|
|
1352
|
-
if (!
|
|
1419
|
+
if (!hasOwn(data, key)) {
|
|
1353
1420
|
continue;
|
|
1354
1421
|
}
|
|
1355
1422
|
count++;
|
|
@@ -1365,7 +1432,7 @@ var ObjectKeywords = {
|
|
|
1365
1432
|
}
|
|
1366
1433
|
let count = 0;
|
|
1367
1434
|
for (const key in data) {
|
|
1368
|
-
if (!
|
|
1435
|
+
if (!hasOwn(data, key)) {
|
|
1369
1436
|
continue;
|
|
1370
1437
|
}
|
|
1371
1438
|
count++;
|
|
@@ -1382,7 +1449,7 @@ var ObjectKeywords = {
|
|
|
1382
1449
|
let apValidate = schema._apValidate;
|
|
1383
1450
|
if (apValidate === void 0) {
|
|
1384
1451
|
apValidate = isCompiledSchema(schema.additionalProperties) ? schema.additionalProperties.$validate : null;
|
|
1385
|
-
|
|
1452
|
+
definePropertyOrThrow(schema, "_apValidate", {
|
|
1386
1453
|
value: apValidate,
|
|
1387
1454
|
enumerable: false,
|
|
1388
1455
|
configurable: false,
|
|
@@ -1391,10 +1458,10 @@ var ObjectKeywords = {
|
|
|
1391
1458
|
}
|
|
1392
1459
|
const patternEntries = getPatternPropertyEntries(schema);
|
|
1393
1460
|
for (const key in data) {
|
|
1394
|
-
if (!
|
|
1461
|
+
if (!hasOwn(data, key)) {
|
|
1395
1462
|
continue;
|
|
1396
1463
|
}
|
|
1397
|
-
if (schema.properties &&
|
|
1464
|
+
if (schema.properties && hasOwn(schema.properties, key)) {
|
|
1398
1465
|
continue;
|
|
1399
1466
|
}
|
|
1400
1467
|
if (patternEntries && patternEntries.length) {
|
|
@@ -1430,12 +1497,12 @@ var ObjectKeywords = {
|
|
|
1430
1497
|
return;
|
|
1431
1498
|
}
|
|
1432
1499
|
for (const key in data) {
|
|
1433
|
-
if (!
|
|
1500
|
+
if (!hasOwn(data, key)) {
|
|
1434
1501
|
continue;
|
|
1435
1502
|
}
|
|
1436
1503
|
const matchingIndexes = getPatternKeyMatchIndexes(schema, key, patternEntries);
|
|
1437
1504
|
if (matchingIndexes.length === 0) {
|
|
1438
|
-
if (schema.additionalProperties === false && !(schema.properties &&
|
|
1505
|
+
if (schema.additionalProperties === false && !(schema.properties && hasOwn(schema.properties, key))) {
|
|
1439
1506
|
return defineError("Additional properties are not allowed", {
|
|
1440
1507
|
item: key,
|
|
1441
1508
|
data: data[key]
|
|
@@ -1476,7 +1543,7 @@ var ObjectKeywords = {
|
|
|
1476
1543
|
if (typeof pn === "boolean") {
|
|
1477
1544
|
if (pn === false) {
|
|
1478
1545
|
for (const key in data) {
|
|
1479
|
-
if (
|
|
1546
|
+
if (hasOwn(data, key)) {
|
|
1480
1547
|
return defineError("Properties are not allowed", { data });
|
|
1481
1548
|
}
|
|
1482
1549
|
}
|
|
@@ -1488,7 +1555,7 @@ var ObjectKeywords = {
|
|
|
1488
1555
|
return;
|
|
1489
1556
|
}
|
|
1490
1557
|
for (const key in data) {
|
|
1491
|
-
if (!
|
|
1558
|
+
if (!hasOwn(data, key)) {
|
|
1492
1559
|
continue;
|
|
1493
1560
|
}
|
|
1494
1561
|
const error = validate(key);
|
|
@@ -1587,7 +1654,7 @@ function getBranchEntries(schema, key) {
|
|
|
1587
1654
|
for (let i = 0; i < source.length; i++) {
|
|
1588
1655
|
entries.push(toBranchEntry(source[i]));
|
|
1589
1656
|
}
|
|
1590
|
-
|
|
1657
|
+
definePropertyOrThrow(schema, cacheKey, {
|
|
1591
1658
|
value: entries,
|
|
1592
1659
|
enumerable: false,
|
|
1593
1660
|
configurable: false,
|
|
@@ -1595,6 +1662,147 @@ function getBranchEntries(schema, key) {
|
|
|
1595
1662
|
});
|
|
1596
1663
|
return entries;
|
|
1597
1664
|
}
|
|
1665
|
+
function evaluateAllOf(branches, data, defineError) {
|
|
1666
|
+
for (let i = 0; i < branches.length; i++) {
|
|
1667
|
+
const branch = branches[i];
|
|
1668
|
+
if (branch.kind === "validate") {
|
|
1669
|
+
const error = branch.validate(data);
|
|
1670
|
+
if (error) {
|
|
1671
|
+
return defineError("Value is not valid", { cause: error, data });
|
|
1672
|
+
}
|
|
1673
|
+
continue;
|
|
1674
|
+
}
|
|
1675
|
+
if (branch.kind === "alwaysValid") {
|
|
1676
|
+
continue;
|
|
1677
|
+
}
|
|
1678
|
+
if (branch.kind === "alwaysInvalid" || data !== branch.value) {
|
|
1679
|
+
return defineError("Value is not valid", { data });
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
function evaluateAnyOf(branches, data, defineError) {
|
|
1684
|
+
for (let i = 0; i < branches.length; i++) {
|
|
1685
|
+
const branch = branches[i];
|
|
1686
|
+
if (branch.kind === "validate") {
|
|
1687
|
+
if (!branch.validate(data)) {
|
|
1688
|
+
return;
|
|
1689
|
+
}
|
|
1690
|
+
continue;
|
|
1691
|
+
}
|
|
1692
|
+
if (branch.kind === "alwaysValid") {
|
|
1693
|
+
return;
|
|
1694
|
+
}
|
|
1695
|
+
if (branch.kind === "literal" && data === branch.value) {
|
|
1696
|
+
return;
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
return defineError("Value is not valid", { data });
|
|
1700
|
+
}
|
|
1701
|
+
function evaluateOneOf(branches, data, defineError) {
|
|
1702
|
+
let validCount = 0;
|
|
1703
|
+
let winnerIndex = -1;
|
|
1704
|
+
for (let i = 0; i < branches.length; i++) {
|
|
1705
|
+
const branch = branches[i];
|
|
1706
|
+
let isValid = false;
|
|
1707
|
+
if (branch.kind === "validate") {
|
|
1708
|
+
isValid = !branch.validate(data);
|
|
1709
|
+
} else if (branch.kind === "alwaysValid") {
|
|
1710
|
+
isValid = true;
|
|
1711
|
+
} else if (branch.kind === "literal") {
|
|
1712
|
+
isValid = data === branch.value;
|
|
1713
|
+
}
|
|
1714
|
+
if (isValid) {
|
|
1715
|
+
validCount++;
|
|
1716
|
+
winnerIndex = i;
|
|
1717
|
+
if (validCount > 1) {
|
|
1718
|
+
return {
|
|
1719
|
+
error: defineError("Value is not valid", { data }),
|
|
1720
|
+
winnerIndex: -1
|
|
1721
|
+
};
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
return {
|
|
1726
|
+
error: validCount === 1 ? void 0 : defineError("Value is not valid", { data }),
|
|
1727
|
+
winnerIndex: validCount === 1 ? winnerIndex : -1
|
|
1728
|
+
};
|
|
1729
|
+
}
|
|
1730
|
+
function createCombinatorValidator(key, schema, defineError, validateSubschema, transactions) {
|
|
1731
|
+
const sourceBranches = getBranchEntries(schema, key);
|
|
1732
|
+
const branches = validateSubschema ? sourceBranches.map(
|
|
1733
|
+
(branch, index) => branch.kind === "validate" ? {
|
|
1734
|
+
kind: "validate",
|
|
1735
|
+
validate: (data) => validateSubschema(schema[key][index], data)
|
|
1736
|
+
} : branch
|
|
1737
|
+
) : sourceBranches;
|
|
1738
|
+
if (!transactions) {
|
|
1739
|
+
if (key === "allOf") {
|
|
1740
|
+
return (data) => evaluateAllOf(branches, data, defineError);
|
|
1741
|
+
}
|
|
1742
|
+
if (key === "anyOf") {
|
|
1743
|
+
return (data) => evaluateAnyOf(branches, data, defineError);
|
|
1744
|
+
}
|
|
1745
|
+
return (data) => evaluateOneOf(branches, data, defineError).error;
|
|
1746
|
+
}
|
|
1747
|
+
if (key === "allOf") {
|
|
1748
|
+
return (data) => {
|
|
1749
|
+
const savepoint = transactions.savepoint();
|
|
1750
|
+
try {
|
|
1751
|
+
const error = evaluateAllOf(branches, data, defineError);
|
|
1752
|
+
if (error) {
|
|
1753
|
+
transactions.rollback(savepoint);
|
|
1754
|
+
}
|
|
1755
|
+
return error;
|
|
1756
|
+
} catch (error) {
|
|
1757
|
+
transactions.rollback(savepoint);
|
|
1758
|
+
throw error;
|
|
1759
|
+
}
|
|
1760
|
+
};
|
|
1761
|
+
}
|
|
1762
|
+
if (key === "anyOf") {
|
|
1763
|
+
return (data) => evaluateAnyOf(branches, data, defineError);
|
|
1764
|
+
}
|
|
1765
|
+
return (data) => {
|
|
1766
|
+
const savepoint = transactions.savepoint();
|
|
1767
|
+
const defaultsByBranch = [];
|
|
1768
|
+
const isolatedBranches = branches.map(
|
|
1769
|
+
(branch, index) => branch.kind === "validate" ? {
|
|
1770
|
+
kind: "validate",
|
|
1771
|
+
validate: (value) => {
|
|
1772
|
+
const branchSavepoint = transactions.savepoint();
|
|
1773
|
+
const error = branch.validate(value);
|
|
1774
|
+
if (!error) {
|
|
1775
|
+
defaultsByBranch[index] = transactions.capture(branchSavepoint);
|
|
1776
|
+
}
|
|
1777
|
+
return error;
|
|
1778
|
+
}
|
|
1779
|
+
} : branch
|
|
1780
|
+
);
|
|
1781
|
+
try {
|
|
1782
|
+
const result = evaluateOneOf(isolatedBranches, data, defineError);
|
|
1783
|
+
if (result.error) {
|
|
1784
|
+
transactions.rollback(savepoint);
|
|
1785
|
+
return result.error;
|
|
1786
|
+
}
|
|
1787
|
+
transactions.restore(defaultsByBranch[result.winnerIndex] || []);
|
|
1788
|
+
return;
|
|
1789
|
+
} catch (error) {
|
|
1790
|
+
transactions.rollback(savepoint);
|
|
1791
|
+
throw error;
|
|
1792
|
+
}
|
|
1793
|
+
};
|
|
1794
|
+
}
|
|
1795
|
+
function prepareCombinatorEntries(schema) {
|
|
1796
|
+
if (Array.isArray(schema.allOf)) {
|
|
1797
|
+
getBranchEntries(schema, "allOf");
|
|
1798
|
+
}
|
|
1799
|
+
if (Array.isArray(schema.anyOf)) {
|
|
1800
|
+
getBranchEntries(schema, "anyOf");
|
|
1801
|
+
}
|
|
1802
|
+
if (Array.isArray(schema.oneOf)) {
|
|
1803
|
+
getBranchEntries(schema, "oneOf");
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1598
1806
|
var OtherKeywords = {
|
|
1599
1807
|
enum(schema, data, defineError) {
|
|
1600
1808
|
let enumCache = schema._enumCache;
|
|
@@ -1611,7 +1819,7 @@ var OtherKeywords = {
|
|
|
1611
1819
|
}
|
|
1612
1820
|
}
|
|
1613
1821
|
enumCache = { primitiveSet, objectValues };
|
|
1614
|
-
|
|
1822
|
+
definePropertyOrThrow(schema, "_enumCache", {
|
|
1615
1823
|
value: enumCache,
|
|
1616
1824
|
enumerable: false,
|
|
1617
1825
|
configurable: false,
|
|
@@ -1631,137 +1839,13 @@ var OtherKeywords = {
|
|
|
1631
1839
|
return defineError("Value is not one of the allowed values", { data });
|
|
1632
1840
|
},
|
|
1633
1841
|
allOf(schema, data, defineError) {
|
|
1634
|
-
|
|
1635
|
-
if (branches.length === 1) {
|
|
1636
|
-
const onlyBranch = branches[0];
|
|
1637
|
-
if (onlyBranch.kind === "validate") {
|
|
1638
|
-
const error = onlyBranch.validate(data);
|
|
1639
|
-
if (error) {
|
|
1640
|
-
return defineError("Value is not valid", { cause: error, data });
|
|
1641
|
-
}
|
|
1642
|
-
return;
|
|
1643
|
-
}
|
|
1644
|
-
if (onlyBranch.kind === "alwaysValid") {
|
|
1645
|
-
return;
|
|
1646
|
-
}
|
|
1647
|
-
if (onlyBranch.kind === "alwaysInvalid") {
|
|
1648
|
-
return defineError("Value is not valid", { data });
|
|
1649
|
-
}
|
|
1650
|
-
if (data !== onlyBranch.value) {
|
|
1651
|
-
return defineError("Value is not valid", { data });
|
|
1652
|
-
}
|
|
1653
|
-
return;
|
|
1654
|
-
}
|
|
1655
|
-
for (let i = 0; i < branches.length; i++) {
|
|
1656
|
-
const branch = branches[i];
|
|
1657
|
-
if (branch.kind === "validate") {
|
|
1658
|
-
const error = branch.validate(data);
|
|
1659
|
-
if (error) {
|
|
1660
|
-
return defineError("Value is not valid", { cause: error, data });
|
|
1661
|
-
}
|
|
1662
|
-
continue;
|
|
1663
|
-
}
|
|
1664
|
-
if (branch.kind === "alwaysValid") {
|
|
1665
|
-
continue;
|
|
1666
|
-
}
|
|
1667
|
-
if (branch.kind === "alwaysInvalid") {
|
|
1668
|
-
return defineError("Value is not valid", { data });
|
|
1669
|
-
}
|
|
1670
|
-
if (data !== branch.value) {
|
|
1671
|
-
return defineError("Value is not valid", { data });
|
|
1672
|
-
}
|
|
1673
|
-
}
|
|
1674
|
-
return;
|
|
1842
|
+
return createCombinatorValidator("allOf", schema, defineError)(data);
|
|
1675
1843
|
},
|
|
1676
1844
|
anyOf(schema, data, defineError) {
|
|
1677
|
-
|
|
1678
|
-
if (branches.length === 1) {
|
|
1679
|
-
const onlyBranch = branches[0];
|
|
1680
|
-
if (onlyBranch.kind === "validate") {
|
|
1681
|
-
const error = onlyBranch.validate(data);
|
|
1682
|
-
if (!error) {
|
|
1683
|
-
return;
|
|
1684
|
-
}
|
|
1685
|
-
return defineError("Value is not valid", { data });
|
|
1686
|
-
}
|
|
1687
|
-
if (onlyBranch.kind === "alwaysValid") {
|
|
1688
|
-
return;
|
|
1689
|
-
}
|
|
1690
|
-
if (onlyBranch.kind === "alwaysInvalid") {
|
|
1691
|
-
return defineError("Value is not valid", { data });
|
|
1692
|
-
}
|
|
1693
|
-
if (data === onlyBranch.value) {
|
|
1694
|
-
return;
|
|
1695
|
-
}
|
|
1696
|
-
return defineError("Value is not valid", { data });
|
|
1697
|
-
}
|
|
1698
|
-
for (let i = 0; i < branches.length; i++) {
|
|
1699
|
-
const branch = branches[i];
|
|
1700
|
-
if (branch.kind === "validate") {
|
|
1701
|
-
const error = branch.validate(data);
|
|
1702
|
-
if (!error) {
|
|
1703
|
-
return;
|
|
1704
|
-
}
|
|
1705
|
-
continue;
|
|
1706
|
-
}
|
|
1707
|
-
if (branch.kind === "alwaysValid") {
|
|
1708
|
-
return;
|
|
1709
|
-
}
|
|
1710
|
-
if (branch.kind === "alwaysInvalid") {
|
|
1711
|
-
continue;
|
|
1712
|
-
}
|
|
1713
|
-
if (data === branch.value) {
|
|
1714
|
-
return;
|
|
1715
|
-
}
|
|
1716
|
-
}
|
|
1717
|
-
return defineError("Value is not valid", { data });
|
|
1845
|
+
return createCombinatorValidator("anyOf", schema, defineError)(data);
|
|
1718
1846
|
},
|
|
1719
1847
|
oneOf(schema, data, defineError) {
|
|
1720
|
-
|
|
1721
|
-
if (branches.length === 1) {
|
|
1722
|
-
const onlyBranch = branches[0];
|
|
1723
|
-
if (onlyBranch.kind === "validate") {
|
|
1724
|
-
const error = onlyBranch.validate(data);
|
|
1725
|
-
if (!error) {
|
|
1726
|
-
return;
|
|
1727
|
-
}
|
|
1728
|
-
return defineError("Value is not valid", { data });
|
|
1729
|
-
}
|
|
1730
|
-
if (onlyBranch.kind === "alwaysValid") {
|
|
1731
|
-
return;
|
|
1732
|
-
}
|
|
1733
|
-
if (onlyBranch.kind === "alwaysInvalid") {
|
|
1734
|
-
return defineError("Value is not valid", { data });
|
|
1735
|
-
}
|
|
1736
|
-
if (data === onlyBranch.value) {
|
|
1737
|
-
return;
|
|
1738
|
-
}
|
|
1739
|
-
return defineError("Value is not valid", { data });
|
|
1740
|
-
}
|
|
1741
|
-
let validCount = 0;
|
|
1742
|
-
for (let i = 0; i < branches.length; i++) {
|
|
1743
|
-
const branch = branches[i];
|
|
1744
|
-
let isValid = false;
|
|
1745
|
-
if (branch.kind === "validate") {
|
|
1746
|
-
isValid = !branch.validate(data);
|
|
1747
|
-
} else if (branch.kind === "alwaysValid") {
|
|
1748
|
-
isValid = true;
|
|
1749
|
-
} else if (branch.kind === "alwaysInvalid") {
|
|
1750
|
-
isValid = false;
|
|
1751
|
-
} else {
|
|
1752
|
-
isValid = data === branch.value;
|
|
1753
|
-
}
|
|
1754
|
-
if (isValid) {
|
|
1755
|
-
validCount++;
|
|
1756
|
-
if (validCount > 1) {
|
|
1757
|
-
return defineError("Value is not valid", { data });
|
|
1758
|
-
}
|
|
1759
|
-
}
|
|
1760
|
-
}
|
|
1761
|
-
if (validCount === 1) {
|
|
1762
|
-
return;
|
|
1763
|
-
}
|
|
1764
|
-
return defineError("Value is not valid", { data });
|
|
1848
|
+
return createCombinatorValidator("oneOf", schema, defineError)(data);
|
|
1765
1849
|
},
|
|
1766
1850
|
const(schema, data, defineError) {
|
|
1767
1851
|
if (data === schema.const) {
|
|
@@ -1821,45 +1905,62 @@ var OtherKeywords = {
|
|
|
1821
1905
|
}
|
|
1822
1906
|
return defineError("Value is not valid", { data });
|
|
1823
1907
|
},
|
|
1824
|
-
$ref(schema, data, defineError
|
|
1825
|
-
if (schema._resolvedRef) {
|
|
1826
|
-
if (schema.$validate !== schema._resolvedRef) {
|
|
1827
|
-
schema.$validate = schema._resolvedRef;
|
|
1828
|
-
}
|
|
1908
|
+
$ref(schema, data, defineError) {
|
|
1909
|
+
if (typeof schema._resolvedRef === "function") {
|
|
1829
1910
|
return schema._resolvedRef(data);
|
|
1830
1911
|
}
|
|
1831
|
-
|
|
1832
|
-
let targetSchema = instance.getSchemaRef(refPath);
|
|
1833
|
-
if (!targetSchema) {
|
|
1834
|
-
targetSchema = instance.getSchemaById(refPath);
|
|
1835
|
-
}
|
|
1836
|
-
if (!targetSchema) {
|
|
1837
|
-
return defineError(`Missing reference: ${refPath}`);
|
|
1838
|
-
}
|
|
1839
|
-
if (!targetSchema.$validate) {
|
|
1840
|
-
return;
|
|
1841
|
-
}
|
|
1842
|
-
schema._resolvedRef = targetSchema.$validate;
|
|
1843
|
-
schema.$validate = schema._resolvedRef;
|
|
1844
|
-
return schema._resolvedRef(data);
|
|
1912
|
+
return defineError(`Missing reference: ${schema.$ref}`);
|
|
1845
1913
|
}
|
|
1846
1914
|
};
|
|
1847
1915
|
|
|
1848
1916
|
// lib/keywords/string-keywords.ts
|
|
1849
1917
|
var PATTERN_MATCH_CACHE_LIMIT = 512;
|
|
1850
1918
|
var FORMAT_RESULT_CACHE_LIMIT = 512;
|
|
1919
|
+
function hasAtLeastCodePoints(value, limit) {
|
|
1920
|
+
let count = 0;
|
|
1921
|
+
for (let index = 0; index < value.length; index++) {
|
|
1922
|
+
const unit = value.charCodeAt(index);
|
|
1923
|
+
if (unit >= 55296 && unit <= 56319 && index + 1 < value.length) {
|
|
1924
|
+
const nextUnit = value.charCodeAt(index + 1);
|
|
1925
|
+
if (nextUnit >= 56320 && nextUnit <= 57343) {
|
|
1926
|
+
index++;
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
count++;
|
|
1930
|
+
if (count >= limit) {
|
|
1931
|
+
return true;
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
return count >= limit;
|
|
1935
|
+
}
|
|
1851
1936
|
var StringKeywords = {
|
|
1852
1937
|
minLength(schema, data, defineError) {
|
|
1853
|
-
if (typeof data !== "string"
|
|
1938
|
+
if (typeof data !== "string") {
|
|
1939
|
+
return;
|
|
1940
|
+
}
|
|
1941
|
+
const units = data.length;
|
|
1942
|
+
const limit = schema.minLength;
|
|
1943
|
+
if (units < limit) {
|
|
1944
|
+
return defineError("Value is shorter than the minimum length", { data });
|
|
1945
|
+
}
|
|
1946
|
+
if (units - limit >= limit || hasAtLeastCodePoints(data, limit)) {
|
|
1854
1947
|
return;
|
|
1855
1948
|
}
|
|
1856
1949
|
return defineError("Value is shorter than the minimum length", { data });
|
|
1857
1950
|
},
|
|
1858
1951
|
maxLength(schema, data, defineError) {
|
|
1859
|
-
if (typeof data !== "string"
|
|
1952
|
+
if (typeof data !== "string") {
|
|
1953
|
+
return;
|
|
1954
|
+
}
|
|
1955
|
+
const units = data.length;
|
|
1956
|
+
const limit = schema.maxLength;
|
|
1957
|
+
if (units <= limit) {
|
|
1860
1958
|
return;
|
|
1861
1959
|
}
|
|
1862
|
-
|
|
1960
|
+
if (units - limit > limit || hasAtLeastCodePoints(data, limit + 1)) {
|
|
1961
|
+
return defineError("Value is longer than the maximum length", { data });
|
|
1962
|
+
}
|
|
1963
|
+
return;
|
|
1863
1964
|
},
|
|
1864
1965
|
pattern(schema, data, defineError) {
|
|
1865
1966
|
if (typeof data !== "string") {
|
|
@@ -1871,7 +1972,7 @@ var StringKeywords = {
|
|
|
1871
1972
|
try {
|
|
1872
1973
|
const compiled = compilePatternMatcher(schema.pattern);
|
|
1873
1974
|
patternMatch = compiled instanceof RegExp ? (value) => compiled.test(value) : compiled;
|
|
1874
|
-
|
|
1975
|
+
definePropertyOrThrow(schema, "_patternMatch", {
|
|
1875
1976
|
value: patternMatch,
|
|
1876
1977
|
enumerable: false,
|
|
1877
1978
|
configurable: false,
|
|
@@ -1886,7 +1987,7 @@ var StringKeywords = {
|
|
|
1886
1987
|
}
|
|
1887
1988
|
if (!patternMatchCache) {
|
|
1888
1989
|
patternMatchCache = /* @__PURE__ */ new Map();
|
|
1889
|
-
|
|
1990
|
+
definePropertyOrThrow(schema, "_patternMatchCache", {
|
|
1890
1991
|
value: patternMatchCache,
|
|
1891
1992
|
enumerable: false,
|
|
1892
1993
|
configurable: false,
|
|
@@ -1918,7 +2019,7 @@ var StringKeywords = {
|
|
|
1918
2019
|
let formatResultCache = schema._formatResultCache;
|
|
1919
2020
|
if (formatValidate === void 0) {
|
|
1920
2021
|
formatValidate = instance.getFormat(schema.format);
|
|
1921
|
-
|
|
2022
|
+
definePropertyOrThrow(schema, "_formatValidate", {
|
|
1922
2023
|
value: formatValidate,
|
|
1923
2024
|
enumerable: false,
|
|
1924
2025
|
configurable: false,
|
|
@@ -1933,7 +2034,7 @@ var StringKeywords = {
|
|
|
1933
2034
|
schema.format,
|
|
1934
2035
|
formatValidate
|
|
1935
2036
|
);
|
|
1936
|
-
|
|
2037
|
+
definePropertyOrThrow(schema, "_formatResultCacheEnabled", {
|
|
1937
2038
|
value: formatResultCacheEnabled,
|
|
1938
2039
|
enumerable: false,
|
|
1939
2040
|
configurable: false,
|
|
@@ -1948,7 +2049,7 @@ var StringKeywords = {
|
|
|
1948
2049
|
}
|
|
1949
2050
|
if (!formatResultCache) {
|
|
1950
2051
|
formatResultCache = /* @__PURE__ */ new Map();
|
|
1951
|
-
|
|
2052
|
+
definePropertyOrThrow(schema, "_formatResultCache", {
|
|
1952
2053
|
value: formatResultCache,
|
|
1953
2054
|
enumerable: false,
|
|
1954
2055
|
configurable: false,
|
|
@@ -1981,20 +2082,61 @@ var keywords = {
|
|
|
1981
2082
|
};
|
|
1982
2083
|
|
|
1983
2084
|
// lib/index.ts
|
|
2085
|
+
var MAX_COMPILE_DEPTH = 128;
|
|
2086
|
+
var LOCAL_SCHEMA_BASE = "schema-shield://local/root";
|
|
2087
|
+
var FAIL_FAST_TYPE_VALIDATORS = {
|
|
2088
|
+
object: (data) => data !== null && typeof data === "object" && !Array.isArray(data) ? void 0 : true,
|
|
2089
|
+
array: (data) => Array.isArray(data) ? void 0 : true,
|
|
2090
|
+
string: (data) => typeof data === "string" ? void 0 : true,
|
|
2091
|
+
number: (data) => typeof data === "number" && Number.isFinite(data) ? void 0 : true,
|
|
2092
|
+
integer: (data) => typeof data === "number" && Number.isFinite(data) && Number.isInteger(data) ? void 0 : true,
|
|
2093
|
+
boolean: (data) => typeof data === "boolean" ? void 0 : true,
|
|
2094
|
+
null: (data) => data === null ? void 0 : true
|
|
2095
|
+
};
|
|
2096
|
+
function createBuiltinTypeValidator(_type, defineError, fallback) {
|
|
2097
|
+
return (data) => {
|
|
2098
|
+
if (!fallback(data)) {
|
|
2099
|
+
return defineError("Invalid type", { data });
|
|
2100
|
+
}
|
|
2101
|
+
};
|
|
2102
|
+
}
|
|
1984
2103
|
var SchemaShield = class {
|
|
1985
2104
|
types = {};
|
|
1986
2105
|
formats = {};
|
|
1987
2106
|
keywords = {};
|
|
1988
2107
|
immutable = false;
|
|
2108
|
+
useDefaults = false;
|
|
1989
2109
|
rootSchema = null;
|
|
1990
|
-
idRegistry = /* @__PURE__ */ new Map();
|
|
1991
2110
|
failFast = true;
|
|
2111
|
+
maxDepth;
|
|
2112
|
+
validationContexts = [];
|
|
2113
|
+
compileCache = /* @__PURE__ */ new WeakMap();
|
|
2114
|
+
compilingRequiresContext = false;
|
|
2115
|
+
compilingMutableSchemas = /* @__PURE__ */ new WeakSet();
|
|
1992
2116
|
constructor({
|
|
1993
2117
|
immutable = false,
|
|
1994
|
-
failFast = true
|
|
2118
|
+
failFast = true,
|
|
2119
|
+
maxDepth = 128,
|
|
2120
|
+
useDefaults = false
|
|
1995
2121
|
} = {}) {
|
|
2122
|
+
if (!Number.isInteger(maxDepth) || maxDepth < 1 || maxDepth > 256) {
|
|
2123
|
+
const error = new ValidationError("maxDepth must be an integer from 1 to 256");
|
|
2124
|
+
error.code = "INVALID_MAX_DEPTH";
|
|
2125
|
+
error.keyword = "maxDepth";
|
|
2126
|
+
throw error;
|
|
2127
|
+
}
|
|
2128
|
+
if (useDefaults !== false && useDefaults !== true && useDefaults !== "empty") {
|
|
2129
|
+
const error = new ValidationError(
|
|
2130
|
+
'useDefaults must be false, true, or "empty"'
|
|
2131
|
+
);
|
|
2132
|
+
error.code = "INVALID_USE_DEFAULTS";
|
|
2133
|
+
error.keyword = "useDefaults";
|
|
2134
|
+
throw error;
|
|
2135
|
+
}
|
|
1996
2136
|
this.immutable = immutable;
|
|
1997
2137
|
this.failFast = failFast;
|
|
2138
|
+
this.maxDepth = maxDepth;
|
|
2139
|
+
this.useDefaults = useDefaults;
|
|
1998
2140
|
for (const [type, validator] of Object.entries(Types)) {
|
|
1999
2141
|
if (validator) {
|
|
2000
2142
|
this.addType(type, validator);
|
|
@@ -2009,6 +2151,50 @@ var SchemaShield = class {
|
|
|
2009
2151
|
}
|
|
2010
2152
|
}
|
|
2011
2153
|
}
|
|
2154
|
+
setDefault(target, key, value) {
|
|
2155
|
+
const context = this.validationContexts[this.validationContexts.length - 1];
|
|
2156
|
+
if (context) {
|
|
2157
|
+
context.defaults.push({
|
|
2158
|
+
target,
|
|
2159
|
+
key,
|
|
2160
|
+
descriptor: Reflect.getOwnPropertyDescriptor(target, key)
|
|
2161
|
+
});
|
|
2162
|
+
}
|
|
2163
|
+
definePropertyOrThrow(target, key, {
|
|
2164
|
+
value,
|
|
2165
|
+
enumerable: true,
|
|
2166
|
+
configurable: true,
|
|
2167
|
+
writable: true
|
|
2168
|
+
});
|
|
2169
|
+
}
|
|
2170
|
+
#defaultSavepoint() {
|
|
2171
|
+
const context = this.validationContexts[this.validationContexts.length - 1];
|
|
2172
|
+
return context ? context.defaults.length : 0;
|
|
2173
|
+
}
|
|
2174
|
+
#rollbackDefaultSavepoint(savepoint) {
|
|
2175
|
+
const context = this.validationContexts[this.validationContexts.length - 1];
|
|
2176
|
+
if (context) {
|
|
2177
|
+
this.rollbackDefaults(context, savepoint);
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
#captureDefaultSavepoint(savepoint) {
|
|
2181
|
+
const context = this.validationContexts[this.validationContexts.length - 1];
|
|
2182
|
+
if (!context || context.defaults.length === savepoint) {
|
|
2183
|
+
return [];
|
|
2184
|
+
}
|
|
2185
|
+
const mutations = context.defaults.slice(savepoint).map((entry) => ({
|
|
2186
|
+
...entry,
|
|
2187
|
+
value: entry.target[entry.key]
|
|
2188
|
+
}));
|
|
2189
|
+
this.rollbackDefaults(context, savepoint);
|
|
2190
|
+
return mutations;
|
|
2191
|
+
}
|
|
2192
|
+
#restoreDefaults(mutations) {
|
|
2193
|
+
for (let index = 0; index < mutations.length; index++) {
|
|
2194
|
+
const mutation = mutations[index];
|
|
2195
|
+
this.setDefault(mutation.target, mutation.key, mutation.value);
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2012
2198
|
addType(name, validator, overwrite = false) {
|
|
2013
2199
|
if (this.types[name] && !overwrite) {
|
|
2014
2200
|
throw new ValidationError(`Type "${name}" already exists`);
|
|
@@ -2046,14 +2232,465 @@ var SchemaShield = class {
|
|
|
2046
2232
|
return resolvePath(this.rootSchema, path);
|
|
2047
2233
|
}
|
|
2048
2234
|
getSchemaById(id) {
|
|
2049
|
-
|
|
2235
|
+
if (!this.rootSchema) {
|
|
2236
|
+
return;
|
|
2237
|
+
}
|
|
2238
|
+
const stack = [this.rootSchema];
|
|
2239
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
2240
|
+
while (stack.length > 0) {
|
|
2241
|
+
const node = stack.pop();
|
|
2242
|
+
if (seen.has(node)) {
|
|
2243
|
+
continue;
|
|
2244
|
+
}
|
|
2245
|
+
seen.add(node);
|
|
2246
|
+
if (node.$id === id) {
|
|
2247
|
+
return node;
|
|
2248
|
+
}
|
|
2249
|
+
const children = this.schemaChildren(node);
|
|
2250
|
+
for (let index = 0; index < children.length; index++) {
|
|
2251
|
+
stack.push(children[index]);
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
return;
|
|
2255
|
+
}
|
|
2256
|
+
depthError(message = "Maximum schema depth exceeded") {
|
|
2257
|
+
if (this.failFast) {
|
|
2258
|
+
return true;
|
|
2259
|
+
}
|
|
2260
|
+
const error = new ValidationError(message);
|
|
2261
|
+
error.code = "MAX_DEPTH_EXCEEDED";
|
|
2262
|
+
error.keyword = "maxDepth";
|
|
2263
|
+
return error;
|
|
2264
|
+
}
|
|
2265
|
+
schemaChildEntries(schema) {
|
|
2266
|
+
const children = [];
|
|
2267
|
+
const mapKeys = [
|
|
2268
|
+
"properties",
|
|
2269
|
+
"patternProperties",
|
|
2270
|
+
"definitions",
|
|
2271
|
+
"$defs",
|
|
2272
|
+
"dependencies"
|
|
2273
|
+
];
|
|
2274
|
+
const arrayKeys = ["allOf", "anyOf", "oneOf", "items"];
|
|
2275
|
+
const singleKeys = [
|
|
2276
|
+
"items",
|
|
2277
|
+
"additionalItems",
|
|
2278
|
+
"additionalProperties",
|
|
2279
|
+
"contains",
|
|
2280
|
+
"propertyNames",
|
|
2281
|
+
"values",
|
|
2282
|
+
"elements",
|
|
2283
|
+
"not",
|
|
2284
|
+
"if",
|
|
2285
|
+
"then",
|
|
2286
|
+
"else"
|
|
2287
|
+
];
|
|
2288
|
+
for (const key of mapKeys) {
|
|
2289
|
+
const value = schema[key];
|
|
2290
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
2291
|
+
continue;
|
|
2292
|
+
}
|
|
2293
|
+
for (const childKey of Object.keys(value)) {
|
|
2294
|
+
const child = value[childKey];
|
|
2295
|
+
if (child && typeof child === "object") {
|
|
2296
|
+
children.push({
|
|
2297
|
+
value: child,
|
|
2298
|
+
pointer: `/${this.escapePointerToken(key)}/${this.escapePointerToken(
|
|
2299
|
+
childKey
|
|
2300
|
+
)}`
|
|
2301
|
+
});
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
for (const key of arrayKeys) {
|
|
2306
|
+
const value = schema[key];
|
|
2307
|
+
if (!Array.isArray(value)) {
|
|
2308
|
+
continue;
|
|
2309
|
+
}
|
|
2310
|
+
for (let index = 0; index < value.length; index++) {
|
|
2311
|
+
const child = value[index];
|
|
2312
|
+
if (child && typeof child === "object") {
|
|
2313
|
+
children.push({
|
|
2314
|
+
value: child,
|
|
2315
|
+
pointer: `/${this.escapePointerToken(key)}/${index}`
|
|
2316
|
+
});
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
for (const key of singleKeys) {
|
|
2321
|
+
const value = schema[key];
|
|
2322
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
2323
|
+
children.push({
|
|
2324
|
+
value,
|
|
2325
|
+
pointer: `/${this.escapePointerToken(key)}`
|
|
2326
|
+
});
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2329
|
+
for (const key of Object.keys(schema)) {
|
|
2330
|
+
if (key === "enum" || key === "const" || key === "default" || key === "examples" || mapKeys.includes(key) || arrayKeys.includes(key) || singleKeys.includes(key)) {
|
|
2331
|
+
continue;
|
|
2332
|
+
}
|
|
2333
|
+
const keyword = this.getKeyword(key);
|
|
2334
|
+
const value = schema[key];
|
|
2335
|
+
if (keyword && keyword !== keywords[key] && value && typeof value === "object") {
|
|
2336
|
+
children.push({
|
|
2337
|
+
value,
|
|
2338
|
+
pointer: `/${this.escapePointerToken(key)}`
|
|
2339
|
+
});
|
|
2340
|
+
}
|
|
2341
|
+
}
|
|
2342
|
+
return children;
|
|
2343
|
+
}
|
|
2344
|
+
schemaChildren(schema) {
|
|
2345
|
+
return this.schemaChildEntries(schema).map((entry) => entry.value);
|
|
2346
|
+
}
|
|
2347
|
+
registrySubschemaEntries(schema) {
|
|
2348
|
+
const children = [];
|
|
2349
|
+
const mapKeys = ["properties", "patternProperties", "definitions"];
|
|
2350
|
+
const arrayKeys = ["allOf", "anyOf", "oneOf", "items"];
|
|
2351
|
+
const singleKeys = [
|
|
2352
|
+
"items",
|
|
2353
|
+
"additionalItems",
|
|
2354
|
+
"additionalProperties",
|
|
2355
|
+
"contains",
|
|
2356
|
+
"propertyNames",
|
|
2357
|
+
"not",
|
|
2358
|
+
"if",
|
|
2359
|
+
"then",
|
|
2360
|
+
"else"
|
|
2361
|
+
];
|
|
2362
|
+
for (const key of mapKeys) {
|
|
2363
|
+
const value = schema[key];
|
|
2364
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
2365
|
+
continue;
|
|
2366
|
+
}
|
|
2367
|
+
for (const childKey of Object.keys(value)) {
|
|
2368
|
+
const child = value[childKey];
|
|
2369
|
+
if (child && typeof child === "object" && !Array.isArray(child)) {
|
|
2370
|
+
children.push({
|
|
2371
|
+
value: child,
|
|
2372
|
+
pointer: `/${this.escapePointerToken(key)}/${this.escapePointerToken(
|
|
2373
|
+
childKey
|
|
2374
|
+
)}`
|
|
2375
|
+
});
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
const dependencies = schema.dependencies;
|
|
2380
|
+
if (dependencies && typeof dependencies === "object" && !Array.isArray(dependencies)) {
|
|
2381
|
+
for (const dependencyKey of Object.keys(dependencies)) {
|
|
2382
|
+
const child = dependencies[dependencyKey];
|
|
2383
|
+
if (child && typeof child === "object" && !Array.isArray(child)) {
|
|
2384
|
+
children.push({
|
|
2385
|
+
value: child,
|
|
2386
|
+
pointer: `/dependencies/${this.escapePointerToken(dependencyKey)}`
|
|
2387
|
+
});
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
for (const key of arrayKeys) {
|
|
2392
|
+
const value = schema[key];
|
|
2393
|
+
if (!Array.isArray(value)) {
|
|
2394
|
+
continue;
|
|
2395
|
+
}
|
|
2396
|
+
for (let index = 0; index < value.length; index++) {
|
|
2397
|
+
const child = value[index];
|
|
2398
|
+
if (child && typeof child === "object" && !Array.isArray(child)) {
|
|
2399
|
+
children.push({
|
|
2400
|
+
value: child,
|
|
2401
|
+
pointer: `/${this.escapePointerToken(key)}/${index}`
|
|
2402
|
+
});
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2405
|
+
}
|
|
2406
|
+
for (const key of singleKeys) {
|
|
2407
|
+
const value = schema[key];
|
|
2408
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
2409
|
+
children.push({
|
|
2410
|
+
value,
|
|
2411
|
+
pointer: `/${this.escapePointerToken(key)}`
|
|
2412
|
+
});
|
|
2413
|
+
}
|
|
2414
|
+
}
|
|
2415
|
+
return children;
|
|
2416
|
+
}
|
|
2417
|
+
escapePointerToken(value) {
|
|
2418
|
+
return value.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
2419
|
+
}
|
|
2420
|
+
resolveUri(reference, baseUri, keyword) {
|
|
2421
|
+
try {
|
|
2422
|
+
return new URL(reference, baseUri).href;
|
|
2423
|
+
} catch {
|
|
2424
|
+
const error = new ValidationError(`Invalid ${keyword} URI: ${reference}`);
|
|
2425
|
+
error.code = keyword === "$id" ? "INVALID_SCHEMA_ID" : "REFERENCE_NOT_FOUND";
|
|
2426
|
+
error.keyword = keyword;
|
|
2427
|
+
throw error;
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2430
|
+
resourceUri(uri) {
|
|
2431
|
+
const hashIndex = uri.indexOf("#");
|
|
2432
|
+
return hashIndex === -1 ? uri : uri.slice(0, hashIndex);
|
|
2433
|
+
}
|
|
2434
|
+
buildReferenceRegistry(schema) {
|
|
2435
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
2436
|
+
const positions = [];
|
|
2437
|
+
const positionsByNode = /* @__PURE__ */ new WeakMap();
|
|
2438
|
+
if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
|
|
2439
|
+
return Object.freeze({
|
|
2440
|
+
aliases,
|
|
2441
|
+
positions: Object.freeze(positions),
|
|
2442
|
+
positionsByNode
|
|
2443
|
+
});
|
|
2444
|
+
}
|
|
2445
|
+
const register = (uri, node) => {
|
|
2446
|
+
const existing = aliases.get(uri);
|
|
2447
|
+
if (existing && existing !== node) {
|
|
2448
|
+
const error = new ValidationError(`Duplicate schema identity: ${uri}`);
|
|
2449
|
+
error.code = "DUPLICATE_SCHEMA_ID";
|
|
2450
|
+
error.keyword = "$id";
|
|
2451
|
+
throw error;
|
|
2452
|
+
}
|
|
2453
|
+
aliases.set(uri, node);
|
|
2454
|
+
};
|
|
2455
|
+
register(LOCAL_SCHEMA_BASE, schema);
|
|
2456
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
2457
|
+
const stack = [
|
|
2458
|
+
{
|
|
2459
|
+
node: schema,
|
|
2460
|
+
inheritedBase: LOCAL_SCHEMA_BASE,
|
|
2461
|
+
resourceRoot: schema,
|
|
2462
|
+
pointer: "#"
|
|
2463
|
+
}
|
|
2464
|
+
];
|
|
2465
|
+
while (stack.length > 0) {
|
|
2466
|
+
const entry = stack.pop();
|
|
2467
|
+
if (visited.has(entry.node)) {
|
|
2468
|
+
continue;
|
|
2469
|
+
}
|
|
2470
|
+
visited.add(entry.node);
|
|
2471
|
+
let baseUri = entry.inheritedBase;
|
|
2472
|
+
let resourceRoot = entry.resourceRoot;
|
|
2473
|
+
if (typeof entry.node.$id === "string" && !("$ref" in entry.node)) {
|
|
2474
|
+
baseUri = this.resolveUri(entry.node.$id, entry.inheritedBase, "$id");
|
|
2475
|
+
register(baseUri, entry.node);
|
|
2476
|
+
if (baseUri.indexOf("#") === -1 || baseUri.endsWith("#")) {
|
|
2477
|
+
resourceRoot = entry.node;
|
|
2478
|
+
register(this.resourceUri(baseUri), entry.node);
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
const position = {
|
|
2482
|
+
source: entry.node,
|
|
2483
|
+
baseUri,
|
|
2484
|
+
resourceRoot,
|
|
2485
|
+
pointer: entry.pointer
|
|
2486
|
+
};
|
|
2487
|
+
positions.push(position);
|
|
2488
|
+
positionsByNode.set(entry.node, position);
|
|
2489
|
+
const children = this.registrySubschemaEntries(entry.node);
|
|
2490
|
+
for (let index = children.length - 1; index >= 0; index--) {
|
|
2491
|
+
const child = children[index];
|
|
2492
|
+
if (Array.isArray(child.value)) {
|
|
2493
|
+
continue;
|
|
2494
|
+
}
|
|
2495
|
+
stack.push({
|
|
2496
|
+
node: child.value,
|
|
2497
|
+
inheritedBase: baseUri,
|
|
2498
|
+
resourceRoot,
|
|
2499
|
+
pointer: `${entry.pointer}${child.pointer}`
|
|
2500
|
+
});
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
return Object.freeze({
|
|
2504
|
+
aliases,
|
|
2505
|
+
positions: Object.freeze(positions),
|
|
2506
|
+
positionsByNode
|
|
2507
|
+
});
|
|
2508
|
+
}
|
|
2509
|
+
resolveReferenceSource(ref, position, registry) {
|
|
2510
|
+
const resolvedUri = this.resolveUri(ref, position.baseUri, "$ref");
|
|
2511
|
+
const exactTarget = registry.aliases.get(resolvedUri);
|
|
2512
|
+
if (exactTarget) {
|
|
2513
|
+
return exactTarget;
|
|
2514
|
+
}
|
|
2515
|
+
const resourceRoot = registry.aliases.get(this.resourceUri(resolvedUri));
|
|
2516
|
+
if (!resourceRoot) {
|
|
2517
|
+
return;
|
|
2518
|
+
}
|
|
2519
|
+
const hashIndex = resolvedUri.indexOf("#");
|
|
2520
|
+
const fragment = hashIndex === -1 ? "" : resolvedUri.slice(hashIndex + 1);
|
|
2521
|
+
if (fragment.length === 0) {
|
|
2522
|
+
return resourceRoot;
|
|
2523
|
+
}
|
|
2524
|
+
if (fragment.startsWith("/")) {
|
|
2525
|
+
return resolvePath(resourceRoot, `#${fragment}`);
|
|
2526
|
+
}
|
|
2527
|
+
return;
|
|
2528
|
+
}
|
|
2529
|
+
analyzeSchema(schema, registry) {
|
|
2530
|
+
if (!schema || typeof schema !== "object") {
|
|
2531
|
+
return {
|
|
2532
|
+
requiresDepthGuard: false,
|
|
2533
|
+
requiresMutationJournal: false,
|
|
2534
|
+
mutableSchemas: /* @__PURE__ */ new WeakSet()
|
|
2535
|
+
};
|
|
2536
|
+
}
|
|
2537
|
+
const visiting = /* @__PURE__ */ new WeakSet();
|
|
2538
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
2539
|
+
const stack = [{ value: schema, depth: 0, exit: false }];
|
|
2540
|
+
let requiresDepthGuard = false;
|
|
2541
|
+
let requiresMutationJournal = false;
|
|
2542
|
+
while (stack.length > 0) {
|
|
2543
|
+
const entry = stack.pop();
|
|
2544
|
+
if (entry.exit) {
|
|
2545
|
+
visiting.delete(entry.value);
|
|
2546
|
+
visited.add(entry.value);
|
|
2547
|
+
continue;
|
|
2548
|
+
}
|
|
2549
|
+
if (visited.has(entry.value)) {
|
|
2550
|
+
continue;
|
|
2551
|
+
}
|
|
2552
|
+
if (visiting.has(entry.value)) {
|
|
2553
|
+
const error = new ValidationError("Cyclic schema graph is not supported");
|
|
2554
|
+
error.code = "CYCLIC_SCHEMA_GRAPH";
|
|
2555
|
+
error.keyword = "compile";
|
|
2556
|
+
throw error;
|
|
2557
|
+
}
|
|
2558
|
+
if (entry.depth > MAX_COMPILE_DEPTH) {
|
|
2559
|
+
const error = new ValidationError("Maximum compile depth exceeded");
|
|
2560
|
+
error.code = "MAX_COMPILE_DEPTH_EXCEEDED";
|
|
2561
|
+
error.keyword = "compile";
|
|
2562
|
+
throw error;
|
|
2563
|
+
}
|
|
2564
|
+
if (entry.depth > this.maxDepth) {
|
|
2565
|
+
requiresDepthGuard = true;
|
|
2566
|
+
}
|
|
2567
|
+
visiting.add(entry.value);
|
|
2568
|
+
stack.push({ ...entry, exit: true });
|
|
2569
|
+
if (this.useDefaults !== false && this.hasPropertyDefaults(entry.value)) {
|
|
2570
|
+
requiresMutationJournal = true;
|
|
2571
|
+
}
|
|
2572
|
+
for (const key of Object.keys(entry.value)) {
|
|
2573
|
+
const keyword = this.getKeyword(key);
|
|
2574
|
+
if (keyword && keyword !== keywords[key]) {
|
|
2575
|
+
requiresDepthGuard = true;
|
|
2576
|
+
requiresMutationJournal = true;
|
|
2577
|
+
}
|
|
2578
|
+
}
|
|
2579
|
+
const children = this.schemaChildren(entry.value);
|
|
2580
|
+
for (let index = children.length - 1; index >= 0; index--) {
|
|
2581
|
+
stack.push({
|
|
2582
|
+
value: children[index],
|
|
2583
|
+
depth: entry.depth + 1,
|
|
2584
|
+
exit: false
|
|
2585
|
+
});
|
|
2586
|
+
}
|
|
2587
|
+
}
|
|
2588
|
+
const semanticState = /* @__PURE__ */ new WeakMap();
|
|
2589
|
+
const semanticStack = [{ value: schema, exit: false }];
|
|
2590
|
+
while (semanticStack.length > 0 && !requiresDepthGuard) {
|
|
2591
|
+
const entry = semanticStack.pop();
|
|
2592
|
+
if (entry.exit) {
|
|
2593
|
+
semanticState.set(entry.value, 2);
|
|
2594
|
+
continue;
|
|
2595
|
+
}
|
|
2596
|
+
const state = semanticState.get(entry.value);
|
|
2597
|
+
if (state === 1) {
|
|
2598
|
+
requiresDepthGuard = true;
|
|
2599
|
+
break;
|
|
2600
|
+
}
|
|
2601
|
+
if (state === 2) {
|
|
2602
|
+
continue;
|
|
2603
|
+
}
|
|
2604
|
+
semanticState.set(entry.value, 1);
|
|
2605
|
+
semanticStack.push({ value: entry.value, exit: true });
|
|
2606
|
+
const children = this.schemaChildren(entry.value);
|
|
2607
|
+
if (typeof entry.value.$ref === "string" && this.getKeyword("$ref") === keywords.$ref) {
|
|
2608
|
+
const position = registry.positionsByNode.get(entry.value);
|
|
2609
|
+
const target = position ? this.resolveReferenceSource(entry.value.$ref, position, registry) : void 0;
|
|
2610
|
+
if (target && typeof target === "object") {
|
|
2611
|
+
children.push(target);
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2614
|
+
for (let index = children.length - 1; index >= 0; index--) {
|
|
2615
|
+
semanticStack.push({
|
|
2616
|
+
value: children[index],
|
|
2617
|
+
exit: false
|
|
2618
|
+
});
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
const mutableSchemas = /* @__PURE__ */ new WeakSet();
|
|
2622
|
+
if (requiresMutationJournal) {
|
|
2623
|
+
const mutationStack = [{ value: schema, exit: false }];
|
|
2624
|
+
const mutationVisited = /* @__PURE__ */ new WeakSet();
|
|
2625
|
+
while (mutationStack.length > 0) {
|
|
2626
|
+
const entry = mutationStack.pop();
|
|
2627
|
+
if (entry.exit) {
|
|
2628
|
+
const children2 = this.schemaChildren(entry.value);
|
|
2629
|
+
const hasCustomKeyword = Object.keys(entry.value).some((key) => {
|
|
2630
|
+
const keyword = this.getKeyword(key);
|
|
2631
|
+
return !!keyword && keyword !== keywords[key];
|
|
2632
|
+
});
|
|
2633
|
+
if (this.useDefaults !== false && this.hasPropertyDefaults(entry.value) || hasCustomKeyword || typeof entry.value.$ref === "string" || children2.some((child) => mutableSchemas.has(child))) {
|
|
2634
|
+
mutableSchemas.add(entry.value);
|
|
2635
|
+
}
|
|
2636
|
+
continue;
|
|
2637
|
+
}
|
|
2638
|
+
if (mutationVisited.has(entry.value)) {
|
|
2639
|
+
continue;
|
|
2640
|
+
}
|
|
2641
|
+
mutationVisited.add(entry.value);
|
|
2642
|
+
mutationStack.push({ value: entry.value, exit: true });
|
|
2643
|
+
const children = this.schemaChildren(entry.value);
|
|
2644
|
+
for (let index = children.length - 1; index >= 0; index--) {
|
|
2645
|
+
mutationStack.push({
|
|
2646
|
+
value: children[index],
|
|
2647
|
+
exit: false
|
|
2648
|
+
});
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
2651
|
+
}
|
|
2652
|
+
return { requiresDepthGuard, requiresMutationJournal, mutableSchemas };
|
|
2050
2653
|
}
|
|
2051
2654
|
compile(schema) {
|
|
2052
|
-
this.
|
|
2655
|
+
const prepared = this.prepareSchema(schema);
|
|
2656
|
+
const compiledSchema = prepared.compiledSchema;
|
|
2657
|
+
if (!prepared.requiresDepthGuard && !prepared.requiresMutationJournal) {
|
|
2658
|
+
const directValidate = compiledSchema.$validate;
|
|
2659
|
+
const validate = this.immutable ? (data) => {
|
|
2660
|
+
const clonedData = deepCloneUnfreeze(data);
|
|
2661
|
+
const error = directValidate(clonedData);
|
|
2662
|
+
return error ? { data: clonedData, error, valid: false } : { data: clonedData, error: null, valid: true };
|
|
2663
|
+
} : (data) => {
|
|
2664
|
+
const error = directValidate(data);
|
|
2665
|
+
return error ? { data, error, valid: false } : { data, error: null, valid: true };
|
|
2666
|
+
};
|
|
2667
|
+
validate.compiledSchema = compiledSchema;
|
|
2668
|
+
return validate;
|
|
2669
|
+
}
|
|
2670
|
+
return this.createGuardedValidator(compiledSchema, prepared.depthGuardState);
|
|
2671
|
+
}
|
|
2672
|
+
prepareSchema(schema) {
|
|
2673
|
+
const referenceRegistry = this.buildReferenceRegistry(schema);
|
|
2674
|
+
const analysis = this.analyzeSchema(schema, referenceRegistry);
|
|
2675
|
+
this.compileCache = /* @__PURE__ */ new WeakMap();
|
|
2676
|
+
this.compilingRequiresContext = analysis.requiresDepthGuard || analysis.requiresMutationJournal;
|
|
2677
|
+
this.compilingMutableSchemas = analysis.mutableSchemas;
|
|
2053
2678
|
const compiledSchema = this.compileSchema(schema);
|
|
2054
2679
|
this.rootSchema = compiledSchema;
|
|
2680
|
+
let depthGuardState = null;
|
|
2681
|
+
if (analysis.requiresDepthGuard) {
|
|
2682
|
+
depthGuardState = this.installDepthGuards(compiledSchema);
|
|
2683
|
+
definePropertyOrThrow(compiledSchema, "_requiresDepthGuard", {
|
|
2684
|
+
value: true,
|
|
2685
|
+
enumerable: false,
|
|
2686
|
+
configurable: false,
|
|
2687
|
+
writable: false
|
|
2688
|
+
});
|
|
2689
|
+
} else if (analysis.requiresMutationJournal) {
|
|
2690
|
+
depthGuardState = { context: null };
|
|
2691
|
+
}
|
|
2055
2692
|
if (compiledSchema._hasRef === true) {
|
|
2056
|
-
this.linkReferences(
|
|
2693
|
+
this.linkReferences(referenceRegistry);
|
|
2057
2694
|
}
|
|
2058
2695
|
if (!compiledSchema.$validate) {
|
|
2059
2696
|
if (schema === false) {
|
|
@@ -2082,14 +2719,53 @@ var SchemaShield = class {
|
|
|
2082
2719
|
);
|
|
2083
2720
|
}
|
|
2084
2721
|
}
|
|
2722
|
+
return {
|
|
2723
|
+
compiledSchema,
|
|
2724
|
+
requiresDepthGuard: analysis.requiresDepthGuard,
|
|
2725
|
+
requiresMutationJournal: analysis.requiresMutationJournal,
|
|
2726
|
+
depthGuardState
|
|
2727
|
+
};
|
|
2728
|
+
}
|
|
2729
|
+
createGuardedValidator(compiledSchema, depthGuardState) {
|
|
2730
|
+
const reusableContext = {
|
|
2731
|
+
active: false,
|
|
2732
|
+
depth: -1,
|
|
2733
|
+
depthExceeded: false,
|
|
2734
|
+
defaults: []
|
|
2735
|
+
};
|
|
2085
2736
|
const validate = (data) => {
|
|
2086
2737
|
this.rootSchema = compiledSchema;
|
|
2087
|
-
const
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2738
|
+
const context = reusableContext.active ? {
|
|
2739
|
+
active: false,
|
|
2740
|
+
depth: -1,
|
|
2741
|
+
depthExceeded: false,
|
|
2742
|
+
defaults: []
|
|
2743
|
+
} : reusableContext;
|
|
2744
|
+
context.active = true;
|
|
2745
|
+
context.depth = -1;
|
|
2746
|
+
context.depthExceeded = false;
|
|
2747
|
+
delete context.depthError;
|
|
2748
|
+
context.defaults.length = 0;
|
|
2749
|
+
this.validationContexts.push(context);
|
|
2750
|
+
const priorContext = depthGuardState.context;
|
|
2751
|
+
depthGuardState.context = context;
|
|
2752
|
+
let clonedData = data;
|
|
2753
|
+
try {
|
|
2754
|
+
clonedData = this.immutable ? deepCloneUnfreeze(data) : data;
|
|
2755
|
+
let error = compiledSchema.$validate(clonedData);
|
|
2756
|
+
if (this.isDepthError(error)) {
|
|
2757
|
+
this.rollbackDefaults(context, 0);
|
|
2758
|
+
error = context.depthError || this.depthError();
|
|
2759
|
+
}
|
|
2760
|
+
return error ? { data: clonedData, error, valid: false } : { data: clonedData, error: null, valid: true };
|
|
2761
|
+
} catch (error) {
|
|
2762
|
+
this.rollbackDefaults(context, 0);
|
|
2763
|
+
throw error;
|
|
2764
|
+
} finally {
|
|
2765
|
+
depthGuardState.context = priorContext;
|
|
2766
|
+
this.validationContexts.pop();
|
|
2767
|
+
context.active = false;
|
|
2091
2768
|
}
|
|
2092
|
-
return { data: clonedData, error: null, valid: true };
|
|
2093
2769
|
};
|
|
2094
2770
|
validate.compiledSchema = compiledSchema;
|
|
2095
2771
|
return validate;
|
|
@@ -2192,7 +2868,7 @@ var SchemaShield = class {
|
|
|
2192
2868
|
if (schema._hasRef === true) {
|
|
2193
2869
|
return;
|
|
2194
2870
|
}
|
|
2195
|
-
|
|
2871
|
+
definePropertyOrThrow(schema, "_hasRef", {
|
|
2196
2872
|
value: true,
|
|
2197
2873
|
enumerable: false,
|
|
2198
2874
|
configurable: false,
|
|
@@ -2250,15 +2926,15 @@ var SchemaShield = class {
|
|
|
2250
2926
|
return false;
|
|
2251
2927
|
}
|
|
2252
2928
|
}
|
|
2253
|
-
|
|
2929
|
+
hasPropertyDefaults(schema) {
|
|
2254
2930
|
const properties = schema.properties;
|
|
2255
2931
|
if (!this.isPlainObject(properties)) {
|
|
2256
2932
|
return false;
|
|
2257
2933
|
}
|
|
2258
|
-
const
|
|
2259
|
-
for (let i = 0; i <
|
|
2260
|
-
const subSchema = properties[
|
|
2261
|
-
if (this.isPlainObject(subSchema) && "default"
|
|
2934
|
+
const propertyKeys = Object.keys(properties);
|
|
2935
|
+
for (let i = 0; i < propertyKeys.length; i++) {
|
|
2936
|
+
const subSchema = properties[propertyKeys[i]];
|
|
2937
|
+
if (this.isPlainObject(subSchema) && hasOwn(subSchema, "default")) {
|
|
2262
2938
|
return true;
|
|
2263
2939
|
}
|
|
2264
2940
|
}
|
|
@@ -2267,24 +2943,134 @@ var SchemaShield = class {
|
|
|
2267
2943
|
isDefaultTypeValidator(type, validator) {
|
|
2268
2944
|
return Types[type] === validator;
|
|
2269
2945
|
}
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
schema = { oneOf: [] };
|
|
2946
|
+
rollbackDefaults(context, start) {
|
|
2947
|
+
for (let index = context.defaults.length - 1; index >= start; index--) {
|
|
2948
|
+
const entry = context.defaults[index];
|
|
2949
|
+
if (entry.descriptor) {
|
|
2950
|
+
definePropertyOrThrow(entry.target, entry.key, entry.descriptor);
|
|
2276
2951
|
} else {
|
|
2277
|
-
|
|
2952
|
+
delete entry.target[entry.key];
|
|
2953
|
+
}
|
|
2954
|
+
}
|
|
2955
|
+
context.defaults.length = start;
|
|
2956
|
+
}
|
|
2957
|
+
isDepthError(error) {
|
|
2958
|
+
const context = this.validationContexts[this.validationContexts.length - 1];
|
|
2959
|
+
if (context?.depthExceeded) {
|
|
2960
|
+
return true;
|
|
2961
|
+
}
|
|
2962
|
+
if (!(error instanceof ValidationError)) {
|
|
2963
|
+
return false;
|
|
2964
|
+
}
|
|
2965
|
+
return error.getCause().code === "MAX_DEPTH_EXCEEDED";
|
|
2966
|
+
}
|
|
2967
|
+
validateSubschema(schema, data) {
|
|
2968
|
+
if (!schema || typeof schema.$validate !== "function") {
|
|
2969
|
+
return;
|
|
2970
|
+
}
|
|
2971
|
+
const context = this.validationContexts[this.validationContexts.length - 1];
|
|
2972
|
+
const savepoint = context?.defaults.length || 0;
|
|
2973
|
+
try {
|
|
2974
|
+
const error = schema.$validate(data);
|
|
2975
|
+
if (error && context) {
|
|
2976
|
+
this.rollbackDefaults(context, savepoint);
|
|
2977
|
+
}
|
|
2978
|
+
return error;
|
|
2979
|
+
} catch (error) {
|
|
2980
|
+
if (context) {
|
|
2981
|
+
this.rollbackDefaults(context, savepoint);
|
|
2982
|
+
}
|
|
2983
|
+
throw error;
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2986
|
+
installDepthGuards(root) {
|
|
2987
|
+
const state = { context: null };
|
|
2988
|
+
const stack = [root];
|
|
2989
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
2990
|
+
while (stack.length > 0) {
|
|
2991
|
+
const schema = stack.pop();
|
|
2992
|
+
if (!schema || typeof schema !== "object" || seen.has(schema)) {
|
|
2993
|
+
continue;
|
|
2994
|
+
}
|
|
2995
|
+
seen.add(schema);
|
|
2996
|
+
if (typeof schema.$validate === "function") {
|
|
2997
|
+
const directValidate = schema.$validate;
|
|
2998
|
+
schema.$validate = getNamedFunction(directValidate.name, (data) => {
|
|
2999
|
+
const context = state.context;
|
|
3000
|
+
if (!context) {
|
|
3001
|
+
return directValidate(data);
|
|
3002
|
+
}
|
|
3003
|
+
const nextDepth = context.depth + 1;
|
|
3004
|
+
if (nextDepth > this.maxDepth) {
|
|
3005
|
+
context.depthExceeded = true;
|
|
3006
|
+
if (!context.depthError) {
|
|
3007
|
+
context.depthError = this.depthError();
|
|
3008
|
+
}
|
|
3009
|
+
return context.depthError;
|
|
3010
|
+
}
|
|
3011
|
+
context.depth = nextDepth;
|
|
3012
|
+
try {
|
|
3013
|
+
return directValidate(data);
|
|
3014
|
+
} finally {
|
|
3015
|
+
context.depth--;
|
|
3016
|
+
}
|
|
3017
|
+
});
|
|
3018
|
+
}
|
|
3019
|
+
const children = this.schemaChildren(schema);
|
|
3020
|
+
for (const child of children) {
|
|
3021
|
+
stack.push(child);
|
|
2278
3022
|
}
|
|
2279
3023
|
}
|
|
3024
|
+
return state;
|
|
3025
|
+
}
|
|
3026
|
+
compileSchema(schema) {
|
|
3027
|
+
if (schema === true) {
|
|
3028
|
+
return {
|
|
3029
|
+
$validate: getNamedFunction("Validate_True", () => {
|
|
3030
|
+
})
|
|
3031
|
+
};
|
|
3032
|
+
}
|
|
3033
|
+
if (schema === false) {
|
|
3034
|
+
const compiledFalse = {};
|
|
3035
|
+
const defineError = getDefinedErrorFunctionForKey(
|
|
3036
|
+
"oneOf",
|
|
3037
|
+
compiledFalse,
|
|
3038
|
+
this.failFast
|
|
3039
|
+
);
|
|
3040
|
+
compiledFalse.$validate = getNamedFunction(
|
|
3041
|
+
"Validate_False",
|
|
3042
|
+
(data) => defineError("Value is not valid", { data })
|
|
3043
|
+
);
|
|
3044
|
+
return compiledFalse;
|
|
3045
|
+
}
|
|
3046
|
+
const sourceSchema = schema && typeof schema === "object" && !Array.isArray(schema) ? schema : null;
|
|
3047
|
+
const schemaCanApplyDefaults = sourceSchema !== null && this.compilingMutableSchemas.has(sourceSchema);
|
|
3048
|
+
if (sourceSchema) {
|
|
3049
|
+
const cached = this.compileCache.get(sourceSchema);
|
|
3050
|
+
if (cached) {
|
|
3051
|
+
return cached;
|
|
3052
|
+
}
|
|
3053
|
+
}
|
|
3054
|
+
if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
|
|
3055
|
+
schema = { oneOf: [schema] };
|
|
3056
|
+
}
|
|
2280
3057
|
schema = this.normalizeSchemaForCompile(schema);
|
|
2281
3058
|
const compiledSchema = deepCloneUnfreeze(
|
|
2282
3059
|
schema
|
|
2283
3060
|
);
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
this.idRegistry.set(schema.$id, compiledSchema);
|
|
3061
|
+
if (sourceSchema) {
|
|
3062
|
+
this.compileCache.set(sourceSchema, compiledSchema);
|
|
2287
3063
|
}
|
|
3064
|
+
if (schemaCanApplyDefaults) {
|
|
3065
|
+
definePropertyOrThrow(compiledSchema, "_canApplyDefaults", {
|
|
3066
|
+
value: true,
|
|
3067
|
+
enumerable: false,
|
|
3068
|
+
configurable: false,
|
|
3069
|
+
writable: false
|
|
3070
|
+
});
|
|
3071
|
+
}
|
|
3072
|
+
const validateSubschema = this.compilingRequiresContext ? this.validateSubschema.bind(this) : void 0;
|
|
3073
|
+
let schemaHasRef = false;
|
|
2288
3074
|
if ("$ref" in schema) {
|
|
2289
3075
|
schemaHasRef = true;
|
|
2290
3076
|
const refValidator = this.getKeyword("$ref");
|
|
@@ -2294,21 +3080,53 @@ var SchemaShield = class {
|
|
|
2294
3080
|
schema["$ref"],
|
|
2295
3081
|
this.failFast
|
|
2296
3082
|
);
|
|
3083
|
+
const isBuiltinRef = refValidator === keywords.$ref;
|
|
2297
3084
|
compiledSchema.$validate = getNamedFunction(
|
|
2298
|
-
"Validate_Reference",
|
|
3085
|
+
isBuiltinRef ? "Validate_Reference" : refValidator.name || "$ref",
|
|
2299
3086
|
(data) => refValidator(
|
|
2300
3087
|
compiledSchema,
|
|
2301
3088
|
data,
|
|
2302
3089
|
defineError,
|
|
2303
|
-
this
|
|
3090
|
+
this,
|
|
3091
|
+
validateSubschema
|
|
2304
3092
|
)
|
|
2305
3093
|
);
|
|
3094
|
+
if (!isBuiltinRef) {
|
|
3095
|
+
schemaHasRef = false;
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3098
|
+
for (const key of ["definitions", "$defs"]) {
|
|
3099
|
+
const definitions = schema[key];
|
|
3100
|
+
if (!definitions || typeof definitions !== "object") {
|
|
3101
|
+
continue;
|
|
3102
|
+
}
|
|
3103
|
+
const compiledDefinitions = {};
|
|
3104
|
+
for (const definitionKey of Object.keys(definitions)) {
|
|
3105
|
+
compiledDefinitions[definitionKey] = this.compileSchema(
|
|
3106
|
+
definitions[definitionKey]
|
|
3107
|
+
);
|
|
3108
|
+
}
|
|
3109
|
+
compiledSchema[key] = compiledDefinitions;
|
|
3110
|
+
}
|
|
3111
|
+
if (schemaHasRef) {
|
|
3112
|
+
this.markSchemaHasRef(compiledSchema);
|
|
2306
3113
|
}
|
|
2307
|
-
this.markSchemaHasRef(compiledSchema);
|
|
2308
3114
|
return compiledSchema;
|
|
2309
3115
|
}
|
|
2310
3116
|
const validators = [];
|
|
2311
3117
|
const activeNames = [];
|
|
3118
|
+
const pendingCombinators = [];
|
|
3119
|
+
if (this.useDefaults !== false && this.getKeyword("properties") === keywords.properties && this.hasPropertyDefaults(schema)) {
|
|
3120
|
+
const applyDefaults = this.useDefaults === "empty" ? applyEmptyPropertyDefaults : applyPropertyDefaults;
|
|
3121
|
+
validators.push({
|
|
3122
|
+
name: applyDefaults.name,
|
|
3123
|
+
validate: getNamedFunction(
|
|
3124
|
+
applyDefaults.name,
|
|
3125
|
+
(data) => applyDefaults(compiledSchema, data, this)
|
|
3126
|
+
)
|
|
3127
|
+
});
|
|
3128
|
+
activeNames.push(applyDefaults.name);
|
|
3129
|
+
}
|
|
2312
3130
|
if ("type" in schema) {
|
|
2313
3131
|
const defineTypeError = getDefinedErrorFunctionForKey(
|
|
2314
3132
|
"type",
|
|
@@ -2344,65 +3162,11 @@ var SchemaShield = class {
|
|
|
2344
3162
|
if (typeFunctions.length === 1 && allTypesDefault) {
|
|
2345
3163
|
const singleTypeName = defaultTypeNames[0];
|
|
2346
3164
|
typeMethodName = singleTypeName;
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
}
|
|
2353
|
-
};
|
|
2354
|
-
break;
|
|
2355
|
-
case "array":
|
|
2356
|
-
combinedTypeValidator = (data) => {
|
|
2357
|
-
if (!Array.isArray(data)) {
|
|
2358
|
-
return defineTypeError("Invalid type", { data });
|
|
2359
|
-
}
|
|
2360
|
-
};
|
|
2361
|
-
break;
|
|
2362
|
-
case "string":
|
|
2363
|
-
combinedTypeValidator = (data) => {
|
|
2364
|
-
if (typeof data !== "string") {
|
|
2365
|
-
return defineTypeError("Invalid type", { data });
|
|
2366
|
-
}
|
|
2367
|
-
};
|
|
2368
|
-
break;
|
|
2369
|
-
case "number":
|
|
2370
|
-
combinedTypeValidator = (data) => {
|
|
2371
|
-
if (typeof data !== "number") {
|
|
2372
|
-
return defineTypeError("Invalid type", { data });
|
|
2373
|
-
}
|
|
2374
|
-
};
|
|
2375
|
-
break;
|
|
2376
|
-
case "integer":
|
|
2377
|
-
combinedTypeValidator = (data) => {
|
|
2378
|
-
if (typeof data !== "number" || !Number.isInteger(data)) {
|
|
2379
|
-
return defineTypeError("Invalid type", { data });
|
|
2380
|
-
}
|
|
2381
|
-
};
|
|
2382
|
-
break;
|
|
2383
|
-
case "boolean":
|
|
2384
|
-
combinedTypeValidator = (data) => {
|
|
2385
|
-
if (typeof data !== "boolean") {
|
|
2386
|
-
return defineTypeError("Invalid type", { data });
|
|
2387
|
-
}
|
|
2388
|
-
};
|
|
2389
|
-
break;
|
|
2390
|
-
case "null":
|
|
2391
|
-
combinedTypeValidator = (data) => {
|
|
2392
|
-
if (data !== null) {
|
|
2393
|
-
return defineTypeError("Invalid type", { data });
|
|
2394
|
-
}
|
|
2395
|
-
};
|
|
2396
|
-
break;
|
|
2397
|
-
default: {
|
|
2398
|
-
const singleTypeFn = typeFunctions[0];
|
|
2399
|
-
combinedTypeValidator = (data) => {
|
|
2400
|
-
if (!singleTypeFn(data)) {
|
|
2401
|
-
return defineTypeError("Invalid type", { data });
|
|
2402
|
-
}
|
|
2403
|
-
};
|
|
2404
|
-
}
|
|
2405
|
-
}
|
|
3165
|
+
combinedTypeValidator = this.failFast && FAIL_FAST_TYPE_VALIDATORS[singleTypeName] ? FAIL_FAST_TYPE_VALIDATORS[singleTypeName] : createBuiltinTypeValidator(
|
|
3166
|
+
singleTypeName,
|
|
3167
|
+
defineTypeError,
|
|
3168
|
+
typeFunctions[0]
|
|
3169
|
+
);
|
|
2406
3170
|
} else if (typeFunctions.length > 1 && allTypesDefault) {
|
|
2407
3171
|
typeMethodName = defaultTypeNames.join("_OR_");
|
|
2408
3172
|
const allowsObject = defaultTypeNames.includes("object");
|
|
@@ -2415,6 +3179,9 @@ var SchemaShield = class {
|
|
|
2415
3179
|
combinedTypeValidator = (data) => {
|
|
2416
3180
|
const dataType = typeof data;
|
|
2417
3181
|
if (dataType === "number") {
|
|
3182
|
+
if (!Number.isFinite(data)) {
|
|
3183
|
+
return defineTypeError("Invalid type", { data });
|
|
3184
|
+
}
|
|
2418
3185
|
if (allowsNumber || allowsInteger && Number.isInteger(data)) {
|
|
2419
3186
|
return;
|
|
2420
3187
|
}
|
|
@@ -2478,7 +3245,8 @@ var SchemaShield = class {
|
|
|
2478
3245
|
activeNames.push(typeMethodName);
|
|
2479
3246
|
}
|
|
2480
3247
|
const { type, $id, $ref, $validate, required, ...otherKeys } = schema;
|
|
2481
|
-
const
|
|
3248
|
+
const otherKeyNames = Object.keys(otherKeys);
|
|
3249
|
+
const keyOrder = required ? ["required", ...otherKeyNames] : otherKeyNames;
|
|
2482
3250
|
for (const key of keyOrder) {
|
|
2483
3251
|
const keywordFn = this.getKeyword(key);
|
|
2484
3252
|
if (!keywordFn) {
|
|
@@ -2493,12 +3261,33 @@ var SchemaShield = class {
|
|
|
2493
3261
|
this.failFast
|
|
2494
3262
|
);
|
|
2495
3263
|
const fnName = keywordFn.name || key;
|
|
3264
|
+
if ((key === "allOf" || key === "anyOf" || key === "oneOf") && keywordFn === keywords[key]) {
|
|
3265
|
+
const item = {
|
|
3266
|
+
name: fnName,
|
|
3267
|
+
validate: () => {
|
|
3268
|
+
throw new ValidationError("Combinator validator was not prepared");
|
|
3269
|
+
}
|
|
3270
|
+
};
|
|
3271
|
+
validators.push(item);
|
|
3272
|
+
pendingCombinators.push({ item, key, defineError });
|
|
3273
|
+
activeNames.push(fnName);
|
|
3274
|
+
continue;
|
|
3275
|
+
}
|
|
3276
|
+
const keywordValidate = validateSubschema ? (data) => keywordFn(
|
|
3277
|
+
compiledSchema,
|
|
3278
|
+
data,
|
|
3279
|
+
defineError,
|
|
3280
|
+
this,
|
|
3281
|
+
validateSubschema
|
|
3282
|
+
) : (data) => keywordFn(
|
|
3283
|
+
compiledSchema,
|
|
3284
|
+
data,
|
|
3285
|
+
defineError,
|
|
3286
|
+
this
|
|
3287
|
+
);
|
|
2496
3288
|
validators.push({
|
|
2497
3289
|
name: fnName,
|
|
2498
|
-
validate: getNamedFunction(
|
|
2499
|
-
fnName,
|
|
2500
|
-
(data) => keywordFn(compiledSchema, data, defineError, this)
|
|
2501
|
-
)
|
|
3290
|
+
validate: getNamedFunction(fnName, keywordValidate)
|
|
2502
3291
|
});
|
|
2503
3292
|
activeNames.push(fnName);
|
|
2504
3293
|
}
|
|
@@ -2540,6 +3329,50 @@ var SchemaShield = class {
|
|
|
2540
3329
|
continue;
|
|
2541
3330
|
}
|
|
2542
3331
|
}
|
|
3332
|
+
if (this.isPlainObject(schema.properties)) {
|
|
3333
|
+
definePropertyOrThrow(compiledSchema, "_propKeys", {
|
|
3334
|
+
value: Object.keys(schema.properties),
|
|
3335
|
+
enumerable: false,
|
|
3336
|
+
configurable: false,
|
|
3337
|
+
writable: false
|
|
3338
|
+
});
|
|
3339
|
+
}
|
|
3340
|
+
if (this.useDefaults !== false && this.isPlainObject(schema.properties) && this.hasPropertyDefaults(schema)) {
|
|
3341
|
+
const defaultKeys = Object.keys(schema.properties).filter(
|
|
3342
|
+
(key) => {
|
|
3343
|
+
const property = schema.properties[key];
|
|
3344
|
+
return property && typeof property === "object" && !Array.isArray(property) && hasOwn(property, "default");
|
|
3345
|
+
}
|
|
3346
|
+
);
|
|
3347
|
+
if (defaultKeys.length > 0) {
|
|
3348
|
+
definePropertyOrThrow(compiledSchema, "_defaultKeys", {
|
|
3349
|
+
value: defaultKeys,
|
|
3350
|
+
enumerable: false,
|
|
3351
|
+
configurable: false,
|
|
3352
|
+
writable: false
|
|
3353
|
+
});
|
|
3354
|
+
}
|
|
3355
|
+
}
|
|
3356
|
+
prepareCombinatorEntries(compiledSchema);
|
|
3357
|
+
for (let index = 0; index < pendingCombinators.length; index++) {
|
|
3358
|
+
const pending = pendingCombinators[index];
|
|
3359
|
+
const transactions = compiledSchema._canApplyDefaults === true ? {
|
|
3360
|
+
savepoint: () => this.#defaultSavepoint(),
|
|
3361
|
+
rollback: (savepoint) => this.#rollbackDefaultSavepoint(savepoint),
|
|
3362
|
+
capture: (savepoint) => this.#captureDefaultSavepoint(savepoint),
|
|
3363
|
+
restore: (mutations) => this.#restoreDefaults(mutations)
|
|
3364
|
+
} : void 0;
|
|
3365
|
+
pending.item.validate = getNamedFunction(
|
|
3366
|
+
pending.item.name,
|
|
3367
|
+
createCombinatorValidator(
|
|
3368
|
+
pending.key,
|
|
3369
|
+
compiledSchema,
|
|
3370
|
+
pending.defineError,
|
|
3371
|
+
validateSubschema,
|
|
3372
|
+
transactions
|
|
3373
|
+
)
|
|
3374
|
+
);
|
|
3375
|
+
}
|
|
2543
3376
|
if (schemaHasRef) {
|
|
2544
3377
|
this.markSchemaHasRef(compiledSchema);
|
|
2545
3378
|
}
|
|
@@ -2581,54 +3414,80 @@ var SchemaShield = class {
|
|
|
2581
3414
|
}
|
|
2582
3415
|
return false;
|
|
2583
3416
|
}
|
|
2584
|
-
|
|
2585
|
-
const
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
3417
|
+
getCompiledReferenceTarget(ref, position, registry) {
|
|
3418
|
+
const resolvedUri = this.resolveUri(ref, position.baseUri, "$ref");
|
|
3419
|
+
const exactTarget = registry.aliases.get(resolvedUri);
|
|
3420
|
+
if (exactTarget) {
|
|
3421
|
+
return this.compileCache.get(exactTarget);
|
|
3422
|
+
}
|
|
3423
|
+
const resourceRoot = registry.aliases.get(this.resourceUri(resolvedUri));
|
|
3424
|
+
if (!resourceRoot) {
|
|
3425
|
+
return;
|
|
3426
|
+
}
|
|
3427
|
+
const compiledResource = this.compileCache.get(resourceRoot);
|
|
3428
|
+
if (!compiledResource) {
|
|
3429
|
+
return;
|
|
3430
|
+
}
|
|
3431
|
+
const hashIndex = resolvedUri.indexOf("#");
|
|
3432
|
+
const fragment = hashIndex === -1 ? "" : resolvedUri.slice(hashIndex + 1);
|
|
3433
|
+
if (fragment.length === 0) {
|
|
3434
|
+
return compiledResource;
|
|
3435
|
+
}
|
|
3436
|
+
if (fragment.startsWith("/")) {
|
|
3437
|
+
return resolvePath(compiledResource, `#${fragment}`);
|
|
3438
|
+
}
|
|
3439
|
+
return;
|
|
3440
|
+
}
|
|
3441
|
+
linkReferences(registry) {
|
|
3442
|
+
for (let index = 0; index < registry.positions.length; index++) {
|
|
3443
|
+
const position = registry.positions[index];
|
|
3444
|
+
if (typeof position.source.$ref !== "string" || this.getKeyword("$ref") !== keywords.$ref) {
|
|
2589
3445
|
continue;
|
|
2590
|
-
if (typeof node.$ref === "string" && typeof node.$validate === "function" && node.$validate.name === "Validate_Reference") {
|
|
2591
|
-
const refPath = node.$ref;
|
|
2592
|
-
let target = this.getSchemaRef(refPath);
|
|
2593
|
-
if (typeof target === "undefined") {
|
|
2594
|
-
target = this.getSchemaById(refPath);
|
|
2595
|
-
}
|
|
2596
|
-
if (typeof target === "boolean") {
|
|
2597
|
-
if (target === true) {
|
|
2598
|
-
node.$validate = getNamedFunction("Validate_Ref_True", () => {
|
|
2599
|
-
});
|
|
2600
|
-
} else {
|
|
2601
|
-
const defineError = getDefinedErrorFunctionForKey(
|
|
2602
|
-
"$ref",
|
|
2603
|
-
node,
|
|
2604
|
-
this.failFast
|
|
2605
|
-
);
|
|
2606
|
-
node.$validate = getNamedFunction(
|
|
2607
|
-
"Validate_Ref_False",
|
|
2608
|
-
(_data) => defineError("Value is not valid")
|
|
2609
|
-
);
|
|
2610
|
-
}
|
|
2611
|
-
continue;
|
|
2612
|
-
}
|
|
2613
|
-
if (target && typeof target.$validate === "function") {
|
|
2614
|
-
node.$validate = target.$validate;
|
|
2615
|
-
}
|
|
2616
3446
|
}
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
3447
|
+
const node = this.compileCache.get(position.source);
|
|
3448
|
+
const target = this.getCompiledReferenceTarget(
|
|
3449
|
+
position.source.$ref,
|
|
3450
|
+
position,
|
|
3451
|
+
registry
|
|
3452
|
+
);
|
|
3453
|
+
if (!node || typeof target === "undefined") {
|
|
3454
|
+
const error = new ValidationError(
|
|
3455
|
+
`Reference not found: ${position.source.$ref}`
|
|
3456
|
+
);
|
|
3457
|
+
error.code = "REFERENCE_NOT_FOUND";
|
|
3458
|
+
error.keyword = "$ref";
|
|
3459
|
+
throw error;
|
|
3460
|
+
}
|
|
3461
|
+
let targetValidate;
|
|
3462
|
+
if (target === true) {
|
|
3463
|
+
targetValidate = getNamedFunction("Validate_Ref_True", () => {
|
|
3464
|
+
});
|
|
3465
|
+
} else if (target === false) {
|
|
3466
|
+
const defineError = getDefinedErrorFunctionForKey(
|
|
3467
|
+
"$ref",
|
|
3468
|
+
node,
|
|
3469
|
+
this.failFast
|
|
3470
|
+
);
|
|
3471
|
+
targetValidate = getNamedFunction(
|
|
3472
|
+
"Validate_Ref_False",
|
|
3473
|
+
(data) => defineError("Value is not valid", { data })
|
|
3474
|
+
);
|
|
3475
|
+
} else {
|
|
3476
|
+
if (typeof target.$validate !== "function") {
|
|
3477
|
+
target.$validate = getNamedFunction(
|
|
3478
|
+
"Validate_Ref_Any",
|
|
3479
|
+
() => {
|
|
2626
3480
|
}
|
|
2627
|
-
|
|
2628
|
-
} else if (typeof value === "object") {
|
|
2629
|
-
stack.push(value);
|
|
3481
|
+
);
|
|
2630
3482
|
}
|
|
3483
|
+
targetValidate = target.$validate;
|
|
2631
3484
|
}
|
|
3485
|
+
definePropertyOrThrow(node, "_resolvedRef", {
|
|
3486
|
+
value: targetValidate,
|
|
3487
|
+
enumerable: false,
|
|
3488
|
+
configurable: false,
|
|
3489
|
+
writable: false
|
|
3490
|
+
});
|
|
2632
3491
|
}
|
|
2633
3492
|
}
|
|
2634
3493
|
};
|