@creejs/commons-lang 2.1.19 → 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.
@@ -618,7 +618,7 @@
618
618
  */
619
619
  function assertArray (value, paramName) {
620
620
  if (!Array.isArray(value)) {
621
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Array: type=${typeof value} value=${JSON.stringify(value)}`)
621
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Array: type=${typeof value} value=${safeToString(value)}`)
622
622
  }
623
623
  }
624
624
  /**
@@ -630,7 +630,7 @@
630
630
  */
631
631
  function assertString (value, paramName) {
632
632
  if (!isString(value)) {
633
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not String: type=${typeof value} value=${JSON.stringify(value)}`)
633
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not String: type=${typeof value} value=${safeToString(value)}`)
634
634
  }
635
635
  }
636
636
  /**
@@ -642,7 +642,7 @@
642
642
  */
643
643
  function assertNumber (value, paramName) {
644
644
  if (!isNumber(value)) {
645
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Number: type=${typeof value} value=${JSON.stringify(value)}`)
645
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Number: type=${typeof value} value=${safeToString(value)}`)
646
646
  }
647
647
  }
648
648
 
@@ -654,7 +654,7 @@
654
654
  */
655
655
  function assertPositive (value, paramName) {
656
656
  if (!isPositive(value)) {
657
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Positive: ${value}`)
657
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Positive: ${value}`)
658
658
  }
659
659
  }
660
660
 
@@ -666,7 +666,7 @@
666
666
  */
667
667
  function assertNegative (value, paramName) {
668
668
  if (!isNegative(value)) {
669
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Negative: ${value}`)
669
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Negative: ${value}`)
670
670
  }
671
671
  }
672
672
 
@@ -678,7 +678,7 @@
678
678
  */
679
679
  function assertNotNegative (value, paramName) {
680
680
  if (!isNotNegative(value)) {
681
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not "0 or Positive": ${value}`)
681
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not "0 or Positive": ${value}`)
682
682
  }
683
683
  }
684
684
 
@@ -691,7 +691,7 @@
691
691
  */
692
692
  function assertBoolean (value, paramName) {
693
693
  if (!isBoolean(value)) {
694
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Boolean: type=${typeof value} value=${JSON.stringify(value)}`)
694
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Boolean: type=${typeof value} value=${safeToString(value)}`)
695
695
  }
696
696
  }
697
697
  /**
@@ -703,7 +703,7 @@
703
703
  */
704
704
  function assertObject (value, paramName) {
705
705
  if (!isObject(value)) {
706
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Object: type=${typeof value} value=${JSON.stringify(value)}`)
706
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Object: type=${typeof value} value=${safeToString(value)}`)
707
707
  }
708
708
  }
709
709
  /**
@@ -715,7 +715,7 @@
715
715
  */
716
716
  function assertPlainObject (value, paramName) {
717
717
  if (!isPlainObject$1(value)) {
718
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not PlainObject: type=${typeof value} value=${JSON.stringify(value)}`)
718
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not PlainObject: type=${typeof value} value=${safeToString(value)}`)
719
719
  }
720
720
  }
721
721
  /**
@@ -727,7 +727,7 @@
727
727
  */
728
728
  function assertSymbol (value, paramName) {
729
729
  if (!isSymbol(value)) {
730
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Symbol: type=${typeof value} value=${JSON.stringify(value)}`)
730
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Symbol: type=${typeof value} value=${safeToString(value)}`)
731
731
  }
732
732
  }
733
733
  /**
@@ -739,7 +739,7 @@
739
739
  */
740
740
  function assertFunction (value, paramName) {
741
741
  if (!isFunction(value)) {
742
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Function: type=${typeof value} value=${JSON.stringify(value)}`)
742
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Function: type=${typeof value} value=${safeToString(value)}`)
743
743
  }
744
744
  }
745
745
  /**
@@ -751,7 +751,7 @@
751
751
  */
752
752
  function assertInstance (value, paramName) {
753
753
  if (!isInstance(value)) {
754
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Class Instance: type=${typeof value} value=${JSON.stringify(value)}`)
754
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Class Instance: type=${typeof value} value=${safeToString(value)}`)
755
755
  }
756
756
  }
757
757
  /**
@@ -763,7 +763,7 @@
763
763
  */
764
764
  function assertPromise (value, paramName) {
765
765
  if (!isPromise(value)) {
766
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Promise: type=${typeof value} value=${JSON.stringify(value)}`)
766
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Promise: type=${typeof value} value=${safeToString(value)}`)
767
767
  }
768
768
  }
769
769
  /**
@@ -775,7 +775,7 @@
775
775
  */
776
776
  function assertNil (value, paramName) {
777
777
  if (!isNil(value)) {
778
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Neither Null nor Undefined: type=${typeof value} value=${JSON.stringify(value)}`)
778
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Neither Null nor Undefined: type=${typeof value} value=${safeToString(value)}`)
779
779
  }
780
780
  }
781
781
 
@@ -787,7 +787,7 @@
787
787
  */
788
788
  function assertNotNil (value, paramName) {
789
789
  if (isNil(value)) {
790
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Should Not Nil`)
790
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Should Not Nil`)
791
791
  }
792
792
  }
793
793
 
@@ -800,7 +800,7 @@
800
800
  */
801
801
  function assertNull (value, paramName) {
802
802
  if (!isNull(value)) {
803
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Null: type=${typeof value} value=${JSON.stringify(value)}`)
803
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Null: type=${typeof value} value=${safeToString(value)}`)
804
804
  }
805
805
  }
806
806
 
@@ -812,7 +812,7 @@
812
812
  */
813
813
  function assertNotNull (value, paramName) {
814
814
  if (isNull(value)) {
815
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Should Not Null`)
815
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Should Not Null`)
816
816
  }
817
817
  }
818
818
  /**
@@ -824,7 +824,7 @@
824
824
  */
825
825
  function assertUndefined (value, paramName) {
826
826
  if (!isUndefined(value)) {
827
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Undefined: type=${typeof value} value=${JSON.stringify(value)}`)
827
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Undefined: type=${typeof value} value=${safeToString(value)}`)
828
828
  }
829
829
  }
830
830
 
@@ -836,7 +836,7 @@
836
836
  */
837
837
  function assertStringOrSymbol (value, paramName) {
838
838
  if (!isString(value) && !isSymbol(value)) {
839
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not String or Symbol: type=${typeof value} value=${JSON.stringify(value)}`)
839
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not String or Symbol: type=${typeof value} value=${safeToString(value)}`)
840
840
  }
841
841
  }
842
842
 
@@ -847,7 +847,7 @@
847
847
  */
848
848
  function assertTypedArray (value, paramName) {
849
849
  if (isTypedArray(value)) {
850
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not TypedArray`)
850
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not TypedArray`)
851
851
  }
852
852
  }
853
853
  /**
@@ -857,7 +857,7 @@
857
857
  */
858
858
  function assertInt8Array (value, paramName) {
859
859
  if (isInt8Array(value)) {
860
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Int8Array`)
860
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Int8Array`)
861
861
  }
862
862
  }
863
863
  /**
@@ -867,7 +867,7 @@
867
867
  */
868
868
  function assertUint8Array (value, paramName) {
869
869
  if (isUint8Array(value)) {
870
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Uint8Array`)
870
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Uint8Array`)
871
871
  }
872
872
  }
873
873
  /**
@@ -877,7 +877,7 @@
877
877
  */
878
878
  function assertUint8ClampedArray (value, paramName) {
879
879
  if (isUint8ClampedArray(value)) {
880
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Uint8ClampedArray`)
880
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Uint8ClampedArray`)
881
881
  }
882
882
  }
883
883
  /**
@@ -887,7 +887,7 @@
887
887
  */
888
888
  function assertInt16Array (value, paramName) {
889
889
  if (isInt16Array(value)) {
890
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Int16Array`)
890
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Int16Array`)
891
891
  }
892
892
  }
893
893
  /**
@@ -897,7 +897,7 @@
897
897
  */
898
898
  function assertUint16Array (value, paramName) {
899
899
  if (isUint16Array(value)) {
900
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Uint16Array`)
900
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Uint16Array`)
901
901
  }
902
902
  }
903
903
  /**
@@ -907,7 +907,7 @@
907
907
  */
908
908
  function assertInt32Array (value, paramName) {
909
909
  if (isInt32Array(value)) {
910
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Int32Array`)
910
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Int32Array`)
911
911
  }
912
912
  }
913
913
  /**
@@ -917,7 +917,7 @@
917
917
  */
918
918
  function assertUint32Array (value, paramName) {
919
919
  if (isUint32Array(value)) {
920
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Uint32Array`)
920
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Uint32Array`)
921
921
  }
922
922
  }
923
923
  /**
@@ -927,7 +927,7 @@
927
927
  */
928
928
  function assertFloat32Array (value, paramName) {
929
929
  if (isFloat32Array(value)) {
930
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Float32Array`)
930
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Float32Array`)
931
931
  }
932
932
  }
933
933
  /**
@@ -937,7 +937,7 @@
937
937
  */
938
938
  function assertFloat64Array (value, paramName) {
939
939
  if (isFloat64Array(value)) {
940
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Float64Array`)
940
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Float64Array`)
941
941
  }
942
942
  }
943
943
  /**
@@ -947,7 +947,7 @@
947
947
  */
948
948
  function assertBigInt64Array (value, paramName) {
949
949
  if (isBigInt64Array(value)) {
950
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not BigInt64Array`)
950
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not BigInt64Array`)
951
951
  }
952
952
  }
953
953
  /**
@@ -957,7 +957,7 @@
957
957
  */
958
958
  function assertBigUint64Array (value, paramName) {
959
959
  if (isBigUint64Array(value)) {
960
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not BigUint64Array`)
960
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not BigUint64Array`)
961
961
  }
962
962
  }
963
963
 
@@ -969,7 +969,7 @@
969
969
  */
970
970
  function assertArrayBuffer (value, paramName) {
971
971
  if (!isArrayBuffer(value)) {
972
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not ArrayBuffer`)
972
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not ArrayBuffer`)
973
973
  }
974
974
  }
975
975
 
@@ -998,7 +998,8 @@
998
998
  substringAfterLast,
999
999
  substringBetween,
1000
1000
  substringBetweenGreedy,
1001
- substringsBetween
1001
+ substringsBetween,
1002
+ safeToString
1002
1003
  };
1003
1004
 
1004
1005
  /**
@@ -1395,6 +1396,22 @@
1395
1396
  return substrings
1396
1397
  }
1397
1398
 
1399
+ /**
1400
+ * Safely converts a value to its string representation.
1401
+ * Attempts to use JSON.stringify first, falls back to toString() if stringify fails.
1402
+ * @param {*} value - The value to convert to string
1403
+ * @returns {string} The string representation of the value
1404
+ */
1405
+ function safeToString (value) {
1406
+ let valueStr;
1407
+ try {
1408
+ valueStr = JSON.stringify(value);
1409
+ } catch (e) {
1410
+ valueStr = value.toString();
1411
+ }
1412
+ return valueStr
1413
+ }
1414
+
1398
1415
  /**
1399
1416
  * @module ExecUtils
1400
1417
  * @description Utils about how to execute task functions.
@@ -1472,6 +1489,7 @@
1472
1489
  * promise: Promise<*>,
1473
1490
  * timerHandler: NodeJS.Timeout,
1474
1491
  * timerCleared: boolean,
1492
+ * pending: boolean,
1475
1493
  * resolved: boolean,
1476
1494
  * rejected: boolean,
1477
1495
  * canceled: boolean,
@@ -1484,7 +1502,8 @@
1484
1502
  * @typedef {{
1485
1503
  * promise: Promise<*>,
1486
1504
  * timerHandler: NodeJS.Timeout,
1487
- * resolve: (...args:any[])=> void
1505
+ * _resolve: (...args:any[])=> void,
1506
+ * wakeup: ()=> void
1488
1507
  * }} Waiter
1489
1508
  */
1490
1509
 
@@ -1493,6 +1512,7 @@
1493
1512
  * @description Promise utility functions for enhanced promise handling, including timeout, delay, parallel execution, and series execution.
1494
1513
  */
1495
1514
  var PromiseUtils = {
1515
+ any,
1496
1516
  defer,
1497
1517
  delay,
1498
1518
  timeout,
@@ -1501,6 +1521,7 @@
1501
1521
  series,
1502
1522
  seriesAllSettled,
1503
1523
  parallel,
1524
+ parallelAny,
1504
1525
  parallelAllSettled,
1505
1526
  wait
1506
1527
  };
@@ -1516,48 +1537,66 @@
1516
1537
  assertNumber(timeout);
1517
1538
  /** @type {Deferred} */
1518
1539
  const rtnVal = {};
1519
-
1540
+ rtnVal.pending = true;
1541
+ rtnVal.canceled = false;
1542
+ rtnVal.rejected = false;
1543
+ rtnVal.resolved = false;
1520
1544
  /**
1521
1545
  * @type {NodeJS.Timeout}
1522
1546
  */
1523
1547
  let timerHandler;
1524
1548
  if (timeout >= 0) {
1549
+ rtnVal.timerCleared = false;
1525
1550
  rtnVal.timerHandler = timerHandler = setTimeout(() => {
1526
1551
  clearTimeout(timerHandler); // must clear it
1527
- rtnVal.timerCleared = true; // easy to check in test case
1552
+ rtnVal.timerCleared = true;
1528
1553
  rtnVal.reject(new Error(timeoutMessage ?? `Promise Timeout: ${timeout}ms`));
1529
1554
  }, timeout);
1530
1555
  }
1531
1556
 
1532
1557
  rtnVal.promise = new Promise((resolve, reject) => {
1533
1558
  rtnVal.resolve = (arg) => {
1559
+ if (rtnVal.resolved || rtnVal.rejected || rtnVal.canceled) {
1560
+ return // already done, Can Not operate again
1561
+ }
1534
1562
  if (timerHandler != null) {
1535
1563
  clearTimeout(timerHandler); // must clear it
1536
- rtnVal.timerCleared = true; // easy to check in test case
1564
+ rtnVal.timerCleared = true;
1537
1565
  }
1566
+ rtnVal.pending = false;
1567
+ rtnVal.canceled = false;
1568
+ rtnVal.rejected = false;
1538
1569
  rtnVal.resolved = true;
1539
1570
  resolve(arg);
1540
1571
  };
1541
1572
 
1542
1573
  rtnVal.reject = (err) => {
1574
+ if (rtnVal.resolved || rtnVal.rejected || rtnVal.canceled) {
1575
+ return // already done, Can Not operate again
1576
+ }
1543
1577
  if (timerHandler != null) {
1544
1578
  clearTimeout(timerHandler); // must clear it
1545
- rtnVal.timerCleared = true; // easy to check in test case
1579
+ rtnVal.timerCleared = true;
1546
1580
  }
1581
+ rtnVal.pending = false;
1582
+ rtnVal.canceled = false;
1583
+ rtnVal.resolved = false;
1547
1584
  rtnVal.rejected = true;
1548
1585
  reject(err);
1549
1586
  };
1550
1587
  });
1551
1588
  // @ts-ignore
1552
- rtnVal.promise.cancel = () => {
1589
+ rtnVal.cancel = rtnVal.promise.cancel = (reason) => {
1590
+ if (rtnVal.resolved || rtnVal.rejected || rtnVal.canceled) {
1591
+ return // already done, Can Not operate again
1592
+ }
1553
1593
  if (timerHandler != null) {
1554
1594
  clearTimeout(timerHandler); // must clear it
1555
- rtnVal.timerCleared = true; // easy to check in test case
1595
+ rtnVal.timerCleared = true;
1556
1596
  }
1557
- rtnVal.rejected = true; // easy to check in test case
1597
+ rtnVal.reject(reason ?? new Error('Cancelled'));
1558
1598
  // @ts-ignore
1559
- rtnVal.canceled = rtnVal.promise.canceled = true; // easy to check in test case
1560
- rtnVal.reject(new Error('Cancelled'));
1599
+ rtnVal.canceled = rtnVal.promise.canceled = true;
1561
1600
  };
1562
1601
  return rtnVal
1563
1602
  }
@@ -1628,7 +1667,7 @@
1628
1667
  function returnValuePromised (task) {
1629
1668
  try {
1630
1669
  const taskRtnVal = task();
1631
- if (isPromise(taskRtnVal)) {
1670
+ if (TypeUtils.isPromise(taskRtnVal)) {
1632
1671
  return taskRtnVal
1633
1672
  }
1634
1673
  return Promise.resolve(taskRtnVal)
@@ -1649,7 +1688,7 @@
1649
1688
  * @returns {Promise<*>} A new promise that settles after the delay period
1650
1689
  */
1651
1690
  function delay (promise, ms) {
1652
- if (isNumber(promise)) { // defer(ms)
1691
+ if (TypeUtils.isNumber(promise)) { // defer(ms)
1653
1692
  // @ts-ignore
1654
1693
  ms = promise;
1655
1694
  promise = Promise.resolve();
@@ -1681,21 +1720,78 @@
1681
1720
  });
1682
1721
  return deferred.promise
1683
1722
  }
1723
+ /**
1724
+ * 1. run all tasks
1725
+ * 2. any Task succeed, return its result
1726
+ * * resolve with the result.
1727
+ * * the others tasks will run to its end, and results will be dropped.
1728
+ * 3. If all tasks fail, rejects with an array of errors. the array length is same as the input tasks
1729
+ * @param {Array<Promise<any>|Function>} tasks - Array of promises or async functions to execute
1730
+ * @returns {Promise<any>} A promise that resolves with the result of the first successful task
1731
+ */
1732
+ function any (tasks) {
1733
+ assertArray(tasks);
1734
+ if (tasks.length === 0) {
1735
+ throw new Error('Empty Tasks')
1736
+ }
1737
+ const deferred = defer();
1738
+ /** @type {any[]} */
1739
+ const errors = [];
1740
+ for (let i = 0; i < tasks.length; i++) {
1741
+ const task = tasks[i];
1742
+ /** @type {Promise<any>} */
1743
+ let taskPromise;
1744
+ if (TypeUtils.isPromise(task)) {
1745
+ // @ts-ignore
1746
+ taskPromise = task;
1747
+ } else if (TypeUtils.isFunction(task)) {
1748
+ // @ts-ignore
1749
+ taskPromise = returnValuePromised(task);
1750
+ } else {
1751
+ errors.push(new Error(`Invalid Task at index ${i}/${tasks.length - 1}: ${task}`));
1752
+ continue
1753
+ }
1754
+ taskPromise.then(/** @type {any} */ rtnVal => {
1755
+ deferred.resolve(rtnVal);
1756
+ }).catch(e => {
1757
+ errors.push(e);
1758
+ // all tasks failed
1759
+ if (errors.length >= tasks.length) {
1760
+ deferred.reject(errors);
1761
+ }
1762
+ });
1763
+ }
1764
+ if (errors.length === tasks.length) {
1765
+ deferred.reject(errors);
1766
+ }
1767
+ return deferred.promise
1768
+ }
1684
1769
 
1685
1770
  /**
1686
- * Fast-Fail mode to execute Tasks(functions) in series (one after another) and returns their results in order.
1687
- * 1. export function are executed one by one
1688
- * 2. Fast Fail: if any tasks fail, the whole chain is rejected with the first error
1689
- * 3. if an element is not function, rejects the whole chain with Error(Not Function)
1690
- * @param {Function[]} tasks
1691
- * @returns {Promise<any[]>} Promise that resolves with an array of results in the same order as input tasks
1692
- */
1771
+ * Execute Tasks(functions) in series (one after another) and returns their results in order.
1772
+ * 1. Tasks are executed one by one
1773
+ * * if task is a function, execute it.
1774
+ * * if task is a promise, wait for it to settle.
1775
+ * 2. Fast Fail: if any tasks fail, the whole chain is rejected with the first error
1776
+ * 3. if an element is not function, rejects the whole chain with Error(Not Function)
1777
+ * 4. All Tasks run successfully, Return Results Array, it's length is same as the input tasks
1778
+ * @param {Array<Promise<any>|Function>} tasks
1779
+ * @returns {Promise<any[]>} Promise that resolves with an array of results in the same order as input tasks
1780
+ */
1693
1781
  async function series (tasks) {
1694
1782
  assertArray(tasks);
1695
1783
  const results = [];
1696
1784
  for (const task of tasks) {
1697
1785
  assertFunction(task);
1698
- results.push(await task());
1786
+ if (TypeUtils.isFunction(task)) {
1787
+ // @ts-ignore
1788
+ results.push(await returnValuePromised(task));
1789
+ } else if (TypeUtils.isPromise(task)) {
1790
+ // @ts-ignore
1791
+ results.push(await task);
1792
+ } else {
1793
+ throw new Error(`Invalid Task: ${task}`)
1794
+ }
1699
1795
  }
1700
1796
  return results
1701
1797
  }
@@ -1770,7 +1866,7 @@
1770
1866
  * 2. all tasks will be executed, even some of them failed.
1771
1867
  * @param {Function[]} tasks
1772
1868
  * @param {number} [maxParallel=5] - Maximum number of tasks to run in parallel
1773
- * @returns {Promise<any[]>} Array of resolved values from all promises
1869
+ * @returns {Promise<{ok: boolean, result: any}[]>}
1774
1870
  * @throws {TypeError} If input is not an array of export function or maxParallel is not a number
1775
1871
  */
1776
1872
  async function parallelAllSettled (tasks, maxParallel = 5) {
@@ -1790,7 +1886,6 @@
1790
1886
  // run group by MaxParallel
1791
1887
  const tasksToRun = [];
1792
1888
  for (const task of tasks) {
1793
- assertFunction(task);
1794
1889
  tasksToRun.push(task);
1795
1890
  if (tasksToRun.length >= maxParallel) {
1796
1891
  const resultsForBatch = await allSettled(tasksToRun.map(task => returnValuePromised(task)));
@@ -1806,6 +1901,76 @@
1806
1901
  return rtnVal
1807
1902
  }
1808
1903
 
1904
+ /**
1905
+ * Executes multiple async tasks in parallel with limited concurrency,
1906
+ * 1. resolving when any task completes successfully.
1907
+ * 2. Maybe multiple tasks are executed as a bulk block, and all of them resolved.
1908
+ * * only the first fulfilled value is returned
1909
+ * * other results are dropped
1910
+ * @param {Array<Function|Promise<any>>} tasks - Array of async functions to execute
1911
+ * @param {number} [maxParallel=5] - Maximum number of tasks to run in parallel
1912
+ * @returns {Promise<any>} Resolves with the result of the first successfully completed task
1913
+ */
1914
+ async function parallelAny (tasks, maxParallel = 5) {
1915
+ assertArray(tasks, 'tasks');
1916
+ assertNumber(maxParallel);
1917
+ if (tasks.length === 0) {
1918
+ throw new Error('Empty Tasks')
1919
+ }
1920
+ if (maxParallel <= 0) {
1921
+ throw new Error(`Invalid maxParallel: ${maxParallel}, should > 0`)
1922
+ }
1923
+ /** @type {any[]} */
1924
+ const errors = [];
1925
+ let taskIndex = 0;
1926
+ let runningTasksCount = 0;
1927
+ const deferred = defer();
1928
+ function takeTaskAndRun () {
1929
+ if (taskIndex >= tasks.length) {
1930
+ return // no more task
1931
+ }
1932
+ // reach max parallel, wait for one task to finish
1933
+ if (runningTasksCount > maxParallel) {
1934
+ return
1935
+ }
1936
+ const task = tasks[taskIndex++];
1937
+ runningTasksCount++;
1938
+ /** @type {Promise<any>} */
1939
+ let taskPromise;
1940
+ if (TypeUtils.isPromise(task)) {
1941
+ // @ts-ignore
1942
+ taskPromise = task;
1943
+ } else if (TypeUtils.isFunction(task)) {
1944
+ // @ts-ignore
1945
+ taskPromise = returnValuePromised(task);
1946
+ } else {
1947
+ errors.push(new TypeError(`Invalid task: ${task}`));
1948
+ takeTaskAndRun();
1949
+ return
1950
+ }
1951
+ taskPromise.then(/** @type {any} */ rtnVal => {
1952
+ deferred.resolve(rtnVal);
1953
+ }).catch(e => {
1954
+ errors.push(e);
1955
+ // No task left, and No successful execution, reject with errors
1956
+ if (errors.length >= tasks.length) {
1957
+ if (deferred.pending) {
1958
+ deferred.reject(errors);
1959
+ return
1960
+ }
1961
+ }
1962
+ takeTaskAndRun();
1963
+ }).finally(() => {
1964
+ runningTasksCount--;
1965
+ });
1966
+ }
1967
+ // start tasks until maxParallel
1968
+ while (runningTasksCount < maxParallel) {
1969
+ takeTaskAndRun();
1970
+ }
1971
+ return deferred.promise
1972
+ }
1973
+
1809
1974
  /**
1810
1975
  * Creates a "Waiter" Object
1811
1976
  * 1. wait the specified time
@@ -1824,17 +1989,20 @@
1824
1989
  let timerHandler;
1825
1990
  rtnVal.timerHandler = timerHandler = setTimeout(() => {
1826
1991
  clearTimeout(timerHandler); // must clear it
1827
- rtnVal.resolve();
1992
+ rtnVal._resolve();
1828
1993
  }, waitTime);
1829
1994
 
1830
1995
  rtnVal.promise = new Promise((resolve, reject) => {
1831
- rtnVal.resolve = (arg) => {
1996
+ rtnVal._resolve = (arg) => {
1832
1997
  if (timerHandler != null) {
1833
1998
  clearTimeout(timerHandler); // must clear it
1834
1999
  }
1835
2000
  resolve(arg);
1836
2001
  };
1837
2002
  });
2003
+ rtnVal.wakeup = () => {
2004
+ rtnVal._resolve();
2005
+ };
1838
2006
  return rtnVal
1839
2007
  }
1840
2008
 
@@ -2295,6 +2463,7 @@
2295
2463
 
2296
2464
  var ArrayUtils = {
2297
2465
  first,
2466
+ chunk,
2298
2467
  last,
2299
2468
  equals,
2300
2469
  equalsIgnoreOrder
@@ -2378,6 +2547,27 @@
2378
2547
  return true
2379
2548
  }
2380
2549
 
2550
+ /**
2551
+ * Splits an array into chunks of the specified size.
2552
+ * @param {any[]} array - The array to be chunked.
2553
+ * @param {number} size - The size of each chunk.
2554
+ * @returns {any[]} An array of arrays containing the chunks.
2555
+ */
2556
+ function chunk (array, size) {
2557
+ assertArray(array, 'array');
2558
+ assertPositive(size, 'size');
2559
+ if (array.length <= size) {
2560
+ return array
2561
+ }
2562
+ const chunked = [];
2563
+ let index = 0;
2564
+ while (index < array.length) {
2565
+ chunked.push(array.slice(index, size + index));
2566
+ index += size;
2567
+ }
2568
+ return chunked
2569
+ }
2570
+
2381
2571
  /**
2382
2572
  * @module Lang
2383
2573
  * @description Core language utilities for type checking, string manipulation, and common operations.