@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.
@@ -14,7 +14,9 @@ var LangUtils = {
14
14
  extends: extend,
15
15
  equals: equals$2,
16
16
  isBrowser,
17
- isNode
17
+ isNode,
18
+ cloneToPlainObject,
19
+ deepCloneToPlainObject
18
20
  };
19
21
 
20
22
  /**
@@ -72,6 +74,41 @@ function extend (target, ...sources) {
72
74
  return target
73
75
  }
74
76
 
77
+ /**
78
+ * Creates a shallow clone of an object by copying its enumerable properties to a new plain object.
79
+ * 1. This returns a PlainObject
80
+ * 2. It lose the type information of the original object
81
+ * 3. Shallow clone, copy only the first level properties
82
+ * @param {{[key:string]: any}} obj - The object to clone.
83
+ * @returns {{[key:string]: any}} A new plain object with the same enumerable properties as the input object.
84
+ */
85
+ function cloneToPlainObject (obj) {
86
+ if (obj == null) {
87
+ return obj
88
+ }
89
+ if (typeof obj !== 'object') {
90
+ throw new Error('Only Object allowed to clone')
91
+ }
92
+ return { ...obj }
93
+ }
94
+
95
+ /**
96
+ * Deep clones an object by converting it to JSON and back to a plain object.
97
+ * 1. This will lose any non-JSON-serializable properties (e.g. functions, Symbols).
98
+ * 2. Only Use this to clone PlainObject
99
+ * @param {{[key:string]: any}} obj - The object to clone
100
+ * @returns {{[key:string]: any}} A new plain object with the cloned properties
101
+ */
102
+ function deepCloneToPlainObject (obj) {
103
+ if (obj == null) {
104
+ return obj
105
+ }
106
+ if (typeof obj !== 'object') {
107
+ throw new Error('Only Object allowed to clone')
108
+ }
109
+ return JSON.parse(JSON.stringify(obj))
110
+ }
111
+
75
112
  /**
76
113
  * Compares two values for equality
77
114
  * 1. First checks strict equality (===),
@@ -579,7 +616,7 @@ var TypeAssert = {
579
616
  */
580
617
  function assertArray (value, paramName) {
581
618
  if (!Array.isArray(value)) {
582
- 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)}`)
583
620
  }
584
621
  }
585
622
  /**
@@ -591,7 +628,7 @@ function assertArray (value, paramName) {
591
628
  */
592
629
  function assertString (value, paramName) {
593
630
  if (!isString(value)) {
594
- 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)}`)
595
632
  }
596
633
  }
597
634
  /**
@@ -603,7 +640,7 @@ function assertString (value, paramName) {
603
640
  */
604
641
  function assertNumber (value, paramName) {
605
642
  if (!isNumber(value)) {
606
- 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)}`)
607
644
  }
608
645
  }
609
646
 
@@ -615,7 +652,7 @@ function assertNumber (value, paramName) {
615
652
  */
616
653
  function assertPositive (value, paramName) {
617
654
  if (!isPositive(value)) {
618
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Positive: ${value}`)
655
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Positive: ${value}`)
619
656
  }
620
657
  }
621
658
 
@@ -627,7 +664,7 @@ function assertPositive (value, paramName) {
627
664
  */
628
665
  function assertNegative (value, paramName) {
629
666
  if (!isNegative(value)) {
630
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Negative: ${value}`)
667
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Negative: ${value}`)
631
668
  }
632
669
  }
633
670
 
@@ -639,7 +676,7 @@ function assertNegative (value, paramName) {
639
676
  */
640
677
  function assertNotNegative (value, paramName) {
641
678
  if (!isNotNegative(value)) {
642
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not "0 or Positive": ${value}`)
679
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not "0 or Positive": ${value}`)
643
680
  }
644
681
  }
645
682
 
@@ -652,7 +689,7 @@ function assertNotNegative (value, paramName) {
652
689
  */
653
690
  function assertBoolean (value, paramName) {
654
691
  if (!isBoolean(value)) {
655
- 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)}`)
656
693
  }
657
694
  }
658
695
  /**
@@ -664,7 +701,7 @@ function assertBoolean (value, paramName) {
664
701
  */
665
702
  function assertObject (value, paramName) {
666
703
  if (!isObject(value)) {
667
- 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)}`)
668
705
  }
669
706
  }
670
707
  /**
@@ -676,7 +713,7 @@ function assertObject (value, paramName) {
676
713
  */
677
714
  function assertPlainObject (value, paramName) {
678
715
  if (!isPlainObject$1(value)) {
679
- 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)}`)
680
717
  }
681
718
  }
682
719
  /**
@@ -688,7 +725,7 @@ function assertPlainObject (value, paramName) {
688
725
  */
689
726
  function assertSymbol (value, paramName) {
690
727
  if (!isSymbol(value)) {
691
- 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)}`)
692
729
  }
693
730
  }
694
731
  /**
@@ -700,7 +737,7 @@ function assertSymbol (value, paramName) {
700
737
  */
701
738
  function assertFunction (value, paramName) {
702
739
  if (!isFunction(value)) {
703
- 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)}`)
704
741
  }
705
742
  }
706
743
  /**
@@ -712,7 +749,7 @@ function assertFunction (value, paramName) {
712
749
  */
713
750
  function assertInstance (value, paramName) {
714
751
  if (!isInstance(value)) {
715
- 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)}`)
716
753
  }
717
754
  }
718
755
  /**
@@ -724,7 +761,7 @@ function assertInstance (value, paramName) {
724
761
  */
725
762
  function assertPromise (value, paramName) {
726
763
  if (!isPromise(value)) {
727
- 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)}`)
728
765
  }
729
766
  }
730
767
  /**
@@ -736,7 +773,7 @@ function assertPromise (value, paramName) {
736
773
  */
737
774
  function assertNil (value, paramName) {
738
775
  if (!isNil(value)) {
739
- 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)}`)
740
777
  }
741
778
  }
742
779
 
@@ -748,7 +785,7 @@ function assertNil (value, paramName) {
748
785
  */
749
786
  function assertNotNil (value, paramName) {
750
787
  if (isNil(value)) {
751
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Should Not Nil`)
788
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Should Not Nil`)
752
789
  }
753
790
  }
754
791
 
@@ -761,7 +798,7 @@ function assertNotNil (value, paramName) {
761
798
  */
762
799
  function assertNull (value, paramName) {
763
800
  if (!isNull(value)) {
764
- 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)}`)
765
802
  }
766
803
  }
767
804
 
@@ -773,7 +810,7 @@ function assertNull (value, paramName) {
773
810
  */
774
811
  function assertNotNull (value, paramName) {
775
812
  if (isNull(value)) {
776
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Should Not Null`)
813
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Should Not Null`)
777
814
  }
778
815
  }
779
816
  /**
@@ -785,7 +822,7 @@ function assertNotNull (value, paramName) {
785
822
  */
786
823
  function assertUndefined (value, paramName) {
787
824
  if (!isUndefined(value)) {
788
- 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)}`)
789
826
  }
790
827
  }
791
828
 
@@ -797,7 +834,7 @@ function assertUndefined (value, paramName) {
797
834
  */
798
835
  function assertStringOrSymbol (value, paramName) {
799
836
  if (!isString(value) && !isSymbol(value)) {
800
- 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)}`)
801
838
  }
802
839
  }
803
840
 
@@ -808,7 +845,7 @@ function assertStringOrSymbol (value, paramName) {
808
845
  */
809
846
  function assertTypedArray (value, paramName) {
810
847
  if (isTypedArray(value)) {
811
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not TypedArray`)
848
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not TypedArray`)
812
849
  }
813
850
  }
814
851
  /**
@@ -818,7 +855,7 @@ function assertTypedArray (value, paramName) {
818
855
  */
819
856
  function assertInt8Array (value, paramName) {
820
857
  if (isInt8Array(value)) {
821
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Int8Array`)
858
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Int8Array`)
822
859
  }
823
860
  }
824
861
  /**
@@ -828,7 +865,7 @@ function assertInt8Array (value, paramName) {
828
865
  */
829
866
  function assertUint8Array (value, paramName) {
830
867
  if (isUint8Array(value)) {
831
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Uint8Array`)
868
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Uint8Array`)
832
869
  }
833
870
  }
834
871
  /**
@@ -838,7 +875,7 @@ function assertUint8Array (value, paramName) {
838
875
  */
839
876
  function assertUint8ClampedArray (value, paramName) {
840
877
  if (isUint8ClampedArray(value)) {
841
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Uint8ClampedArray`)
878
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Uint8ClampedArray`)
842
879
  }
843
880
  }
844
881
  /**
@@ -848,7 +885,7 @@ function assertUint8ClampedArray (value, paramName) {
848
885
  */
849
886
  function assertInt16Array (value, paramName) {
850
887
  if (isInt16Array(value)) {
851
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Int16Array`)
888
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Int16Array`)
852
889
  }
853
890
  }
854
891
  /**
@@ -858,7 +895,7 @@ function assertInt16Array (value, paramName) {
858
895
  */
859
896
  function assertUint16Array (value, paramName) {
860
897
  if (isUint16Array(value)) {
861
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Uint16Array`)
898
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Uint16Array`)
862
899
  }
863
900
  }
864
901
  /**
@@ -868,7 +905,7 @@ function assertUint16Array (value, paramName) {
868
905
  */
869
906
  function assertInt32Array (value, paramName) {
870
907
  if (isInt32Array(value)) {
871
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Int32Array`)
908
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Int32Array`)
872
909
  }
873
910
  }
874
911
  /**
@@ -878,7 +915,7 @@ function assertInt32Array (value, paramName) {
878
915
  */
879
916
  function assertUint32Array (value, paramName) {
880
917
  if (isUint32Array(value)) {
881
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Uint32Array`)
918
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Uint32Array`)
882
919
  }
883
920
  }
884
921
  /**
@@ -888,7 +925,7 @@ function assertUint32Array (value, paramName) {
888
925
  */
889
926
  function assertFloat32Array (value, paramName) {
890
927
  if (isFloat32Array(value)) {
891
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Float32Array`)
928
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Float32Array`)
892
929
  }
893
930
  }
894
931
  /**
@@ -898,7 +935,7 @@ function assertFloat32Array (value, paramName) {
898
935
  */
899
936
  function assertFloat64Array (value, paramName) {
900
937
  if (isFloat64Array(value)) {
901
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not Float64Array`)
938
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not Float64Array`)
902
939
  }
903
940
  }
904
941
  /**
@@ -908,7 +945,7 @@ function assertFloat64Array (value, paramName) {
908
945
  */
909
946
  function assertBigInt64Array (value, paramName) {
910
947
  if (isBigInt64Array(value)) {
911
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not BigInt64Array`)
948
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not BigInt64Array`)
912
949
  }
913
950
  }
914
951
  /**
@@ -918,7 +955,7 @@ function assertBigInt64Array (value, paramName) {
918
955
  */
919
956
  function assertBigUint64Array (value, paramName) {
920
957
  if (isBigUint64Array(value)) {
921
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not BigUint64Array`)
958
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not BigUint64Array`)
922
959
  }
923
960
  }
924
961
 
@@ -930,7 +967,7 @@ function assertBigUint64Array (value, paramName) {
930
967
  */
931
968
  function assertArrayBuffer (value, paramName) {
932
969
  if (!isArrayBuffer(value)) {
933
- throw new Error(`${paramName ? '"' + paramName + '" ' : ' '}Not ArrayBuffer`)
970
+ throw new Error(`${paramName ? '"' + paramName + '" ' : ''}Not ArrayBuffer`)
934
971
  }
935
972
  }
936
973
 
@@ -959,7 +996,8 @@ var StringUtils = {
959
996
  substringAfterLast,
960
997
  substringBetween,
961
998
  substringBetweenGreedy,
962
- substringsBetween
999
+ substringsBetween,
1000
+ safeToString
963
1001
  };
964
1002
 
965
1003
  /**
@@ -1356,6 +1394,22 @@ function substringsBetween (str, startMarker, endMarker) {
1356
1394
  return substrings
1357
1395
  }
1358
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
+
1359
1413
  /**
1360
1414
  * @module ExecUtils
1361
1415
  * @description Utils about how to execute task functions.
@@ -1433,6 +1487,7 @@ var ExecUtils = {
1433
1487
  * promise: Promise<*>,
1434
1488
  * timerHandler: NodeJS.Timeout,
1435
1489
  * timerCleared: boolean,
1490
+ * pending: boolean,
1436
1491
  * resolved: boolean,
1437
1492
  * rejected: boolean,
1438
1493
  * canceled: boolean,
@@ -1445,7 +1500,8 @@ var ExecUtils = {
1445
1500
  * @typedef {{
1446
1501
  * promise: Promise<*>,
1447
1502
  * timerHandler: NodeJS.Timeout,
1448
- * resolve: (...args:any[])=> void
1503
+ * _resolve: (...args:any[])=> void,
1504
+ * wakeup: ()=> void
1449
1505
  * }} Waiter
1450
1506
  */
1451
1507
 
@@ -1454,6 +1510,7 @@ var ExecUtils = {
1454
1510
  * @description Promise utility functions for enhanced promise handling, including timeout, delay, parallel execution, and series execution.
1455
1511
  */
1456
1512
  var PromiseUtils = {
1513
+ any,
1457
1514
  defer,
1458
1515
  delay,
1459
1516
  timeout,
@@ -1462,6 +1519,7 @@ var PromiseUtils = {
1462
1519
  series,
1463
1520
  seriesAllSettled,
1464
1521
  parallel,
1522
+ parallelAny,
1465
1523
  parallelAllSettled,
1466
1524
  wait
1467
1525
  };
@@ -1477,48 +1535,66 @@ function defer (timeout = -1, timeoutMessage) {
1477
1535
  assertNumber(timeout);
1478
1536
  /** @type {Deferred} */
1479
1537
  const rtnVal = {};
1480
-
1538
+ rtnVal.pending = true;
1539
+ rtnVal.canceled = false;
1540
+ rtnVal.rejected = false;
1541
+ rtnVal.resolved = false;
1481
1542
  /**
1482
1543
  * @type {NodeJS.Timeout}
1483
1544
  */
1484
1545
  let timerHandler;
1485
1546
  if (timeout >= 0) {
1547
+ rtnVal.timerCleared = false;
1486
1548
  rtnVal.timerHandler = timerHandler = setTimeout(() => {
1487
1549
  clearTimeout(timerHandler); // must clear it
1488
- rtnVal.timerCleared = true; // easy to check in test case
1550
+ rtnVal.timerCleared = true;
1489
1551
  rtnVal.reject(new Error(timeoutMessage ?? `Promise Timeout: ${timeout}ms`));
1490
1552
  }, timeout);
1491
1553
  }
1492
1554
 
1493
1555
  rtnVal.promise = new Promise((resolve, reject) => {
1494
1556
  rtnVal.resolve = (arg) => {
1557
+ if (rtnVal.resolved || rtnVal.rejected || rtnVal.canceled) {
1558
+ return // already done, Can Not operate again
1559
+ }
1495
1560
  if (timerHandler != null) {
1496
1561
  clearTimeout(timerHandler); // must clear it
1497
- rtnVal.timerCleared = true; // easy to check in test case
1562
+ rtnVal.timerCleared = true;
1498
1563
  }
1564
+ rtnVal.pending = false;
1565
+ rtnVal.canceled = false;
1566
+ rtnVal.rejected = false;
1499
1567
  rtnVal.resolved = true;
1500
1568
  resolve(arg);
1501
1569
  };
1502
1570
 
1503
1571
  rtnVal.reject = (err) => {
1572
+ if (rtnVal.resolved || rtnVal.rejected || rtnVal.canceled) {
1573
+ return // already done, Can Not operate again
1574
+ }
1504
1575
  if (timerHandler != null) {
1505
1576
  clearTimeout(timerHandler); // must clear it
1506
- rtnVal.timerCleared = true; // easy to check in test case
1577
+ rtnVal.timerCleared = true;
1507
1578
  }
1579
+ rtnVal.pending = false;
1580
+ rtnVal.canceled = false;
1581
+ rtnVal.resolved = false;
1508
1582
  rtnVal.rejected = true;
1509
1583
  reject(err);
1510
1584
  };
1511
1585
  });
1512
1586
  // @ts-ignore
1513
- 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
+ }
1514
1591
  if (timerHandler != null) {
1515
1592
  clearTimeout(timerHandler); // must clear it
1516
- rtnVal.timerCleared = true; // easy to check in test case
1593
+ rtnVal.timerCleared = true;
1517
1594
  }
1518
- rtnVal.rejected = true; // easy to check in test case
1595
+ rtnVal.reject(reason ?? new Error('Cancelled'));
1519
1596
  // @ts-ignore
1520
- rtnVal.canceled = rtnVal.promise.canceled = true; // easy to check in test case
1521
- rtnVal.reject(new Error('Cancelled'));
1597
+ rtnVal.canceled = rtnVal.promise.canceled = true;
1522
1598
  };
1523
1599
  return rtnVal
1524
1600
  }
@@ -1589,7 +1665,7 @@ async function allSettled (promises) {
1589
1665
  function returnValuePromised (task) {
1590
1666
  try {
1591
1667
  const taskRtnVal = task();
1592
- if (isPromise(taskRtnVal)) {
1668
+ if (TypeUtils.isPromise(taskRtnVal)) {
1593
1669
  return taskRtnVal
1594
1670
  }
1595
1671
  return Promise.resolve(taskRtnVal)
@@ -1610,7 +1686,7 @@ function returnValuePromised (task) {
1610
1686
  * @returns {Promise<*>} A new promise that settles after the delay period
1611
1687
  */
1612
1688
  function delay (promise, ms) {
1613
- if (isNumber(promise)) { // defer(ms)
1689
+ if (TypeUtils.isNumber(promise)) { // defer(ms)
1614
1690
  // @ts-ignore
1615
1691
  ms = promise;
1616
1692
  promise = Promise.resolve();
@@ -1642,21 +1718,78 @@ function delay (promise, ms) {
1642
1718
  });
1643
1719
  return deferred.promise
1644
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
+ }
1645
1767
 
1646
1768
  /**
1647
- * Fast-Fail mode to execute Tasks(functions) in series (one after another) and returns their results in order.
1648
- * 1. export function are executed one by one
1649
- * 2. Fast Fail: if any tasks fail, the whole chain is rejected with the first error
1650
- * 3. if an element is not function, rejects the whole chain with Error(Not Function)
1651
- * @param {Function[]} tasks
1652
- * @returns {Promise<any[]>} Promise that resolves with an array of results in the same order as input tasks
1653
- */
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
+ */
1654
1779
  async function series (tasks) {
1655
1780
  assertArray(tasks);
1656
1781
  const results = [];
1657
1782
  for (const task of tasks) {
1658
1783
  assertFunction(task);
1659
- 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
+ }
1660
1793
  }
1661
1794
  return results
1662
1795
  }
@@ -1731,7 +1864,7 @@ async function parallel (tasks, maxParallel = 5) {
1731
1864
  * 2. all tasks will be executed, even some of them failed.
1732
1865
  * @param {Function[]} tasks
1733
1866
  * @param {number} [maxParallel=5] - Maximum number of tasks to run in parallel
1734
- * @returns {Promise<any[]>} Array of resolved values from all promises
1867
+ * @returns {Promise<{ok: boolean, result: any}[]>}
1735
1868
  * @throws {TypeError} If input is not an array of export function or maxParallel is not a number
1736
1869
  */
1737
1870
  async function parallelAllSettled (tasks, maxParallel = 5) {
@@ -1751,7 +1884,6 @@ async function parallelAllSettled (tasks, maxParallel = 5) {
1751
1884
  // run group by MaxParallel
1752
1885
  const tasksToRun = [];
1753
1886
  for (const task of tasks) {
1754
- assertFunction(task);
1755
1887
  tasksToRun.push(task);
1756
1888
  if (tasksToRun.length >= maxParallel) {
1757
1889
  const resultsForBatch = await allSettled(tasksToRun.map(task => returnValuePromised(task)));
@@ -1767,6 +1899,76 @@ async function parallelAllSettled (tasks, maxParallel = 5) {
1767
1899
  return rtnVal
1768
1900
  }
1769
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
+
1770
1972
  /**
1771
1973
  * Creates a "Waiter" Object
1772
1974
  * 1. wait the specified time
@@ -1785,17 +1987,20 @@ function wait (waitTime) {
1785
1987
  let timerHandler;
1786
1988
  rtnVal.timerHandler = timerHandler = setTimeout(() => {
1787
1989
  clearTimeout(timerHandler); // must clear it
1788
- rtnVal.resolve();
1990
+ rtnVal._resolve();
1789
1991
  }, waitTime);
1790
1992
 
1791
1993
  rtnVal.promise = new Promise((resolve, reject) => {
1792
- rtnVal.resolve = (arg) => {
1994
+ rtnVal._resolve = (arg) => {
1793
1995
  if (timerHandler != null) {
1794
1996
  clearTimeout(timerHandler); // must clear it
1795
1997
  }
1796
1998
  resolve(arg);
1797
1999
  };
1798
2000
  });
2001
+ rtnVal.wakeup = () => {
2002
+ rtnVal._resolve();
2003
+ };
1799
2004
  return rtnVal
1800
2005
  }
1801
2006
 
@@ -2256,6 +2461,7 @@ function timeoutMillis (nanoTimestamp64, millisTimeout) {
2256
2461
 
2257
2462
  var ArrayUtils = {
2258
2463
  first,
2464
+ chunk,
2259
2465
  last,
2260
2466
  equals,
2261
2467
  equalsIgnoreOrder
@@ -2339,6 +2545,27 @@ function equals (arr1, arr2, compareFn) {
2339
2545
  return true
2340
2546
  }
2341
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
+
2342
2569
  /**
2343
2570
  * @module Lang
2344
2571
  * @description Core language utilities for type checking, string manipulation, and common operations.