schema-shield 1.0.5 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +400 -1050
- package/dist/formats.d.ts.map +1 -1
- package/dist/index.d.ts +33 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1247 -392
- package/dist/index.min.js +2 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.mjs +1247 -392
- package/dist/keywords/array-keywords.d.ts.map +1 -1
- package/dist/keywords/number-keywords.d.ts.map +1 -1
- package/dist/keywords/object-keywords.d.ts +7 -1
- package/dist/keywords/object-keywords.d.ts.map +1 -1
- package/dist/keywords/other-keywords.d.ts +17 -1
- package/dist/keywords/other-keywords.d.ts.map +1 -1
- package/dist/keywords/string-keywords.d.ts.map +1 -1
- package/dist/utils/deep-freeze.d.ts.map +1 -1
- package/dist/utils/main-utils.d.ts +7 -4
- package/dist/utils/main-utils.d.ts.map +1 -1
- package/lib/formats.ts +36 -10
- package/lib/index.ts +1157 -155
- package/lib/keywords/array-keywords.ts +18 -3
- package/lib/keywords/number-keywords.ts +19 -5
- package/lib/keywords/object-keywords.ts +59 -61
- package/lib/keywords/other-keywords.ts +205 -192
- package/lib/keywords/string-keywords.ts +51 -8
- package/lib/types.ts +2 -2
- package/lib/utils/deep-freeze.ts +6 -4
- package/lib/utils/main-utils.ts +91 -47
- package/package.json +8 -10
package/dist/index.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;
|
|
@@ -39,42 +53,57 @@ var ValidationError = class extends Error {
|
|
|
39
53
|
super(message);
|
|
40
54
|
this.message = message;
|
|
41
55
|
}
|
|
42
|
-
_getCause(pointer = "#", instancePointer = "#") {
|
|
43
|
-
let schemaPath = `${pointer}/${this.keyword}`;
|
|
44
|
-
let instancePath = `${instancePointer}`;
|
|
45
|
-
if (typeof this.item !== "undefined") {
|
|
46
|
-
if (typeof this.item === "string" && this.schema && typeof this.schema === "object" && this.item in this.schema) {
|
|
47
|
-
schemaPath += `/${this.item}`;
|
|
48
|
-
}
|
|
49
|
-
instancePath += `/${this.item}`;
|
|
50
|
-
}
|
|
51
|
-
this.instancePath = instancePath;
|
|
52
|
-
this.schemaPath = schemaPath;
|
|
53
|
-
if (!this.cause || !(this.cause instanceof ValidationError)) {
|
|
54
|
-
return this;
|
|
55
|
-
}
|
|
56
|
-
return this.cause._getCause(schemaPath, instancePath);
|
|
57
|
-
}
|
|
58
56
|
getCause() {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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;
|
|
72
79
|
}
|
|
73
|
-
return
|
|
80
|
+
return current;
|
|
74
81
|
}
|
|
75
82
|
getTree() {
|
|
76
83
|
this.getCause();
|
|
77
|
-
|
|
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;
|
|
78
107
|
}
|
|
79
108
|
getPath() {
|
|
80
109
|
const cause = this.getCause();
|
|
@@ -94,8 +123,11 @@ function getDefinedErrorFunctionForKey(key, schema, failFast) {
|
|
|
94
123
|
KeywordError.schema = schema;
|
|
95
124
|
const defineError = (message, options = {}) => {
|
|
96
125
|
KeywordError.message = message;
|
|
126
|
+
KeywordError.code = options.code;
|
|
97
127
|
KeywordError.item = options.item;
|
|
98
|
-
|
|
128
|
+
if (options.cause !== KeywordError) {
|
|
129
|
+
KeywordError.cause = options.cause && options.cause !== true ? options.cause : void 0;
|
|
130
|
+
}
|
|
99
131
|
KeywordError.data = options.data;
|
|
100
132
|
return KeywordError;
|
|
101
133
|
};
|
|
@@ -104,11 +136,14 @@ function getDefinedErrorFunctionForKey(key, schema, failFast) {
|
|
|
104
136
|
defineError
|
|
105
137
|
);
|
|
106
138
|
}
|
|
139
|
+
function escapeJsonPointerToken(value) {
|
|
140
|
+
return String(value).replace(/~/g, "~0").replace(/\//g, "~1");
|
|
141
|
+
}
|
|
107
142
|
function isCompiledSchema(subSchema) {
|
|
108
143
|
return !!subSchema && typeof subSchema === "object" && !Array.isArray(subSchema) && "$validate" in subSchema;
|
|
109
144
|
}
|
|
110
145
|
function getNamedFunction(name, fn) {
|
|
111
|
-
return
|
|
146
|
+
return definePropertyOrThrow(fn, "name", { value: name });
|
|
112
147
|
}
|
|
113
148
|
function resolvePath(root, path) {
|
|
114
149
|
if (!path || path === "#") {
|
|
@@ -153,7 +188,6 @@ var DURATION_REGEX = /^P(?!$)((\d+Y)?(\d+M)?(\d+W)?(\d+D)?)(T(?=\d)(\d+H)?(\d+M)
|
|
|
153
188
|
var URI_REGEX = /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/;
|
|
154
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;
|
|
155
190
|
var HOSTNAME_REGEX = /^[a-z0-9][a-z0-9-]{0,62}(?:\.[a-z0-9][a-z0-9-]{0,62})*[a-z0-9]$/i;
|
|
156
|
-
var DATE_REGEX = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
157
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))$/;
|
|
158
192
|
var URI_REFERENCE_REGEX = /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#((?![^#]*\\)[^#]*))?/i;
|
|
159
193
|
var IRI_REGEX = /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/;
|
|
@@ -218,6 +252,22 @@ function isValidIpv4(data) {
|
|
|
218
252
|
function isHexCharCode(code) {
|
|
219
253
|
return code >= 48 && code <= 57 || code >= 65 && code <= 70 || code >= 97 && code <= 102;
|
|
220
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
|
+
}
|
|
221
271
|
function isValidIpv6(data) {
|
|
222
272
|
const length = data.length;
|
|
223
273
|
if (length === 0) {
|
|
@@ -322,7 +372,7 @@ function isValidJsonPointer(data) {
|
|
|
322
372
|
}
|
|
323
373
|
function isValidRelativeJsonPointer(data) {
|
|
324
374
|
if (data.length === 0) {
|
|
325
|
-
return
|
|
375
|
+
return false;
|
|
326
376
|
}
|
|
327
377
|
let i = 0;
|
|
328
378
|
while (i < data.length) {
|
|
@@ -335,6 +385,9 @@ function isValidRelativeJsonPointer(data) {
|
|
|
335
385
|
if (i === 0) {
|
|
336
386
|
return false;
|
|
337
387
|
}
|
|
388
|
+
if (i > 1 && data.charCodeAt(0) === 48) {
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
338
391
|
if (i === data.length) {
|
|
339
392
|
return true;
|
|
340
393
|
}
|
|
@@ -461,7 +514,7 @@ var Formats = {
|
|
|
461
514
|
return true;
|
|
462
515
|
},
|
|
463
516
|
uri(data) {
|
|
464
|
-
return URI_REGEX.test(data);
|
|
517
|
+
return URI_REGEX.test(data) && hasValidPercentEncoding(data);
|
|
465
518
|
},
|
|
466
519
|
email(data) {
|
|
467
520
|
return EMAIL_REGEX.test(data);
|
|
@@ -476,15 +529,13 @@ var Formats = {
|
|
|
476
529
|
return HOSTNAME_REGEX.test(data);
|
|
477
530
|
},
|
|
478
531
|
date(data) {
|
|
479
|
-
|
|
480
|
-
if (!match) {
|
|
532
|
+
if (data.length !== 10 || data.charCodeAt(4) !== 45 || data.charCodeAt(7) !== 45) {
|
|
481
533
|
return false;
|
|
482
534
|
}
|
|
483
|
-
const
|
|
484
|
-
const
|
|
485
|
-
const
|
|
486
|
-
|
|
487
|
-
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) {
|
|
488
539
|
return false;
|
|
489
540
|
}
|
|
490
541
|
if (day < 1) {
|
|
@@ -556,10 +607,10 @@ var Types = {
|
|
|
556
607
|
return typeof data === "string";
|
|
557
608
|
},
|
|
558
609
|
number(data) {
|
|
559
|
-
return typeof data === "number";
|
|
610
|
+
return typeof data === "number" && Number.isFinite(data);
|
|
560
611
|
},
|
|
561
612
|
integer(data) {
|
|
562
|
-
return typeof data === "number" && data % 1 === 0;
|
|
613
|
+
return typeof data === "number" && Number.isFinite(data) && data % 1 === 0;
|
|
563
614
|
},
|
|
564
615
|
boolean(data) {
|
|
565
616
|
return typeof data === "boolean";
|
|
@@ -784,7 +835,7 @@ var ArrayKeywords = {
|
|
|
784
835
|
let tupleLength = schema._tupleItemsLength;
|
|
785
836
|
if (tupleLength === void 0) {
|
|
786
837
|
tupleLength = schema.items.length;
|
|
787
|
-
|
|
838
|
+
definePropertyOrThrow(schema, "_tupleItemsLength", {
|
|
788
839
|
value: tupleLength,
|
|
789
840
|
enumerable: false,
|
|
790
841
|
configurable: false,
|
|
@@ -841,13 +892,23 @@ var ArrayKeywords = {
|
|
|
841
892
|
}
|
|
842
893
|
return;
|
|
843
894
|
}
|
|
844
|
-
|
|
895
|
+
let hasFirstPrimitive = false;
|
|
896
|
+
let firstPrimitive;
|
|
897
|
+
let primitiveSeen;
|
|
845
898
|
let primitiveArraySignatures;
|
|
846
899
|
let arrayBuckets;
|
|
847
900
|
let objectBuckets;
|
|
848
901
|
for (let i = 0; i < len; i++) {
|
|
849
902
|
const item = data[i];
|
|
850
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
|
+
}
|
|
851
912
|
if (primitiveSeen.has(item)) {
|
|
852
913
|
return defineError("Array items are not unique", { data: item });
|
|
853
914
|
}
|
|
@@ -933,7 +994,7 @@ function isPlainObject(value) {
|
|
|
933
994
|
if (!value || typeof value !== "object") {
|
|
934
995
|
return false;
|
|
935
996
|
}
|
|
936
|
-
const proto =
|
|
997
|
+
const proto = Reflect.getPrototypeOf(value);
|
|
937
998
|
return proto === Object.prototype || proto === null;
|
|
938
999
|
}
|
|
939
1000
|
function canUseStructuredClone(value) {
|
|
@@ -1028,7 +1089,7 @@ function deepCloneUnfreeze(obj, cloneClassInstances = false, seen = /* @__PURE__
|
|
|
1028
1089
|
seen.set(source, clone);
|
|
1029
1090
|
return clone;
|
|
1030
1091
|
}
|
|
1031
|
-
clone = Object.create(
|
|
1092
|
+
clone = Object.create(Reflect.getPrototypeOf(source));
|
|
1032
1093
|
seen.set(source, clone);
|
|
1033
1094
|
break;
|
|
1034
1095
|
}
|
|
@@ -1057,7 +1118,7 @@ function deepCloneUnfreeze(obj, cloneClassInstances = false, seen = /* @__PURE__
|
|
|
1057
1118
|
seen
|
|
1058
1119
|
);
|
|
1059
1120
|
}
|
|
1060
|
-
|
|
1121
|
+
definePropertyOrThrow(clone, key, descriptor);
|
|
1061
1122
|
}
|
|
1062
1123
|
return clone;
|
|
1063
1124
|
}
|
|
@@ -1068,6 +1129,9 @@ var NumberKeywords = {
|
|
|
1068
1129
|
if (typeof data !== "number") {
|
|
1069
1130
|
return;
|
|
1070
1131
|
}
|
|
1132
|
+
if (!Number.isFinite(data)) {
|
|
1133
|
+
return defineError("Value must be finite", { data });
|
|
1134
|
+
}
|
|
1071
1135
|
let min = schema.minimum;
|
|
1072
1136
|
if (typeof schema.exclusiveMinimum === "number") {
|
|
1073
1137
|
min = schema.exclusiveMinimum + 1e-15;
|
|
@@ -1083,6 +1147,9 @@ var NumberKeywords = {
|
|
|
1083
1147
|
if (typeof data !== "number") {
|
|
1084
1148
|
return;
|
|
1085
1149
|
}
|
|
1150
|
+
if (!Number.isFinite(data)) {
|
|
1151
|
+
return defineError("Value must be finite", { data });
|
|
1152
|
+
}
|
|
1086
1153
|
let max = schema.maximum;
|
|
1087
1154
|
if (typeof schema.exclusiveMaximum === "number") {
|
|
1088
1155
|
max = schema.exclusiveMaximum - 1e-15;
|
|
@@ -1098,11 +1165,14 @@ var NumberKeywords = {
|
|
|
1098
1165
|
if (typeof data !== "number") {
|
|
1099
1166
|
return;
|
|
1100
1167
|
}
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
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
|
+
});
|
|
1104
1172
|
}
|
|
1105
|
-
|
|
1173
|
+
const quotient = data / schema.multipleOf;
|
|
1174
|
+
const valid = Number.isFinite(quotient) ? areCloseEnough(quotient, Math.round(quotient)) : data % schema.multipleOf === 0;
|
|
1175
|
+
if (!valid) {
|
|
1106
1176
|
return defineError("Value is not a multiple of the multipleOf", { data });
|
|
1107
1177
|
}
|
|
1108
1178
|
return;
|
|
@@ -1191,6 +1261,29 @@ function compilePatternMatcher(pattern) {
|
|
|
1191
1261
|
|
|
1192
1262
|
// lib/keywords/object-keywords.ts
|
|
1193
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);
|
|
1194
1287
|
function getPatternPropertyEntries(schema) {
|
|
1195
1288
|
let entries = schema._patternPropertyEntries;
|
|
1196
1289
|
if (entries) {
|
|
@@ -1210,7 +1303,7 @@ function getPatternPropertyEntries(schema) {
|
|
|
1210
1303
|
match
|
|
1211
1304
|
};
|
|
1212
1305
|
}
|
|
1213
|
-
|
|
1306
|
+
definePropertyOrThrow(schema, "_patternPropertyEntries", {
|
|
1214
1307
|
value: entries,
|
|
1215
1308
|
enumerable: false,
|
|
1216
1309
|
configurable: false,
|
|
@@ -1227,7 +1320,7 @@ function getPatternKeyMatchIndexes(schema, key, entries) {
|
|
|
1227
1320
|
}
|
|
1228
1321
|
} else {
|
|
1229
1322
|
cache = /* @__PURE__ */ new Map();
|
|
1230
|
-
|
|
1323
|
+
definePropertyOrThrow(schema, "_patternKeyMatchIndexCache", {
|
|
1231
1324
|
value: cache,
|
|
1232
1325
|
enumerable: false,
|
|
1233
1326
|
configurable: false,
|
|
@@ -1252,7 +1345,7 @@ var ObjectKeywords = {
|
|
|
1252
1345
|
}
|
|
1253
1346
|
for (let i = 0; i < schema.required.length; i++) {
|
|
1254
1347
|
const key = schema.required[i];
|
|
1255
|
-
if (!
|
|
1348
|
+
if (!hasOwn(data, key)) {
|
|
1256
1349
|
return defineError("Required property is missing", {
|
|
1257
1350
|
item: key,
|
|
1258
1351
|
data: data[key]
|
|
@@ -1261,45 +1354,15 @@ var ObjectKeywords = {
|
|
|
1261
1354
|
}
|
|
1262
1355
|
return;
|
|
1263
1356
|
},
|
|
1264
|
-
properties(schema, data, defineError) {
|
|
1357
|
+
properties(schema, data, defineError, instance) {
|
|
1265
1358
|
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
1266
1359
|
return;
|
|
1267
1360
|
}
|
|
1268
|
-
|
|
1269
|
-
if (!propKeys) {
|
|
1270
|
-
propKeys = Object.keys(schema.properties || {});
|
|
1271
|
-
Object.defineProperty(schema, "_propKeys", {
|
|
1272
|
-
value: propKeys,
|
|
1273
|
-
enumerable: false,
|
|
1274
|
-
configurable: false,
|
|
1275
|
-
writable: false
|
|
1276
|
-
});
|
|
1277
|
-
}
|
|
1278
|
-
let requiredSet = schema._requiredSet;
|
|
1279
|
-
if (requiredSet === void 0) {
|
|
1280
|
-
requiredSet = Array.isArray(schema.required) ? new Set(schema.required) : null;
|
|
1281
|
-
Object.defineProperty(schema, "_requiredSet", {
|
|
1282
|
-
value: requiredSet,
|
|
1283
|
-
enumerable: false,
|
|
1284
|
-
configurable: false,
|
|
1285
|
-
writable: false
|
|
1286
|
-
});
|
|
1287
|
-
}
|
|
1361
|
+
const propKeys = schema._propKeys;
|
|
1288
1362
|
for (let i = 0; i < propKeys.length; i++) {
|
|
1289
1363
|
const key = propKeys[i];
|
|
1290
1364
|
const schemaProp = schema.properties[key];
|
|
1291
|
-
if (!
|
|
1292
|
-
if (requiredSet && requiredSet.has(key) && schemaProp && typeof schemaProp === "object" && !Array.isArray(schemaProp) && "default" in schemaProp) {
|
|
1293
|
-
const error = schemaProp.$validate(schemaProp.default);
|
|
1294
|
-
if (error) {
|
|
1295
|
-
return defineError("Default property is invalid", {
|
|
1296
|
-
item: key,
|
|
1297
|
-
cause: error,
|
|
1298
|
-
data: schemaProp.default
|
|
1299
|
-
});
|
|
1300
|
-
}
|
|
1301
|
-
data[key] = deepCloneUnfreeze(schemaProp.default);
|
|
1302
|
-
}
|
|
1365
|
+
if (!hasOwn(data, key)) {
|
|
1303
1366
|
continue;
|
|
1304
1367
|
}
|
|
1305
1368
|
if (typeof schemaProp === "boolean") {
|
|
@@ -1334,7 +1397,7 @@ var ObjectKeywords = {
|
|
|
1334
1397
|
return;
|
|
1335
1398
|
}
|
|
1336
1399
|
for (const key in data) {
|
|
1337
|
-
if (!
|
|
1400
|
+
if (!hasOwn(data, key)) {
|
|
1338
1401
|
continue;
|
|
1339
1402
|
}
|
|
1340
1403
|
const error = validate(data[key]);
|
|
@@ -1353,7 +1416,7 @@ var ObjectKeywords = {
|
|
|
1353
1416
|
}
|
|
1354
1417
|
let count = 0;
|
|
1355
1418
|
for (const key in data) {
|
|
1356
|
-
if (!
|
|
1419
|
+
if (!hasOwn(data, key)) {
|
|
1357
1420
|
continue;
|
|
1358
1421
|
}
|
|
1359
1422
|
count++;
|
|
@@ -1369,7 +1432,7 @@ var ObjectKeywords = {
|
|
|
1369
1432
|
}
|
|
1370
1433
|
let count = 0;
|
|
1371
1434
|
for (const key in data) {
|
|
1372
|
-
if (!
|
|
1435
|
+
if (!hasOwn(data, key)) {
|
|
1373
1436
|
continue;
|
|
1374
1437
|
}
|
|
1375
1438
|
count++;
|
|
@@ -1386,7 +1449,7 @@ var ObjectKeywords = {
|
|
|
1386
1449
|
let apValidate = schema._apValidate;
|
|
1387
1450
|
if (apValidate === void 0) {
|
|
1388
1451
|
apValidate = isCompiledSchema(schema.additionalProperties) ? schema.additionalProperties.$validate : null;
|
|
1389
|
-
|
|
1452
|
+
definePropertyOrThrow(schema, "_apValidate", {
|
|
1390
1453
|
value: apValidate,
|
|
1391
1454
|
enumerable: false,
|
|
1392
1455
|
configurable: false,
|
|
@@ -1395,10 +1458,10 @@ var ObjectKeywords = {
|
|
|
1395
1458
|
}
|
|
1396
1459
|
const patternEntries = getPatternPropertyEntries(schema);
|
|
1397
1460
|
for (const key in data) {
|
|
1398
|
-
if (!
|
|
1461
|
+
if (!hasOwn(data, key)) {
|
|
1399
1462
|
continue;
|
|
1400
1463
|
}
|
|
1401
|
-
if (schema.properties &&
|
|
1464
|
+
if (schema.properties && hasOwn(schema.properties, key)) {
|
|
1402
1465
|
continue;
|
|
1403
1466
|
}
|
|
1404
1467
|
if (patternEntries && patternEntries.length) {
|
|
@@ -1434,12 +1497,12 @@ var ObjectKeywords = {
|
|
|
1434
1497
|
return;
|
|
1435
1498
|
}
|
|
1436
1499
|
for (const key in data) {
|
|
1437
|
-
if (!
|
|
1500
|
+
if (!hasOwn(data, key)) {
|
|
1438
1501
|
continue;
|
|
1439
1502
|
}
|
|
1440
1503
|
const matchingIndexes = getPatternKeyMatchIndexes(schema, key, patternEntries);
|
|
1441
1504
|
if (matchingIndexes.length === 0) {
|
|
1442
|
-
if (schema.additionalProperties === false && !(schema.properties &&
|
|
1505
|
+
if (schema.additionalProperties === false && !(schema.properties && hasOwn(schema.properties, key))) {
|
|
1443
1506
|
return defineError("Additional properties are not allowed", {
|
|
1444
1507
|
item: key,
|
|
1445
1508
|
data: data[key]
|
|
@@ -1480,7 +1543,7 @@ var ObjectKeywords = {
|
|
|
1480
1543
|
if (typeof pn === "boolean") {
|
|
1481
1544
|
if (pn === false) {
|
|
1482
1545
|
for (const key in data) {
|
|
1483
|
-
if (
|
|
1546
|
+
if (hasOwn(data, key)) {
|
|
1484
1547
|
return defineError("Properties are not allowed", { data });
|
|
1485
1548
|
}
|
|
1486
1549
|
}
|
|
@@ -1492,7 +1555,7 @@ var ObjectKeywords = {
|
|
|
1492
1555
|
return;
|
|
1493
1556
|
}
|
|
1494
1557
|
for (const key in data) {
|
|
1495
|
-
if (!
|
|
1558
|
+
if (!hasOwn(data, key)) {
|
|
1496
1559
|
continue;
|
|
1497
1560
|
}
|
|
1498
1561
|
const error = validate(key);
|
|
@@ -1591,7 +1654,7 @@ function getBranchEntries(schema, key) {
|
|
|
1591
1654
|
for (let i = 0; i < source.length; i++) {
|
|
1592
1655
|
entries.push(toBranchEntry(source[i]));
|
|
1593
1656
|
}
|
|
1594
|
-
|
|
1657
|
+
definePropertyOrThrow(schema, cacheKey, {
|
|
1595
1658
|
value: entries,
|
|
1596
1659
|
enumerable: false,
|
|
1597
1660
|
configurable: false,
|
|
@@ -1599,6 +1662,147 @@ function getBranchEntries(schema, key) {
|
|
|
1599
1662
|
});
|
|
1600
1663
|
return entries;
|
|
1601
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
|
+
}
|
|
1602
1806
|
var OtherKeywords = {
|
|
1603
1807
|
enum(schema, data, defineError) {
|
|
1604
1808
|
let enumCache = schema._enumCache;
|
|
@@ -1615,7 +1819,7 @@ var OtherKeywords = {
|
|
|
1615
1819
|
}
|
|
1616
1820
|
}
|
|
1617
1821
|
enumCache = { primitiveSet, objectValues };
|
|
1618
|
-
|
|
1822
|
+
definePropertyOrThrow(schema, "_enumCache", {
|
|
1619
1823
|
value: enumCache,
|
|
1620
1824
|
enumerable: false,
|
|
1621
1825
|
configurable: false,
|
|
@@ -1635,137 +1839,13 @@ var OtherKeywords = {
|
|
|
1635
1839
|
return defineError("Value is not one of the allowed values", { data });
|
|
1636
1840
|
},
|
|
1637
1841
|
allOf(schema, data, defineError) {
|
|
1638
|
-
|
|
1639
|
-
if (branches.length === 1) {
|
|
1640
|
-
const onlyBranch = branches[0];
|
|
1641
|
-
if (onlyBranch.kind === "validate") {
|
|
1642
|
-
const error = onlyBranch.validate(data);
|
|
1643
|
-
if (error) {
|
|
1644
|
-
return defineError("Value is not valid", { cause: error, data });
|
|
1645
|
-
}
|
|
1646
|
-
return;
|
|
1647
|
-
}
|
|
1648
|
-
if (onlyBranch.kind === "alwaysValid") {
|
|
1649
|
-
return;
|
|
1650
|
-
}
|
|
1651
|
-
if (onlyBranch.kind === "alwaysInvalid") {
|
|
1652
|
-
return defineError("Value is not valid", { data });
|
|
1653
|
-
}
|
|
1654
|
-
if (data !== onlyBranch.value) {
|
|
1655
|
-
return defineError("Value is not valid", { data });
|
|
1656
|
-
}
|
|
1657
|
-
return;
|
|
1658
|
-
}
|
|
1659
|
-
for (let i = 0; i < branches.length; i++) {
|
|
1660
|
-
const branch = branches[i];
|
|
1661
|
-
if (branch.kind === "validate") {
|
|
1662
|
-
const error = branch.validate(data);
|
|
1663
|
-
if (error) {
|
|
1664
|
-
return defineError("Value is not valid", { cause: error, data });
|
|
1665
|
-
}
|
|
1666
|
-
continue;
|
|
1667
|
-
}
|
|
1668
|
-
if (branch.kind === "alwaysValid") {
|
|
1669
|
-
continue;
|
|
1670
|
-
}
|
|
1671
|
-
if (branch.kind === "alwaysInvalid") {
|
|
1672
|
-
return defineError("Value is not valid", { data });
|
|
1673
|
-
}
|
|
1674
|
-
if (data !== branch.value) {
|
|
1675
|
-
return defineError("Value is not valid", { data });
|
|
1676
|
-
}
|
|
1677
|
-
}
|
|
1678
|
-
return;
|
|
1842
|
+
return createCombinatorValidator("allOf", schema, defineError)(data);
|
|
1679
1843
|
},
|
|
1680
1844
|
anyOf(schema, data, defineError) {
|
|
1681
|
-
|
|
1682
|
-
if (branches.length === 1) {
|
|
1683
|
-
const onlyBranch = branches[0];
|
|
1684
|
-
if (onlyBranch.kind === "validate") {
|
|
1685
|
-
const error = onlyBranch.validate(data);
|
|
1686
|
-
if (!error) {
|
|
1687
|
-
return;
|
|
1688
|
-
}
|
|
1689
|
-
return defineError("Value is not valid", { data });
|
|
1690
|
-
}
|
|
1691
|
-
if (onlyBranch.kind === "alwaysValid") {
|
|
1692
|
-
return;
|
|
1693
|
-
}
|
|
1694
|
-
if (onlyBranch.kind === "alwaysInvalid") {
|
|
1695
|
-
return defineError("Value is not valid", { data });
|
|
1696
|
-
}
|
|
1697
|
-
if (data === onlyBranch.value) {
|
|
1698
|
-
return;
|
|
1699
|
-
}
|
|
1700
|
-
return defineError("Value is not valid", { data });
|
|
1701
|
-
}
|
|
1702
|
-
for (let i = 0; i < branches.length; i++) {
|
|
1703
|
-
const branch = branches[i];
|
|
1704
|
-
if (branch.kind === "validate") {
|
|
1705
|
-
const error = branch.validate(data);
|
|
1706
|
-
if (!error) {
|
|
1707
|
-
return;
|
|
1708
|
-
}
|
|
1709
|
-
continue;
|
|
1710
|
-
}
|
|
1711
|
-
if (branch.kind === "alwaysValid") {
|
|
1712
|
-
return;
|
|
1713
|
-
}
|
|
1714
|
-
if (branch.kind === "alwaysInvalid") {
|
|
1715
|
-
continue;
|
|
1716
|
-
}
|
|
1717
|
-
if (data === branch.value) {
|
|
1718
|
-
return;
|
|
1719
|
-
}
|
|
1720
|
-
}
|
|
1721
|
-
return defineError("Value is not valid", { data });
|
|
1845
|
+
return createCombinatorValidator("anyOf", schema, defineError)(data);
|
|
1722
1846
|
},
|
|
1723
1847
|
oneOf(schema, data, defineError) {
|
|
1724
|
-
|
|
1725
|
-
if (branches.length === 1) {
|
|
1726
|
-
const onlyBranch = branches[0];
|
|
1727
|
-
if (onlyBranch.kind === "validate") {
|
|
1728
|
-
const error = onlyBranch.validate(data);
|
|
1729
|
-
if (!error) {
|
|
1730
|
-
return;
|
|
1731
|
-
}
|
|
1732
|
-
return defineError("Value is not valid", { data });
|
|
1733
|
-
}
|
|
1734
|
-
if (onlyBranch.kind === "alwaysValid") {
|
|
1735
|
-
return;
|
|
1736
|
-
}
|
|
1737
|
-
if (onlyBranch.kind === "alwaysInvalid") {
|
|
1738
|
-
return defineError("Value is not valid", { data });
|
|
1739
|
-
}
|
|
1740
|
-
if (data === onlyBranch.value) {
|
|
1741
|
-
return;
|
|
1742
|
-
}
|
|
1743
|
-
return defineError("Value is not valid", { data });
|
|
1744
|
-
}
|
|
1745
|
-
let validCount = 0;
|
|
1746
|
-
for (let i = 0; i < branches.length; i++) {
|
|
1747
|
-
const branch = branches[i];
|
|
1748
|
-
let isValid = false;
|
|
1749
|
-
if (branch.kind === "validate") {
|
|
1750
|
-
isValid = !branch.validate(data);
|
|
1751
|
-
} else if (branch.kind === "alwaysValid") {
|
|
1752
|
-
isValid = true;
|
|
1753
|
-
} else if (branch.kind === "alwaysInvalid") {
|
|
1754
|
-
isValid = false;
|
|
1755
|
-
} else {
|
|
1756
|
-
isValid = data === branch.value;
|
|
1757
|
-
}
|
|
1758
|
-
if (isValid) {
|
|
1759
|
-
validCount++;
|
|
1760
|
-
if (validCount > 1) {
|
|
1761
|
-
return defineError("Value is not valid", { data });
|
|
1762
|
-
}
|
|
1763
|
-
}
|
|
1764
|
-
}
|
|
1765
|
-
if (validCount === 1) {
|
|
1766
|
-
return;
|
|
1767
|
-
}
|
|
1768
|
-
return defineError("Value is not valid", { data });
|
|
1848
|
+
return createCombinatorValidator("oneOf", schema, defineError)(data);
|
|
1769
1849
|
},
|
|
1770
1850
|
const(schema, data, defineError) {
|
|
1771
1851
|
if (data === schema.const) {
|
|
@@ -1825,45 +1905,62 @@ var OtherKeywords = {
|
|
|
1825
1905
|
}
|
|
1826
1906
|
return defineError("Value is not valid", { data });
|
|
1827
1907
|
},
|
|
1828
|
-
$ref(schema, data, defineError
|
|
1829
|
-
if (schema._resolvedRef) {
|
|
1830
|
-
if (schema.$validate !== schema._resolvedRef) {
|
|
1831
|
-
schema.$validate = schema._resolvedRef;
|
|
1832
|
-
}
|
|
1908
|
+
$ref(schema, data, defineError) {
|
|
1909
|
+
if (typeof schema._resolvedRef === "function") {
|
|
1833
1910
|
return schema._resolvedRef(data);
|
|
1834
1911
|
}
|
|
1835
|
-
|
|
1836
|
-
let targetSchema = instance.getSchemaRef(refPath);
|
|
1837
|
-
if (!targetSchema) {
|
|
1838
|
-
targetSchema = instance.getSchemaById(refPath);
|
|
1839
|
-
}
|
|
1840
|
-
if (!targetSchema) {
|
|
1841
|
-
return defineError(`Missing reference: ${refPath}`);
|
|
1842
|
-
}
|
|
1843
|
-
if (!targetSchema.$validate) {
|
|
1844
|
-
return;
|
|
1845
|
-
}
|
|
1846
|
-
schema._resolvedRef = targetSchema.$validate;
|
|
1847
|
-
schema.$validate = schema._resolvedRef;
|
|
1848
|
-
return schema._resolvedRef(data);
|
|
1912
|
+
return defineError(`Missing reference: ${schema.$ref}`);
|
|
1849
1913
|
}
|
|
1850
1914
|
};
|
|
1851
1915
|
|
|
1852
1916
|
// lib/keywords/string-keywords.ts
|
|
1853
1917
|
var PATTERN_MATCH_CACHE_LIMIT = 512;
|
|
1854
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
|
+
}
|
|
1855
1936
|
var StringKeywords = {
|
|
1856
1937
|
minLength(schema, data, defineError) {
|
|
1857
|
-
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)) {
|
|
1858
1947
|
return;
|
|
1859
1948
|
}
|
|
1860
1949
|
return defineError("Value is shorter than the minimum length", { data });
|
|
1861
1950
|
},
|
|
1862
1951
|
maxLength(schema, data, defineError) {
|
|
1863
|
-
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) {
|
|
1864
1958
|
return;
|
|
1865
1959
|
}
|
|
1866
|
-
|
|
1960
|
+
if (units - limit > limit || hasAtLeastCodePoints(data, limit + 1)) {
|
|
1961
|
+
return defineError("Value is longer than the maximum length", { data });
|
|
1962
|
+
}
|
|
1963
|
+
return;
|
|
1867
1964
|
},
|
|
1868
1965
|
pattern(schema, data, defineError) {
|
|
1869
1966
|
if (typeof data !== "string") {
|
|
@@ -1875,7 +1972,7 @@ var StringKeywords = {
|
|
|
1875
1972
|
try {
|
|
1876
1973
|
const compiled = compilePatternMatcher(schema.pattern);
|
|
1877
1974
|
patternMatch = compiled instanceof RegExp ? (value) => compiled.test(value) : compiled;
|
|
1878
|
-
|
|
1975
|
+
definePropertyOrThrow(schema, "_patternMatch", {
|
|
1879
1976
|
value: patternMatch,
|
|
1880
1977
|
enumerable: false,
|
|
1881
1978
|
configurable: false,
|
|
@@ -1890,7 +1987,7 @@ var StringKeywords = {
|
|
|
1890
1987
|
}
|
|
1891
1988
|
if (!patternMatchCache) {
|
|
1892
1989
|
patternMatchCache = /* @__PURE__ */ new Map();
|
|
1893
|
-
|
|
1990
|
+
definePropertyOrThrow(schema, "_patternMatchCache", {
|
|
1894
1991
|
value: patternMatchCache,
|
|
1895
1992
|
enumerable: false,
|
|
1896
1993
|
configurable: false,
|
|
@@ -1922,7 +2019,7 @@ var StringKeywords = {
|
|
|
1922
2019
|
let formatResultCache = schema._formatResultCache;
|
|
1923
2020
|
if (formatValidate === void 0) {
|
|
1924
2021
|
formatValidate = instance.getFormat(schema.format);
|
|
1925
|
-
|
|
2022
|
+
definePropertyOrThrow(schema, "_formatValidate", {
|
|
1926
2023
|
value: formatValidate,
|
|
1927
2024
|
enumerable: false,
|
|
1928
2025
|
configurable: false,
|
|
@@ -1937,7 +2034,7 @@ var StringKeywords = {
|
|
|
1937
2034
|
schema.format,
|
|
1938
2035
|
formatValidate
|
|
1939
2036
|
);
|
|
1940
|
-
|
|
2037
|
+
definePropertyOrThrow(schema, "_formatResultCacheEnabled", {
|
|
1941
2038
|
value: formatResultCacheEnabled,
|
|
1942
2039
|
enumerable: false,
|
|
1943
2040
|
configurable: false,
|
|
@@ -1952,7 +2049,7 @@ var StringKeywords = {
|
|
|
1952
2049
|
}
|
|
1953
2050
|
if (!formatResultCache) {
|
|
1954
2051
|
formatResultCache = /* @__PURE__ */ new Map();
|
|
1955
|
-
|
|
2052
|
+
definePropertyOrThrow(schema, "_formatResultCache", {
|
|
1956
2053
|
value: formatResultCache,
|
|
1957
2054
|
enumerable: false,
|
|
1958
2055
|
configurable: false,
|
|
@@ -1985,20 +2082,61 @@ var keywords = {
|
|
|
1985
2082
|
};
|
|
1986
2083
|
|
|
1987
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
|
+
}
|
|
1988
2103
|
var SchemaShield = class {
|
|
1989
2104
|
types = {};
|
|
1990
2105
|
formats = {};
|
|
1991
2106
|
keywords = {};
|
|
1992
2107
|
immutable = false;
|
|
2108
|
+
useDefaults = false;
|
|
1993
2109
|
rootSchema = null;
|
|
1994
|
-
idRegistry = /* @__PURE__ */ new Map();
|
|
1995
2110
|
failFast = true;
|
|
2111
|
+
maxDepth;
|
|
2112
|
+
validationContexts = [];
|
|
2113
|
+
compileCache = /* @__PURE__ */ new WeakMap();
|
|
2114
|
+
compilingRequiresContext = false;
|
|
2115
|
+
compilingMutableSchemas = /* @__PURE__ */ new WeakSet();
|
|
1996
2116
|
constructor({
|
|
1997
2117
|
immutable = false,
|
|
1998
|
-
failFast = true
|
|
2118
|
+
failFast = true,
|
|
2119
|
+
maxDepth = 128,
|
|
2120
|
+
useDefaults = false
|
|
1999
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
|
+
}
|
|
2000
2136
|
this.immutable = immutable;
|
|
2001
2137
|
this.failFast = failFast;
|
|
2138
|
+
this.maxDepth = maxDepth;
|
|
2139
|
+
this.useDefaults = useDefaults;
|
|
2002
2140
|
for (const [type, validator] of Object.entries(Types)) {
|
|
2003
2141
|
if (validator) {
|
|
2004
2142
|
this.addType(type, validator);
|
|
@@ -2013,6 +2151,50 @@ var SchemaShield = class {
|
|
|
2013
2151
|
}
|
|
2014
2152
|
}
|
|
2015
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
|
+
}
|
|
2016
2198
|
addType(name, validator, overwrite = false) {
|
|
2017
2199
|
if (this.types[name] && !overwrite) {
|
|
2018
2200
|
throw new ValidationError(`Type "${name}" already exists`);
|
|
@@ -2050,14 +2232,465 @@ var SchemaShield = class {
|
|
|
2050
2232
|
return resolvePath(this.rootSchema, path);
|
|
2051
2233
|
}
|
|
2052
2234
|
getSchemaById(id) {
|
|
2053
|
-
|
|
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 };
|
|
2054
2653
|
}
|
|
2055
2654
|
compile(schema) {
|
|
2056
|
-
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;
|
|
2057
2678
|
const compiledSchema = this.compileSchema(schema);
|
|
2058
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
|
+
}
|
|
2059
2692
|
if (compiledSchema._hasRef === true) {
|
|
2060
|
-
this.linkReferences(
|
|
2693
|
+
this.linkReferences(referenceRegistry);
|
|
2061
2694
|
}
|
|
2062
2695
|
if (!compiledSchema.$validate) {
|
|
2063
2696
|
if (schema === false) {
|
|
@@ -2086,14 +2719,53 @@ var SchemaShield = class {
|
|
|
2086
2719
|
);
|
|
2087
2720
|
}
|
|
2088
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
|
+
};
|
|
2089
2736
|
const validate = (data) => {
|
|
2090
2737
|
this.rootSchema = compiledSchema;
|
|
2091
|
-
const
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
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;
|
|
2095
2768
|
}
|
|
2096
|
-
return { data: clonedData, error: null, valid: true };
|
|
2097
2769
|
};
|
|
2098
2770
|
validate.compiledSchema = compiledSchema;
|
|
2099
2771
|
return validate;
|
|
@@ -2196,7 +2868,7 @@ var SchemaShield = class {
|
|
|
2196
2868
|
if (schema._hasRef === true) {
|
|
2197
2869
|
return;
|
|
2198
2870
|
}
|
|
2199
|
-
|
|
2871
|
+
definePropertyOrThrow(schema, "_hasRef", {
|
|
2200
2872
|
value: true,
|
|
2201
2873
|
enumerable: false,
|
|
2202
2874
|
configurable: false,
|
|
@@ -2254,15 +2926,15 @@ var SchemaShield = class {
|
|
|
2254
2926
|
return false;
|
|
2255
2927
|
}
|
|
2256
2928
|
}
|
|
2257
|
-
|
|
2929
|
+
hasPropertyDefaults(schema) {
|
|
2258
2930
|
const properties = schema.properties;
|
|
2259
2931
|
if (!this.isPlainObject(properties)) {
|
|
2260
2932
|
return false;
|
|
2261
2933
|
}
|
|
2262
|
-
const
|
|
2263
|
-
for (let i = 0; i <
|
|
2264
|
-
const subSchema = properties[
|
|
2265
|
-
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")) {
|
|
2266
2938
|
return true;
|
|
2267
2939
|
}
|
|
2268
2940
|
}
|
|
@@ -2271,24 +2943,134 @@ var SchemaShield = class {
|
|
|
2271
2943
|
isDefaultTypeValidator(type, validator) {
|
|
2272
2944
|
return Types[type] === validator;
|
|
2273
2945
|
}
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
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);
|
|
2280
2951
|
} else {
|
|
2281
|
-
|
|
2952
|
+
delete entry.target[entry.key];
|
|
2282
2953
|
}
|
|
2283
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);
|
|
3022
|
+
}
|
|
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
|
+
}
|
|
2284
3057
|
schema = this.normalizeSchemaForCompile(schema);
|
|
2285
3058
|
const compiledSchema = deepCloneUnfreeze(
|
|
2286
3059
|
schema
|
|
2287
3060
|
);
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
this.idRegistry.set(schema.$id, compiledSchema);
|
|
3061
|
+
if (sourceSchema) {
|
|
3062
|
+
this.compileCache.set(sourceSchema, compiledSchema);
|
|
2291
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;
|
|
2292
3074
|
if ("$ref" in schema) {
|
|
2293
3075
|
schemaHasRef = true;
|
|
2294
3076
|
const refValidator = this.getKeyword("$ref");
|
|
@@ -2298,21 +3080,53 @@ var SchemaShield = class {
|
|
|
2298
3080
|
schema["$ref"],
|
|
2299
3081
|
this.failFast
|
|
2300
3082
|
);
|
|
3083
|
+
const isBuiltinRef = refValidator === keywords.$ref;
|
|
2301
3084
|
compiledSchema.$validate = getNamedFunction(
|
|
2302
|
-
"Validate_Reference",
|
|
3085
|
+
isBuiltinRef ? "Validate_Reference" : refValidator.name || "$ref",
|
|
2303
3086
|
(data) => refValidator(
|
|
2304
3087
|
compiledSchema,
|
|
2305
3088
|
data,
|
|
2306
3089
|
defineError,
|
|
2307
|
-
this
|
|
3090
|
+
this,
|
|
3091
|
+
validateSubschema
|
|
2308
3092
|
)
|
|
2309
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);
|
|
2310
3113
|
}
|
|
2311
|
-
this.markSchemaHasRef(compiledSchema);
|
|
2312
3114
|
return compiledSchema;
|
|
2313
3115
|
}
|
|
2314
3116
|
const validators = [];
|
|
2315
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
|
+
}
|
|
2316
3130
|
if ("type" in schema) {
|
|
2317
3131
|
const defineTypeError = getDefinedErrorFunctionForKey(
|
|
2318
3132
|
"type",
|
|
@@ -2348,65 +3162,11 @@ var SchemaShield = class {
|
|
|
2348
3162
|
if (typeFunctions.length === 1 && allTypesDefault) {
|
|
2349
3163
|
const singleTypeName = defaultTypeNames[0];
|
|
2350
3164
|
typeMethodName = singleTypeName;
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
}
|
|
2357
|
-
};
|
|
2358
|
-
break;
|
|
2359
|
-
case "array":
|
|
2360
|
-
combinedTypeValidator = (data) => {
|
|
2361
|
-
if (!Array.isArray(data)) {
|
|
2362
|
-
return defineTypeError("Invalid type", { data });
|
|
2363
|
-
}
|
|
2364
|
-
};
|
|
2365
|
-
break;
|
|
2366
|
-
case "string":
|
|
2367
|
-
combinedTypeValidator = (data) => {
|
|
2368
|
-
if (typeof data !== "string") {
|
|
2369
|
-
return defineTypeError("Invalid type", { data });
|
|
2370
|
-
}
|
|
2371
|
-
};
|
|
2372
|
-
break;
|
|
2373
|
-
case "number":
|
|
2374
|
-
combinedTypeValidator = (data) => {
|
|
2375
|
-
if (typeof data !== "number") {
|
|
2376
|
-
return defineTypeError("Invalid type", { data });
|
|
2377
|
-
}
|
|
2378
|
-
};
|
|
2379
|
-
break;
|
|
2380
|
-
case "integer":
|
|
2381
|
-
combinedTypeValidator = (data) => {
|
|
2382
|
-
if (typeof data !== "number" || !Number.isInteger(data)) {
|
|
2383
|
-
return defineTypeError("Invalid type", { data });
|
|
2384
|
-
}
|
|
2385
|
-
};
|
|
2386
|
-
break;
|
|
2387
|
-
case "boolean":
|
|
2388
|
-
combinedTypeValidator = (data) => {
|
|
2389
|
-
if (typeof data !== "boolean") {
|
|
2390
|
-
return defineTypeError("Invalid type", { data });
|
|
2391
|
-
}
|
|
2392
|
-
};
|
|
2393
|
-
break;
|
|
2394
|
-
case "null":
|
|
2395
|
-
combinedTypeValidator = (data) => {
|
|
2396
|
-
if (data !== null) {
|
|
2397
|
-
return defineTypeError("Invalid type", { data });
|
|
2398
|
-
}
|
|
2399
|
-
};
|
|
2400
|
-
break;
|
|
2401
|
-
default: {
|
|
2402
|
-
const singleTypeFn = typeFunctions[0];
|
|
2403
|
-
combinedTypeValidator = (data) => {
|
|
2404
|
-
if (!singleTypeFn(data)) {
|
|
2405
|
-
return defineTypeError("Invalid type", { data });
|
|
2406
|
-
}
|
|
2407
|
-
};
|
|
2408
|
-
}
|
|
2409
|
-
}
|
|
3165
|
+
combinedTypeValidator = this.failFast && FAIL_FAST_TYPE_VALIDATORS[singleTypeName] ? FAIL_FAST_TYPE_VALIDATORS[singleTypeName] : createBuiltinTypeValidator(
|
|
3166
|
+
singleTypeName,
|
|
3167
|
+
defineTypeError,
|
|
3168
|
+
typeFunctions[0]
|
|
3169
|
+
);
|
|
2410
3170
|
} else if (typeFunctions.length > 1 && allTypesDefault) {
|
|
2411
3171
|
typeMethodName = defaultTypeNames.join("_OR_");
|
|
2412
3172
|
const allowsObject = defaultTypeNames.includes("object");
|
|
@@ -2419,6 +3179,9 @@ var SchemaShield = class {
|
|
|
2419
3179
|
combinedTypeValidator = (data) => {
|
|
2420
3180
|
const dataType = typeof data;
|
|
2421
3181
|
if (dataType === "number") {
|
|
3182
|
+
if (!Number.isFinite(data)) {
|
|
3183
|
+
return defineTypeError("Invalid type", { data });
|
|
3184
|
+
}
|
|
2422
3185
|
if (allowsNumber || allowsInteger && Number.isInteger(data)) {
|
|
2423
3186
|
return;
|
|
2424
3187
|
}
|
|
@@ -2482,7 +3245,8 @@ var SchemaShield = class {
|
|
|
2482
3245
|
activeNames.push(typeMethodName);
|
|
2483
3246
|
}
|
|
2484
3247
|
const { type, $id, $ref, $validate, required, ...otherKeys } = schema;
|
|
2485
|
-
const
|
|
3248
|
+
const otherKeyNames = Object.keys(otherKeys);
|
|
3249
|
+
const keyOrder = required ? ["required", ...otherKeyNames] : otherKeyNames;
|
|
2486
3250
|
for (const key of keyOrder) {
|
|
2487
3251
|
const keywordFn = this.getKeyword(key);
|
|
2488
3252
|
if (!keywordFn) {
|
|
@@ -2497,12 +3261,33 @@ var SchemaShield = class {
|
|
|
2497
3261
|
this.failFast
|
|
2498
3262
|
);
|
|
2499
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
|
+
);
|
|
2500
3288
|
validators.push({
|
|
2501
3289
|
name: fnName,
|
|
2502
|
-
validate: getNamedFunction(
|
|
2503
|
-
fnName,
|
|
2504
|
-
(data) => keywordFn(compiledSchema, data, defineError, this)
|
|
2505
|
-
)
|
|
3290
|
+
validate: getNamedFunction(fnName, keywordValidate)
|
|
2506
3291
|
});
|
|
2507
3292
|
activeNames.push(fnName);
|
|
2508
3293
|
}
|
|
@@ -2544,6 +3329,50 @@ var SchemaShield = class {
|
|
|
2544
3329
|
continue;
|
|
2545
3330
|
}
|
|
2546
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
|
+
}
|
|
2547
3376
|
if (schemaHasRef) {
|
|
2548
3377
|
this.markSchemaHasRef(compiledSchema);
|
|
2549
3378
|
}
|
|
@@ -2585,54 +3414,80 @@ var SchemaShield = class {
|
|
|
2585
3414
|
}
|
|
2586
3415
|
return false;
|
|
2587
3416
|
}
|
|
2588
|
-
|
|
2589
|
-
const
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
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) {
|
|
2593
3445
|
continue;
|
|
2594
|
-
if (typeof node.$ref === "string" && typeof node.$validate === "function" && node.$validate.name === "Validate_Reference") {
|
|
2595
|
-
const refPath = node.$ref;
|
|
2596
|
-
let target = this.getSchemaRef(refPath);
|
|
2597
|
-
if (typeof target === "undefined") {
|
|
2598
|
-
target = this.getSchemaById(refPath);
|
|
2599
|
-
}
|
|
2600
|
-
if (typeof target === "boolean") {
|
|
2601
|
-
if (target === true) {
|
|
2602
|
-
node.$validate = getNamedFunction("Validate_Ref_True", () => {
|
|
2603
|
-
});
|
|
2604
|
-
} else {
|
|
2605
|
-
const defineError = getDefinedErrorFunctionForKey(
|
|
2606
|
-
"$ref",
|
|
2607
|
-
node,
|
|
2608
|
-
this.failFast
|
|
2609
|
-
);
|
|
2610
|
-
node.$validate = getNamedFunction(
|
|
2611
|
-
"Validate_Ref_False",
|
|
2612
|
-
(_data) => defineError("Value is not valid")
|
|
2613
|
-
);
|
|
2614
|
-
}
|
|
2615
|
-
continue;
|
|
2616
|
-
}
|
|
2617
|
-
if (target && typeof target.$validate === "function") {
|
|
2618
|
-
node.$validate = target.$validate;
|
|
2619
|
-
}
|
|
2620
3446
|
}
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
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
|
+
() => {
|
|
2630
3480
|
}
|
|
2631
|
-
|
|
2632
|
-
} else if (typeof value === "object") {
|
|
2633
|
-
stack.push(value);
|
|
3481
|
+
);
|
|
2634
3482
|
}
|
|
3483
|
+
targetValidate = target.$validate;
|
|
2635
3484
|
}
|
|
3485
|
+
definePropertyOrThrow(node, "_resolvedRef", {
|
|
3486
|
+
value: targetValidate,
|
|
3487
|
+
enumerable: false,
|
|
3488
|
+
configurable: false,
|
|
3489
|
+
writable: false
|
|
3490
|
+
});
|
|
2636
3491
|
}
|
|
2637
3492
|
}
|
|
2638
3493
|
};
|