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