@creejs/commons-lang 2.1.18 → 2.1.20

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.
@@ -10,7 +10,9 @@ var LangUtils = {
10
10
  extends: extend,
11
11
  equals: equals$2,
12
12
  isBrowser,
13
- isNode
13
+ isNode,
14
+ cloneToPlainObject,
15
+ deepCloneToPlainObject
14
16
  };
15
17
 
16
18
  /**
@@ -68,6 +70,41 @@ function extend (target, ...sources) {
68
70
  return target
69
71
  }
70
72
 
73
+ /**
74
+ * Creates a shallow clone of an object by copying its enumerable properties to a new plain object.
75
+ * 1. This returns a PlainObject
76
+ * 2. It lose the type information of the original object
77
+ * 3. Shallow clone, copy only the first level properties
78
+ * @param {{[key:string]: any}} obj - The object to clone.
79
+ * @returns {{[key:string]: any}} A new plain object with the same enumerable properties as the input object.
80
+ */
81
+ function cloneToPlainObject (obj) {
82
+ if (obj == null) {
83
+ return obj
84
+ }
85
+ if (typeof obj !== 'object') {
86
+ throw new Error('Only Object allowed to clone')
87
+ }
88
+ return { ...obj }
89
+ }
90
+
91
+ /**
92
+ * Deep clones an object by converting it to JSON and back to a plain object.
93
+ * 1. This will lose any non-JSON-serializable properties (e.g. functions, Symbols).
94
+ * 2. Only Use this to clone PlainObject
95
+ * @param {{[key:string]: any}} obj - The object to clone
96
+ * @returns {{[key:string]: any}} A new plain object with the cloned properties
97
+ */
98
+ function deepCloneToPlainObject (obj) {
99
+ if (obj == null) {
100
+ return obj
101
+ }
102
+ if (typeof obj !== 'object') {
103
+ throw new Error('Only Object allowed to clone')
104
+ }
105
+ return JSON.parse(JSON.stringify(obj))
106
+ }
107
+
71
108
  /**
72
109
  * Compares two values for equality
73
110
  * 1. First checks strict equality (===),
@@ -575,7 +612,7 @@ var TypeAssert = {
575
612
  */
576
613
  function assertArray (value, paramName) {
577
614
  if (!Array.isArray(value)) {
578
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Array: type=${typeof value} value=${JSON.stringify(value)}`)
615
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Array: type=${typeof value} value=${safeToString(value)}`)
579
616
  }
580
617
  }
581
618
  /**
@@ -587,7 +624,7 @@ function assertArray (value, paramName) {
587
624
  */
588
625
  function assertString (value, paramName) {
589
626
  if (!isString(value)) {
590
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not String: type=${typeof value} value=${JSON.stringify(value)}`)
627
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not String: type=${typeof value} value=${safeToString(value)}`)
591
628
  }
592
629
  }
593
630
  /**
@@ -599,7 +636,7 @@ function assertString (value, paramName) {
599
636
  */
600
637
  function assertNumber (value, paramName) {
601
638
  if (!isNumber(value)) {
602
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Number: type=${typeof value} value=${JSON.stringify(value)}`)
639
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Number: type=${typeof value} value=${safeToString(value)}`)
603
640
  }
604
641
  }
605
642
 
@@ -611,7 +648,7 @@ function assertNumber (value, paramName) {
611
648
  */
612
649
  function assertPositive (value, paramName) {
613
650
  if (!isPositive(value)) {
614
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Positive: ${value}`)
651
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Positive: ${value}`)
615
652
  }
616
653
  }
617
654
 
@@ -623,7 +660,7 @@ function assertPositive (value, paramName) {
623
660
  */
624
661
  function assertNegative (value, paramName) {
625
662
  if (!isNegative(value)) {
626
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Negative: ${value}`)
663
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Negative: ${value}`)
627
664
  }
628
665
  }
629
666
 
@@ -635,7 +672,7 @@ function assertNegative (value, paramName) {
635
672
  */
636
673
  function assertNotNegative (value, paramName) {
637
674
  if (!isNotNegative(value)) {
638
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not "0 or Positive": ${value}`)
675
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not "0 or Positive": ${value}`)
639
676
  }
640
677
  }
641
678
 
@@ -648,7 +685,7 @@ function assertNotNegative (value, paramName) {
648
685
  */
649
686
  function assertBoolean (value, paramName) {
650
687
  if (!isBoolean(value)) {
651
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Boolean: type=${typeof value} value=${JSON.stringify(value)}`)
688
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Boolean: type=${typeof value} value=${safeToString(value)}`)
652
689
  }
653
690
  }
654
691
  /**
@@ -660,7 +697,7 @@ function assertBoolean (value, paramName) {
660
697
  */
661
698
  function assertObject (value, paramName) {
662
699
  if (!isObject(value)) {
663
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Object: type=${typeof value} value=${JSON.stringify(value)}`)
700
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Object: type=${typeof value} value=${safeToString(value)}`)
664
701
  }
665
702
  }
666
703
  /**
@@ -672,7 +709,7 @@ function assertObject (value, paramName) {
672
709
  */
673
710
  function assertPlainObject (value, paramName) {
674
711
  if (!isPlainObject$1(value)) {
675
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not PlainObject: type=${typeof value} value=${JSON.stringify(value)}`)
712
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not PlainObject: type=${typeof value} value=${safeToString(value)}`)
676
713
  }
677
714
  }
678
715
  /**
@@ -684,7 +721,7 @@ function assertPlainObject (value, paramName) {
684
721
  */
685
722
  function assertSymbol (value, paramName) {
686
723
  if (!isSymbol(value)) {
687
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Symbol: type=${typeof value} value=${JSON.stringify(value)}`)
724
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Symbol: type=${typeof value} value=${safeToString(value)}`)
688
725
  }
689
726
  }
690
727
  /**
@@ -696,7 +733,7 @@ function assertSymbol (value, paramName) {
696
733
  */
697
734
  function assertFunction (value, paramName) {
698
735
  if (!isFunction(value)) {
699
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Function: type=${typeof value} value=${JSON.stringify(value)}`)
736
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Function: type=${typeof value} value=${safeToString(value)}`)
700
737
  }
701
738
  }
702
739
  /**
@@ -708,7 +745,7 @@ function assertFunction (value, paramName) {
708
745
  */
709
746
  function assertInstance (value, paramName) {
710
747
  if (!isInstance(value)) {
711
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Class Instance: type=${typeof value} value=${JSON.stringify(value)}`)
748
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Class Instance: type=${typeof value} value=${safeToString(value)}`)
712
749
  }
713
750
  }
714
751
  /**
@@ -720,7 +757,7 @@ function assertInstance (value, paramName) {
720
757
  */
721
758
  function assertPromise (value, paramName) {
722
759
  if (!isPromise(value)) {
723
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Promise: type=${typeof value} value=${JSON.stringify(value)}`)
760
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Promise: type=${typeof value} value=${safeToString(value)}`)
724
761
  }
725
762
  }
726
763
  /**
@@ -732,7 +769,7 @@ function assertPromise (value, paramName) {
732
769
  */
733
770
  function assertNil (value, paramName) {
734
771
  if (!isNil(value)) {
735
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Neither Null nor Undefined: type=${typeof value} value=${JSON.stringify(value)}`)
772
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Neither Null nor Undefined: type=${typeof value} value=${safeToString(value)}`)
736
773
  }
737
774
  }
738
775
 
@@ -744,7 +781,7 @@ function assertNil (value, paramName) {
744
781
  */
745
782
  function assertNotNil (value, paramName) {
746
783
  if (isNil(value)) {
747
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Should Not Nil`)
784
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Should Not Nil`)
748
785
  }
749
786
  }
750
787
 
@@ -757,7 +794,7 @@ function assertNotNil (value, paramName) {
757
794
  */
758
795
  function assertNull (value, paramName) {
759
796
  if (!isNull(value)) {
760
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Null: type=${typeof value} value=${JSON.stringify(value)}`)
797
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Null: type=${typeof value} value=${safeToString(value)}`)
761
798
  }
762
799
  }
763
800
 
@@ -769,7 +806,7 @@ function assertNull (value, paramName) {
769
806
  */
770
807
  function assertNotNull (value, paramName) {
771
808
  if (isNull(value)) {
772
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Should Not Null`)
809
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Should Not Null`)
773
810
  }
774
811
  }
775
812
  /**
@@ -781,7 +818,7 @@ function assertNotNull (value, paramName) {
781
818
  */
782
819
  function assertUndefined (value, paramName) {
783
820
  if (!isUndefined(value)) {
784
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Undefined: type=${typeof value} value=${JSON.stringify(value)}`)
821
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Undefined: type=${typeof value} value=${safeToString(value)}`)
785
822
  }
786
823
  }
787
824
 
@@ -793,7 +830,7 @@ function assertUndefined (value, paramName) {
793
830
  */
794
831
  function assertStringOrSymbol (value, paramName) {
795
832
  if (!isString(value) && !isSymbol(value)) {
796
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not String or Symbol: type=${typeof value} value=${JSON.stringify(value)}`)
833
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not String or Symbol: type=${typeof value} value=${safeToString(value)}`)
797
834
  }
798
835
  }
799
836
 
@@ -804,7 +841,7 @@ function assertStringOrSymbol (value, paramName) {
804
841
  */
805
842
  function assertTypedArray (value, paramName) {
806
843
  if (isTypedArray(value)) {
807
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not TypedArray`)
844
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not TypedArray`)
808
845
  }
809
846
  }
810
847
  /**
@@ -814,7 +851,7 @@ function assertTypedArray (value, paramName) {
814
851
  */
815
852
  function assertInt8Array (value, paramName) {
816
853
  if (isInt8Array(value)) {
817
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Int8Array`)
854
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Int8Array`)
818
855
  }
819
856
  }
820
857
  /**
@@ -824,7 +861,7 @@ function assertInt8Array (value, paramName) {
824
861
  */
825
862
  function assertUint8Array (value, paramName) {
826
863
  if (isUint8Array(value)) {
827
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Uint8Array`)
864
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Uint8Array`)
828
865
  }
829
866
  }
830
867
  /**
@@ -834,7 +871,7 @@ function assertUint8Array (value, paramName) {
834
871
  */
835
872
  function assertUint8ClampedArray (value, paramName) {
836
873
  if (isUint8ClampedArray(value)) {
837
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Uint8ClampedArray`)
874
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Uint8ClampedArray`)
838
875
  }
839
876
  }
840
877
  /**
@@ -844,7 +881,7 @@ function assertUint8ClampedArray (value, paramName) {
844
881
  */
845
882
  function assertInt16Array (value, paramName) {
846
883
  if (isInt16Array(value)) {
847
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Int16Array`)
884
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Int16Array`)
848
885
  }
849
886
  }
850
887
  /**
@@ -854,7 +891,7 @@ function assertInt16Array (value, paramName) {
854
891
  */
855
892
  function assertUint16Array (value, paramName) {
856
893
  if (isUint16Array(value)) {
857
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Uint16Array`)
894
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Uint16Array`)
858
895
  }
859
896
  }
860
897
  /**
@@ -864,7 +901,7 @@ function assertUint16Array (value, paramName) {
864
901
  */
865
902
  function assertInt32Array (value, paramName) {
866
903
  if (isInt32Array(value)) {
867
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Int32Array`)
904
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Int32Array`)
868
905
  }
869
906
  }
870
907
  /**
@@ -874,7 +911,7 @@ function assertInt32Array (value, paramName) {
874
911
  */
875
912
  function assertUint32Array (value, paramName) {
876
913
  if (isUint32Array(value)) {
877
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Uint32Array`)
914
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Uint32Array`)
878
915
  }
879
916
  }
880
917
  /**
@@ -884,7 +921,7 @@ function assertUint32Array (value, paramName) {
884
921
  */
885
922
  function assertFloat32Array (value, paramName) {
886
923
  if (isFloat32Array(value)) {
887
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Float32Array`)
924
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Float32Array`)
888
925
  }
889
926
  }
890
927
  /**
@@ -894,7 +931,7 @@ function assertFloat32Array (value, paramName) {
894
931
  */
895
932
  function assertFloat64Array (value, paramName) {
896
933
  if (isFloat64Array(value)) {
897
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Float64Array`)
934
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Float64Array`)
898
935
  }
899
936
  }
900
937
  /**
@@ -904,7 +941,7 @@ function assertFloat64Array (value, paramName) {
904
941
  */
905
942
  function assertBigInt64Array (value, paramName) {
906
943
  if (isBigInt64Array(value)) {
907
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not BigInt64Array`)
944
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not BigInt64Array`)
908
945
  }
909
946
  }
910
947
  /**
@@ -914,7 +951,7 @@ function assertBigInt64Array (value, paramName) {
914
951
  */
915
952
  function assertBigUint64Array (value, paramName) {
916
953
  if (isBigUint64Array(value)) {
917
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not BigUint64Array`)
954
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not BigUint64Array`)
918
955
  }
919
956
  }
920
957
 
@@ -926,7 +963,7 @@ function assertBigUint64Array (value, paramName) {
926
963
  */
927
964
  function assertArrayBuffer (value, paramName) {
928
965
  if (!isArrayBuffer(value)) {
929
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not ArrayBuffer`)
966
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not ArrayBuffer`)
930
967
  }
931
968
  }
932
969
 
@@ -955,7 +992,8 @@ var StringUtils = {
955
992
  substringAfterLast,
956
993
  substringBetween,
957
994
  substringBetweenGreedy,
958
- substringsBetween
995
+ substringsBetween,
996
+ safeToString
959
997
  };
960
998
 
961
999
  /**
@@ -1352,6 +1390,22 @@ function substringsBetween (str, startMarker, endMarker) {
1352
1390
  return substrings
1353
1391
  }
1354
1392
 
1393
+ /**
1394
+ * Safely converts a value to its string representation.
1395
+ * Attempts to use JSON.stringify first, falls back to toString() if stringify fails.
1396
+ * @param {*} value - The value to convert to string
1397
+ * @returns {string} The string representation of the value
1398
+ */
1399
+ function safeToString (value) {
1400
+ let valueStr;
1401
+ try {
1402
+ valueStr = JSON.stringify(value);
1403
+ } catch (e) {
1404
+ valueStr = value.toString();
1405
+ }
1406
+ return valueStr
1407
+ }
1408
+
1355
1409
  /**
1356
1410
  * @module ExecUtils
1357
1411
  * @description Utils about how to execute task functions.
@@ -1429,6 +1483,7 @@ var ExecUtils = {
1429
1483
  * promise: Promise<*>,
1430
1484
  * timerHandler: NodeJS.Timeout,
1431
1485
  * timerCleared: boolean,
1486
+ * pending: boolean,
1432
1487
  * resolved: boolean,
1433
1488
  * rejected: boolean,
1434
1489
  * canceled: boolean,
@@ -1441,7 +1496,8 @@ var ExecUtils = {
1441
1496
  * @typedef {{
1442
1497
  * promise: Promise<*>,
1443
1498
  * timerHandler: NodeJS.Timeout,
1444
- * resolve: (...args:any[])=> void
1499
+ * _resolve: (...args:any[])=> void,
1500
+ * wakeup: ()=> void
1445
1501
  * }} Waiter
1446
1502
  */
1447
1503
 
@@ -1450,6 +1506,7 @@ var ExecUtils = {
1450
1506
  * @description Promise utility functions for enhanced promise handling, including timeout, delay, parallel execution, and series execution.
1451
1507
  */
1452
1508
  var PromiseUtils = {
1509
+ any,
1453
1510
  defer,
1454
1511
  delay,
1455
1512
  timeout,
@@ -1458,6 +1515,7 @@ var PromiseUtils = {
1458
1515
  series,
1459
1516
  seriesAllSettled,
1460
1517
  parallel,
1518
+ parallelAny,
1461
1519
  parallelAllSettled,
1462
1520
  wait
1463
1521
  };
@@ -1473,48 +1531,66 @@ function defer (timeout = -1, timeoutMessage) {
1473
1531
  assertNumber(timeout);
1474
1532
  /** @type {Deferred} */
1475
1533
  const rtnVal = {};
1476
-
1534
+ rtnVal.pending = true;
1535
+ rtnVal.canceled = false;
1536
+ rtnVal.rejected = false;
1537
+ rtnVal.resolved = false;
1477
1538
  /**
1478
1539
  * @type {NodeJS.Timeout}
1479
1540
  */
1480
1541
  let timerHandler;
1481
1542
  if (timeout >= 0) {
1543
+ rtnVal.timerCleared = false;
1482
1544
  rtnVal.timerHandler = timerHandler = setTimeout(() => {
1483
1545
  clearTimeout(timerHandler); // must clear it
1484
- rtnVal.timerCleared = true; // easy to check in test case
1546
+ rtnVal.timerCleared = true;
1485
1547
  rtnVal.reject(new Error(timeoutMessage ?? `Promise Timeout: ${timeout}ms`));
1486
1548
  }, timeout);
1487
1549
  }
1488
1550
 
1489
1551
  rtnVal.promise = new Promise((resolve, reject) => {
1490
1552
  rtnVal.resolve = (arg) => {
1553
+ if (rtnVal.resolved || rtnVal.rejected || rtnVal.canceled) {
1554
+ return // already done, Can Not operate again
1555
+ }
1491
1556
  if (timerHandler != null) {
1492
1557
  clearTimeout(timerHandler); // must clear it
1493
- rtnVal.timerCleared = true; // easy to check in test case
1558
+ rtnVal.timerCleared = true;
1494
1559
  }
1560
+ rtnVal.pending = false;
1561
+ rtnVal.canceled = false;
1562
+ rtnVal.rejected = false;
1495
1563
  rtnVal.resolved = true;
1496
1564
  resolve(arg);
1497
1565
  };
1498
1566
 
1499
1567
  rtnVal.reject = (err) => {
1568
+ if (rtnVal.resolved || rtnVal.rejected || rtnVal.canceled) {
1569
+ return // already done, Can Not operate again
1570
+ }
1500
1571
  if (timerHandler != null) {
1501
1572
  clearTimeout(timerHandler); // must clear it
1502
- rtnVal.timerCleared = true; // easy to check in test case
1573
+ rtnVal.timerCleared = true;
1503
1574
  }
1575
+ rtnVal.pending = false;
1576
+ rtnVal.canceled = false;
1577
+ rtnVal.resolved = false;
1504
1578
  rtnVal.rejected = true;
1505
1579
  reject(err);
1506
1580
  };
1507
1581
  });
1508
1582
  // @ts-ignore
1509
- rtnVal.promise.cancel = () => {
1583
+ rtnVal.cancel = rtnVal.promise.cancel = (reason) => {
1584
+ if (rtnVal.resolved || rtnVal.rejected || rtnVal.canceled) {
1585
+ return // already done, Can Not operate again
1586
+ }
1510
1587
  if (timerHandler != null) {
1511
1588
  clearTimeout(timerHandler); // must clear it
1512
- rtnVal.timerCleared = true; // easy to check in test case
1589
+ rtnVal.timerCleared = true;
1513
1590
  }
1514
- rtnVal.rejected = true; // easy to check in test case
1591
+ rtnVal.reject(reason ?? new Error('Cancelled'));
1515
1592
  // @ts-ignore
1516
- rtnVal.canceled = rtnVal.promise.canceled = true; // easy to check in test case
1517
- rtnVal.reject(new Error('Cancelled'));
1593
+ rtnVal.canceled = rtnVal.promise.canceled = true;
1518
1594
  };
1519
1595
  return rtnVal
1520
1596
  }
@@ -1585,7 +1661,7 @@ async function allSettled (promises) {
1585
1661
  function returnValuePromised (task) {
1586
1662
  try {
1587
1663
  const taskRtnVal = task();
1588
- if (isPromise(taskRtnVal)) {
1664
+ if (TypeUtils.isPromise(taskRtnVal)) {
1589
1665
  return taskRtnVal
1590
1666
  }
1591
1667
  return Promise.resolve(taskRtnVal)
@@ -1606,7 +1682,7 @@ function returnValuePromised (task) {
1606
1682
  * @returns {Promise<*>} A new promise that settles after the delay period
1607
1683
  */
1608
1684
  function delay (promise, ms) {
1609
- if (isNumber(promise)) { // defer(ms)
1685
+ if (TypeUtils.isNumber(promise)) { // defer(ms)
1610
1686
  // @ts-ignore
1611
1687
  ms = promise;
1612
1688
  promise = Promise.resolve();
@@ -1638,21 +1714,78 @@ function delay (promise, ms) {
1638
1714
  });
1639
1715
  return deferred.promise
1640
1716
  }
1717
+ /**
1718
+ * 1. run all tasks
1719
+ * 2. any Task succeed, return its result
1720
+ * * resolve with the result.
1721
+ * * the others tasks will run to its end, and results will be dropped.
1722
+ * 3. If all tasks fail, rejects with an array of errors. the array length is same as the input tasks
1723
+ * @param {Array<Promise<any>|Function>} tasks - Array of promises or async functions to execute
1724
+ * @returns {Promise<any>} A promise that resolves with the result of the first successful task
1725
+ */
1726
+ function any (tasks) {
1727
+ assertArray(tasks);
1728
+ if (tasks.length === 0) {
1729
+ throw new Error('Empty Tasks')
1730
+ }
1731
+ const deferred = defer();
1732
+ /** @type {any[]} */
1733
+ const errors = [];
1734
+ for (let i = 0; i < tasks.length; i++) {
1735
+ const task = tasks[i];
1736
+ /** @type {Promise<any>} */
1737
+ let taskPromise;
1738
+ if (TypeUtils.isPromise(task)) {
1739
+ // @ts-ignore
1740
+ taskPromise = task;
1741
+ } else if (TypeUtils.isFunction(task)) {
1742
+ // @ts-ignore
1743
+ taskPromise = returnValuePromised(task);
1744
+ } else {
1745
+ errors.push(new Error(`Invalid Task at index ${i}/${tasks.length - 1}: ${task}`));
1746
+ continue
1747
+ }
1748
+ taskPromise.then(/** @type {any} */ rtnVal => {
1749
+ deferred.resolve(rtnVal);
1750
+ }).catch(e => {
1751
+ errors.push(e);
1752
+ // all tasks failed
1753
+ if (errors.length >= tasks.length) {
1754
+ deferred.reject(errors);
1755
+ }
1756
+ });
1757
+ }
1758
+ if (errors.length === tasks.length) {
1759
+ deferred.reject(errors);
1760
+ }
1761
+ return deferred.promise
1762
+ }
1641
1763
 
1642
1764
  /**
1643
- * Fast-Fail mode to execute Tasks(functions) in series (one after another) and returns their results in order.
1644
- * 1. export function are executed one by one
1645
- * 2. Fast Fail: if any tasks fail, the whole chain is rejected with the first error
1646
- * 3. if an element is not function, rejects the whole chain with Error(Not Function)
1647
- * @param {Function[]} tasks
1648
- * @returns {Promise<any[]>} Promise that resolves with an array of results in the same order as input tasks
1649
- */
1765
+ * Execute Tasks(functions) in series (one after another) and returns their results in order.
1766
+ * 1. Tasks are executed one by one
1767
+ * * if task is a function, execute it.
1768
+ * * if task is a promise, wait for it to settle.
1769
+ * 2. Fast Fail: if any tasks fail, the whole chain is rejected with the first error
1770
+ * 3. if an element is not function, rejects the whole chain with Error(Not Function)
1771
+ * 4. All Tasks run successfully, Return Results Array, it's length is same as the input tasks
1772
+ * @param {Array<Promise<any>|Function>} tasks
1773
+ * @returns {Promise<any[]>} Promise that resolves with an array of results in the same order as input tasks
1774
+ */
1650
1775
  async function series (tasks) {
1651
1776
  assertArray(tasks);
1652
1777
  const results = [];
1653
1778
  for (const task of tasks) {
1654
1779
  assertFunction(task);
1655
- results.push(await task());
1780
+ if (TypeUtils.isFunction(task)) {
1781
+ // @ts-ignore
1782
+ results.push(await returnValuePromised(task));
1783
+ } else if (TypeUtils.isPromise(task)) {
1784
+ // @ts-ignore
1785
+ results.push(await task);
1786
+ } else {
1787
+ throw new Error(`Invalid Task: ${task}`)
1788
+ }
1656
1789
  }
1657
1790
  return results
1658
1791
  }
@@ -1727,7 +1860,7 @@ async function parallel (tasks, maxParallel = 5) {
1727
1860
  * 2. all tasks will be executed, even some of them failed.
1728
1861
  * @param {Function[]} tasks
1729
1862
  * @param {number} [maxParallel=5] - Maximum number of tasks to run in parallel
1730
- * @returns {Promise<any[]>} Array of resolved values from all promises
1863
+ * @returns {Promise<{ok: boolean, result: any}[]>}
1731
1864
  * @throws {TypeError} If input is not an array of export function or maxParallel is not a number
1732
1865
  */
1733
1866
  async function parallelAllSettled (tasks, maxParallel = 5) {
@@ -1747,7 +1880,6 @@ async function parallelAllSettled (tasks, maxParallel = 5) {
1747
1880
  // run group by MaxParallel
1748
1881
  const tasksToRun = [];
1749
1882
  for (const task of tasks) {
1750
- assertFunction(task);
1751
1883
  tasksToRun.push(task);
1752
1884
  if (tasksToRun.length >= maxParallel) {
1753
1885
  const resultsForBatch = await allSettled(tasksToRun.map(task => returnValuePromised(task)));
@@ -1763,6 +1895,76 @@ async function parallelAllSettled (tasks, maxParallel = 5) {
1763
1895
  return rtnVal
1764
1896
  }
1765
1897
 
1898
+ /**
1899
+ * Executes multiple async tasks in parallel with limited concurrency,
1900
+ * 1. resolving when any task completes successfully.
1901
+ * 2. Maybe multiple tasks are executed as a bulk block, and all of them resolved.
1902
+ * * only the first fulfilled value is returned
1903
+ * * other results are dropped
1904
+ * @param {Array<Function|Promise<any>>} tasks - Array of async functions to execute
1905
+ * @param {number} [maxParallel=5] - Maximum number of tasks to run in parallel
1906
+ * @returns {Promise<any>} Resolves with the result of the first successfully completed task
1907
+ */
1908
+ async function parallelAny (tasks, maxParallel = 5) {
1909
+ assertArray(tasks, 'tasks');
1910
+ assertNumber(maxParallel);
1911
+ if (tasks.length === 0) {
1912
+ throw new Error('Empty Tasks')
1913
+ }
1914
+ if (maxParallel <= 0) {
1915
+ throw new Error(`Invalid maxParallel: ${maxParallel}, should > 0`)
1916
+ }
1917
+ /** @type {any[]} */
1918
+ const errors = [];
1919
+ let taskIndex = 0;
1920
+ let runningTasksCount = 0;
1921
+ const deferred = defer();
1922
+ function takeTaskAndRun () {
1923
+ if (taskIndex >= tasks.length) {
1924
+ return // no more task
1925
+ }
1926
+ // reach max parallel, wait for one task to finish
1927
+ if (runningTasksCount > maxParallel) {
1928
+ return
1929
+ }
1930
+ const task = tasks[taskIndex++];
1931
+ runningTasksCount++;
1932
+ /** @type {Promise<any>} */
1933
+ let taskPromise;
1934
+ if (TypeUtils.isPromise(task)) {
1935
+ // @ts-ignore
1936
+ taskPromise = task;
1937
+ } else if (TypeUtils.isFunction(task)) {
1938
+ // @ts-ignore
1939
+ taskPromise = returnValuePromised(task);
1940
+ } else {
1941
+ errors.push(new TypeError(`Invalid task: ${task}`));
1942
+ takeTaskAndRun();
1943
+ return
1944
+ }
1945
+ taskPromise.then(/** @type {any} */ rtnVal => {
1946
+ deferred.resolve(rtnVal);
1947
+ }).catch(e => {
1948
+ errors.push(e);
1949
+ // No task left, and No successful execution, reject with errors
1950
+ if (errors.length >= tasks.length) {
1951
+ if (deferred.pending) {
1952
+ deferred.reject(errors);
1953
+ return
1954
+ }
1955
+ }
1956
+ takeTaskAndRun();
1957
+ }).finally(() => {
1958
+ runningTasksCount--;
1959
+ });
1960
+ }
1961
+ // start tasks until maxParallel
1962
+ while (runningTasksCount < maxParallel) {
1963
+ takeTaskAndRun();
1964
+ }
1965
+ return deferred.promise
1966
+ }
1967
+
1766
1968
  /**
1767
1969
  * Creates a "Waiter" Object
1768
1970
  * 1. wait the specified time
@@ -1781,17 +1983,20 @@ function wait (waitTime) {
1781
1983
  let timerHandler;
1782
1984
  rtnVal.timerHandler = timerHandler = setTimeout(() => {
1783
1985
  clearTimeout(timerHandler); // must clear it
1784
- rtnVal.resolve();
1986
+ rtnVal._resolve();
1785
1987
  }, waitTime);
1786
1988
 
1787
1989
  rtnVal.promise = new Promise((resolve, reject) => {
1788
- rtnVal.resolve = (arg) => {
1990
+ rtnVal._resolve = (arg) => {
1789
1991
  if (timerHandler != null) {
1790
1992
  clearTimeout(timerHandler); // must clear it
1791
1993
  }
1792
1994
  resolve(arg);
1793
1995
  };
1794
1996
  });
1997
+ rtnVal.wakeup = () => {
1998
+ rtnVal._resolve();
1999
+ };
1795
2000
  return rtnVal
1796
2001
  }
1797
2002
 
@@ -2252,6 +2457,7 @@ function timeoutMillis (nanoTimestamp64, millisTimeout) {
2252
2457
 
2253
2458
  var ArrayUtils = {
2254
2459
  first,
2460
+ chunk,
2255
2461
  last,
2256
2462
  equals,
2257
2463
  equalsIgnoreOrder
@@ -2335,6 +2541,27 @@ function equals (arr1, arr2, compareFn) {
2335
2541
  return true
2336
2542
  }
2337
2543
 
2544
+ /**
2545
+ * Splits an array into chunks of the specified size.
2546
+ * @param {any[]} array - The array to be chunked.
2547
+ * @param {number} size - The size of each chunk.
2548
+ * @returns {any[]} An array of arrays containing the chunks.
2549
+ */
2550
+ function chunk (array, size) {
2551
+ assertArray(array, 'array');
2552
+ assertPositive(size, 'size');
2553
+ if (array.length <= size) {
2554
+ return array
2555
+ }
2556
+ const chunked = [];
2557
+ let index = 0;
2558
+ while (index < array.length) {
2559
+ chunked.push(array.slice(index, size + index));
2560
+ index += size;
2561
+ }
2562
+ return chunked
2563
+ }
2564
+
2338
2565
  /**
2339
2566
  * @module Lang
2340
2567
  * @description Core language utilities for type checking, string manipulation, and common operations.