@ls-stack/utils 3.48.0 → 3.49.1
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/dist/partialEqual.cjs +551 -695
- package/dist/partialEqual.d.cts +38 -5
- package/dist/partialEqual.d.ts +38 -5
- package/dist/partialEqual.js +550 -634
- package/package.json +1 -1
package/dist/partialEqual.cjs
CHANGED
|
@@ -26,72 +26,13 @@ __export(partialEqual_exports, {
|
|
|
26
26
|
module.exports = __toCommonJS(partialEqual_exports);
|
|
27
27
|
var import_t_result = require("t-result");
|
|
28
28
|
|
|
29
|
-
// src/
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
for (const key of iter.keys()) {
|
|
33
|
-
if (deepEqual(key, tar, maxDepth)) return key;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
function deepEqual(foo, bar, maxDepth = 20) {
|
|
37
|
-
let ctor, len, tmp;
|
|
38
|
-
if (foo === bar) return true;
|
|
39
|
-
if (maxDepth && maxDepth <= 0) return false;
|
|
40
|
-
if (foo && bar && (ctor = foo.constructor) === bar.constructor) {
|
|
41
|
-
if (ctor === Date)
|
|
42
|
-
return deepEqual(foo.getTime(), bar.getTime(), maxDepth - 1);
|
|
43
|
-
if (ctor === RegExp) return foo.toString() === bar.toString();
|
|
44
|
-
if (ctor === Array) {
|
|
45
|
-
if ((len = foo.length) === bar.length) {
|
|
46
|
-
while (len-- && deepEqual(foo[len], bar[len], maxDepth - 1)) ;
|
|
47
|
-
}
|
|
48
|
-
return len === -1;
|
|
49
|
-
}
|
|
50
|
-
if (ctor === Set) {
|
|
51
|
-
if (foo.size !== bar.size) {
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
for (len of foo) {
|
|
55
|
-
tmp = len;
|
|
56
|
-
if (tmp && typeof tmp === "object") {
|
|
57
|
-
tmp = find(bar, tmp, maxDepth - 1);
|
|
58
|
-
if (!tmp) return false;
|
|
59
|
-
}
|
|
60
|
-
if (!bar.has(tmp)) return false;
|
|
61
|
-
}
|
|
62
|
-
return true;
|
|
63
|
-
}
|
|
64
|
-
if (ctor === Map) {
|
|
65
|
-
if (foo.size !== bar.size) {
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
for (len of foo) {
|
|
69
|
-
tmp = len[0];
|
|
70
|
-
if (tmp && typeof tmp === "object") {
|
|
71
|
-
tmp = find(bar, tmp, maxDepth - 1);
|
|
72
|
-
if (!tmp) return false;
|
|
73
|
-
}
|
|
74
|
-
if (!deepEqual(len[1], bar.get(tmp), maxDepth - 1)) {
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return true;
|
|
79
|
-
}
|
|
80
|
-
if (!ctor || typeof foo === "object") {
|
|
81
|
-
len = 0;
|
|
82
|
-
for (ctor in foo) {
|
|
83
|
-
if (has.call(foo, ctor) && ++len && !has.call(bar, ctor)) return false;
|
|
84
|
-
if (!(ctor in bar) || !deepEqual(foo[ctor], bar[ctor], maxDepth - 1))
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
return Object.keys(bar).length === len;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return foo !== foo && bar !== bar;
|
|
29
|
+
// src/assertions.ts
|
|
30
|
+
function exhaustiveCheck(narrowedType) {
|
|
31
|
+
return new Error("This should never happen");
|
|
91
32
|
}
|
|
92
33
|
|
|
93
34
|
// src/partialEqual.ts
|
|
94
|
-
var
|
|
35
|
+
var has = Object.prototype.hasOwnProperty;
|
|
95
36
|
function createComparison(type) {
|
|
96
37
|
return { "~sc": type };
|
|
97
38
|
}
|
|
@@ -129,8 +70,24 @@ var match = {
|
|
|
129
70
|
partialEqual: (value) => createComparison(["partialEqual", value]),
|
|
130
71
|
custom: (isEqual) => createComparison(["custom", isEqual]),
|
|
131
72
|
keyNotBePresent: createComparison(["keyNotBePresent", null]),
|
|
132
|
-
any: (...
|
|
133
|
-
|
|
73
|
+
any: (...values) => createComparison([
|
|
74
|
+
"any",
|
|
75
|
+
values.map((v) => {
|
|
76
|
+
if (isComparison(v)) return v["~sc"];
|
|
77
|
+
if (typeof v === "object" && v !== null)
|
|
78
|
+
return ["partialEqual", v];
|
|
79
|
+
return ["deepEqual", v];
|
|
80
|
+
})
|
|
81
|
+
]),
|
|
82
|
+
all: (...values) => createComparison([
|
|
83
|
+
"all",
|
|
84
|
+
values.map((v) => {
|
|
85
|
+
if (isComparison(v)) return v["~sc"];
|
|
86
|
+
if (typeof v === "object" && v !== null)
|
|
87
|
+
return ["partialEqual", v];
|
|
88
|
+
return ["deepEqual", v];
|
|
89
|
+
})
|
|
90
|
+
]),
|
|
134
91
|
not: {
|
|
135
92
|
hasType: {
|
|
136
93
|
string: createComparison(["not", ["hasType", "string"]]),
|
|
@@ -161,741 +118,640 @@ var match = {
|
|
|
161
118
|
equal: (value) => createComparison(["not", ["deepEqual", value]]),
|
|
162
119
|
partialEqual: (value) => createComparison(["not", ["partialEqual", value]]),
|
|
163
120
|
custom: (value) => createComparison(["not", ["custom", value]]),
|
|
164
|
-
any: (...
|
|
165
|
-
|
|
121
|
+
any: (...values) => createComparison([
|
|
122
|
+
"not",
|
|
123
|
+
[
|
|
124
|
+
"any",
|
|
125
|
+
values.map((v) => {
|
|
126
|
+
if (isComparison(v)) return v["~sc"];
|
|
127
|
+
if (typeof v === "object" && v !== null)
|
|
128
|
+
return ["partialEqual", v];
|
|
129
|
+
return ["deepEqual", v];
|
|
130
|
+
})
|
|
131
|
+
]
|
|
132
|
+
]),
|
|
133
|
+
all: (...values) => createComparison([
|
|
134
|
+
"not",
|
|
135
|
+
[
|
|
136
|
+
"all",
|
|
137
|
+
values.map((v) => {
|
|
138
|
+
if (isComparison(v)) return v["~sc"];
|
|
139
|
+
if (typeof v === "object" && v !== null)
|
|
140
|
+
return ["partialEqual", v];
|
|
141
|
+
return ["deepEqual", v];
|
|
142
|
+
})
|
|
143
|
+
]
|
|
144
|
+
]),
|
|
166
145
|
noExtraKeys: (partialShape) => createComparison(["not", ["withNoExtraKeys", partialShape]]),
|
|
167
146
|
deepNoExtraKeys: (partialShape) => createComparison(["not", ["withDeepNoExtraKeys", partialShape]]),
|
|
168
147
|
noExtraDefinedKeys: (partialShape) => createComparison(["not", ["noExtraDefinedKeys", partialShape]]),
|
|
169
148
|
deepNoExtraDefinedKeys: (partialShape) => createComparison(["not", ["deepNoExtraDefinedKeys", partialShape]])
|
|
170
149
|
}
|
|
171
150
|
};
|
|
172
|
-
function
|
|
173
|
-
|
|
174
|
-
if (partialEqual(key, tar)) return key;
|
|
175
|
-
}
|
|
151
|
+
function isComparison(value) {
|
|
152
|
+
return value && typeof value === "object" && "~sc" in value;
|
|
176
153
|
}
|
|
177
|
-
function
|
|
178
|
-
const [type, value] = comp;
|
|
179
|
-
if (type === "keyNotBePresent") {
|
|
180
|
-
return !keyExists;
|
|
181
|
-
}
|
|
182
|
-
if (type === "any") {
|
|
183
|
-
for (const childComp of value) {
|
|
184
|
-
if (executeComparisonWithKeyContext(target, childComp, keyExists)) {
|
|
185
|
-
return true;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
return false;
|
|
189
|
-
}
|
|
190
|
-
if (type === "not") {
|
|
191
|
-
return !executeComparisonWithKeyContext(target, value, keyExists);
|
|
192
|
-
}
|
|
193
|
-
return executeComparison(target, comp);
|
|
194
|
-
}
|
|
195
|
-
function executeComparison(target, comparison) {
|
|
154
|
+
function executeComparison(target, comparison, context) {
|
|
196
155
|
const [type, value] = comparison;
|
|
197
156
|
switch (type) {
|
|
198
|
-
case "hasType":
|
|
199
|
-
switch (value) {
|
|
200
|
-
case "string":
|
|
201
|
-
return typeof target === "string";
|
|
202
|
-
case "number":
|
|
203
|
-
return typeof target === "number";
|
|
204
|
-
case "boolean":
|
|
205
|
-
return typeof target === "boolean";
|
|
206
|
-
case "function":
|
|
207
|
-
return typeof target === "function";
|
|
208
|
-
case "array":
|
|
209
|
-
return Array.isArray(target);
|
|
210
|
-
case "object":
|
|
211
|
-
return typeof target === "object" && target !== null && !Array.isArray(target);
|
|
212
|
-
default:
|
|
213
|
-
return false;
|
|
214
|
-
}
|
|
215
|
-
case "isInstanceOf":
|
|
216
|
-
return target instanceof value;
|
|
217
157
|
case "strStartsWith":
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
case "strMatchesRegex":
|
|
224
|
-
return typeof target === "string" && value.test(target);
|
|
225
|
-
case "numIsGreaterThan":
|
|
226
|
-
return typeof target === "number" && target > value;
|
|
227
|
-
case "numIsGreaterThanOrEqual":
|
|
228
|
-
return typeof target === "number" && target >= value;
|
|
229
|
-
case "numIsLessThan":
|
|
230
|
-
return typeof target === "number" && target < value;
|
|
231
|
-
case "numIsLessThanOrEqual":
|
|
232
|
-
return typeof target === "number" && target <= value;
|
|
233
|
-
case "numIsInRange":
|
|
234
|
-
return typeof target === "number" && target >= value[0] && target <= value[1];
|
|
235
|
-
case "jsonStringHasPartial":
|
|
236
|
-
if (typeof target !== "string") return false;
|
|
237
|
-
try {
|
|
238
|
-
const parsed = JSON.parse(target);
|
|
239
|
-
return partialEqual(parsed, value);
|
|
240
|
-
} catch {
|
|
241
|
-
return false;
|
|
242
|
-
}
|
|
243
|
-
case "deepEqual":
|
|
244
|
-
return deepEqual(target, value);
|
|
245
|
-
case "partialEqual":
|
|
246
|
-
return partialEqual(target, value);
|
|
247
|
-
case "custom":
|
|
248
|
-
return value(target);
|
|
249
|
-
case "keyNotBePresent":
|
|
250
|
-
return false;
|
|
251
|
-
case "any":
|
|
252
|
-
for (const comp of value) {
|
|
253
|
-
if (executeComparison(target, comp)) {
|
|
254
|
-
return true;
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
return false;
|
|
258
|
-
case "all":
|
|
259
|
-
for (const comp of value) {
|
|
260
|
-
if (!executeComparison(target, comp)) {
|
|
261
|
-
return false;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
return true;
|
|
265
|
-
case "not":
|
|
266
|
-
return !executeComparison(target, value);
|
|
267
|
-
case "withNoExtraKeys":
|
|
268
|
-
if (typeof target !== "object" || target === null || Array.isArray(target)) {
|
|
158
|
+
if (typeof target !== "string") {
|
|
159
|
+
addError(context, {
|
|
160
|
+
message: `Expected string starting with "${value}"`,
|
|
161
|
+
received: target
|
|
162
|
+
});
|
|
269
163
|
return false;
|
|
270
164
|
}
|
|
271
|
-
if (
|
|
165
|
+
if (!target.startsWith(value)) {
|
|
166
|
+
addError(context, {
|
|
167
|
+
message: `Expected string starting with "${value}"`,
|
|
168
|
+
received: target
|
|
169
|
+
});
|
|
272
170
|
return false;
|
|
273
171
|
}
|
|
274
|
-
for (const key in target) {
|
|
275
|
-
if (has2.call(target, key) && !has2.call(value, key)) {
|
|
276
|
-
return false;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
for (const key in value) {
|
|
280
|
-
if (has2.call(value, key)) {
|
|
281
|
-
if (!has2.call(target, key)) {
|
|
282
|
-
return false;
|
|
283
|
-
}
|
|
284
|
-
if (!partialEqual(target[key], value[key])) {
|
|
285
|
-
return false;
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
172
|
return true;
|
|
290
|
-
case "
|
|
291
|
-
if (typeof target !== "
|
|
173
|
+
case "strEndsWith":
|
|
174
|
+
if (typeof target !== "string") {
|
|
175
|
+
addError(context, {
|
|
176
|
+
message: `Expected string ending with "${value}"`,
|
|
177
|
+
received: target
|
|
178
|
+
});
|
|
292
179
|
return false;
|
|
293
180
|
}
|
|
294
|
-
if (
|
|
181
|
+
if (!target.endsWith(value)) {
|
|
182
|
+
addError(context, {
|
|
183
|
+
message: `Expected string ending with "${value}"`,
|
|
184
|
+
received: target
|
|
185
|
+
});
|
|
295
186
|
return false;
|
|
296
187
|
}
|
|
297
|
-
for (const key in target) {
|
|
298
|
-
if (has2.call(target, key) && !has2.call(value, key)) {
|
|
299
|
-
return false;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
for (const key in value) {
|
|
303
|
-
if (has2.call(value, key)) {
|
|
304
|
-
if (!has2.call(target, key)) {
|
|
305
|
-
return false;
|
|
306
|
-
}
|
|
307
|
-
const targetValue = target[key];
|
|
308
|
-
const partialValue = value[key];
|
|
309
|
-
if (partialValue && typeof partialValue === "object" && "~sc" in partialValue && partialValue["~sc"][0] === "withDeepNoExtraKeys") {
|
|
310
|
-
if (!executeComparison(targetValue, partialValue["~sc"])) {
|
|
311
|
-
return false;
|
|
312
|
-
}
|
|
313
|
-
} else if (partialValue && typeof partialValue === "object" && !Array.isArray(partialValue) && partialValue.constructor === Object && targetValue && typeof targetValue === "object" && !Array.isArray(targetValue) && targetValue.constructor === Object) {
|
|
314
|
-
if (!executeComparison(targetValue, [
|
|
315
|
-
"withDeepNoExtraKeys",
|
|
316
|
-
partialValue
|
|
317
|
-
])) {
|
|
318
|
-
return false;
|
|
319
|
-
}
|
|
320
|
-
} else {
|
|
321
|
-
if (!partialEqual(targetValue, partialValue)) {
|
|
322
|
-
return false;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
188
|
return true;
|
|
328
|
-
case "
|
|
329
|
-
if (typeof target !== "
|
|
189
|
+
case "strContains":
|
|
190
|
+
if (typeof target !== "string") {
|
|
191
|
+
addError(context, {
|
|
192
|
+
message: `Expected string containing "${value}"`,
|
|
193
|
+
received: target
|
|
194
|
+
});
|
|
330
195
|
return false;
|
|
331
196
|
}
|
|
332
|
-
if (
|
|
197
|
+
if (!target.includes(value)) {
|
|
198
|
+
addError(context, {
|
|
199
|
+
message: `Expected string containing "${value}"`,
|
|
200
|
+
received: target
|
|
201
|
+
});
|
|
333
202
|
return false;
|
|
334
203
|
}
|
|
335
|
-
for (const key in target) {
|
|
336
|
-
if (has2.call(target, key) && target[key] !== void 0 && !has2.call(value, key)) {
|
|
337
|
-
return false;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
for (const key in value) {
|
|
341
|
-
if (has2.call(value, key)) {
|
|
342
|
-
if (!has2.call(target, key)) {
|
|
343
|
-
return false;
|
|
344
|
-
}
|
|
345
|
-
if (!partialEqual(target[key], value[key])) {
|
|
346
|
-
return false;
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
204
|
return true;
|
|
351
|
-
case "
|
|
352
|
-
if (typeof target !== "
|
|
205
|
+
case "strMatchesRegex":
|
|
206
|
+
if (typeof target !== "string") {
|
|
207
|
+
addError(context, {
|
|
208
|
+
message: `Expected string matching regex ${value}`,
|
|
209
|
+
received: target
|
|
210
|
+
});
|
|
353
211
|
return false;
|
|
354
212
|
}
|
|
355
|
-
if (
|
|
213
|
+
if (!value.test(target)) {
|
|
214
|
+
addError(context, {
|
|
215
|
+
message: `Expected string matching regex ${value}`,
|
|
216
|
+
received: target
|
|
217
|
+
});
|
|
356
218
|
return false;
|
|
357
219
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
220
|
+
return true;
|
|
221
|
+
case "hasType": {
|
|
222
|
+
let actualType;
|
|
223
|
+
if (value === "array") {
|
|
224
|
+
actualType = Array.isArray(target) ? "array" : typeof target;
|
|
225
|
+
} else if (value === "object") {
|
|
226
|
+
if (target === null || Array.isArray(target)) {
|
|
227
|
+
actualType = "not-object";
|
|
228
|
+
} else {
|
|
229
|
+
actualType = typeof target;
|
|
361
230
|
}
|
|
231
|
+
} else {
|
|
232
|
+
actualType = typeof target;
|
|
362
233
|
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
const partialValue = value[key];
|
|
370
|
-
if (partialValue && typeof partialValue === "object" && "~sc" in partialValue && partialValue["~sc"][0] === "deepNoExtraDefinedKeys") {
|
|
371
|
-
if (!executeComparison(targetValue, partialValue["~sc"])) {
|
|
372
|
-
return false;
|
|
373
|
-
}
|
|
374
|
-
} else if (partialValue && typeof partialValue === "object" && !Array.isArray(partialValue) && partialValue.constructor === Object && targetValue && typeof targetValue === "object" && !Array.isArray(targetValue) && targetValue.constructor === Object) {
|
|
375
|
-
if (!executeComparison(targetValue, [
|
|
376
|
-
"deepNoExtraDefinedKeys",
|
|
377
|
-
partialValue
|
|
378
|
-
])) {
|
|
379
|
-
return false;
|
|
380
|
-
}
|
|
381
|
-
} else {
|
|
382
|
-
if (!partialEqual(targetValue, partialValue)) {
|
|
383
|
-
return false;
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
}
|
|
234
|
+
if (actualType !== value) {
|
|
235
|
+
addError(context, {
|
|
236
|
+
message: `Expected type ${value}`,
|
|
237
|
+
received: target
|
|
238
|
+
});
|
|
239
|
+
return false;
|
|
387
240
|
}
|
|
388
241
|
return true;
|
|
389
|
-
default:
|
|
390
|
-
return false;
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
function formatPath(path) {
|
|
394
|
-
if (path.length === 0) return "";
|
|
395
|
-
let result = path[0] || "";
|
|
396
|
-
for (let i = 1; i < path.length; i++) {
|
|
397
|
-
const segment = path[i];
|
|
398
|
-
if (segment && segment.startsWith("[") && segment.endsWith("]")) {
|
|
399
|
-
result += segment;
|
|
400
|
-
} else if (segment) {
|
|
401
|
-
result += `.${segment}`;
|
|
402
242
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
};
|
|
412
|
-
if (expected !== void 0) {
|
|
413
|
-
error.expected = expected;
|
|
414
|
-
}
|
|
415
|
-
context.errors.push(error);
|
|
416
|
-
}
|
|
417
|
-
function executeComparisonWithErrorCollection(target, comparison, context) {
|
|
418
|
-
const [type, value] = comparison;
|
|
419
|
-
switch (type) {
|
|
420
|
-
case "hasType":
|
|
421
|
-
switch (value) {
|
|
422
|
-
case "string":
|
|
423
|
-
if (typeof target !== "string") {
|
|
424
|
-
addError(context, `Expected type string`, target);
|
|
425
|
-
}
|
|
426
|
-
break;
|
|
427
|
-
case "number":
|
|
428
|
-
if (typeof target !== "number") {
|
|
429
|
-
addError(context, `Expected type number`, target);
|
|
430
|
-
}
|
|
431
|
-
break;
|
|
432
|
-
case "boolean":
|
|
433
|
-
if (typeof target !== "boolean") {
|
|
434
|
-
addError(context, `Expected type boolean`, target);
|
|
435
|
-
}
|
|
436
|
-
break;
|
|
437
|
-
case "function":
|
|
438
|
-
if (typeof target !== "function") {
|
|
439
|
-
addError(context, `Expected type function`, target);
|
|
440
|
-
}
|
|
441
|
-
break;
|
|
442
|
-
case "array":
|
|
443
|
-
if (!Array.isArray(target)) {
|
|
444
|
-
addError(context, `Expected array`, target);
|
|
445
|
-
}
|
|
446
|
-
break;
|
|
447
|
-
case "object":
|
|
448
|
-
if (typeof target !== "object" || target === null || Array.isArray(target)) {
|
|
449
|
-
addError(context, `Expected object`, target);
|
|
450
|
-
}
|
|
451
|
-
break;
|
|
452
|
-
}
|
|
453
|
-
break;
|
|
454
|
-
case "isInstanceOf":
|
|
455
|
-
if (!(target instanceof value)) {
|
|
456
|
-
addError(
|
|
457
|
-
context,
|
|
458
|
-
`Expected instance of ${value.name}`,
|
|
459
|
-
target
|
|
460
|
-
);
|
|
461
|
-
}
|
|
462
|
-
break;
|
|
463
|
-
case "strStartsWith":
|
|
464
|
-
if (typeof target !== "string" || !target.startsWith(value)) {
|
|
465
|
-
addError(
|
|
466
|
-
context,
|
|
467
|
-
`Expected string starting with "${value}"`,
|
|
468
|
-
target
|
|
469
|
-
);
|
|
470
|
-
}
|
|
471
|
-
break;
|
|
472
|
-
case "strEndsWith":
|
|
473
|
-
if (typeof target !== "string" || !target.endsWith(value)) {
|
|
474
|
-
addError(
|
|
475
|
-
context,
|
|
476
|
-
`Expected string ending with "${value}"`,
|
|
477
|
-
target
|
|
478
|
-
);
|
|
479
|
-
}
|
|
480
|
-
break;
|
|
481
|
-
case "strContains":
|
|
482
|
-
if (typeof target !== "string" || !target.includes(value)) {
|
|
483
|
-
addError(
|
|
484
|
-
context,
|
|
485
|
-
`Expected string containing "${value}"`,
|
|
486
|
-
target
|
|
487
|
-
);
|
|
488
|
-
}
|
|
489
|
-
break;
|
|
490
|
-
case "strMatchesRegex":
|
|
491
|
-
if (typeof target !== "string" || !value.test(target)) {
|
|
492
|
-
addError(
|
|
493
|
-
context,
|
|
494
|
-
`Expected string matching regex ${value}`,
|
|
495
|
-
target
|
|
496
|
-
);
|
|
243
|
+
case "deepEqual":
|
|
244
|
+
if (!deepEqual(target, value)) {
|
|
245
|
+
addError(context, {
|
|
246
|
+
message: "Values are not deeply equal",
|
|
247
|
+
received: target,
|
|
248
|
+
expected: value
|
|
249
|
+
});
|
|
250
|
+
return false;
|
|
497
251
|
}
|
|
498
|
-
|
|
252
|
+
return true;
|
|
499
253
|
case "numIsGreaterThan":
|
|
500
254
|
if (typeof target !== "number" || target <= value) {
|
|
501
|
-
addError(
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
255
|
+
addError(context, {
|
|
256
|
+
message: `Expected number greater than ${value}`,
|
|
257
|
+
received: target
|
|
258
|
+
});
|
|
259
|
+
return false;
|
|
506
260
|
}
|
|
507
|
-
|
|
261
|
+
return true;
|
|
508
262
|
case "numIsGreaterThanOrEqual":
|
|
509
263
|
if (typeof target !== "number" || target < value) {
|
|
510
|
-
addError(
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
264
|
+
addError(context, {
|
|
265
|
+
message: `Expected number greater than or equal to ${value}`,
|
|
266
|
+
received: target
|
|
267
|
+
});
|
|
268
|
+
return false;
|
|
515
269
|
}
|
|
516
|
-
|
|
270
|
+
return true;
|
|
517
271
|
case "numIsLessThan":
|
|
518
272
|
if (typeof target !== "number" || target >= value) {
|
|
519
|
-
addError(
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
273
|
+
addError(context, {
|
|
274
|
+
message: `Expected number less than ${value}`,
|
|
275
|
+
received: target
|
|
276
|
+
});
|
|
277
|
+
return false;
|
|
524
278
|
}
|
|
525
|
-
|
|
279
|
+
return true;
|
|
526
280
|
case "numIsLessThanOrEqual":
|
|
527
281
|
if (typeof target !== "number" || target > value) {
|
|
528
|
-
addError(
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
282
|
+
addError(context, {
|
|
283
|
+
message: `Expected number less than or equal to ${value}`,
|
|
284
|
+
received: target
|
|
285
|
+
});
|
|
286
|
+
return false;
|
|
533
287
|
}
|
|
534
|
-
|
|
288
|
+
return true;
|
|
535
289
|
case "numIsInRange":
|
|
536
290
|
if (typeof target !== "number" || target < value[0] || target > value[1]) {
|
|
537
|
-
addError(
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
291
|
+
addError(context, {
|
|
292
|
+
message: `Expected number in range [${value[0]}, ${value[1]}]`,
|
|
293
|
+
received: target
|
|
294
|
+
});
|
|
295
|
+
return false;
|
|
542
296
|
}
|
|
543
|
-
|
|
297
|
+
return true;
|
|
544
298
|
case "jsonStringHasPartial":
|
|
545
299
|
if (typeof target !== "string") {
|
|
546
|
-
addError(context,
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
} catch {
|
|
552
|
-
addError(
|
|
553
|
-
context,
|
|
554
|
-
`Expected valid JSON string`,
|
|
555
|
-
target
|
|
556
|
-
);
|
|
557
|
-
}
|
|
300
|
+
addError(context, {
|
|
301
|
+
message: "Expected JSON string",
|
|
302
|
+
received: target
|
|
303
|
+
});
|
|
304
|
+
return false;
|
|
558
305
|
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
306
|
+
try {
|
|
307
|
+
const parsed = JSON.parse(target);
|
|
308
|
+
if (!partialEqualInternal(parsed, value, context)) {
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
} catch {
|
|
312
|
+
addError(context, {
|
|
313
|
+
message: "Expected valid JSON string",
|
|
314
|
+
received: target
|
|
315
|
+
});
|
|
316
|
+
return false;
|
|
563
317
|
}
|
|
564
|
-
|
|
318
|
+
return true;
|
|
565
319
|
case "partialEqual":
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
if (
|
|
570
|
-
addError(context,
|
|
320
|
+
return partialEqualInternal(target, value, context);
|
|
321
|
+
case "custom": {
|
|
322
|
+
const result = value(target);
|
|
323
|
+
if (result !== true) {
|
|
324
|
+
addError(context, {
|
|
325
|
+
message: `Custom validation failed ${typeof result === "object" ? `: ${result.error}` : ""}`,
|
|
326
|
+
received: target
|
|
327
|
+
});
|
|
328
|
+
return false;
|
|
571
329
|
}
|
|
572
|
-
|
|
330
|
+
return true;
|
|
331
|
+
}
|
|
332
|
+
case "isInstanceOf":
|
|
333
|
+
if (!(target instanceof value)) {
|
|
334
|
+
addError(context, {
|
|
335
|
+
message: `Expected instance of ${value.name}`,
|
|
336
|
+
received: target
|
|
337
|
+
});
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
return true;
|
|
573
341
|
case "keyNotBePresent":
|
|
574
|
-
addError(context,
|
|
575
|
-
|
|
342
|
+
addError(context, {
|
|
343
|
+
message: "This property should not be present",
|
|
344
|
+
received: target
|
|
345
|
+
});
|
|
346
|
+
return false;
|
|
347
|
+
case "not": {
|
|
348
|
+
const tempContext = {
|
|
349
|
+
errors: [],
|
|
350
|
+
path: context.path
|
|
351
|
+
};
|
|
352
|
+
const result = executeComparison(target, value, tempContext);
|
|
353
|
+
if (result) {
|
|
354
|
+
addError(context, {
|
|
355
|
+
message: "Expected negated condition to fail",
|
|
356
|
+
received: target,
|
|
357
|
+
expected: { "not match": value }
|
|
358
|
+
});
|
|
359
|
+
return false;
|
|
360
|
+
}
|
|
361
|
+
return true;
|
|
362
|
+
}
|
|
576
363
|
case "any": {
|
|
577
|
-
for (const
|
|
578
|
-
const
|
|
364
|
+
for (const subComparison of value) {
|
|
365
|
+
const anyTempContext = {
|
|
579
366
|
errors: [],
|
|
580
|
-
path:
|
|
367
|
+
path: context.path
|
|
581
368
|
};
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
return;
|
|
369
|
+
if (executeComparison(target, subComparison, anyTempContext)) {
|
|
370
|
+
return true;
|
|
585
371
|
}
|
|
586
372
|
}
|
|
587
|
-
addError(
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
373
|
+
addError(context, {
|
|
374
|
+
message: "None of the alternative comparisons matched",
|
|
375
|
+
received: target,
|
|
376
|
+
expected: {
|
|
377
|
+
matchAny: value
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
return false;
|
|
593
381
|
}
|
|
594
|
-
case "all":
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
const subContext = {
|
|
601
|
-
errors: [],
|
|
602
|
-
path: [...context.path]
|
|
603
|
-
};
|
|
604
|
-
executeComparisonWithErrorCollection(target, value, subContext);
|
|
605
|
-
if (subContext.errors.length === 0) {
|
|
606
|
-
addError(
|
|
607
|
-
context,
|
|
608
|
-
`Expected negated condition to fail`,
|
|
609
|
-
target
|
|
610
|
-
);
|
|
382
|
+
case "all": {
|
|
383
|
+
let allMatch = true;
|
|
384
|
+
for (const subComparison of value) {
|
|
385
|
+
if (!executeComparison(target, subComparison, context)) {
|
|
386
|
+
allMatch = false;
|
|
387
|
+
}
|
|
611
388
|
}
|
|
612
|
-
|
|
389
|
+
return allMatch;
|
|
613
390
|
}
|
|
614
391
|
case "withNoExtraKeys":
|
|
392
|
+
return checkNoExtraKeys(target, value, context, false);
|
|
615
393
|
case "withDeepNoExtraKeys":
|
|
394
|
+
return checkNoExtraKeys(target, value, context, true);
|
|
616
395
|
case "noExtraDefinedKeys":
|
|
396
|
+
return checkNoExtraDefinedKeys(target, value, context, false);
|
|
617
397
|
case "deepNoExtraDefinedKeys":
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
target
|
|
622
|
-
);
|
|
623
|
-
break;
|
|
398
|
+
return checkNoExtraDefinedKeys(target, value, context, true);
|
|
399
|
+
default:
|
|
400
|
+
throw exhaustiveCheck(type);
|
|
624
401
|
}
|
|
625
402
|
}
|
|
626
|
-
function
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
403
|
+
function formatPath(path) {
|
|
404
|
+
if (path.length === 0) return "";
|
|
405
|
+
let result = path[0] || "";
|
|
406
|
+
for (let i = 1; i < path.length; i++) {
|
|
407
|
+
const segment = path[i];
|
|
408
|
+
if (segment && segment.startsWith("[") && segment.endsWith("]")) {
|
|
409
|
+
result += segment;
|
|
410
|
+
} else if (segment) {
|
|
411
|
+
if (result) {
|
|
412
|
+
result += `.${segment}`;
|
|
413
|
+
} else {
|
|
414
|
+
result += segment;
|
|
415
|
+
}
|
|
631
416
|
}
|
|
632
|
-
return;
|
|
633
417
|
}
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
418
|
+
return result;
|
|
419
|
+
}
|
|
420
|
+
function addError(context, error) {
|
|
421
|
+
context.errors.push({
|
|
422
|
+
path: formatPath(context.path),
|
|
423
|
+
...error
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
function deepEqual(a, b) {
|
|
427
|
+
if (a === b) return true;
|
|
428
|
+
if (Number.isNaN(a) && Number.isNaN(b)) return true;
|
|
429
|
+
if (a === null || b === null) return false;
|
|
430
|
+
if (typeof a !== typeof b) return false;
|
|
431
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
432
|
+
if (a.length !== b.length) return false;
|
|
433
|
+
for (let i = 0; i < a.length; i++) {
|
|
434
|
+
if (!deepEqual(a[i], b[i])) return false;
|
|
649
435
|
}
|
|
650
|
-
|
|
651
|
-
context,
|
|
652
|
-
`None of the alternative comparisons matched`,
|
|
653
|
-
target,
|
|
654
|
-
"any alternative match"
|
|
655
|
-
);
|
|
656
|
-
return;
|
|
436
|
+
return true;
|
|
657
437
|
}
|
|
658
|
-
if (
|
|
659
|
-
const
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
target,
|
|
665
|
-
value,
|
|
666
|
-
keyExists,
|
|
667
|
-
subContext
|
|
668
|
-
);
|
|
669
|
-
if (subContext.errors.length === 0) {
|
|
670
|
-
addError(
|
|
671
|
-
context,
|
|
672
|
-
`Expected negated condition to fail`,
|
|
673
|
-
target,
|
|
674
|
-
"negated condition"
|
|
675
|
-
);
|
|
438
|
+
if (typeof a === "object") {
|
|
439
|
+
const keysA = Object.keys(a);
|
|
440
|
+
const keysB = Object.keys(b);
|
|
441
|
+
if (keysA.length !== keysB.length) return false;
|
|
442
|
+
for (const key of keysA) {
|
|
443
|
+
if (!has.call(b, key) || !deepEqual(a[key], b[key])) return false;
|
|
676
444
|
}
|
|
677
|
-
return;
|
|
445
|
+
return true;
|
|
678
446
|
}
|
|
679
|
-
|
|
447
|
+
return false;
|
|
680
448
|
}
|
|
681
|
-
function
|
|
682
|
-
if (sub
|
|
683
|
-
|
|
684
|
-
executeComparisonWithErrorCollection(target, sub["~sc"], context);
|
|
685
|
-
return;
|
|
449
|
+
function partialEqualInternal(target, sub, context) {
|
|
450
|
+
if (isComparison(sub)) {
|
|
451
|
+
return executeComparison(target, sub["~sc"], context);
|
|
686
452
|
}
|
|
687
|
-
if (sub &&
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
453
|
+
if (isComparison(sub) && sub["~sc"][0] === "keyNotBePresent") {
|
|
454
|
+
addError(context, {
|
|
455
|
+
message: "This property should not be present",
|
|
456
|
+
received: target
|
|
457
|
+
});
|
|
458
|
+
return false;
|
|
459
|
+
}
|
|
460
|
+
if (target === sub) return true;
|
|
461
|
+
if (Number.isNaN(target) && Number.isNaN(sub)) return true;
|
|
462
|
+
if (target === null || sub === null || target === void 0 || sub === void 0) {
|
|
463
|
+
if (target !== sub) {
|
|
464
|
+
addError(context, {
|
|
465
|
+
message: "Value mismatch",
|
|
466
|
+
received: target,
|
|
467
|
+
expected: sub
|
|
468
|
+
});
|
|
469
|
+
return false;
|
|
694
470
|
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
471
|
+
return true;
|
|
472
|
+
}
|
|
473
|
+
if (target instanceof Date && sub instanceof Date) {
|
|
474
|
+
if (target.getTime() !== sub.getTime()) {
|
|
475
|
+
addError(context, {
|
|
476
|
+
message: "Date mismatch",
|
|
477
|
+
received: target,
|
|
478
|
+
expected: sub
|
|
479
|
+
});
|
|
480
|
+
return false;
|
|
700
481
|
}
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
for (let i = 0; i < sub.length; i++) {
|
|
712
|
-
context.path.push(`[${i}]`);
|
|
713
|
-
partialEqualWithErrorCollection(target[i], sub[i], context);
|
|
714
|
-
context.path.pop();
|
|
715
|
-
}
|
|
716
|
-
return;
|
|
482
|
+
return true;
|
|
483
|
+
}
|
|
484
|
+
if (target instanceof RegExp && sub instanceof RegExp) {
|
|
485
|
+
if (target.source !== sub.source || target.flags !== sub.flags) {
|
|
486
|
+
addError(context, {
|
|
487
|
+
message: "RegExp mismatch",
|
|
488
|
+
received: target,
|
|
489
|
+
expected: sub
|
|
490
|
+
});
|
|
491
|
+
return false;
|
|
717
492
|
}
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
493
|
+
return true;
|
|
494
|
+
}
|
|
495
|
+
if (target instanceof Set && sub instanceof Set) {
|
|
496
|
+
if (sub.size > target.size) {
|
|
497
|
+
addError(context, {
|
|
498
|
+
message: "Set too small",
|
|
499
|
+
received: target,
|
|
500
|
+
expected: sub
|
|
501
|
+
});
|
|
502
|
+
return false;
|
|
503
|
+
}
|
|
504
|
+
for (const subValue of sub) {
|
|
505
|
+
let found = false;
|
|
506
|
+
for (const targetValue of target) {
|
|
507
|
+
const tempContext = {
|
|
508
|
+
errors: [],
|
|
509
|
+
path: context.path
|
|
510
|
+
};
|
|
511
|
+
if (partialEqualInternal(targetValue, subValue, tempContext)) {
|
|
512
|
+
found = true;
|
|
513
|
+
break;
|
|
737
514
|
}
|
|
738
515
|
}
|
|
739
|
-
|
|
516
|
+
if (!found) {
|
|
517
|
+
addError(context, {
|
|
518
|
+
message: "Set element not found",
|
|
519
|
+
received: target,
|
|
520
|
+
expected: sub
|
|
521
|
+
});
|
|
522
|
+
return false;
|
|
523
|
+
}
|
|
740
524
|
}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
525
|
+
return true;
|
|
526
|
+
}
|
|
527
|
+
if (target instanceof Map && sub instanceof Map) {
|
|
528
|
+
if (sub.size > target.size) {
|
|
529
|
+
addError(context, {
|
|
530
|
+
message: "Map has less entries than expected",
|
|
531
|
+
received: `${target.size} entries`,
|
|
532
|
+
expected: `${sub.size} entries`
|
|
533
|
+
});
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
for (const [subKey, subValue] of sub) {
|
|
537
|
+
let found = false;
|
|
538
|
+
for (const [targetKey, targetValue] of target) {
|
|
539
|
+
const tempContextKey = {
|
|
540
|
+
errors: [],
|
|
541
|
+
path: context.path
|
|
542
|
+
};
|
|
543
|
+
const tempContextValue = {
|
|
544
|
+
errors: [],
|
|
545
|
+
path: context.path
|
|
546
|
+
};
|
|
547
|
+
if (partialEqualInternal(targetKey, subKey, tempContextKey) && partialEqualInternal(targetValue, subValue, tempContextValue)) {
|
|
548
|
+
found = true;
|
|
549
|
+
break;
|
|
763
550
|
}
|
|
764
|
-
context.path.push(`[${key}]`);
|
|
765
|
-
partialEqualWithErrorCollection(target.get(targetKey), value, context);
|
|
766
|
-
context.path.pop();
|
|
767
551
|
}
|
|
768
|
-
|
|
552
|
+
if (!found) {
|
|
553
|
+
addError(context, {
|
|
554
|
+
message: "Map entry not found",
|
|
555
|
+
received: target,
|
|
556
|
+
expected: sub
|
|
557
|
+
});
|
|
558
|
+
return false;
|
|
559
|
+
}
|
|
769
560
|
}
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
561
|
+
return true;
|
|
562
|
+
}
|
|
563
|
+
if (typeof target !== typeof sub) {
|
|
564
|
+
addError(context, {
|
|
565
|
+
message: "Value mismatch",
|
|
566
|
+
received: target,
|
|
567
|
+
expected: sub
|
|
568
|
+
});
|
|
569
|
+
return false;
|
|
570
|
+
}
|
|
571
|
+
if (Array.isArray(sub)) {
|
|
572
|
+
if (!Array.isArray(target)) {
|
|
573
|
+
addError(context, {
|
|
574
|
+
message: "Expected array",
|
|
575
|
+
received: target,
|
|
576
|
+
expected: sub
|
|
577
|
+
});
|
|
578
|
+
return false;
|
|
579
|
+
}
|
|
580
|
+
if (target.length < sub.length) {
|
|
581
|
+
addError(context, {
|
|
582
|
+
message: `Array too short: expected at least ${sub.length} elements, got ${target.length}`,
|
|
583
|
+
received: target,
|
|
584
|
+
expected: sub
|
|
585
|
+
});
|
|
586
|
+
return false;
|
|
587
|
+
}
|
|
588
|
+
let allMatch = true;
|
|
589
|
+
for (let i = 0; i < sub.length; i++) {
|
|
590
|
+
const oldPath = context.path;
|
|
591
|
+
context.path = [...oldPath, `[${i}]`];
|
|
592
|
+
const result = partialEqualInternal(target[i], sub[i], context);
|
|
593
|
+
context.path = oldPath;
|
|
594
|
+
if (!result) allMatch = false;
|
|
595
|
+
}
|
|
596
|
+
return allMatch;
|
|
597
|
+
}
|
|
598
|
+
if (typeof sub === "object") {
|
|
599
|
+
if (typeof target !== "object" || Array.isArray(target)) {
|
|
600
|
+
addError(context, {
|
|
601
|
+
message: "Expected object",
|
|
602
|
+
received: target,
|
|
603
|
+
expected: sub
|
|
604
|
+
});
|
|
605
|
+
return false;
|
|
606
|
+
}
|
|
607
|
+
let allMatch = true;
|
|
608
|
+
for (const key of Object.keys(sub)) {
|
|
609
|
+
if (isComparison(sub[key]) && sub[key]["~sc"][0] === "keyNotBePresent") {
|
|
610
|
+
if (has.call(target, key)) {
|
|
611
|
+
const oldPath2 = context.path;
|
|
612
|
+
context.path = [...oldPath2, key];
|
|
613
|
+
addError(context, {
|
|
614
|
+
message: "Key should not be present",
|
|
615
|
+
received: target[key]
|
|
616
|
+
});
|
|
617
|
+
context.path = oldPath2;
|
|
618
|
+
allMatch = false;
|
|
619
|
+
}
|
|
620
|
+
continue;
|
|
621
|
+
}
|
|
622
|
+
if (!has.call(target, key)) {
|
|
623
|
+
if (isComparison(sub[key])) {
|
|
624
|
+
const comparison = sub[key]["~sc"];
|
|
625
|
+
if (comparison[0] === "any") {
|
|
626
|
+
const anyComparisons = comparison[1];
|
|
627
|
+
const hasKeyNotBePresent = anyComparisons.some(
|
|
628
|
+
(comp) => comp[0] === "keyNotBePresent"
|
|
792
629
|
);
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
addError(context, `Missing property`, void 0, subValue);
|
|
796
|
-
} else {
|
|
797
|
-
partialEqualWithErrorCollection(target[key], subValue, context);
|
|
630
|
+
if (hasKeyNotBePresent) {
|
|
631
|
+
continue;
|
|
798
632
|
}
|
|
799
633
|
}
|
|
800
|
-
context.path.pop();
|
|
801
634
|
}
|
|
802
|
-
|
|
803
|
-
|
|
635
|
+
const oldPath2 = context.path;
|
|
636
|
+
context.path = [...oldPath2, key];
|
|
637
|
+
addError(context, {
|
|
638
|
+
message: "Missing property",
|
|
639
|
+
expected: sub[key],
|
|
640
|
+
received: { objectWithKeys: Object.keys(target) }
|
|
641
|
+
});
|
|
642
|
+
context.path = oldPath2;
|
|
643
|
+
allMatch = false;
|
|
644
|
+
continue;
|
|
645
|
+
}
|
|
646
|
+
const oldPath = context.path;
|
|
647
|
+
context.path = [...oldPath, key];
|
|
648
|
+
const result = partialEqualInternal(target[key], sub[key], context);
|
|
649
|
+
context.path = oldPath;
|
|
650
|
+
if (!result) allMatch = false;
|
|
804
651
|
}
|
|
652
|
+
return allMatch;
|
|
805
653
|
}
|
|
806
|
-
if (
|
|
807
|
-
|
|
654
|
+
if (target !== sub) {
|
|
655
|
+
addError(context, {
|
|
656
|
+
message: "Value mismatch",
|
|
657
|
+
received: target,
|
|
658
|
+
expected: sub
|
|
659
|
+
});
|
|
660
|
+
return false;
|
|
808
661
|
}
|
|
809
|
-
|
|
662
|
+
return true;
|
|
810
663
|
}
|
|
811
|
-
function
|
|
812
|
-
if (
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
};
|
|
817
|
-
|
|
818
|
-
if (context.errors.length === 0) {
|
|
819
|
-
return (0, import_t_result.ok)(void 0);
|
|
820
|
-
} else {
|
|
821
|
-
return (0, import_t_result.err)(context.errors);
|
|
822
|
-
}
|
|
664
|
+
function checkNoExtraKeys(target, partialShape, context, deep) {
|
|
665
|
+
if (typeof target !== "object" || target === null || Array.isArray(target)) {
|
|
666
|
+
addError(context, {
|
|
667
|
+
message: "Expected object for key validation",
|
|
668
|
+
received: target
|
|
669
|
+
});
|
|
670
|
+
return false;
|
|
823
671
|
}
|
|
824
|
-
if (
|
|
825
|
-
|
|
826
|
-
return executeComparison(target, sub["~sc"]);
|
|
672
|
+
if (!partialEqualInternal(target, partialShape, context)) {
|
|
673
|
+
return false;
|
|
827
674
|
}
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
if (
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
if (!partialEqual(target[i], sub[i])) return false;
|
|
840
|
-
}
|
|
841
|
-
return true;
|
|
675
|
+
const allowedKeys = new Set(Object.keys(partialShape));
|
|
676
|
+
for (const key of Object.keys(target)) {
|
|
677
|
+
if (!allowedKeys.has(key)) {
|
|
678
|
+
const oldPath = context.path;
|
|
679
|
+
context.path = [...oldPath, key];
|
|
680
|
+
addError(context, {
|
|
681
|
+
message: `Extra key "${key}" should not be present`,
|
|
682
|
+
received: target[key]
|
|
683
|
+
});
|
|
684
|
+
context.path = oldPath;
|
|
685
|
+
return false;
|
|
842
686
|
}
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
687
|
+
}
|
|
688
|
+
if (deep) {
|
|
689
|
+
for (const key of Object.keys(partialShape)) {
|
|
690
|
+
if (typeof partialShape[key] === "object" && partialShape[key] !== null && !Array.isArray(partialShape[key]) && !isComparison(partialShape[key])) {
|
|
691
|
+
const oldPath = context.path;
|
|
692
|
+
context.path = [...oldPath, key];
|
|
693
|
+
const result = checkNoExtraKeys(
|
|
694
|
+
target[key],
|
|
695
|
+
partialShape[key],
|
|
696
|
+
context,
|
|
697
|
+
true
|
|
698
|
+
);
|
|
699
|
+
context.path = oldPath;
|
|
700
|
+
if (!result) return false;
|
|
853
701
|
}
|
|
854
|
-
return true;
|
|
855
702
|
}
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
703
|
+
}
|
|
704
|
+
return true;
|
|
705
|
+
}
|
|
706
|
+
function checkNoExtraDefinedKeys(target, partialShape, context, deep) {
|
|
707
|
+
if (typeof target !== "object" || target === null || Array.isArray(target)) {
|
|
708
|
+
addError(context, {
|
|
709
|
+
message: "Expected object for key validation",
|
|
710
|
+
received: target
|
|
711
|
+
});
|
|
712
|
+
return false;
|
|
713
|
+
}
|
|
714
|
+
if (!partialEqualInternal(target, partialShape, context)) {
|
|
715
|
+
return false;
|
|
716
|
+
}
|
|
717
|
+
const allowedKeys = new Set(Object.keys(partialShape));
|
|
718
|
+
for (const key of Object.keys(target)) {
|
|
719
|
+
if (!allowedKeys.has(key) && target[key] !== void 0) {
|
|
720
|
+
const oldPath = context.path;
|
|
721
|
+
context.path = [...oldPath, key];
|
|
722
|
+
addError(context, {
|
|
723
|
+
message: `Extra defined key "${key}" should not be present`,
|
|
724
|
+
received: target[key]
|
|
725
|
+
});
|
|
726
|
+
context.path = oldPath;
|
|
727
|
+
return false;
|
|
869
728
|
}
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
targetHasKey
|
|
885
|
-
)) {
|
|
886
|
-
return false;
|
|
887
|
-
}
|
|
888
|
-
} else {
|
|
889
|
-
if (!has2.call(target, key) || !partialEqual(target[key], subValue)) {
|
|
890
|
-
return false;
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
}
|
|
729
|
+
}
|
|
730
|
+
if (deep) {
|
|
731
|
+
for (const key of Object.keys(partialShape)) {
|
|
732
|
+
if (typeof partialShape[key] === "object" && partialShape[key] !== null && !Array.isArray(partialShape[key]) && !isComparison(partialShape[key])) {
|
|
733
|
+
const oldPath = context.path;
|
|
734
|
+
context.path = [...oldPath, key];
|
|
735
|
+
const result = checkNoExtraDefinedKeys(
|
|
736
|
+
target[key],
|
|
737
|
+
partialShape[key],
|
|
738
|
+
context,
|
|
739
|
+
true
|
|
740
|
+
);
|
|
741
|
+
context.path = oldPath;
|
|
742
|
+
if (!result) return false;
|
|
894
743
|
}
|
|
895
|
-
return true;
|
|
896
744
|
}
|
|
897
745
|
}
|
|
898
|
-
return
|
|
746
|
+
return true;
|
|
747
|
+
}
|
|
748
|
+
function partialEqual(target, sub, returnErrors) {
|
|
749
|
+
const context = { errors: [], path: [] };
|
|
750
|
+
const result = partialEqualInternal(target, sub, context);
|
|
751
|
+
if (returnErrors) {
|
|
752
|
+
return result ? (0, import_t_result.ok)(void 0) : (0, import_t_result.err)(context.errors);
|
|
753
|
+
}
|
|
754
|
+
return result;
|
|
899
755
|
}
|
|
900
756
|
// Annotate the CommonJS export names for ESM import in node:
|
|
901
757
|
0 && (module.exports = {
|