@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.
@@ -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/deepEqual.ts
29
- var has = Object.prototype.hasOwnProperty;
30
- function find(iter, tar, maxDepth) {
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 has2 = Object.prototype.hasOwnProperty;
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: (...comparisons) => createComparison(["any", comparisons.map((c) => c["~sc"])]),
132
- all: (...comparisons) => createComparison(["all", comparisons.map((c) => c["~sc"])]),
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: (...comparisons) => createComparison(["not", ["any", comparisons.map((c) => c["~sc"])]]),
164
- all: (...comparisons) => createComparison(["not", ["all", comparisons.map((c) => c["~sc"])]]),
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 find2(iter, tar) {
172
- for (const key of iter.keys()) {
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 executeComparisonWithKeyContext(target, comp, keyExists) {
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
- return typeof target === "string" && target.startsWith(value);
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
- return typeof target === "string" && target.endsWith(value);
220
- case "strContains":
221
- return typeof target === "string" && target.includes(value);
222
- case "strMatchesRegex":
223
- return typeof target === "string" && value.test(target);
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
- case "deepEqual":
243
- return deepEqual(target, value);
244
- case "partialEqual":
245
- return partialEqual(target, value);
246
- case "custom":
247
- return value(target);
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 false;
257
- case "all":
258
- for (const comp of value) {
259
- if (!executeComparison(target, comp)) {
260
- return false;
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 "not":
265
- return !executeComparison(target, value);
266
- case "withNoExtraKeys":
267
- if (typeof target !== "object" || target === null || Array.isArray(target)) {
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 (typeof value !== "object" || value === null || Array.isArray(value)) {
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
- for (const key in target) {
274
- if (has2.call(target, key) && !has2.call(value, key)) {
275
- return false;
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
- for (const key in value) {
279
- if (has2.call(value, key)) {
280
- if (!has2.call(target, key)) {
281
- return false;
282
- }
283
- if (!partialEqual(target[key], value[key])) {
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
- case "withDeepNoExtraKeys":
290
- if (typeof target !== "object" || target === null || Array.isArray(target)) {
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
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
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
- for (const key in target) {
297
- if (has2.call(target, key) && !has2.call(value, key)) {
298
- return false;
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
- for (const key in value) {
302
- if (has2.call(value, key)) {
303
- if (!has2.call(target, key)) {
304
- return false;
305
- }
306
- const targetValue = target[key];
307
- const partialValue = value[key];
308
- if (partialValue && typeof partialValue === "object" && "~sc" in partialValue && partialValue["~sc"][0] === "withDeepNoExtraKeys") {
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 "noExtraDefinedKeys":
328
- if (typeof target !== "object" || target === null || Array.isArray(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
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
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
- for (const key in target) {
335
- if (has2.call(target, key) && target[key] !== void 0 && !has2.call(value, key)) {
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
- for (const key in value) {
340
- if (has2.call(value, key)) {
341
- if (!has2.call(target, key)) {
342
- return false;
343
- }
344
- if (!partialEqual(target[key], value[key])) {
345
- return false;
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
- case "deepNoExtraDefinedKeys":
351
- if (typeof target !== "object" || target === null || Array.isArray(target)) {
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
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
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
- for (const key in target) {
358
- if (has2.call(target, key) && target[key] !== void 0 && !has2.call(value, key)) {
359
- return false;
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
- for (const key in value) {
363
- if (has2.call(value, key)) {
364
- if (!has2.call(target, key)) {
365
- return false;
366
- }
367
- const targetValue = target[key];
368
- const partialValue = value[key];
369
- if (partialValue && typeof partialValue === "object" && "~sc" in partialValue && partialValue["~sc"][0] === "deepNoExtraDefinedKeys") {
370
- if (!executeComparison(targetValue, partialValue["~sc"])) {
371
- return false;
372
- }
373
- } else if (partialValue && typeof partialValue === "object" && !Array.isArray(partialValue) && partialValue.constructor === Object && targetValue && typeof targetValue === "object" && !Array.isArray(targetValue) && targetValue.constructor === Object) {
374
- if (!executeComparison(targetValue, [
375
- "deepNoExtraDefinedKeys",
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 true;
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
- return false;
400
+ throw exhaustiveCheck(type);
390
401
  }
391
402
  }
392
- function partialEqual(target, sub) {
393
- if (sub === target) return true;
394
- if (sub && typeof sub === "object" && "~sc" in sub) {
395
- return executeComparison(target, sub["~sc"]);
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
- if (sub && target && sub.constructor === target.constructor) {
398
- const ctor = sub.constructor;
399
- if (ctor === Date) {
400
- return sub.getTime() === target.getTime();
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
- if (ctor === RegExp) {
403
- return sub.toString() === target.toString();
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
- if (ctor === Array) {
406
- if (sub.length > target.length) return false;
407
- for (let i = 0; i < sub.length; i++) {
408
- if (!partialEqual(target[i], sub[i])) return false;
409
- }
410
- return true;
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
- if (ctor === Set) {
413
- if (sub.size > target.size) return false;
414
- for (const value of sub) {
415
- let found = false;
416
- if (value && typeof value === "object") {
417
- found = !!find2(target, value);
418
- } else {
419
- found = target.has(value);
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
- return true;
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
- if (ctor === Map) {
426
- if (sub.size > target.size) return false;
427
- for (const [key, value] of sub) {
428
- let targetKey = key;
429
- if (key && typeof key === "object") {
430
- targetKey = find2(target, key);
431
- if (!targetKey) return false;
432
- }
433
- if (!target.has(targetKey) || !partialEqual(target.get(targetKey), value)) {
434
- return false;
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
- return true;
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
- if (!ctor || typeof sub === "object") {
440
- for (const key in sub) {
441
- if (has2.call(sub, key)) {
442
- const subValue = sub[key];
443
- if (subValue && typeof subValue === "object" && "~sc" in subValue && subValue["~sc"][0] === "keyNotBePresent") {
444
- if (has2.call(target, key)) {
445
- return false;
446
- }
447
- } else if (subValue && typeof subValue === "object" && "~sc" in subValue && subValue["~sc"][0] === "any") {
448
- const targetHasKey = has2.call(target, key);
449
- const targetValue = targetHasKey ? target[key] : void 0;
450
- if (!executeComparisonWithKeyContext(
451
- targetValue,
452
- subValue["~sc"],
453
- targetHasKey
454
- )) {
455
- return false;
456
- }
457
- } else {
458
- if (!has2.call(target, key) || !partialEqual(target[key], subValue)) {
459
- return false;
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
- return true;
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 sub !== sub && target !== target;
754
+ return result;
468
755
  }
469
756
  // Annotate the CommonJS export names for ESM import in node:
470
757
  0 && (module.exports = {