@ls-stack/utils 3.46.0 → 3.48.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.
@@ -0,0 +1,52 @@
1
+ import {
2
+ isPlainObject
3
+ } from "./chunk-JF2MDHOJ.js";
4
+
5
+ // src/deepReplaceValues.ts
6
+ function applyValueReplacements(value, replaceValues, visited, currentPath) {
7
+ function processValue(val, path) {
8
+ const replacement = replaceValues(val, path);
9
+ if (replacement !== false) {
10
+ return replacement.newValue;
11
+ }
12
+ if (Array.isArray(val)) {
13
+ if (visited.has(val)) {
14
+ throw new Error("Circular reference detected in array");
15
+ }
16
+ visited.add(val);
17
+ try {
18
+ return val.map((item, index) => {
19
+ const itemPath = path ? `${path}[${index}]` : `[${index}]`;
20
+ return processValue(item, itemPath);
21
+ });
22
+ } finally {
23
+ visited.delete(val);
24
+ }
25
+ }
26
+ if (isPlainObject(val)) {
27
+ if (visited.has(val)) {
28
+ throw new Error("Circular reference detected in object");
29
+ }
30
+ visited.add(val);
31
+ try {
32
+ const result = {};
33
+ for (const [key, itemValue] of Object.entries(val)) {
34
+ const itemPath = path ? `${path}.${key}` : key;
35
+ result[key] = processValue(itemValue, itemPath);
36
+ }
37
+ return result;
38
+ } finally {
39
+ visited.delete(val);
40
+ }
41
+ }
42
+ return val;
43
+ }
44
+ return processValue(value, currentPath);
45
+ }
46
+ function deepReplaceValues(value, replaceValues) {
47
+ return applyValueReplacements(value, replaceValues, /* @__PURE__ */ new Set(), "");
48
+ }
49
+
50
+ export {
51
+ deepReplaceValues
52
+ };
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/deepReplaceValues.ts
21
+ var deepReplaceValues_exports = {};
22
+ __export(deepReplaceValues_exports, {
23
+ deepReplaceValues: () => deepReplaceValues
24
+ });
25
+ module.exports = __toCommonJS(deepReplaceValues_exports);
26
+
27
+ // src/typeGuards.ts
28
+ function isPlainObject(value) {
29
+ if (!value || typeof value !== "object") return false;
30
+ const proto = Object.getPrototypeOf(value);
31
+ if (proto === null) {
32
+ return true;
33
+ }
34
+ const Ctor = Object.hasOwnProperty.call(proto, "constructor") && proto.constructor;
35
+ if (Ctor === Object) return true;
36
+ const objectCtorString = Object.prototype.constructor.toString();
37
+ return typeof Ctor == "function" && Function.toString.call(Ctor) === objectCtorString;
38
+ }
39
+
40
+ // src/deepReplaceValues.ts
41
+ function applyValueReplacements(value, replaceValues, visited, currentPath) {
42
+ function processValue(val, path) {
43
+ const replacement = replaceValues(val, path);
44
+ if (replacement !== false) {
45
+ return replacement.newValue;
46
+ }
47
+ if (Array.isArray(val)) {
48
+ if (visited.has(val)) {
49
+ throw new Error("Circular reference detected in array");
50
+ }
51
+ visited.add(val);
52
+ try {
53
+ return val.map((item, index) => {
54
+ const itemPath = path ? `${path}[${index}]` : `[${index}]`;
55
+ return processValue(item, itemPath);
56
+ });
57
+ } finally {
58
+ visited.delete(val);
59
+ }
60
+ }
61
+ if (isPlainObject(val)) {
62
+ if (visited.has(val)) {
63
+ throw new Error("Circular reference detected in object");
64
+ }
65
+ visited.add(val);
66
+ try {
67
+ const result = {};
68
+ for (const [key, itemValue] of Object.entries(val)) {
69
+ const itemPath = path ? `${path}.${key}` : key;
70
+ result[key] = processValue(itemValue, itemPath);
71
+ }
72
+ return result;
73
+ } finally {
74
+ visited.delete(val);
75
+ }
76
+ }
77
+ return val;
78
+ }
79
+ return processValue(value, currentPath);
80
+ }
81
+ function deepReplaceValues(value, replaceValues) {
82
+ return applyValueReplacements(value, replaceValues, /* @__PURE__ */ new Set(), "");
83
+ }
84
+ // Annotate the CommonJS export names for ESM import in node:
85
+ 0 && (module.exports = {
86
+ deepReplaceValues
87
+ });
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Recursively traverses an object or array and allows conditional replacement of values
3
+ * based on a provided callback function. The callback receives each value and its path
4
+ * within the data structure.
5
+ *
6
+ * @param value - The input value to process (object, array, or primitive)
7
+ * @param replaceValues - Callback function that receives each value and its path.
8
+ * Return `false` to keep the original value, or `{ newValue: unknown }` to replace it.
9
+ * The path uses dot notation for objects (e.g., "user.name") and bracket notation for arrays (e.g., "items[0]")
10
+ * @returns A new structure with replaced values. The original structure is not modified.
11
+ * @throws Error if circular references are detected
12
+ *
13
+ * @example
14
+ * const data = { user: { id: 1, name: "Alice" }, scores: [85, 92] };
15
+ * const result = deepReplaceValues(data, (value, path) => {
16
+ * if (typeof value === "number") {
17
+ * return { newValue: value * 2 };
18
+ * }
19
+ * return false;
20
+ * });
21
+ * // Result: { user: { id: 2, name: "Alice" }, scores: [170, 184] }
22
+ */
23
+ declare function deepReplaceValues<T, R = T>(value: T, replaceValues: (value: unknown, path: string) => false | {
24
+ newValue: unknown;
25
+ }): R;
26
+
27
+ export { deepReplaceValues };
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Recursively traverses an object or array and allows conditional replacement of values
3
+ * based on a provided callback function. The callback receives each value and its path
4
+ * within the data structure.
5
+ *
6
+ * @param value - The input value to process (object, array, or primitive)
7
+ * @param replaceValues - Callback function that receives each value and its path.
8
+ * Return `false` to keep the original value, or `{ newValue: unknown }` to replace it.
9
+ * The path uses dot notation for objects (e.g., "user.name") and bracket notation for arrays (e.g., "items[0]")
10
+ * @returns A new structure with replaced values. The original structure is not modified.
11
+ * @throws Error if circular references are detected
12
+ *
13
+ * @example
14
+ * const data = { user: { id: 1, name: "Alice" }, scores: [85, 92] };
15
+ * const result = deepReplaceValues(data, (value, path) => {
16
+ * if (typeof value === "number") {
17
+ * return { newValue: value * 2 };
18
+ * }
19
+ * return false;
20
+ * });
21
+ * // Result: { user: { id: 2, name: "Alice" }, scores: [170, 184] }
22
+ */
23
+ declare function deepReplaceValues<T, R = T>(value: T, replaceValues: (value: unknown, path: string) => false | {
24
+ newValue: unknown;
25
+ }): R;
26
+
27
+ export { deepReplaceValues };
@@ -0,0 +1,7 @@
1
+ import {
2
+ deepReplaceValues
3
+ } from "./chunk-PUKVXYYL.js";
4
+ import "./chunk-JF2MDHOJ.js";
5
+ export {
6
+ deepReplaceValues
7
+ };
@@ -39,12 +39,18 @@ function fastCache({ maxCacheSize = 1e3 } = {}) {
39
39
  }
40
40
  function getOrInsert(cacheKey, val) {
41
41
  if (!cache2.has(cacheKey)) {
42
- cache2.set(cacheKey, val());
42
+ const value = val();
43
+ cache2.set(cacheKey, value);
43
44
  trimCache();
45
+ return cache2.get(cacheKey) ?? value;
44
46
  }
45
47
  return cache2.get(cacheKey);
46
48
  }
47
- return { getOrInsert, clear: () => cache2.clear() };
49
+ return {
50
+ getOrInsert,
51
+ /** Clears all cached values */
52
+ clear: () => cache2.clear()
53
+ };
48
54
  }
49
55
 
50
56
  // src/matchPath.ts
package/dist/matchPath.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  fastCache
3
- } from "./chunk-OIAGLRII.js";
3
+ } from "./chunk-AULH7VMS.js";
4
4
  import "./chunk-5MNYPLZI.js";
5
5
  import "./chunk-HTCYUMDR.js";
6
6
  import "./chunk-II4R3VVX.js";
@@ -24,6 +24,7 @@ __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
29
  // src/deepEqual.ts
29
30
  var has = Object.prototype.hasOwnProperty;
@@ -389,7 +390,437 @@ function executeComparison(target, comparison) {
389
390
  return false;
390
391
  }
391
392
  }
392
- function partialEqual(target, sub) {
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
+ }
403
+ }
404
+ return result;
405
+ }
406
+ function addError(context, message, received, expected) {
407
+ const error = {
408
+ path: formatPath(context.path),
409
+ message,
410
+ received
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
+ );
497
+ }
498
+ break;
499
+ case "numIsGreaterThan":
500
+ if (typeof target !== "number" || target <= value) {
501
+ addError(
502
+ context,
503
+ `Expected number greater than ${value}`,
504
+ target
505
+ );
506
+ }
507
+ break;
508
+ case "numIsGreaterThanOrEqual":
509
+ if (typeof target !== "number" || target < value) {
510
+ addError(
511
+ context,
512
+ `Expected number greater than or equal to ${value}`,
513
+ target
514
+ );
515
+ }
516
+ break;
517
+ case "numIsLessThan":
518
+ if (typeof target !== "number" || target >= value) {
519
+ addError(
520
+ context,
521
+ `Expected number less than ${value}`,
522
+ target
523
+ );
524
+ }
525
+ break;
526
+ case "numIsLessThanOrEqual":
527
+ if (typeof target !== "number" || target > value) {
528
+ addError(
529
+ context,
530
+ `Expected number less than or equal to ${value}`,
531
+ target
532
+ );
533
+ }
534
+ break;
535
+ case "numIsInRange":
536
+ if (typeof target !== "number" || target < value[0] || target > value[1]) {
537
+ addError(
538
+ context,
539
+ `Expected number in range [${value[0]}, ${value[1]}]`,
540
+ target
541
+ );
542
+ }
543
+ break;
544
+ case "jsonStringHasPartial":
545
+ if (typeof target !== "string") {
546
+ addError(context, `Expected JSON string`, target);
547
+ } else {
548
+ try {
549
+ const parsed = JSON.parse(target);
550
+ partialEqualWithErrorCollection(parsed, value, context);
551
+ } catch {
552
+ addError(
553
+ context,
554
+ `Expected valid JSON string`,
555
+ target
556
+ );
557
+ }
558
+ }
559
+ break;
560
+ case "deepEqual":
561
+ if (!deepEqual(target, value)) {
562
+ addError(context, `Expected deep equal`, target, value);
563
+ }
564
+ break;
565
+ case "partialEqual":
566
+ partialEqualWithErrorCollection(target, value, context);
567
+ break;
568
+ case "custom":
569
+ if (!value(target)) {
570
+ addError(context, `Custom validation failed`, target, "valid value");
571
+ }
572
+ break;
573
+ case "keyNotBePresent":
574
+ addError(context, `Key should not be present`, target);
575
+ break;
576
+ case "any": {
577
+ for (const comp of value) {
578
+ const subContext = {
579
+ errors: [],
580
+ path: [...context.path]
581
+ };
582
+ executeComparisonWithErrorCollection(target, comp, subContext);
583
+ if (subContext.errors.length === 0) {
584
+ return;
585
+ }
586
+ }
587
+ addError(
588
+ context,
589
+ `None of the alternative comparisons matched`,
590
+ target
591
+ );
592
+ break;
593
+ }
594
+ case "all":
595
+ for (const comp of value) {
596
+ executeComparisonWithErrorCollection(target, comp, context);
597
+ }
598
+ break;
599
+ case "not": {
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
+ );
611
+ }
612
+ break;
613
+ }
614
+ case "withNoExtraKeys":
615
+ case "withDeepNoExtraKeys":
616
+ case "noExtraDefinedKeys":
617
+ case "deepNoExtraDefinedKeys":
618
+ addError(
619
+ context,
620
+ `Complex validation not supported in error collection mode yet`,
621
+ target
622
+ );
623
+ break;
624
+ }
625
+ }
626
+ function executeComparisonWithKeyContextAndErrorCollection(target, comp, keyExists, context) {
627
+ const [type, value] = comp;
628
+ if (type === "keyNotBePresent") {
629
+ if (keyExists) {
630
+ addError(context, `Key should not be present`, target);
631
+ }
632
+ return;
633
+ }
634
+ if (type === "any") {
635
+ for (const childComp of value) {
636
+ const subContext = {
637
+ errors: [],
638
+ path: [...context.path]
639
+ };
640
+ executeComparisonWithKeyContextAndErrorCollection(
641
+ target,
642
+ childComp,
643
+ keyExists,
644
+ subContext
645
+ );
646
+ if (subContext.errors.length === 0) {
647
+ return;
648
+ }
649
+ }
650
+ addError(
651
+ context,
652
+ `None of the alternative comparisons matched`,
653
+ target,
654
+ "any alternative match"
655
+ );
656
+ return;
657
+ }
658
+ if (type === "not") {
659
+ const subContext = {
660
+ errors: [],
661
+ path: [...context.path]
662
+ };
663
+ executeComparisonWithKeyContextAndErrorCollection(
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
+ );
676
+ }
677
+ return;
678
+ }
679
+ executeComparisonWithErrorCollection(target, comp, context);
680
+ }
681
+ function partialEqualWithErrorCollection(target, sub, context) {
682
+ if (sub === target) return;
683
+ if (sub && typeof sub === "object" && "~sc" in sub) {
684
+ executeComparisonWithErrorCollection(target, sub["~sc"], context);
685
+ return;
686
+ }
687
+ if (sub && target && sub.constructor === target.constructor) {
688
+ const ctor = sub.constructor;
689
+ if (ctor === Date) {
690
+ if (sub.getTime() !== target.getTime()) {
691
+ addError(context, `Date mismatch`, target, sub);
692
+ }
693
+ return;
694
+ }
695
+ if (ctor === RegExp) {
696
+ if (sub.toString() !== target.toString()) {
697
+ addError(context, `RegExp mismatch`, target, sub);
698
+ }
699
+ return;
700
+ }
701
+ if (ctor === Array) {
702
+ if (sub.length > target.length) {
703
+ addError(
704
+ context,
705
+ `Array too short: expected at least ${sub.length} elements, got ${target.length}`,
706
+ target,
707
+ sub
708
+ );
709
+ return;
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;
717
+ }
718
+ if (ctor === Set) {
719
+ if (sub.size > target.size) {
720
+ addError(
721
+ context,
722
+ `Set too small: expected at least ${sub.size} elements, got ${target.size}`,
723
+ target,
724
+ sub
725
+ );
726
+ return;
727
+ }
728
+ for (const value of sub) {
729
+ let found = false;
730
+ if (value && typeof value === "object") {
731
+ found = !!find2(target, value);
732
+ } else {
733
+ found = target.has(value);
734
+ }
735
+ if (!found) {
736
+ addError(context, `Set missing value`, target, value);
737
+ }
738
+ }
739
+ return;
740
+ }
741
+ if (ctor === Map) {
742
+ if (sub.size > target.size) {
743
+ addError(
744
+ context,
745
+ `Map too small: expected at least ${sub.size} entries, got ${target.size}`,
746
+ target,
747
+ sub
748
+ );
749
+ return;
750
+ }
751
+ for (const [key, value] of sub) {
752
+ let targetKey = key;
753
+ if (key && typeof key === "object") {
754
+ targetKey = find2(target, key);
755
+ if (!targetKey) {
756
+ addError(context, `Map missing key`, target, key);
757
+ continue;
758
+ }
759
+ }
760
+ if (!target.has(targetKey)) {
761
+ addError(context, `Map missing key`, target, key);
762
+ continue;
763
+ }
764
+ context.path.push(`[${key}]`);
765
+ partialEqualWithErrorCollection(target.get(targetKey), value, context);
766
+ context.path.pop();
767
+ }
768
+ return;
769
+ }
770
+ if (!ctor || typeof sub === "object") {
771
+ for (const key in sub) {
772
+ if (has2.call(sub, key)) {
773
+ const subValue = sub[key];
774
+ context.path.push(key);
775
+ if (subValue && typeof subValue === "object" && "~sc" in subValue && subValue["~sc"][0] === "keyNotBePresent") {
776
+ if (has2.call(target, key)) {
777
+ addError(
778
+ context,
779
+ `Key should not be present`,
780
+ target[key],
781
+ "key not present"
782
+ );
783
+ }
784
+ } else if (subValue && typeof subValue === "object" && "~sc" in subValue && subValue["~sc"][0] === "any") {
785
+ const targetHasKey = has2.call(target, key);
786
+ const targetValue = targetHasKey ? target[key] : void 0;
787
+ executeComparisonWithKeyContextAndErrorCollection(
788
+ targetValue,
789
+ subValue["~sc"],
790
+ targetHasKey,
791
+ context
792
+ );
793
+ } else {
794
+ if (!has2.call(target, key)) {
795
+ addError(context, `Missing property`, void 0, subValue);
796
+ } else {
797
+ partialEqualWithErrorCollection(target[key], subValue, context);
798
+ }
799
+ }
800
+ context.path.pop();
801
+ }
802
+ }
803
+ return;
804
+ }
805
+ }
806
+ if (sub !== sub && target !== target) {
807
+ return;
808
+ }
809
+ addError(context, `Value mismatch`, target, sub);
810
+ }
811
+ function partialEqual(target, sub, returnErrors) {
812
+ if (returnErrors === true) {
813
+ const context = {
814
+ errors: [],
815
+ path: []
816
+ };
817
+ partialEqualWithErrorCollection(target, sub, context);
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
+ }
823
+ }
393
824
  if (sub === target) return true;
394
825
  if (sub && typeof sub === "object" && "~sc" in sub) {
395
826
  return executeComparison(target, sub["~sc"]);
@@ -1,3 +1,5 @@
1
+ import { Result } from 't-result';
2
+
1
3
  type ComparisonsType = [type: 'strStartsWith', value: string] | [type: 'strEndsWith', value: string] | [
2
4
  type: 'hasType',
3
5
  value: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'function'
@@ -46,6 +48,13 @@ type Match = BaseMatch & {
46
48
  not: BaseMatch;
47
49
  };
48
50
  declare const match: Match;
51
+ type PartialError = {
52
+ path: string;
53
+ message: string;
54
+ received: any;
55
+ expected?: any;
56
+ };
57
+ declare function partialEqual(target: any, sub: any, returnErrors: true): Result<void, PartialError[]>;
49
58
  declare function partialEqual(target: any, sub: any): boolean;
50
59
 
51
60
  export { match, partialEqual };