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