schema-shield 0.0.5 → 1.0.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 +194 -66
- package/dist/formats.d.ts.map +1 -1
- package/dist/index.d.ts +13 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +705 -348
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.mjs +705 -348
- package/dist/keywords/array-keywords.d.ts.map +1 -1
- package/dist/keywords/object-keywords.d.ts.map +1 -1
- package/dist/keywords/other-keywords.d.ts.map +1 -1
- package/dist/keywords/string-keywords.d.ts.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +6 -5
- package/dist/utils.d.ts.map +1 -1
- package/lib/formats.ts +125 -130
- package/lib/index.ts +247 -96
- package/lib/keywords/array-keywords.ts +60 -46
- package/lib/keywords/object-keywords.ts +155 -53
- package/lib/keywords/other-keywords.ts +68 -28
- package/lib/keywords/string-keywords.ts +32 -6
- package/lib/types.ts +1 -13
- package/lib/utils.ts +202 -44
- package/package.json +2 -2
- package/tsconfig.json +4 -4
package/dist/index.js
CHANGED
|
@@ -19,7 +19,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
// lib/index.ts
|
|
20
20
|
var lib_exports = {};
|
|
21
21
|
__export(lib_exports, {
|
|
22
|
-
SchemaShield: () => SchemaShield
|
|
22
|
+
SchemaShield: () => SchemaShield,
|
|
23
|
+
ValidationError: () => ValidationError,
|
|
24
|
+
deepClone: () => deepClone
|
|
23
25
|
});
|
|
24
26
|
module.exports = __toCommonJS(lib_exports);
|
|
25
27
|
|
|
@@ -78,14 +80,18 @@ var ValidationError = class extends Error {
|
|
|
78
80
|
};
|
|
79
81
|
}
|
|
80
82
|
};
|
|
81
|
-
|
|
83
|
+
var FAIL_FAST_DEFINE_ERROR = () => true;
|
|
84
|
+
function getDefinedErrorFunctionForKey(key, schema, failFast) {
|
|
85
|
+
if (failFast) {
|
|
86
|
+
return FAIL_FAST_DEFINE_ERROR;
|
|
87
|
+
}
|
|
82
88
|
const KeywordError = new ValidationError(`Invalid ${key}`);
|
|
83
89
|
KeywordError.keyword = key;
|
|
84
90
|
KeywordError.schema = schema;
|
|
85
91
|
const defineError = (message, options = {}) => {
|
|
86
92
|
KeywordError.message = message;
|
|
87
93
|
KeywordError.item = options.item;
|
|
88
|
-
KeywordError.cause = options.cause;
|
|
94
|
+
KeywordError.cause = options.cause && options.cause !== true ? options.cause : void 0;
|
|
89
95
|
KeywordError.data = options.data;
|
|
90
96
|
return KeywordError;
|
|
91
97
|
};
|
|
@@ -94,34 +100,38 @@ function getDefinedErrorFunctionForKey(key, schema) {
|
|
|
94
100
|
defineError
|
|
95
101
|
);
|
|
96
102
|
}
|
|
97
|
-
function
|
|
98
|
-
if (Array.isArray(
|
|
99
|
-
if (
|
|
100
|
-
return
|
|
103
|
+
function hasChanged(prev, current) {
|
|
104
|
+
if (Array.isArray(prev)) {
|
|
105
|
+
if (Array.isArray(current) === false) {
|
|
106
|
+
return true;
|
|
101
107
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
108
|
+
if (prev.length !== current.length) {
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
for (let i = 0; i < current.length; i++) {
|
|
112
|
+
if (hasChanged(prev[i], current[i])) {
|
|
113
|
+
return true;
|
|
105
114
|
}
|
|
106
115
|
}
|
|
107
|
-
return
|
|
116
|
+
return false;
|
|
108
117
|
}
|
|
109
|
-
if (typeof
|
|
110
|
-
if (
|
|
111
|
-
return
|
|
118
|
+
if (typeof prev === "object" && prev !== null) {
|
|
119
|
+
if (typeof current !== "object" || current === null) {
|
|
120
|
+
return true;
|
|
112
121
|
}
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
122
|
+
for (const key in current) {
|
|
123
|
+
if (hasChanged(prev[key], current[key])) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
116
126
|
}
|
|
117
|
-
for (const key
|
|
118
|
-
if (
|
|
119
|
-
return
|
|
127
|
+
for (const key in prev) {
|
|
128
|
+
if (hasChanged(prev[key], current[key])) {
|
|
129
|
+
return true;
|
|
120
130
|
}
|
|
121
131
|
}
|
|
122
|
-
return
|
|
132
|
+
return false;
|
|
123
133
|
}
|
|
124
|
-
return
|
|
134
|
+
return Object.is(prev, current) === false;
|
|
125
135
|
}
|
|
126
136
|
function isObject(data) {
|
|
127
137
|
return typeof data === "object" && data !== null && !Array.isArray(data);
|
|
@@ -129,27 +139,116 @@ function isObject(data) {
|
|
|
129
139
|
function areCloseEnough(a, b, epsilon = 1e-15) {
|
|
130
140
|
return Math.abs(a - b) <= epsilon * Math.max(Math.abs(a), Math.abs(b));
|
|
131
141
|
}
|
|
132
|
-
function deepClone(obj) {
|
|
133
|
-
if (
|
|
134
|
-
const result = [];
|
|
135
|
-
for (let i = 0; i < obj.length; i++) {
|
|
136
|
-
result[i] = deepClone(obj[i]);
|
|
137
|
-
}
|
|
138
|
-
return result;
|
|
139
|
-
}
|
|
140
|
-
if (obj && obj.constructor && obj.constructor.name !== "Object") {
|
|
142
|
+
function deepClone(obj, cloneClassInstances = false, seen = /* @__PURE__ */ new WeakMap()) {
|
|
143
|
+
if (typeof obj === "undefined" || obj === null || typeof obj !== "object") {
|
|
141
144
|
return obj;
|
|
142
145
|
}
|
|
143
|
-
if (
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
if (seen.has(obj)) {
|
|
147
|
+
return seen.get(obj);
|
|
148
|
+
}
|
|
149
|
+
let clone;
|
|
150
|
+
if (typeof structuredClone === "function") {
|
|
151
|
+
clone = structuredClone(obj);
|
|
152
|
+
seen.set(obj, clone);
|
|
153
|
+
return clone;
|
|
154
|
+
}
|
|
155
|
+
switch (true) {
|
|
156
|
+
case Array.isArray(obj): {
|
|
157
|
+
clone = [];
|
|
158
|
+
seen.set(obj, clone);
|
|
159
|
+
for (let i = 0, l = obj.length; i < l; i++) {
|
|
160
|
+
clone[i] = deepClone(obj[i], cloneClassInstances, seen);
|
|
161
|
+
}
|
|
162
|
+
return clone;
|
|
163
|
+
}
|
|
164
|
+
case obj instanceof Date: {
|
|
165
|
+
clone = new Date(obj.getTime());
|
|
166
|
+
seen.set(obj, clone);
|
|
167
|
+
return clone;
|
|
168
|
+
}
|
|
169
|
+
case obj instanceof RegExp: {
|
|
170
|
+
clone = new RegExp(obj.source, obj.flags);
|
|
171
|
+
seen.set(obj, clone);
|
|
172
|
+
return clone;
|
|
173
|
+
}
|
|
174
|
+
case obj instanceof Map: {
|
|
175
|
+
clone = /* @__PURE__ */ new Map();
|
|
176
|
+
seen.set(obj, clone);
|
|
177
|
+
for (const [key, value] of obj.entries()) {
|
|
178
|
+
clone.set(
|
|
179
|
+
deepClone(key, cloneClassInstances, seen),
|
|
180
|
+
deepClone(value, cloneClassInstances, seen)
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
return clone;
|
|
184
|
+
}
|
|
185
|
+
case obj instanceof Set: {
|
|
186
|
+
clone = /* @__PURE__ */ new Set();
|
|
187
|
+
seen.set(obj, clone);
|
|
188
|
+
for (const value of obj.values()) {
|
|
189
|
+
clone.add(deepClone(value, cloneClassInstances, seen));
|
|
190
|
+
}
|
|
191
|
+
return clone;
|
|
192
|
+
}
|
|
193
|
+
case obj instanceof ArrayBuffer: {
|
|
194
|
+
clone = obj.slice(0);
|
|
195
|
+
seen.set(obj, clone);
|
|
196
|
+
return clone;
|
|
197
|
+
}
|
|
198
|
+
case ArrayBuffer.isView(obj): {
|
|
199
|
+
clone = new obj.constructor(obj.buffer.slice(0));
|
|
200
|
+
seen.set(obj, clone);
|
|
201
|
+
return clone;
|
|
202
|
+
}
|
|
203
|
+
case (typeof Buffer !== "undefined" && obj instanceof Buffer): {
|
|
204
|
+
clone = Buffer.from(obj);
|
|
205
|
+
seen.set(obj, clone);
|
|
206
|
+
return clone;
|
|
207
|
+
}
|
|
208
|
+
case obj instanceof Error: {
|
|
209
|
+
clone = new obj.constructor(obj.message);
|
|
210
|
+
seen.set(obj, clone);
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
case (obj instanceof Promise || obj instanceof WeakMap || obj instanceof WeakSet): {
|
|
214
|
+
clone = obj;
|
|
215
|
+
seen.set(obj, clone);
|
|
216
|
+
return clone;
|
|
217
|
+
}
|
|
218
|
+
case (obj.constructor && obj.constructor !== Object): {
|
|
219
|
+
if (!cloneClassInstances) {
|
|
220
|
+
clone = obj;
|
|
221
|
+
seen.set(obj, clone);
|
|
222
|
+
return clone;
|
|
223
|
+
}
|
|
224
|
+
clone = Object.create(Object.getPrototypeOf(obj));
|
|
225
|
+
seen.set(obj, clone);
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
default: {
|
|
229
|
+
clone = {};
|
|
230
|
+
seen.set(obj, clone);
|
|
231
|
+
const keys = Reflect.ownKeys(obj);
|
|
232
|
+
for (let i = 0, l = keys.length; i < l; i++) {
|
|
233
|
+
const key = keys[i];
|
|
234
|
+
clone[key] = deepClone(
|
|
235
|
+
obj[key],
|
|
236
|
+
cloneClassInstances,
|
|
237
|
+
seen
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
return clone;
|
|
149
241
|
}
|
|
150
|
-
return result;
|
|
151
242
|
}
|
|
152
|
-
|
|
243
|
+
const descriptors = Object.getOwnPropertyDescriptors(obj);
|
|
244
|
+
for (const key of Reflect.ownKeys(descriptors)) {
|
|
245
|
+
const descriptor = descriptors[key];
|
|
246
|
+
if ("value" in descriptor) {
|
|
247
|
+
descriptor.value = deepClone(descriptor.value, cloneClassInstances, seen);
|
|
248
|
+
}
|
|
249
|
+
Object.defineProperty(clone, key, descriptor);
|
|
250
|
+
}
|
|
251
|
+
return clone;
|
|
153
252
|
}
|
|
154
253
|
function isCompiledSchema(subSchema) {
|
|
155
254
|
return isObject(subSchema) && "$validate" in subSchema;
|
|
@@ -157,82 +256,86 @@ function isCompiledSchema(subSchema) {
|
|
|
157
256
|
function getNamedFunction(name, fn) {
|
|
158
257
|
return Object.defineProperty(fn, "name", { value: name });
|
|
159
258
|
}
|
|
259
|
+
function resolvePath(root, path) {
|
|
260
|
+
if (!path || path === "#") {
|
|
261
|
+
return root;
|
|
262
|
+
}
|
|
263
|
+
if (path.startsWith("#/")) {
|
|
264
|
+
const parts = path.split("/").slice(1);
|
|
265
|
+
let current = root;
|
|
266
|
+
for (const part of parts) {
|
|
267
|
+
const decodedUriPart = decodeURIComponent(part);
|
|
268
|
+
const key = decodedUriPart.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
269
|
+
if (current && typeof current === "object" && key in current) {
|
|
270
|
+
current = current[key];
|
|
271
|
+
} else {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return current;
|
|
276
|
+
}
|
|
277
|
+
if (!path.includes("#")) {
|
|
278
|
+
if (root.definitions && root.definitions[path]) {
|
|
279
|
+
return root.definitions[path];
|
|
280
|
+
}
|
|
281
|
+
if (root.defs && root.defs[path]) {
|
|
282
|
+
return root.defs[path];
|
|
283
|
+
}
|
|
284
|
+
if (root.$id && typeof root.$id === "string") {
|
|
285
|
+
if (root.$id === path || root.$id.endsWith("/" + path)) {
|
|
286
|
+
return root;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
160
292
|
|
|
161
293
|
// lib/formats.ts
|
|
294
|
+
var UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
295
|
+
var DURATION_REGEX = /^P(?!$)((\d+Y)?(\d+M)?(\d+W)?(\d+D)?)(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?$/;
|
|
296
|
+
var DATE_TIME_REGEX = /^(\d{4})-(0[0-9]|1[0-2])-(\d{2})T(0[0-9]|1\d|2[0-3]):([0-5]\d):((?:[0-5]\d|60))(?:.\d+)?(?:([+-])(0[0-9]|1\d|2[0-3]):([0-5]\d)|Z)?$/i;
|
|
297
|
+
var URI_REGEX = /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/;
|
|
298
|
+
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;
|
|
299
|
+
var IPV4_REGEX = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])$/;
|
|
300
|
+
var IPV6_REGEX = /(?:\s+|:::+|^\w{5,}|\w{5}$|^:{1}\w|\w:{1}$)/;
|
|
301
|
+
var IPV6_SHORT_REGEX = /^[0-9a-fA-F:.]*$/;
|
|
302
|
+
var IPV6_FULL_REGEX = /^(?:(?:[0-9a-fA-F]{1,4}:){7}(?:[0-9a-fA-F]{1,4}|:))$/;
|
|
303
|
+
var IPV6_INVALID_CHAR_REGEX = /(?:[0-9a-fA-F]{5,}|\D[0-9a-fA-F]{3}:)/;
|
|
304
|
+
var IPV6_FAST_FAIL_REGEX = /^(?:(?:(?:[0-9a-fA-F]{1,4}(?::|$)){1,6}))|(?:::(?:[0-9a-fA-F]{1,4})){0,5}$/;
|
|
305
|
+
var HOSTNAME_REGEX = /^[a-z0-9][a-z0-9-]{0,62}(?:\.[a-z0-9][a-z0-9-]{0,62})*[a-z0-9]$/i;
|
|
306
|
+
var DATE_REGEX = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
307
|
+
var JSON_POINTER_REGEX = /^\/(?:[^~]|~0|~1)*$/;
|
|
308
|
+
var RELATIVE_JSON_POINTER_REGEX = /^([0-9]+)(#|\/(?:[^~]|~0|~1)*)?$/;
|
|
309
|
+
var TIME_REGEX = /^([01]\d|2[0-3]):([0-5]\d):([0-5]\d)(\.\d+)?(Z|([+-])([01]\d|2[0-3]):([0-5]\d))$/;
|
|
310
|
+
var URI_REFERENCE_REGEX = /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#((?![^#]*\\)[^#]*))?/i;
|
|
311
|
+
var URI_TEMPLATE_REGEX = /^(?:[^{}]|\{[^}]+\})*$/;
|
|
312
|
+
var IRI_REGEX = /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/;
|
|
313
|
+
var IRI_REFERENCE_REGEX = /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#((?![^#]*\\)[^#]*))?/i;
|
|
314
|
+
var IDN_EMAIL_REGEX = /^[^@\s]+@[^@\s]+\.[^@\s]+$/;
|
|
315
|
+
var IDN_HOSTNAME_REGEX = /^[^\s!@#$%^&*()_+\=\[\]{};':"\\|,<>\/?]+$/;
|
|
316
|
+
var BACK_SLASH_REGEX = /\\/;
|
|
317
|
+
var DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
162
318
|
var Formats = {
|
|
163
319
|
["date-time"](data) {
|
|
164
|
-
const match = data.match(
|
|
165
|
-
/^(\d{4})-(0[0-9]|1[0-2])-(\d{2})T(0[0-9]|1\d|2[0-3]):([0-5]\d):((?:[0-5]\d|60))(?:.\d+)?(?:([+-])(0[0-9]|1\d|2[0-3]):([0-5]\d)|Z)?$/i
|
|
166
|
-
);
|
|
320
|
+
const match = data.match(DATE_TIME_REGEX);
|
|
167
321
|
if (!match) {
|
|
168
322
|
return false;
|
|
169
323
|
}
|
|
170
|
-
|
|
171
|
-
|
|
324
|
+
const [, yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr] = match;
|
|
325
|
+
const year = Number(yearStr);
|
|
326
|
+
const month = Number(monthStr);
|
|
327
|
+
const day = Number(dayStr);
|
|
328
|
+
const hour = Number(hourStr);
|
|
329
|
+
const minute = Number(minuteStr);
|
|
330
|
+
const second = Number(secondStr);
|
|
331
|
+
if (month < 1 || month > 12) {
|
|
172
332
|
return false;
|
|
173
333
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
yearStr,
|
|
177
|
-
monthStr,
|
|
178
|
-
,
|
|
179
|
-
hourStr,
|
|
180
|
-
minuteStr,
|
|
181
|
-
secondStr,
|
|
182
|
-
timezoneSign,
|
|
183
|
-
timezoneHourStr,
|
|
184
|
-
timezoneMinuteStr
|
|
185
|
-
] = match;
|
|
186
|
-
let year = Number(yearStr);
|
|
187
|
-
let month = Number(monthStr);
|
|
188
|
-
let hour = Number(hourStr);
|
|
189
|
-
let minute = Number(minuteStr);
|
|
190
|
-
let second = Number(secondStr);
|
|
191
|
-
if (timezoneSign === "-" || timezoneSign === "+") {
|
|
192
|
-
const timezoneHour = Number(timezoneHourStr);
|
|
193
|
-
const timezoneMinute = Number(timezoneMinuteStr);
|
|
194
|
-
if (timezoneSign === "-") {
|
|
195
|
-
hour += timezoneHour;
|
|
196
|
-
minute += timezoneMinute;
|
|
197
|
-
} else if (timezoneSign === "+") {
|
|
198
|
-
hour -= timezoneHour;
|
|
199
|
-
minute -= timezoneMinute;
|
|
200
|
-
}
|
|
201
|
-
if (minute > 59) {
|
|
202
|
-
hour += 1;
|
|
203
|
-
minute -= 60;
|
|
204
|
-
} else if (minute < 0) {
|
|
205
|
-
hour -= 1;
|
|
206
|
-
minute += 60;
|
|
207
|
-
}
|
|
208
|
-
if (hour > 23) {
|
|
209
|
-
day += 1;
|
|
210
|
-
hour -= 24;
|
|
211
|
-
} else if (hour < 0) {
|
|
212
|
-
day -= 1;
|
|
213
|
-
hour += 24;
|
|
214
|
-
}
|
|
215
|
-
if (day > 31) {
|
|
216
|
-
month += 1;
|
|
217
|
-
day -= 31;
|
|
218
|
-
} else if (day < 1) {
|
|
219
|
-
month -= 1;
|
|
220
|
-
day += 31;
|
|
221
|
-
}
|
|
222
|
-
if (month > 12) {
|
|
223
|
-
year += 1;
|
|
224
|
-
month -= 12;
|
|
225
|
-
} else if (month < 1) {
|
|
226
|
-
year -= 1;
|
|
227
|
-
month += 12;
|
|
228
|
-
}
|
|
229
|
-
if (year < 0) {
|
|
230
|
-
return false;
|
|
231
|
-
}
|
|
334
|
+
if (day < 1) {
|
|
335
|
+
return false;
|
|
232
336
|
}
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
if (day > maxDays) {
|
|
337
|
+
const maxDays = month === 2 ? year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28 : DAYS_IN_MONTH[month - 1];
|
|
338
|
+
if (!maxDays || day > maxDays) {
|
|
236
339
|
return false;
|
|
237
340
|
}
|
|
238
341
|
if (second === 60 && (minute !== 59 || hour !== 23)) {
|
|
@@ -241,24 +344,20 @@ var Formats = {
|
|
|
241
344
|
return true;
|
|
242
345
|
},
|
|
243
346
|
uri(data) {
|
|
244
|
-
return
|
|
347
|
+
return URI_REGEX.test(data);
|
|
245
348
|
},
|
|
246
349
|
email(data) {
|
|
247
|
-
return
|
|
248
|
-
data
|
|
249
|
-
);
|
|
350
|
+
return EMAIL_REGEX.test(data);
|
|
250
351
|
},
|
|
251
352
|
ipv4(data) {
|
|
252
|
-
return
|
|
253
|
-
data
|
|
254
|
-
);
|
|
353
|
+
return IPV4_REGEX.test(data);
|
|
255
354
|
},
|
|
256
355
|
// ipv6: isMyIpValid({ version: 6 }),
|
|
257
356
|
ipv6(data) {
|
|
258
357
|
if (data === "::") {
|
|
259
358
|
return true;
|
|
260
359
|
}
|
|
261
|
-
if (data.indexOf(":") === -1 ||
|
|
360
|
+
if (data.indexOf(":") === -1 || IPV6_REGEX.test(data)) {
|
|
262
361
|
return false;
|
|
263
362
|
}
|
|
264
363
|
const hasIpv4 = data.indexOf(".") !== -1;
|
|
@@ -266,9 +365,7 @@ var Formats = {
|
|
|
266
365
|
if (hasIpv4) {
|
|
267
366
|
addressParts = data.split(":");
|
|
268
367
|
const ipv4Part = addressParts.pop();
|
|
269
|
-
if (
|
|
270
|
-
ipv4Part
|
|
271
|
-
)) {
|
|
368
|
+
if (!IPV4_REGEX.test(ipv4Part)) {
|
|
272
369
|
return false;
|
|
273
370
|
}
|
|
274
371
|
}
|
|
@@ -278,32 +375,38 @@ var Formats = {
|
|
|
278
375
|
if (ipv6Part.split("::").length - 1 > 1) {
|
|
279
376
|
return false;
|
|
280
377
|
}
|
|
281
|
-
if (
|
|
378
|
+
if (!IPV6_SHORT_REGEX.test(ipv6Part)) {
|
|
282
379
|
return false;
|
|
283
380
|
}
|
|
284
|
-
return
|
|
285
|
-
ipv6Part
|
|
286
|
-
);
|
|
381
|
+
return IPV6_FAST_FAIL_REGEX.test(ipv6Part);
|
|
287
382
|
}
|
|
288
|
-
const isIpv6Valid =
|
|
289
|
-
const hasInvalidChar =
|
|
290
|
-
ipv6Part
|
|
291
|
-
);
|
|
383
|
+
const isIpv6Valid = IPV6_FULL_REGEX.test(ipv6Part);
|
|
384
|
+
const hasInvalidChar = IPV6_INVALID_CHAR_REGEX.test(ipv6Part);
|
|
292
385
|
if (hasIpv4) {
|
|
293
386
|
return isIpv6Valid || !hasInvalidChar;
|
|
294
387
|
}
|
|
295
388
|
return isIpv6Valid && !hasInvalidChar;
|
|
296
389
|
},
|
|
297
390
|
hostname(data) {
|
|
298
|
-
return
|
|
299
|
-
data
|
|
300
|
-
);
|
|
391
|
+
return HOSTNAME_REGEX.test(data);
|
|
301
392
|
},
|
|
302
393
|
date(data) {
|
|
303
|
-
|
|
394
|
+
const match = DATE_REGEX.exec(data);
|
|
395
|
+
if (!match) {
|
|
304
396
|
return false;
|
|
305
397
|
}
|
|
306
|
-
|
|
398
|
+
const [, yearStr, monthStr, dayStr] = match;
|
|
399
|
+
const year = Number(yearStr);
|
|
400
|
+
const month = Number(monthStr);
|
|
401
|
+
const day = Number(dayStr);
|
|
402
|
+
if (month < 1 || month > 12) {
|
|
403
|
+
return false;
|
|
404
|
+
}
|
|
405
|
+
if (day < 1) {
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
const maxDays = month === 2 ? year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28 : DAYS_IN_MONTH[month - 1];
|
|
409
|
+
return !!maxDays && day <= maxDays;
|
|
307
410
|
},
|
|
308
411
|
regex(data) {
|
|
309
412
|
try {
|
|
@@ -317,39 +420,49 @@ var Formats = {
|
|
|
317
420
|
if (data === "") {
|
|
318
421
|
return true;
|
|
319
422
|
}
|
|
320
|
-
return
|
|
423
|
+
return JSON_POINTER_REGEX.test(data);
|
|
321
424
|
},
|
|
322
425
|
"relative-json-pointer"(data) {
|
|
323
426
|
if (data === "") {
|
|
324
427
|
return true;
|
|
325
428
|
}
|
|
326
|
-
return
|
|
429
|
+
return RELATIVE_JSON_POINTER_REGEX.test(data);
|
|
327
430
|
},
|
|
328
431
|
time(data) {
|
|
329
|
-
return
|
|
330
|
-
data
|
|
331
|
-
);
|
|
432
|
+
return TIME_REGEX.test(data);
|
|
332
433
|
},
|
|
333
434
|
"uri-reference"(data) {
|
|
334
|
-
if (
|
|
435
|
+
if (BACK_SLASH_REGEX.test(data)) {
|
|
335
436
|
return false;
|
|
336
437
|
}
|
|
337
|
-
return
|
|
338
|
-
data
|
|
339
|
-
);
|
|
438
|
+
return URI_REFERENCE_REGEX.test(data);
|
|
340
439
|
},
|
|
341
440
|
"uri-template"(data) {
|
|
342
|
-
return
|
|
343
|
-
|
|
344
|
-
|
|
441
|
+
return URI_TEMPLATE_REGEX.test(data);
|
|
442
|
+
},
|
|
443
|
+
duration(data) {
|
|
444
|
+
return DURATION_REGEX.test(data);
|
|
445
|
+
},
|
|
446
|
+
uuid(data) {
|
|
447
|
+
return UUID_REGEX.test(data);
|
|
448
|
+
},
|
|
449
|
+
// IRI is like URI but allows Unicode. We reuse a permissive logic.
|
|
450
|
+
iri(data) {
|
|
451
|
+
return IRI_REGEX.test(data);
|
|
345
452
|
},
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
453
|
+
"iri-reference"(data) {
|
|
454
|
+
if (BACK_SLASH_REGEX.test(data)) {
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
return IRI_REFERENCE_REGEX.test(data);
|
|
458
|
+
},
|
|
459
|
+
// Best-effort structural validation for IDN (no punycode/tables)
|
|
460
|
+
"idn-email"(data) {
|
|
461
|
+
return IDN_EMAIL_REGEX.test(data);
|
|
462
|
+
},
|
|
463
|
+
"idn-hostname"(data) {
|
|
464
|
+
return IDN_HOSTNAME_REGEX.test(data);
|
|
465
|
+
}
|
|
353
466
|
};
|
|
354
467
|
|
|
355
468
|
// lib/types.ts
|
|
@@ -358,10 +471,7 @@ var Types = {
|
|
|
358
471
|
return isObject(data);
|
|
359
472
|
},
|
|
360
473
|
array(data) {
|
|
361
|
-
|
|
362
|
-
return true;
|
|
363
|
-
}
|
|
364
|
-
return typeof data === "object" && data !== null && "length" in data && "0" in data && Object.keys(data).length - 1 === data.length;
|
|
474
|
+
return Array.isArray(data);
|
|
365
475
|
},
|
|
366
476
|
string(data) {
|
|
367
477
|
return typeof data === "string";
|
|
@@ -392,6 +502,7 @@ var Types = {
|
|
|
392
502
|
|
|
393
503
|
// lib/keywords/array-keywords.ts
|
|
394
504
|
var ArrayKeywords = {
|
|
505
|
+
// lib/keywords/array-keywords.ts
|
|
395
506
|
items(schema, data, defineError) {
|
|
396
507
|
if (!Array.isArray(data)) {
|
|
397
508
|
return;
|
|
@@ -406,11 +517,11 @@ var ArrayKeywords = {
|
|
|
406
517
|
}
|
|
407
518
|
if (Array.isArray(schemaItems)) {
|
|
408
519
|
const schemaItemsLength = schemaItems.length;
|
|
409
|
-
const itemsLength =
|
|
520
|
+
const itemsLength = schemaItemsLength < dataLength ? schemaItemsLength : dataLength;
|
|
410
521
|
for (let i = 0; i < itemsLength; i++) {
|
|
411
522
|
const schemaItem = schemaItems[i];
|
|
412
523
|
if (typeof schemaItem === "boolean") {
|
|
413
|
-
if (schemaItem === false &&
|
|
524
|
+
if (schemaItem === false && data[i] !== void 0) {
|
|
414
525
|
return defineError("Array item is not allowed", {
|
|
415
526
|
item: i,
|
|
416
527
|
data: data[i]
|
|
@@ -418,8 +529,9 @@ var ArrayKeywords = {
|
|
|
418
529
|
}
|
|
419
530
|
continue;
|
|
420
531
|
}
|
|
421
|
-
|
|
422
|
-
|
|
532
|
+
const validate2 = schemaItem && schemaItem.$validate;
|
|
533
|
+
if (typeof validate2 === "function") {
|
|
534
|
+
const error = validate2(data[i]);
|
|
423
535
|
if (error) {
|
|
424
536
|
return defineError("Array item is invalid", {
|
|
425
537
|
item: i,
|
|
@@ -431,26 +543,32 @@ var ArrayKeywords = {
|
|
|
431
543
|
}
|
|
432
544
|
return;
|
|
433
545
|
}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
546
|
+
const validate = schemaItems && schemaItems.$validate;
|
|
547
|
+
if (typeof validate !== "function") {
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
for (let i = 0; i < dataLength; i++) {
|
|
551
|
+
const error = validate(data[i]);
|
|
552
|
+
if (error) {
|
|
553
|
+
return defineError("Array item is invalid", {
|
|
554
|
+
item: i,
|
|
555
|
+
cause: error,
|
|
556
|
+
data: data[i]
|
|
557
|
+
});
|
|
444
558
|
}
|
|
445
559
|
}
|
|
446
|
-
return;
|
|
447
560
|
},
|
|
448
561
|
elements(schema, data, defineError) {
|
|
449
|
-
if (!Array.isArray(data)
|
|
562
|
+
if (!Array.isArray(data)) {
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
const elementsSchema = schema.elements;
|
|
566
|
+
const validate = elementsSchema && elementsSchema.$validate;
|
|
567
|
+
if (typeof validate !== "function") {
|
|
450
568
|
return;
|
|
451
569
|
}
|
|
452
570
|
for (let i = 0; i < data.length; i++) {
|
|
453
|
-
const error =
|
|
571
|
+
const error = validate(data[i]);
|
|
454
572
|
if (error) {
|
|
455
573
|
return defineError("Array item is invalid", {
|
|
456
574
|
item: i,
|
|
@@ -459,7 +577,6 @@ var ArrayKeywords = {
|
|
|
459
577
|
});
|
|
460
578
|
}
|
|
461
579
|
}
|
|
462
|
-
return;
|
|
463
580
|
},
|
|
464
581
|
minItems(schema, data, defineError) {
|
|
465
582
|
if (!Array.isArray(data) || data.length >= schema.minItems) {
|
|
@@ -505,28 +622,30 @@ var ArrayKeywords = {
|
|
|
505
622
|
if (!Array.isArray(data) || !schema.uniqueItems) {
|
|
506
623
|
return;
|
|
507
624
|
}
|
|
508
|
-
const
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
itemStr = String(item);
|
|
625
|
+
const len = data.length;
|
|
626
|
+
if (len <= 1) {
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
const primitiveSeen = /* @__PURE__ */ new Set();
|
|
630
|
+
for (let i = 0; i < len; i++) {
|
|
631
|
+
const item = data[i];
|
|
632
|
+
const type = typeof item;
|
|
633
|
+
if (item === null || type === "string" || type === "number" || type === "boolean") {
|
|
634
|
+
if (primitiveSeen.has(item)) {
|
|
635
|
+
return defineError("Array items are not unique", { data: item });
|
|
636
|
+
}
|
|
637
|
+
primitiveSeen.add(item);
|
|
638
|
+
continue;
|
|
523
639
|
}
|
|
524
|
-
if (
|
|
525
|
-
|
|
640
|
+
if (item && typeof item === "object") {
|
|
641
|
+
for (let j = 0; j < i; j++) {
|
|
642
|
+
const prev = data[j];
|
|
643
|
+
if (prev && typeof prev === "object" && !hasChanged(prev, item)) {
|
|
644
|
+
return defineError("Array items are not unique", { data: item });
|
|
645
|
+
}
|
|
646
|
+
}
|
|
526
647
|
}
|
|
527
|
-
unique.add(itemStr);
|
|
528
648
|
}
|
|
529
|
-
return;
|
|
530
649
|
},
|
|
531
650
|
contains(schema, data, defineError) {
|
|
532
651
|
if (!Array.isArray(data)) {
|
|
@@ -622,7 +741,6 @@ var NumberKeywords = {
|
|
|
622
741
|
|
|
623
742
|
// lib/keywords/object-keywords.ts
|
|
624
743
|
var ObjectKeywords = {
|
|
625
|
-
// Object
|
|
626
744
|
required(schema, data, defineError) {
|
|
627
745
|
if (!isObject(data)) {
|
|
628
746
|
return;
|
|
@@ -642,16 +760,46 @@ var ObjectKeywords = {
|
|
|
642
760
|
if (!isObject(data)) {
|
|
643
761
|
return;
|
|
644
762
|
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
763
|
+
let propKeys = schema._propKeys;
|
|
764
|
+
if (!propKeys) {
|
|
765
|
+
propKeys = Object.keys(schema.properties || {});
|
|
766
|
+
Object.defineProperty(schema, "_propKeys", {
|
|
767
|
+
value: propKeys,
|
|
768
|
+
enumerable: false,
|
|
769
|
+
configurable: false,
|
|
770
|
+
writable: false
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
let requiredKeys = schema._requiredKeys;
|
|
774
|
+
if (requiredKeys === void 0) {
|
|
775
|
+
requiredKeys = Array.isArray(schema.required) ? schema.required : null;
|
|
776
|
+
Object.defineProperty(schema, "_requiredKeys", {
|
|
777
|
+
value: requiredKeys,
|
|
778
|
+
enumerable: false,
|
|
779
|
+
configurable: false,
|
|
780
|
+
writable: false
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
const required = requiredKeys || [];
|
|
784
|
+
for (let i = 0; i < propKeys.length; i++) {
|
|
785
|
+
const key = propKeys[i];
|
|
786
|
+
const schemaProp = schema.properties[key];
|
|
787
|
+
if (!Object.prototype.hasOwnProperty.call(data, key)) {
|
|
788
|
+
if (required.length && required.indexOf(key) !== -1 && isObject(schemaProp) && "default" in schemaProp) {
|
|
789
|
+
const error = schemaProp.$validate(schemaProp.default);
|
|
790
|
+
if (error) {
|
|
791
|
+
return defineError("Default property is invalid", {
|
|
792
|
+
item: key,
|
|
793
|
+
cause: error,
|
|
794
|
+
data: schemaProp.default
|
|
795
|
+
});
|
|
796
|
+
}
|
|
797
|
+
data[key] = deepClone(schemaProp.default);
|
|
650
798
|
}
|
|
651
799
|
continue;
|
|
652
800
|
}
|
|
653
|
-
if (typeof
|
|
654
|
-
if (
|
|
801
|
+
if (typeof schemaProp === "boolean") {
|
|
802
|
+
if (schemaProp === false) {
|
|
655
803
|
return defineError("Property is not allowed", {
|
|
656
804
|
item: key,
|
|
657
805
|
data: data[key]
|
|
@@ -659,8 +807,8 @@ var ObjectKeywords = {
|
|
|
659
807
|
}
|
|
660
808
|
continue;
|
|
661
809
|
}
|
|
662
|
-
if ("$validate" in
|
|
663
|
-
const error =
|
|
810
|
+
if (schemaProp && "$validate" in schemaProp) {
|
|
811
|
+
const error = schemaProp.$validate(data[key]);
|
|
664
812
|
if (error) {
|
|
665
813
|
return defineError("Property is invalid", {
|
|
666
814
|
item: key,
|
|
@@ -673,12 +821,18 @@ var ObjectKeywords = {
|
|
|
673
821
|
return;
|
|
674
822
|
},
|
|
675
823
|
values(schema, data, defineError) {
|
|
676
|
-
if (!isObject(data)
|
|
824
|
+
if (!isObject(data)) {
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
const valueSchema = schema.values;
|
|
828
|
+
const validate = valueSchema && valueSchema.$validate;
|
|
829
|
+
if (typeof validate !== "function") {
|
|
677
830
|
return;
|
|
678
831
|
}
|
|
679
832
|
const keys = Object.keys(data);
|
|
680
|
-
for (
|
|
681
|
-
const
|
|
833
|
+
for (let i = 0; i < keys.length; i++) {
|
|
834
|
+
const key = keys[i];
|
|
835
|
+
const error = validate(data[key]);
|
|
682
836
|
if (error) {
|
|
683
837
|
return defineError("Property is invalid", {
|
|
684
838
|
item: key,
|
|
@@ -687,7 +841,6 @@ var ObjectKeywords = {
|
|
|
687
841
|
});
|
|
688
842
|
}
|
|
689
843
|
}
|
|
690
|
-
return;
|
|
691
844
|
},
|
|
692
845
|
maxProperties(schema, data, defineError) {
|
|
693
846
|
if (!isObject(data) || Object.keys(data).length <= schema.maxProperties) {
|
|
@@ -706,15 +859,37 @@ var ObjectKeywords = {
|
|
|
706
859
|
return;
|
|
707
860
|
}
|
|
708
861
|
const keys = Object.keys(data);
|
|
709
|
-
|
|
710
|
-
|
|
862
|
+
let apIsCompiled = schema._apIsCompiled;
|
|
863
|
+
if (apIsCompiled === void 0) {
|
|
864
|
+
apIsCompiled = isCompiledSchema(schema.additionalProperties);
|
|
865
|
+
Object.defineProperty(schema, "_apIsCompiled", {
|
|
866
|
+
value: apIsCompiled,
|
|
867
|
+
enumerable: false
|
|
868
|
+
});
|
|
869
|
+
}
|
|
870
|
+
let patternList = schema._patternPropertiesList;
|
|
871
|
+
if (schema.patternProperties && !patternList) {
|
|
872
|
+
patternList = [];
|
|
873
|
+
for (const pattern in schema.patternProperties) {
|
|
874
|
+
patternList.push({
|
|
875
|
+
regex: new RegExp(pattern, "u"),
|
|
876
|
+
key: pattern
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
Object.defineProperty(schema, "_patternPropertiesList", {
|
|
880
|
+
value: patternList,
|
|
881
|
+
enumerable: false
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
for (let i = 0; i < keys.length; i++) {
|
|
885
|
+
const key = keys[i];
|
|
711
886
|
if (schema.properties && schema.properties.hasOwnProperty(key)) {
|
|
712
887
|
continue;
|
|
713
888
|
}
|
|
714
|
-
if (
|
|
889
|
+
if (patternList && patternList.length) {
|
|
715
890
|
let match = false;
|
|
716
|
-
for (
|
|
717
|
-
if (
|
|
891
|
+
for (let j = 0; j < patternList.length; j++) {
|
|
892
|
+
if (patternList[j].regex.test(key)) {
|
|
718
893
|
match = true;
|
|
719
894
|
break;
|
|
720
895
|
}
|
|
@@ -729,7 +904,7 @@ var ObjectKeywords = {
|
|
|
729
904
|
data: data[key]
|
|
730
905
|
});
|
|
731
906
|
}
|
|
732
|
-
if (
|
|
907
|
+
if (apIsCompiled && isCompiledSchema(schema.additionalProperties)) {
|
|
733
908
|
const error = schema.additionalProperties.$validate(data[key]);
|
|
734
909
|
if (error) {
|
|
735
910
|
return defineError("Additional properties are invalid", {
|
|
@@ -746,12 +921,30 @@ var ObjectKeywords = {
|
|
|
746
921
|
if (!isObject(data)) {
|
|
747
922
|
return;
|
|
748
923
|
}
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
924
|
+
let patternList = schema._patternPropertiesList;
|
|
925
|
+
if (!patternList) {
|
|
926
|
+
patternList = [];
|
|
927
|
+
const patterns = Object.keys(schema.patternProperties || {});
|
|
928
|
+
for (let i = 0; i < patterns.length; i++) {
|
|
929
|
+
const pattern = patterns[i];
|
|
930
|
+
patternList.push({
|
|
931
|
+
regex: new RegExp(pattern, "u"),
|
|
932
|
+
key: pattern
|
|
933
|
+
});
|
|
934
|
+
}
|
|
935
|
+
Object.defineProperty(schema, "_patternPropertiesList", {
|
|
936
|
+
value: patternList,
|
|
937
|
+
enumerable: false
|
|
938
|
+
});
|
|
939
|
+
}
|
|
940
|
+
const dataKeys = Object.keys(data);
|
|
941
|
+
for (let p = 0; p < patternList.length; p++) {
|
|
942
|
+
const { regex, key: patternKey } = patternList[p];
|
|
943
|
+
const schemaProp = schema.patternProperties[patternKey];
|
|
944
|
+
if (typeof schemaProp === "boolean") {
|
|
945
|
+
if (schemaProp === false) {
|
|
946
|
+
for (let i = 0; i < dataKeys.length; i++) {
|
|
947
|
+
const key = dataKeys[i];
|
|
755
948
|
if (regex.test(key)) {
|
|
756
949
|
return defineError("Property is not allowed", {
|
|
757
950
|
item: key,
|
|
@@ -762,13 +955,11 @@ var ObjectKeywords = {
|
|
|
762
955
|
}
|
|
763
956
|
continue;
|
|
764
957
|
}
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
if (
|
|
769
|
-
const error =
|
|
770
|
-
data[key]
|
|
771
|
-
);
|
|
958
|
+
if ("$validate" in schemaProp) {
|
|
959
|
+
for (let i = 0; i < dataKeys.length; i++) {
|
|
960
|
+
const key = dataKeys[i];
|
|
961
|
+
if (regex.test(key)) {
|
|
962
|
+
const error = schemaProp.$validate(data[key]);
|
|
772
963
|
if (error) {
|
|
773
964
|
return defineError("Property is invalid", {
|
|
774
965
|
item: key,
|
|
@@ -786,24 +977,30 @@ var ObjectKeywords = {
|
|
|
786
977
|
if (!isObject(data)) {
|
|
787
978
|
return;
|
|
788
979
|
}
|
|
789
|
-
|
|
790
|
-
|
|
980
|
+
const pn = schema.propertyNames;
|
|
981
|
+
if (typeof pn === "boolean") {
|
|
982
|
+
if (pn === false && Object.keys(data).length > 0) {
|
|
791
983
|
return defineError("Properties are not allowed", { data });
|
|
792
984
|
}
|
|
985
|
+
return;
|
|
793
986
|
}
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
987
|
+
const validate = pn && pn.$validate;
|
|
988
|
+
if (typeof validate !== "function") {
|
|
989
|
+
return;
|
|
990
|
+
}
|
|
991
|
+
for (const key in data) {
|
|
992
|
+
if (!Object.prototype.hasOwnProperty.call(data, key)) {
|
|
993
|
+
continue;
|
|
994
|
+
}
|
|
995
|
+
const error = validate(key);
|
|
996
|
+
if (error) {
|
|
997
|
+
return defineError("Property name is invalid", {
|
|
998
|
+
item: key,
|
|
999
|
+
cause: error,
|
|
1000
|
+
data: data[key]
|
|
1001
|
+
});
|
|
804
1002
|
}
|
|
805
1003
|
}
|
|
806
|
-
return;
|
|
807
1004
|
},
|
|
808
1005
|
dependencies(schema, data, defineError) {
|
|
809
1006
|
if (!isObject(data)) {
|
|
@@ -852,7 +1049,6 @@ var ObjectKeywords = {
|
|
|
852
1049
|
else: false,
|
|
853
1050
|
default: false,
|
|
854
1051
|
// Not implemented yet
|
|
855
|
-
$ref: false,
|
|
856
1052
|
definitions: false,
|
|
857
1053
|
$id: false,
|
|
858
1054
|
$schema: false,
|
|
@@ -871,17 +1067,14 @@ var ObjectKeywords = {
|
|
|
871
1067
|
// lib/keywords/other-keywords.ts
|
|
872
1068
|
var OtherKeywords = {
|
|
873
1069
|
enum(schema, data, defineError) {
|
|
874
|
-
const
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
const enumItem = schema.enum[i];
|
|
1070
|
+
const list = schema.enum;
|
|
1071
|
+
for (let i = 0; i < list.length; i++) {
|
|
1072
|
+
const enumItem = list[i];
|
|
878
1073
|
if (enumItem === data) {
|
|
879
1074
|
return;
|
|
880
1075
|
}
|
|
881
|
-
if (
|
|
882
|
-
|
|
883
|
-
return;
|
|
884
|
-
}
|
|
1076
|
+
if (enumItem !== null && data !== null && typeof enumItem === "object" && typeof data === "object" && !hasChanged(enumItem, data)) {
|
|
1077
|
+
return;
|
|
885
1078
|
}
|
|
886
1079
|
}
|
|
887
1080
|
return defineError("Value is not one of the allowed values", { data });
|
|
@@ -934,27 +1127,40 @@ var OtherKeywords = {
|
|
|
934
1127
|
return defineError("Value is not valid", { data });
|
|
935
1128
|
},
|
|
936
1129
|
oneOf(schema, data, defineError) {
|
|
1130
|
+
const list = schema.oneOf;
|
|
937
1131
|
let validCount = 0;
|
|
938
|
-
for (let i = 0; i <
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
1132
|
+
for (let i = 0; i < list.length; i++) {
|
|
1133
|
+
const sub = list[i];
|
|
1134
|
+
if (isObject(sub)) {
|
|
1135
|
+
if ("$validate" in sub) {
|
|
1136
|
+
const error = sub.$validate(data);
|
|
942
1137
|
if (!error) {
|
|
943
1138
|
validCount++;
|
|
1139
|
+
if (validCount > 1) {
|
|
1140
|
+
return defineError("Value is not valid", { data });
|
|
1141
|
+
}
|
|
944
1142
|
}
|
|
945
1143
|
continue;
|
|
946
1144
|
}
|
|
947
1145
|
validCount++;
|
|
1146
|
+
if (validCount > 1) {
|
|
1147
|
+
return defineError("Value is not valid", { data });
|
|
1148
|
+
}
|
|
948
1149
|
continue;
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
1150
|
+
}
|
|
1151
|
+
if (typeof sub === "boolean") {
|
|
1152
|
+
if (Boolean(data) === sub) {
|
|
1153
|
+
validCount++;
|
|
1154
|
+
if (validCount > 1) {
|
|
1155
|
+
return defineError("Value is not valid", { data });
|
|
953
1156
|
}
|
|
954
|
-
continue;
|
|
955
1157
|
}
|
|
956
|
-
|
|
957
|
-
|
|
1158
|
+
continue;
|
|
1159
|
+
}
|
|
1160
|
+
if (data === sub) {
|
|
1161
|
+
validCount++;
|
|
1162
|
+
if (validCount > 1) {
|
|
1163
|
+
return defineError("Value is not valid", { data });
|
|
958
1164
|
}
|
|
959
1165
|
}
|
|
960
1166
|
}
|
|
@@ -964,12 +1170,15 @@ var OtherKeywords = {
|
|
|
964
1170
|
return defineError("Value is not valid", { data });
|
|
965
1171
|
},
|
|
966
1172
|
const(schema, data, defineError) {
|
|
967
|
-
if (data === schema.const
|
|
1173
|
+
if (data === schema.const) {
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
if (isObject(data) && isObject(schema.const) && !hasChanged(data, schema.const) || Array.isArray(data) && Array.isArray(schema.const) && !hasChanged(data, schema.const)) {
|
|
968
1177
|
return;
|
|
969
1178
|
}
|
|
970
1179
|
return defineError("Value is not valid", { data });
|
|
971
1180
|
},
|
|
972
|
-
if(schema, data
|
|
1181
|
+
if(schema, data) {
|
|
973
1182
|
if ("then" in schema === false && "else" in schema === false) {
|
|
974
1183
|
return;
|
|
975
1184
|
}
|
|
@@ -1017,6 +1226,24 @@ var OtherKeywords = {
|
|
|
1017
1226
|
return defineError("Value is not valid", { data });
|
|
1018
1227
|
}
|
|
1019
1228
|
return defineError("Value is not valid", { data });
|
|
1229
|
+
},
|
|
1230
|
+
$ref(schema, data, defineError, instance) {
|
|
1231
|
+
if (schema._resolvedRef) {
|
|
1232
|
+
return schema._resolvedRef(data);
|
|
1233
|
+
}
|
|
1234
|
+
const refPath = schema.$ref;
|
|
1235
|
+
let targetSchema = instance.getSchemaRef(refPath);
|
|
1236
|
+
if (!targetSchema) {
|
|
1237
|
+
targetSchema = instance.getSchemaById(refPath);
|
|
1238
|
+
}
|
|
1239
|
+
if (!targetSchema) {
|
|
1240
|
+
return defineError(`Missing reference: ${refPath}`);
|
|
1241
|
+
}
|
|
1242
|
+
if (!targetSchema.$validate) {
|
|
1243
|
+
return;
|
|
1244
|
+
}
|
|
1245
|
+
schema._resolvedRef = targetSchema.$validate;
|
|
1246
|
+
return schema._resolvedRef(data);
|
|
1020
1247
|
}
|
|
1021
1248
|
};
|
|
1022
1249
|
|
|
@@ -1038,9 +1265,22 @@ var StringKeywords = {
|
|
|
1038
1265
|
if (typeof data !== "string") {
|
|
1039
1266
|
return;
|
|
1040
1267
|
}
|
|
1041
|
-
|
|
1042
|
-
if (patternRegexp
|
|
1043
|
-
|
|
1268
|
+
let patternRegexp = schema._patternRegexp;
|
|
1269
|
+
if (!patternRegexp) {
|
|
1270
|
+
try {
|
|
1271
|
+
patternRegexp = new RegExp(schema.pattern, "u");
|
|
1272
|
+
Object.defineProperty(schema, "_patternRegexp", {
|
|
1273
|
+
value: patternRegexp,
|
|
1274
|
+
enumerable: false,
|
|
1275
|
+
configurable: false,
|
|
1276
|
+
writable: false
|
|
1277
|
+
});
|
|
1278
|
+
} catch (error) {
|
|
1279
|
+
return defineError("Invalid regular expression", {
|
|
1280
|
+
data,
|
|
1281
|
+
cause: error
|
|
1282
|
+
});
|
|
1283
|
+
}
|
|
1044
1284
|
}
|
|
1045
1285
|
if (patternRegexp.test(data)) {
|
|
1046
1286
|
return;
|
|
@@ -1053,7 +1293,16 @@ var StringKeywords = {
|
|
|
1053
1293
|
if (typeof data !== "string") {
|
|
1054
1294
|
return;
|
|
1055
1295
|
}
|
|
1056
|
-
|
|
1296
|
+
let formatValidate = schema._formatValidate;
|
|
1297
|
+
if (formatValidate === void 0) {
|
|
1298
|
+
formatValidate = instance.getFormat(schema.format);
|
|
1299
|
+
Object.defineProperty(schema, "_formatValidate", {
|
|
1300
|
+
value: formatValidate,
|
|
1301
|
+
enumerable: false,
|
|
1302
|
+
configurable: false,
|
|
1303
|
+
writable: false
|
|
1304
|
+
});
|
|
1305
|
+
}
|
|
1057
1306
|
if (!formatValidate || formatValidate(data)) {
|
|
1058
1307
|
return;
|
|
1059
1308
|
}
|
|
@@ -1076,10 +1325,15 @@ var SchemaShield = class {
|
|
|
1076
1325
|
formats = {};
|
|
1077
1326
|
keywords = {};
|
|
1078
1327
|
immutable = false;
|
|
1328
|
+
rootSchema = null;
|
|
1329
|
+
idRegistry = /* @__PURE__ */ new Map();
|
|
1330
|
+
failFast = true;
|
|
1079
1331
|
constructor({
|
|
1080
|
-
immutable = false
|
|
1332
|
+
immutable = false,
|
|
1333
|
+
failFast = true
|
|
1081
1334
|
} = {}) {
|
|
1082
1335
|
this.immutable = immutable;
|
|
1336
|
+
this.failFast = failFast;
|
|
1083
1337
|
for (const [type, validator] of Object.entries(Types)) {
|
|
1084
1338
|
if (validator) {
|
|
1085
1339
|
this.addType(type, validator);
|
|
@@ -1121,26 +1375,38 @@ var SchemaShield = class {
|
|
|
1121
1375
|
getKeyword(keyword) {
|
|
1122
1376
|
return this.keywords[keyword];
|
|
1123
1377
|
}
|
|
1378
|
+
getSchemaRef(path) {
|
|
1379
|
+
if (!this.rootSchema) {
|
|
1380
|
+
return;
|
|
1381
|
+
}
|
|
1382
|
+
return resolvePath(this.rootSchema, path);
|
|
1383
|
+
}
|
|
1384
|
+
getSchemaById(id) {
|
|
1385
|
+
return this.idRegistry.get(id);
|
|
1386
|
+
}
|
|
1124
1387
|
compile(schema) {
|
|
1388
|
+
this.idRegistry.clear();
|
|
1125
1389
|
const compiledSchema = this.compileSchema(schema);
|
|
1390
|
+
this.rootSchema = compiledSchema;
|
|
1391
|
+
this.linkReferences(compiledSchema);
|
|
1126
1392
|
if (!compiledSchema.$validate) {
|
|
1127
1393
|
if (this.isSchemaLike(schema) === false) {
|
|
1128
1394
|
throw new ValidationError("Invalid schema");
|
|
1129
1395
|
}
|
|
1130
1396
|
compiledSchema.$validate = getNamedFunction(
|
|
1131
|
-
"
|
|
1397
|
+
"Validate_Any",
|
|
1132
1398
|
() => {
|
|
1133
1399
|
}
|
|
1134
1400
|
);
|
|
1135
1401
|
}
|
|
1136
1402
|
const validate = (data) => {
|
|
1403
|
+
this.rootSchema = compiledSchema;
|
|
1137
1404
|
const clonedData = this.immutable ? deepClone(data) : data;
|
|
1138
|
-
const
|
|
1139
|
-
|
|
1140
|
-
data: clonedData,
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
};
|
|
1405
|
+
const res = compiledSchema.$validate(clonedData);
|
|
1406
|
+
if (res) {
|
|
1407
|
+
return { data: clonedData, error: res, valid: false };
|
|
1408
|
+
}
|
|
1409
|
+
return { data: clonedData, error: null, valid: true };
|
|
1144
1410
|
};
|
|
1145
1411
|
validate.compiledSchema = compiledSchema;
|
|
1146
1412
|
return validate;
|
|
@@ -1148,99 +1414,113 @@ var SchemaShield = class {
|
|
|
1148
1414
|
compileSchema(schema) {
|
|
1149
1415
|
if (!isObject(schema)) {
|
|
1150
1416
|
if (schema === true) {
|
|
1151
|
-
schema = {
|
|
1152
|
-
anyOf: [{}]
|
|
1153
|
-
};
|
|
1417
|
+
schema = { anyOf: [{}] };
|
|
1154
1418
|
} else if (schema === false) {
|
|
1155
|
-
schema = {
|
|
1156
|
-
oneOf: []
|
|
1157
|
-
};
|
|
1419
|
+
schema = { oneOf: [] };
|
|
1158
1420
|
} else {
|
|
1159
|
-
schema = {
|
|
1160
|
-
oneOf: [schema]
|
|
1161
|
-
};
|
|
1421
|
+
schema = { oneOf: [schema] };
|
|
1162
1422
|
}
|
|
1163
1423
|
}
|
|
1164
1424
|
const compiledSchema = deepClone(schema);
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1425
|
+
if (typeof schema.$id === "string") {
|
|
1426
|
+
this.idRegistry.set(schema.$id, compiledSchema);
|
|
1427
|
+
}
|
|
1428
|
+
if ("$ref" in schema) {
|
|
1429
|
+
const refValidator = this.getKeyword("$ref");
|
|
1430
|
+
if (refValidator) {
|
|
1431
|
+
const defineError = getDefinedErrorFunctionForKey(
|
|
1432
|
+
"$ref",
|
|
1433
|
+
schema["$ref"],
|
|
1434
|
+
this.failFast
|
|
1435
|
+
);
|
|
1436
|
+
compiledSchema.$validate = getNamedFunction(
|
|
1437
|
+
"Validate_Reference",
|
|
1438
|
+
(data) => refValidator(
|
|
1439
|
+
compiledSchema,
|
|
1440
|
+
data,
|
|
1441
|
+
defineError,
|
|
1442
|
+
this
|
|
1443
|
+
)
|
|
1444
|
+
);
|
|
1445
|
+
}
|
|
1446
|
+
return compiledSchema;
|
|
1447
|
+
}
|
|
1448
|
+
const validators = [];
|
|
1449
|
+
const activeNames = [];
|
|
1168
1450
|
if ("type" in schema) {
|
|
1451
|
+
const defineTypeError = getDefinedErrorFunctionForKey(
|
|
1452
|
+
"type",
|
|
1453
|
+
schema,
|
|
1454
|
+
this.failFast
|
|
1455
|
+
);
|
|
1169
1456
|
const types = Array.isArray(schema.type) ? schema.type : schema.type.split(",").map((t) => t.trim());
|
|
1170
|
-
|
|
1171
|
-
|
|
1457
|
+
const typeFunctions = [];
|
|
1458
|
+
const typeNames = [];
|
|
1459
|
+
for (const type2 of types) {
|
|
1460
|
+
const validator = this.getType(type2);
|
|
1172
1461
|
if (validator) {
|
|
1173
|
-
|
|
1174
|
-
|
|
1462
|
+
typeFunctions.push(validator);
|
|
1463
|
+
typeNames.push(validator.name);
|
|
1175
1464
|
}
|
|
1176
1465
|
}
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1466
|
+
if (typeFunctions.length === 0) {
|
|
1467
|
+
throw getDefinedErrorFunctionForKey(
|
|
1468
|
+
"type",
|
|
1469
|
+
schema,
|
|
1470
|
+
this.failFast
|
|
1471
|
+
)("Invalid type for schema", { data: schema.type });
|
|
1472
|
+
}
|
|
1473
|
+
let combinedTypeValidator;
|
|
1474
|
+
let typeMethodName = "";
|
|
1475
|
+
if (typeFunctions.length === 1) {
|
|
1476
|
+
typeMethodName = typeNames[0];
|
|
1477
|
+
const singleTypeFn = typeFunctions[0];
|
|
1478
|
+
combinedTypeValidator = (data) => {
|
|
1479
|
+
if (!singleTypeFn(data)) {
|
|
1480
|
+
return defineTypeError("Invalid type", { data });
|
|
1189
1481
|
}
|
|
1190
|
-
|
|
1191
|
-
} else
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
(
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
return;
|
|
1198
|
-
}
|
|
1482
|
+
};
|
|
1483
|
+
} else {
|
|
1484
|
+
typeMethodName = typeNames.join("_OR_");
|
|
1485
|
+
combinedTypeValidator = (data) => {
|
|
1486
|
+
for (let i = 0; i < typeFunctions.length; i++) {
|
|
1487
|
+
if (typeFunctions[i](data)) {
|
|
1488
|
+
return;
|
|
1199
1489
|
}
|
|
1200
|
-
return defineTypeError("Invalid type", { data });
|
|
1201
1490
|
}
|
|
1491
|
+
return defineTypeError("Invalid type", { data });
|
|
1492
|
+
};
|
|
1493
|
+
}
|
|
1494
|
+
const typeAdapter = (_s, data) => combinedTypeValidator(data);
|
|
1495
|
+
validators.push({
|
|
1496
|
+
fn: getNamedFunction(typeMethodName, typeAdapter),
|
|
1497
|
+
defineError: defineTypeError
|
|
1498
|
+
});
|
|
1499
|
+
activeNames.push(typeMethodName);
|
|
1500
|
+
}
|
|
1501
|
+
const { type, $id, $ref, $validate, required, ...otherKeys } = schema;
|
|
1502
|
+
const keyOrder = required ? [...Object.keys(otherKeys), "required"] : Object.keys(otherKeys);
|
|
1503
|
+
for (const key of keyOrder) {
|
|
1504
|
+
const keywordFn = this.getKeyword(key);
|
|
1505
|
+
if (keywordFn) {
|
|
1506
|
+
const defineError = getDefinedErrorFunctionForKey(
|
|
1507
|
+
key,
|
|
1508
|
+
schema[key],
|
|
1509
|
+
this.failFast
|
|
1202
1510
|
);
|
|
1511
|
+
const fnName = keywordFn.name || key;
|
|
1512
|
+
validators.push({
|
|
1513
|
+
fn: keywordFn,
|
|
1514
|
+
defineError
|
|
1515
|
+
});
|
|
1516
|
+
activeNames.push(fnName);
|
|
1203
1517
|
}
|
|
1204
1518
|
}
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1519
|
+
const literalKeywords = ["enum", "const", "default", "examples"];
|
|
1520
|
+
for (const key of keyOrder) {
|
|
1521
|
+
if (literalKeywords.includes(key)) {
|
|
1208
1522
|
continue;
|
|
1209
1523
|
}
|
|
1210
|
-
const keywordValidator = this.getKeyword(key);
|
|
1211
|
-
if (keywordValidator) {
|
|
1212
|
-
const defineError = getDefinedErrorFunctionForKey(key, schema[key]);
|
|
1213
|
-
if (compiledSchema.$validate) {
|
|
1214
|
-
const prevValidator = compiledSchema.$validate;
|
|
1215
|
-
methodName += `_AND_${keywordValidator.name}`;
|
|
1216
|
-
compiledSchema.$validate = getNamedFunction(
|
|
1217
|
-
methodName,
|
|
1218
|
-
(data) => {
|
|
1219
|
-
const error = prevValidator(data);
|
|
1220
|
-
if (error) {
|
|
1221
|
-
return error;
|
|
1222
|
-
}
|
|
1223
|
-
return keywordValidator(
|
|
1224
|
-
compiledSchema,
|
|
1225
|
-
data,
|
|
1226
|
-
defineError,
|
|
1227
|
-
this
|
|
1228
|
-
);
|
|
1229
|
-
}
|
|
1230
|
-
);
|
|
1231
|
-
} else {
|
|
1232
|
-
methodName = keywordValidator.name;
|
|
1233
|
-
compiledSchema.$validate = getNamedFunction(
|
|
1234
|
-
methodName,
|
|
1235
|
-
(data) => keywordValidator(
|
|
1236
|
-
compiledSchema,
|
|
1237
|
-
data,
|
|
1238
|
-
defineError,
|
|
1239
|
-
this
|
|
1240
|
-
)
|
|
1241
|
-
);
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1244
1524
|
if (isObject(schema[key])) {
|
|
1245
1525
|
if (key === "properties") {
|
|
1246
1526
|
for (const subKey of Object.keys(schema[key])) {
|
|
@@ -1254,12 +1534,39 @@ var SchemaShield = class {
|
|
|
1254
1534
|
continue;
|
|
1255
1535
|
}
|
|
1256
1536
|
if (Array.isArray(schema[key])) {
|
|
1257
|
-
|
|
1258
|
-
(
|
|
1259
|
-
|
|
1537
|
+
for (let i = 0; i < schema[key].length; i++) {
|
|
1538
|
+
if (this.isSchemaLike(schema[key][i])) {
|
|
1539
|
+
compiledSchema[key][i] = this.compileSchema(schema[key][i]);
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1260
1542
|
continue;
|
|
1261
1543
|
}
|
|
1262
|
-
|
|
1544
|
+
}
|
|
1545
|
+
if (validators.length === 0) {
|
|
1546
|
+
return compiledSchema;
|
|
1547
|
+
}
|
|
1548
|
+
if (validators.length === 1) {
|
|
1549
|
+
const v = validators[0];
|
|
1550
|
+
compiledSchema.$validate = getNamedFunction(
|
|
1551
|
+
activeNames[0],
|
|
1552
|
+
(data) => v.fn(compiledSchema, data, v.defineError, this)
|
|
1553
|
+
);
|
|
1554
|
+
} else {
|
|
1555
|
+
const compositeName = "Validate_" + activeNames.join("_AND_");
|
|
1556
|
+
const masterValidator = (data) => {
|
|
1557
|
+
for (let i = 0; i < validators.length; i++) {
|
|
1558
|
+
const v = validators[i];
|
|
1559
|
+
const error = v.fn(compiledSchema, data, v.defineError, this);
|
|
1560
|
+
if (error) {
|
|
1561
|
+
return error;
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
return;
|
|
1565
|
+
};
|
|
1566
|
+
compiledSchema.$validate = getNamedFunction(
|
|
1567
|
+
compositeName,
|
|
1568
|
+
masterValidator
|
|
1569
|
+
);
|
|
1263
1570
|
}
|
|
1264
1571
|
return compiledSchema;
|
|
1265
1572
|
}
|
|
@@ -1276,4 +1583,54 @@ var SchemaShield = class {
|
|
|
1276
1583
|
}
|
|
1277
1584
|
return false;
|
|
1278
1585
|
}
|
|
1586
|
+
linkReferences(root) {
|
|
1587
|
+
const stack = [root];
|
|
1588
|
+
while (stack.length > 0) {
|
|
1589
|
+
const node = stack.pop();
|
|
1590
|
+
if (!node || typeof node !== "object")
|
|
1591
|
+
continue;
|
|
1592
|
+
if (typeof node.$ref === "string" && typeof node.$validate === "function" && node.$validate.name === "Validate_Reference") {
|
|
1593
|
+
const refPath = node.$ref;
|
|
1594
|
+
let target = this.getSchemaRef(refPath);
|
|
1595
|
+
if (typeof target === "undefined") {
|
|
1596
|
+
target = this.getSchemaById(refPath);
|
|
1597
|
+
}
|
|
1598
|
+
if (typeof target === "boolean") {
|
|
1599
|
+
if (target === true) {
|
|
1600
|
+
node.$validate = getNamedFunction("Validate_Ref_True", () => {
|
|
1601
|
+
});
|
|
1602
|
+
} else {
|
|
1603
|
+
const defineError = getDefinedErrorFunctionForKey(
|
|
1604
|
+
"$ref",
|
|
1605
|
+
node,
|
|
1606
|
+
this.failFast
|
|
1607
|
+
);
|
|
1608
|
+
node.$validate = getNamedFunction(
|
|
1609
|
+
"Validate_Ref_False",
|
|
1610
|
+
(_data) => defineError("Value is not valid")
|
|
1611
|
+
);
|
|
1612
|
+
}
|
|
1613
|
+
continue;
|
|
1614
|
+
}
|
|
1615
|
+
if (target && typeof target.$validate === "function") {
|
|
1616
|
+
node.$validate = target.$validate;
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
for (const key in node) {
|
|
1620
|
+
const value = node[key];
|
|
1621
|
+
if (!value)
|
|
1622
|
+
continue;
|
|
1623
|
+
if (Array.isArray(value)) {
|
|
1624
|
+
for (let i = 0; i < value.length; i++) {
|
|
1625
|
+
const v = value[i];
|
|
1626
|
+
if (v && typeof v === "object") {
|
|
1627
|
+
stack.push(v);
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
} else if (typeof value === "object") {
|
|
1631
|
+
stack.push(value);
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1279
1636
|
};
|