@oscarpalmer/atoms 0.194.0 → 0.195.1

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.
Files changed (86) hide show
  1. package/dist/array/index.d.mts +2 -2
  2. package/dist/array/index.mjs +2 -2
  3. package/dist/array/move.mjs +1 -1
  4. package/dist/array/swap.mjs +1 -1
  5. package/dist/color/instance.mjs +1 -1
  6. package/dist/color/misc/state.d.mts +1 -1
  7. package/dist/color/models.d.mts +1 -1
  8. package/dist/color/space/hex.mjs +1 -1
  9. package/dist/color/space/rgb.mjs +1 -1
  10. package/dist/function/index.d.mts +1 -2
  11. package/dist/function/index.mjs +1 -2
  12. package/dist/function/limit.d.mts +6 -0
  13. package/dist/function/limit.mjs +2 -0
  14. package/dist/function/once.d.mts +3 -0
  15. package/dist/function/once.mjs +2 -1
  16. package/dist/function/retry.d.mts +24 -1
  17. package/dist/function/retry.mjs +1 -0
  18. package/dist/herald.d.mts +2 -71
  19. package/dist/herald.mjs +1 -109
  20. package/dist/index.d.mts +3325 -3282
  21. package/dist/index.mjs +1508 -1498
  22. package/dist/{array → internal/array}/get.d.mts +2 -2
  23. package/dist/{array → internal/array}/get.mjs +2 -2
  24. package/dist/{array → internal/array}/match.d.mts +2 -2
  25. package/dist/{array → internal/array}/match.mjs +2 -2
  26. package/dist/internal/defaults.d.mts +5 -0
  27. package/dist/internal/defaults.mjs +9 -0
  28. package/dist/{function → internal/function}/assert.d.mts +2 -2
  29. package/dist/{function → internal/function}/assert.mjs +2 -2
  30. package/dist/{function → internal/function}/memoize.d.mts +2 -2
  31. package/dist/{function → internal/function}/memoize.mjs +3 -3
  32. package/dist/{function → internal/function}/work.d.mts +2 -2
  33. package/dist/{function → internal/function}/work.mjs +2 -2
  34. package/dist/internal/herald.d.mts +71 -0
  35. package/dist/internal/herald.mjs +110 -0
  36. package/dist/internal/number.d.mts +1 -2
  37. package/dist/internal/number.mjs +1 -4
  38. package/dist/internal/{result.d.mts → result/misc.d.mts} +42 -3
  39. package/dist/internal/{result.mjs → result/misc.mjs} +29 -3
  40. package/dist/{result → internal/result}/models.d.mts +2 -2
  41. package/dist/{sized → internal/sized}/map.d.mts +1 -1
  42. package/dist/{sized → internal/sized}/map.mjs +2 -2
  43. package/dist/internal/{sized.d.mts → sized/misc.d.mts} +1 -1
  44. package/dist/internal/{sized.mjs → sized/misc.mjs} +2 -2
  45. package/dist/{string → internal/string}/case.d.mts +1 -1
  46. package/dist/{string → internal/string}/case.mjs +2 -2
  47. package/dist/internal/{string.d.mts → string/misc.d.mts} +1 -1
  48. package/dist/internal/{string.mjs → string/misc.mjs} +1 -1
  49. package/dist/internal/value/compare.mjs +1 -1
  50. package/dist/internal/value/has.d.mts +1 -1
  51. package/dist/internal/value/misc.d.mts +1 -1
  52. package/dist/internal/value/misc.mjs +2 -2
  53. package/dist/is.mjs +2 -2
  54. package/dist/logger.mjs +1 -1
  55. package/dist/promise/helpers.d.mts +1 -1
  56. package/dist/promise/helpers.mjs +2 -2
  57. package/dist/promise/index.d.mts +1 -1
  58. package/dist/promise/misc.d.mts +1 -1
  59. package/dist/promise/misc.mjs +2 -1
  60. package/dist/promise/models.d.mts +1 -1
  61. package/dist/query.mjs +1 -1
  62. package/dist/queue.mjs +1 -4
  63. package/dist/random.mjs +1 -1
  64. package/dist/result/index.d.mts +4 -1
  65. package/dist/result/index.mjs +2 -1
  66. package/dist/result/match.d.mts +4 -1
  67. package/dist/result/match.mjs +2 -1
  68. package/dist/result/misc.d.mts +3 -42
  69. package/dist/result/misc.mjs +2 -28
  70. package/dist/result/work/flow.d.mts +4 -1
  71. package/dist/result/work/flow.mjs +3 -2
  72. package/dist/result/work/pipe.d.mts +4 -1
  73. package/dist/result/work/pipe.mjs +3 -2
  74. package/dist/sized/set.mjs +1 -1
  75. package/dist/string/fuzzy.mjs +2 -2
  76. package/dist/string/index.d.mts +1 -1
  77. package/dist/string/index.mjs +1 -1
  78. package/dist/string/match.mjs +1 -1
  79. package/dist/string/normalize.mjs +2 -2
  80. package/dist/string/template.mjs +1 -1
  81. package/dist/subscription.d.mts +2 -0
  82. package/dist/subscription.mjs +2 -0
  83. package/dist/value/diff.mjs +1 -1
  84. package/dist/value/smush.mjs +1 -1
  85. package/package.json +23 -11
  86. /package/dist/{result → internal/result}/models.mjs +0 -0
package/dist/index.mjs CHANGED
@@ -181,15 +181,6 @@ function compact(array, strict) {
181
181
  return compacted;
182
182
  }
183
183
  //#endregion
184
- //#region src/internal/array/index-of.ts
185
- function indexOf(array, ...parameters) {
186
- return findValue(FIND_VALUE_INDEX, array, parameters, false);
187
- }
188
- indexOf.last = lastIndexOf;
189
- function lastIndexOf(array, ...parameters) {
190
- return findValue(FIND_VALUE_INDEX, array, parameters, true);
191
- }
192
- //#endregion
193
184
  //#region src/internal/is.ts
194
185
  /**
195
186
  * Is the value an array or a plain object?
@@ -365,6 +356,89 @@ function isTypedArray(value) {
365
356
  return isTypedArray.types.has(value?.constructor);
366
357
  }
367
358
  //#endregion
359
+ //#region src/internal/array/get.ts
360
+ function getArray(value, indiced) {
361
+ if (Array.isArray(value)) return value;
362
+ if (value instanceof Map) return [...value.entries()];
363
+ if (value instanceof Set) return [...value.values()];
364
+ if (isNonPlainObject(value)) return [value];
365
+ if (indiced !== true) return Object.entries(value);
366
+ const keys = Object.keys(value);
367
+ const { length } = keys;
368
+ const array = [];
369
+ for (let index = 0; index < length; index += 1) {
370
+ const key = keys[index];
371
+ const asNumber = Number.parseInt(key, 10);
372
+ if (!Number.isNaN(asNumber)) array[asNumber] = value[key];
373
+ }
374
+ return array;
375
+ }
376
+ //#endregion
377
+ //#region src/internal/array/index-of.ts
378
+ function indexOf(array, ...parameters) {
379
+ return findValue(FIND_VALUE_INDEX, array, parameters, false);
380
+ }
381
+ indexOf.last = lastIndexOf;
382
+ function lastIndexOf(array, ...parameters) {
383
+ return findValue(FIND_VALUE_INDEX, array, parameters, true);
384
+ }
385
+ //#endregion
386
+ //#region src/internal/array/match.ts
387
+ function endsWithArray(haystack, needle, key) {
388
+ return endings.has(getPosition(haystack, needle, key)[1]);
389
+ }
390
+ function getArrayComparison(haystack, needle, key) {
391
+ return getPosition(haystack, needle, key)[1];
392
+ }
393
+ function getName(start, haystack, needle) {
394
+ if (start === 0) return haystack === needle ? MATCH_COMPARISON_SAME : MATCH_COMPARISON_START;
395
+ return start + needle === haystack ? MATCH_COMPARISON_END : MATCH_COMPARISON_INSIDE;
396
+ }
397
+ function getPosition(haystack, needle, key) {
398
+ if (!Array.isArray(haystack) || !Array.isArray(needle)) return invalid;
399
+ const haystackLength = haystack.length;
400
+ const needleLength = needle.length;
401
+ if (haystackLength === 0 || needleLength === 0) return outside;
402
+ if (needleLength > haystackLength) return outside;
403
+ const callback = getArrayCallback(key);
404
+ const limit = haystackLength - needleLength + 1;
405
+ let needleValues = callback == null ? needle : needle.slice();
406
+ if (callback != null) for (let needleIndex = 0; needleIndex < needleLength; needleIndex += 1) needleValues[needleIndex] = callback(needle[needleIndex], needleIndex, needle);
407
+ for (let haystackIndex = 0; haystackIndex < limit; haystackIndex += 1) {
408
+ let haystackItem = haystack[haystackIndex];
409
+ let haystackValue = callback?.(haystackItem, haystackIndex, haystack) ?? haystackItem;
410
+ if (!Object.is(haystackValue, needleValues[0])) continue;
411
+ if (needleLength === 1) return [haystackIndex, getName(haystackIndex, haystackLength, needleLength)];
412
+ for (let needleIndex = 1; needleIndex < needleLength; needleIndex += 1) {
413
+ haystackItem = haystack[haystackIndex + needleIndex];
414
+ haystackValue = callback?.(haystackItem, haystackIndex + needleIndex, haystack) ?? haystackItem;
415
+ if (!Object.is(haystackValue, needleValues[needleIndex])) break;
416
+ if (needleIndex === needleLength - 1) return [haystackIndex, getName(haystackIndex, haystackLength, needleLength)];
417
+ }
418
+ }
419
+ return outside;
420
+ }
421
+ function includesArray(haystack, needle, key) {
422
+ return !outsides.has(getPosition(haystack, needle, key)[1]);
423
+ }
424
+ function indexOfArray(haystack, needle, key) {
425
+ return getPosition(haystack, needle, key)[0];
426
+ }
427
+ function startsWithArray(haystack, needle, key) {
428
+ return starts.has(getPosition(haystack, needle, key)[1]);
429
+ }
430
+ const MATCH_COMPARISON_END = "end";
431
+ const MATCH_COMPARISON_INSIDE = "inside";
432
+ const MATCH_COMPARISON_INVALID = "invalid";
433
+ const MATCH_COMPARISON_OUTSIDE = "outside";
434
+ const MATCH_COMPARISON_SAME = "same";
435
+ const MATCH_COMPARISON_START = "start";
436
+ const endings = /* @__PURE__ */ new Set([MATCH_COMPARISON_END, MATCH_COMPARISON_SAME]);
437
+ const invalid = [-1, MATCH_COMPARISON_INVALID];
438
+ const outside = [-1, MATCH_COMPARISON_OUTSIDE];
439
+ const outsides = /* @__PURE__ */ new Set([MATCH_COMPARISON_INVALID, MATCH_COMPARISON_OUTSIDE]);
440
+ const starts = /* @__PURE__ */ new Set([MATCH_COMPARISON_START, MATCH_COMPARISON_SAME]);
441
+ //#endregion
368
442
  //#region src/internal/random.ts
369
443
  function getRandomFloatingNumberValue(inclusive, minimum, maximum) {
370
444
  let maxFloat = isNumber(maximum) && maximum <= Number.MAX_SAFE_INTEGER ? maximum : Number.MAX_SAFE_INTEGER;
@@ -498,24 +572,6 @@ function times(length, value) {
498
572
  return values;
499
573
  }
500
574
  //#endregion
501
- //#region src/array/get.ts
502
- function getArray(value, indiced) {
503
- if (Array.isArray(value)) return value;
504
- if (value instanceof Map) return [...value.entries()];
505
- if (value instanceof Set) return [...value.values()];
506
- if (isNonPlainObject(value)) return [value];
507
- if (indiced !== true) return Object.entries(value);
508
- const keys = Object.keys(value);
509
- const { length } = keys;
510
- const array = [];
511
- for (let index = 0; index < length; index += 1) {
512
- const key = keys[index];
513
- const asNumber = Number.parseInt(key, 10);
514
- if (!Number.isNaN(asNumber)) array[asNumber] = value[key];
515
- }
516
- return array;
517
- }
518
- //#endregion
519
575
  //#region src/internal/array/insert.ts
520
576
  function insertChunkedValues(type, array, items, start, deleteCount) {
521
577
  const actualDeleteCount = deleteCount < 0 ? 0 : deleteCount;
@@ -558,62 +614,6 @@ function partition(array, ...parameters) {
558
614
  return [matched, notMatched];
559
615
  }
560
616
  //#endregion
561
- //#region src/array/match.ts
562
- function endsWithArray(haystack, needle, key) {
563
- return endings.has(getPosition(haystack, needle, key)[1]);
564
- }
565
- function getArrayComparison(haystack, needle, key) {
566
- return getPosition(haystack, needle, key)[1];
567
- }
568
- function getName(start, haystack, needle) {
569
- if (start === 0) return haystack === needle ? MATCH_COMPARISON_SAME : MATCH_COMPARISON_START;
570
- return start + needle === haystack ? MATCH_COMPARISON_END : MATCH_COMPARISON_INSIDE;
571
- }
572
- function getPosition(haystack, needle, key) {
573
- if (!Array.isArray(haystack) || !Array.isArray(needle)) return invalid;
574
- const haystackLength = haystack.length;
575
- const needleLength = needle.length;
576
- if (haystackLength === 0 || needleLength === 0) return outside;
577
- if (needleLength > haystackLength) return outside;
578
- const callback = getArrayCallback(key);
579
- const limit = haystackLength - needleLength + 1;
580
- let needleValues = callback == null ? needle : needle.slice();
581
- if (callback != null) for (let needleIndex = 0; needleIndex < needleLength; needleIndex += 1) needleValues[needleIndex] = callback(needle[needleIndex], needleIndex, needle);
582
- for (let haystackIndex = 0; haystackIndex < limit; haystackIndex += 1) {
583
- let haystackItem = haystack[haystackIndex];
584
- let haystackValue = callback?.(haystackItem, haystackIndex, haystack) ?? haystackItem;
585
- if (!Object.is(haystackValue, needleValues[0])) continue;
586
- if (needleLength === 1) return [haystackIndex, getName(haystackIndex, haystackLength, needleLength)];
587
- for (let needleIndex = 1; needleIndex < needleLength; needleIndex += 1) {
588
- haystackItem = haystack[haystackIndex + needleIndex];
589
- haystackValue = callback?.(haystackItem, haystackIndex + needleIndex, haystack) ?? haystackItem;
590
- if (!Object.is(haystackValue, needleValues[needleIndex])) break;
591
- if (needleIndex === needleLength - 1) return [haystackIndex, getName(haystackIndex, haystackLength, needleLength)];
592
- }
593
- }
594
- return outside;
595
- }
596
- function includesArray(haystack, needle, key) {
597
- return !outsides.has(getPosition(haystack, needle, key)[1]);
598
- }
599
- function indexOfArray(haystack, needle, key) {
600
- return getPosition(haystack, needle, key)[0];
601
- }
602
- function startsWithArray(haystack, needle, key) {
603
- return starts.has(getPosition(haystack, needle, key)[1]);
604
- }
605
- const MATCH_COMPARISON_END = "end";
606
- const MATCH_COMPARISON_INSIDE = "inside";
607
- const MATCH_COMPARISON_INVALID = "invalid";
608
- const MATCH_COMPARISON_OUTSIDE = "outside";
609
- const MATCH_COMPARISON_SAME = "same";
610
- const MATCH_COMPARISON_START = "start";
611
- const endings = /* @__PURE__ */ new Set([MATCH_COMPARISON_END, MATCH_COMPARISON_SAME]);
612
- const invalid = [-1, MATCH_COMPARISON_INVALID];
613
- const outside = [-1, MATCH_COMPARISON_OUTSIDE];
614
- const outsides = /* @__PURE__ */ new Set([MATCH_COMPARISON_INVALID, MATCH_COMPARISON_OUTSIDE]);
615
- const starts = /* @__PURE__ */ new Set([MATCH_COMPARISON_START, MATCH_COMPARISON_SAME]);
616
- //#endregion
617
617
  //#region src/array/push.ts
618
618
  /**
619
619
  * Push items into an array _(at the end)_
@@ -927,7 +927,7 @@ const aggregators = {
927
927
  sum: calculateSum
928
928
  };
929
929
  //#endregion
930
- //#region src/internal/string.ts
930
+ //#region src/internal/string/misc.ts
931
931
  /**
932
932
  * Get the string value from any value
933
933
  *
@@ -1381,70 +1381,206 @@ function toRecordArrays(array, first, second) {
1381
1381
  return groupValues(array, first, second, true);
1382
1382
  }
1383
1383
  //#endregion
1384
- //#region src/internal/result.ts
1385
- function isError(value, extended) {
1386
- return isResultValue(value, false) && (extended === true ? value.original instanceof Error : true);
1387
- }
1388
- function isOk(value) {
1389
- return isResultValue(value, true);
1390
- }
1384
+ //#region src/internal/function/misc.ts
1391
1385
  /**
1392
- * Is the value a _Result_?
1393
- *
1394
- * @param value Value to check
1395
- * @returns `true` if the value is a _Result_, otherwise `false`
1386
+ * A function that does nothing, which can be useful, I guess…
1396
1387
  */
1397
- function isResult(value) {
1398
- return isResultValue(value, true) || isResultValue(value, false);
1399
- }
1400
- function isResultValue(value, okValue) {
1401
- if (isNonPlainObject(value)) return false;
1402
- return value.ok === okValue && (okValue ? RESULT_PROPERTY_VALUE : RESULT_PROPERTY_ERROR) in value;
1403
- }
1404
- const RESULT_PROPERTY_ERROR = "error";
1405
- const RESULT_PROPERTY_VALUE = "value";
1388
+ function noop() {}
1406
1389
  //#endregion
1407
- //#region src/result/misc.ts
1408
- function error(value, original) {
1409
- return getError(value, original);
1410
- }
1411
- function getError(value, original) {
1412
- const errorResult = {
1413
- error: value,
1414
- ok: false
1390
+ //#region src/internal/function/timer.ts
1391
+ function getAsyncTimer(type, callback, time) {
1392
+ function cancel() {
1393
+ clearTimer(id);
1394
+ if (last != null && !last.running) {
1395
+ last.reject();
1396
+ last = void 0;
1397
+ }
1398
+ }
1399
+ async function run(item) {
1400
+ const now = performance.now();
1401
+ start ??= now;
1402
+ if (interval === 0 || now - start >= interval - TIMER_OFFSET) {
1403
+ start = throttle ? now : void 0;
1404
+ item.running = true;
1405
+ try {
1406
+ let result = callback(...item.parameters);
1407
+ if (result instanceof Promise) result = await result;
1408
+ item.resolve(result);
1409
+ } catch (error) {
1410
+ item.reject(error);
1411
+ } finally {
1412
+ item.running = false;
1413
+ }
1414
+ } else id = startTimer(() => run(item));
1415
+ }
1416
+ const interval = getInterval(time);
1417
+ const throttle = type === TIMER_THROTTLE;
1418
+ let id;
1419
+ let last;
1420
+ let start;
1421
+ const timer = (...parameters) => {
1422
+ cancel();
1423
+ const next = {
1424
+ parameters,
1425
+ running: false
1426
+ };
1427
+ next.promise = new Promise((resolve, reject) => {
1428
+ next.reject = reject;
1429
+ next.resolve = resolve;
1430
+ });
1431
+ last = next;
1432
+ if (throttle) run(next);
1433
+ else id = startTimer(() => run(next));
1434
+ return next.promise;
1415
1435
  };
1416
- if (original instanceof Error) errorResult.original = original;
1417
- return errorResult;
1436
+ Object.defineProperty(timer, TIMER_CANCEL, { value: () => cancel() });
1437
+ return timer;
1418
1438
  }
1419
- /**
1420
- * Creates an ok result
1421
- *
1422
- * @param value Value
1423
- * @returns Ok result
1424
- */
1425
- function ok(value) {
1426
- return {
1427
- ok: true,
1428
- value
1429
- };
1439
+ function getInterval(value) {
1440
+ return typeof value === "number" && value > 0 ? value : 0;
1430
1441
  }
1431
- /**
1432
- * Converts a _Result_ to a _Promise_
1442
+ function getTimer(type, callback, time) {
1443
+ function cancel() {
1444
+ clearTimer(id);
1445
+ }
1446
+ function run() {
1447
+ const now = performance.now();
1448
+ start ??= now;
1449
+ if (interval === 0 || now - start >= interval - TIMER_OFFSET) {
1450
+ start = throttle ? now : void 0;
1451
+ callback(...args);
1452
+ } else id = startTimer(run);
1453
+ }
1454
+ const interval = getInterval(time);
1455
+ const throttle = type === TIMER_THROTTLE;
1456
+ let args;
1457
+ let id;
1458
+ let start;
1459
+ const timer = (...parameters) => {
1460
+ cancel();
1461
+ args = parameters;
1462
+ if (throttle) run();
1463
+ else id = startTimer(run);
1464
+ };
1465
+ Object.defineProperty(timer, TIMER_CANCEL, { value: () => cancel() });
1466
+ return timer;
1467
+ }
1468
+ const TIMER_CANCEL = "cancel";
1469
+ const TIMER_DEBOUNCE = "debounce";
1470
+ const TIMER_OFFSET = 5;
1471
+ const TIMER_THROTTLE = "throttle";
1472
+ const TIMER_WAIT = "wait";
1473
+ // istanbul ignore next
1474
+ const clearTimer = typeof cancelAnimationFrame === "function" ? cancelAnimationFrame : clearTimeout;
1475
+ // istanbul ignore next
1476
+ const startTimer = typeof requestAnimationFrame === "function" ? requestAnimationFrame : setTimeout;
1477
+ //#endregion
1478
+ //#region src/function/limit.ts
1479
+ /**
1480
+ * Debounce a function, ensuring it is only called after `time` milliseconds have passed
1433
1481
  *
1434
- * Resolves if ok, rejects for error
1482
+ * - When called, successful _(finished)_ results will resolve and errors will reject
1483
+ * - On subsequent calls, existing calls will be canceled _(rejected)_, the timer reset, and will wait another `time` milliseconds before the new call is made _(and so on...)_
1435
1484
  *
1436
- * @param result _Result_ to convert
1437
- * @returns Promised result
1485
+ * _Available as `asyncDebounce` and `debounce.async`_
1486
+ *
1487
+ * @param callback Callback to debounce
1488
+ * @param time Time in milliseconds to wait before calling the callback _(defaults to `0`; e.g., as soon as possible)_
1489
+ * @returns Debounced callback handler with a `cancel` method
1438
1490
  */
1439
- async function toPromise(result) {
1440
- const actual = typeof result === "function" ? result() : result;
1441
- if (!isResult(actual)) return Promise.reject(new Error(RESULT_MESSAGE_PROMISE));
1442
- return isOk(actual) ? Promise.resolve(actual.value) : Promise.reject(actual.error);
1491
+ function asyncDebounce(callback, time) {
1492
+ return getAsyncTimer(TIMER_DEBOUNCE, callback, time);
1493
+ }
1494
+ /**
1495
+ * Throttle a function, ensuring it is only called once every `time` milliseconds
1496
+ *
1497
+ * - When called, successful _(finished)_ results will resolve and errors will reject
1498
+ * - On subsequent calls, existing calls will be canceled _(rejected)_ and will wait until the next valid time to call the callback again _(and so on...)_
1499
+ *
1500
+ * _Available as `asyncThrottle` and `throttle.async`_
1501
+ *
1502
+ * @param callback Callback to throttle
1503
+ * @param time Time in milliseconds to wait before calling the callback again _(defaults to `0`; e.g., as soon as possible)_
1504
+ * @returns Throttled callback handler with a `cancel` method
1505
+ */
1506
+ function asyncThrottle(callback, time) {
1507
+ return getAsyncTimer(TIMER_THROTTLE, callback, time);
1508
+ }
1509
+ /**
1510
+ * Debounce a function, ensuring it is only called after `time` milliseconds have passed
1511
+ *
1512
+ * On subsequent calls, the timer is reset and will wait another `time` milliseconds _(and so on...)_
1513
+ *
1514
+ * @param callback Callback to debounce
1515
+ * @param time Time in milliseconds to wait before calling the callback _(defaults to `0`; e.g., as soon as possible)_
1516
+ * @returns Debounced callback handler with a `cancel` method
1517
+ */
1518
+ function debounce(callback, time) {
1519
+ return getTimer(TIMER_DEBOUNCE, callback, time);
1520
+ }
1521
+ /**
1522
+ * Throttle a function, ensuring it is only called once every `time` milliseconds
1523
+ *
1524
+ * @param callback Callback to throttle
1525
+ * @param time Time in milliseconds to wait before calling the callback again _(defaults to `0`; e.g., as soon as possible)_
1526
+ * @returns Throttled callback handler with a `cancel` method
1527
+ */
1528
+ function throttle(callback, time) {
1529
+ return getTimer(TIMER_THROTTLE, callback, time);
1530
+ }
1531
+ debounce.async = asyncDebounce;
1532
+ throttle.async = asyncThrottle;
1533
+ Object.defineProperty(debounce, "async", { value: asyncDebounce });
1534
+ Object.defineProperty(throttle, "async", { value: asyncThrottle });
1535
+ //#endregion
1536
+ //#region src/internal/result/misc.ts
1537
+ function error(value, original) {
1538
+ return getError(value, original);
1539
+ }
1540
+ function getError(value, original) {
1541
+ const errorResult = {
1542
+ error: value,
1543
+ ok: false
1544
+ };
1545
+ if (original instanceof Error) errorResult.original = original;
1546
+ return errorResult;
1547
+ }
1548
+ function isError(value, extended) {
1549
+ return isResultValue(value, false) && (extended === true ? value.original instanceof Error : true);
1550
+ }
1551
+ function isOk(value) {
1552
+ return isResultValue(value, true);
1553
+ }
1554
+ /**
1555
+ * Is the value a _Result_?
1556
+ *
1557
+ * @param value Value to check
1558
+ * @returns `true` if the value is a _Result_, otherwise `false`
1559
+ */
1560
+ function isResult(value) {
1561
+ return isResultValue(value, true) || isResultValue(value, false);
1562
+ }
1563
+ function isResultValue(value, okValue) {
1564
+ if (isNonPlainObject(value)) return false;
1565
+ return value.ok === okValue && (okValue ? RESULT_PROPERTY_VALUE : RESULT_PROPERTY_ERROR) in value;
1566
+ }
1567
+ /**
1568
+ * Creates an ok result
1569
+ *
1570
+ * @param value Value
1571
+ * @returns Ok result
1572
+ */
1573
+ function ok(value) {
1574
+ return {
1575
+ ok: true,
1576
+ value
1577
+ };
1443
1578
  }
1444
1579
  function unwrap(value, defaultValue) {
1445
1580
  return isOk(value) ? value.value : defaultValue;
1446
1581
  }
1447
- const RESULT_MESSAGE_PROMISE = "toPromise expected to receive a Result";
1582
+ const RESULT_PROPERTY_ERROR = "error";
1583
+ const RESULT_PROPERTY_VALUE = "value";
1448
1584
  //#endregion
1449
1585
  //#region src/internal/value/misc.ts
1450
1586
  function findKey(needle, haystack) {
@@ -1499,7 +1635,7 @@ function hasValueResult(data, path, ignoreCase) {
1499
1635
  return getNestedValue(data, path, ignoreCase === true);
1500
1636
  }
1501
1637
  //#endregion
1502
- //#region src/function/assert.ts
1638
+ //#region src/internal/function/assert.ts
1503
1639
  /**
1504
1640
  * Asserts that a condition is true, throwing an error if it is not
1505
1641
  *
@@ -1593,51 +1729,311 @@ function assertProperty(path, condition, message, error) {
1593
1729
  }
1594
1730
  const ASSERT_MESSAGE_VALUE_DEFINED = "Expected value to be defined";
1595
1731
  //#endregion
1596
- //#region src/internal/function/misc.ts
1597
- /**
1598
- * A function that does nothing, which can be useful, I guess…
1599
- */
1600
- function noop() {}
1601
- //#endregion
1602
- //#region src/internal/number.ts
1732
+ //#region src/function/once.ts
1603
1733
  /**
1604
- * Is the number between a minimum and maximum value?
1734
+ * Create an asynchronous function that can only be called once, rejecting or resolving the same result on subsequent calls
1605
1735
  *
1606
- * @param value Value to check
1607
- * @param minimum Minimum value
1608
- * @param maximum Maximum value
1609
- * @returns `true` if the value is between the minimum and maximum, otherwise `false`
1736
+ * _Available as `asyncOnce` and `once.async`_
1737
+ *
1738
+ * @param callback Callback to use once
1739
+ * @returns _Once_ callback
1610
1740
  */
1611
- function between(value, minimum, maximum) {
1612
- if (![
1613
- value,
1614
- minimum,
1615
- maximum
1616
- ].every(isNumber)) return false;
1617
- if (Object.is(minimum, maximum)) return Object.is(value, minimum);
1618
- return value >= (maximum > minimum ? minimum : maximum) && value <= (maximum > minimum ? maximum : minimum);
1741
+ function asyncOnce(callback) {
1742
+ assert(() => typeof callback === "function", ONCE_MESSAGE_EXPECTATION);
1743
+ const state = {
1744
+ called: false,
1745
+ cleared: false,
1746
+ error: false,
1747
+ finished: false,
1748
+ items: [],
1749
+ value: void 0
1750
+ };
1751
+ const fn = (...parameters) => {
1752
+ if (state.cleared) return Promise.reject(new Error(ONCE_MESSAGE_CLEARED));
1753
+ if (state.finished) return state.error ? Promise.reject(state.value) : Promise.resolve(state.value);
1754
+ if (state.called) return new Promise((resolve, reject) => {
1755
+ state.items.push({
1756
+ reject,
1757
+ resolve
1758
+ });
1759
+ });
1760
+ state.called = true;
1761
+ return new Promise((resolve, reject) => {
1762
+ state.items.push({
1763
+ reject,
1764
+ resolve
1765
+ });
1766
+ callback(...parameters).then((value) => {
1767
+ handleOnceResult(state, value, false);
1768
+ }).catch((error) => {
1769
+ handleOnceResult(state, error, true);
1770
+ });
1771
+ });
1772
+ };
1773
+ Object.defineProperties(fn, {
1774
+ called: {
1775
+ enumerable: true,
1776
+ get: () => state.called
1777
+ },
1778
+ clear: { value: () => clearState(state) },
1779
+ cleared: {
1780
+ enumerable: true,
1781
+ get: () => state.cleared
1782
+ },
1783
+ error: {
1784
+ enumerable: true,
1785
+ get: () => state.error
1786
+ },
1787
+ finished: {
1788
+ enumerable: true,
1789
+ get: () => state.finished
1790
+ }
1791
+ });
1792
+ return fn;
1793
+ }
1794
+ function clearState(state) {
1795
+ if (!state.called || state.cleared) return;
1796
+ state.cleared = true;
1797
+ state.value = void 0;
1798
+ }
1799
+ function handleOnceResult(state, value, error) {
1800
+ state.error = error;
1801
+ state.finished = true;
1802
+ state.value = value;
1803
+ const items = state.items.splice(0);
1804
+ const { length } = items;
1805
+ for (let index = 0; index < length; index += 1) {
1806
+ const { reject, resolve } = items[index];
1807
+ if (error) reject(value);
1808
+ else resolve(value);
1809
+ }
1619
1810
  }
1620
1811
  /**
1621
- * Clamp a number between a minimum and maximum value
1622
- *
1623
- * @param value Value to clamp
1624
- * @param minimum Minimum value
1625
- * @param maximum Maximum value
1626
- * @param loop If `true`, the value will loop around when smaller than the minimum or larger than the maximum _(defaults to `false`)_
1627
- * @returns Clamped value
1812
+ * Create a function that can only be called once, returning the same value on subsequent calls
1628
1813
  *
1629
- * @example
1630
- * ```typescript
1631
- * clamp(10, 0, 5); // => 5
1632
- * clamp(10, 0, 5, true); // => 0
1633
- * ```
1814
+ * @param callback Callback to use once
1815
+ * @returns _Once_ callback
1634
1816
  */
1635
- function clamp(value, minimum, maximum, loop) {
1636
- if (![
1637
- value,
1638
- minimum,
1639
- maximum
1640
- ].every(isNumber)) return NaN;
1817
+ function once(callback) {
1818
+ assert(() => typeof callback === "function", ONCE_MESSAGE_EXPECTATION);
1819
+ const state = {
1820
+ called: false,
1821
+ cleared: false,
1822
+ value: void 0
1823
+ };
1824
+ const fn = (...parameters) => {
1825
+ if (state.cleared) throw new Error(ONCE_MESSAGE_CLEARED);
1826
+ if (state.called) return state.value;
1827
+ state.called = true;
1828
+ state.value = callback(...parameters);
1829
+ return state.value;
1830
+ };
1831
+ Object.defineProperties(fn, {
1832
+ called: {
1833
+ enumerable: true,
1834
+ get: () => state.called
1835
+ },
1836
+ clear: { value: () => clearState(state) },
1837
+ cleared: {
1838
+ enumerable: true,
1839
+ get: () => state.cleared
1840
+ }
1841
+ });
1842
+ return fn;
1843
+ }
1844
+ const ONCE_MESSAGE_CLEARED = "Once has been cleared";
1845
+ const ONCE_MESSAGE_EXPECTATION = "Once expected a function";
1846
+ once.async = asyncOnce;
1847
+ Object.defineProperty(once, "async", { value: asyncOnce });
1848
+ //#endregion
1849
+ //#region src/function/retry.ts
1850
+ /**
1851
+ * An error thrown when a retry fails
1852
+ */
1853
+ var RetryError = class extends Error {
1854
+ original;
1855
+ constructor(message, original) {
1856
+ super(message);
1857
+ this.original = original;
1858
+ this.name = RETRY_ERROR_NAME;
1859
+ }
1860
+ };
1861
+ /**
1862
+ * Retry a callback a specified number of times, with a delay between attempts
1863
+ *
1864
+ * _Available as `asyncRetry` and `retry.async`_
1865
+ *
1866
+ * @param callback Callback to retry
1867
+ * @param options Retry options
1868
+ * @returns Callback result
1869
+ */
1870
+ async function asyncRetry(callback, options) {
1871
+ if (typeof callback !== "function") throw new TypeError(RETRY_MESSAGE_EXPECTATION);
1872
+ async function handle() {
1873
+ try {
1874
+ const result = await callback();
1875
+ resolver(result);
1876
+ } catch (error) {
1877
+ if (attempts >= times || !when(error)) rejector(new RetryError(RETRY_MESSAGE_FAILED, error));
1878
+ else {
1879
+ attempts += 1;
1880
+ timer();
1881
+ }
1882
+ }
1883
+ }
1884
+ const { delay, times, when } = getRetryOptions(options);
1885
+ const timer = getTimer(TIMER_WAIT, handle, delay);
1886
+ let attempts = 0;
1887
+ let rejector;
1888
+ let resolver;
1889
+ return new Promise((resolve, reject) => {
1890
+ rejector = reject;
1891
+ resolver = resolve;
1892
+ handle();
1893
+ });
1894
+ }
1895
+ function getRetryNumber(value) {
1896
+ return typeof value === "number" && value > 0 ? value : 0;
1897
+ }
1898
+ function getRetryOptions(input) {
1899
+ const options = isPlainObject(input) ? input : {};
1900
+ return {
1901
+ delay: getRetryNumber(options.delay),
1902
+ times: getRetryNumber(options.times),
1903
+ when: typeof options.when === "function" ? options.when : shouldRetry
1904
+ };
1905
+ }
1906
+ /**
1907
+ * Retry a callback a specified number of times
1908
+ *
1909
+ * @param callback Callback to retry
1910
+ * @param options Retry options
1911
+ * @returns Callback result
1912
+ */
1913
+ function retry(callback, options) {
1914
+ if (typeof callback !== "function") throw new TypeError(RETRY_MESSAGE_EXPECTATION);
1915
+ const { times, when } = getRetryOptions(options);
1916
+ let last;
1917
+ for (let index = 0; index <= times; index += 1) try {
1918
+ return callback();
1919
+ } catch (error) {
1920
+ if (index >= times || !when(error)) {
1921
+ last = error;
1922
+ break;
1923
+ }
1924
+ }
1925
+ throw new RetryError(RETRY_MESSAGE_FAILED, last);
1926
+ }
1927
+ function shouldRetry() {
1928
+ return true;
1929
+ }
1930
+ const RETRY_ERROR_NAME = "RetryError";
1931
+ const RETRY_MESSAGE_EXPECTATION = "Retry expected a function";
1932
+ const RETRY_MESSAGE_FAILED = "Retry failed";
1933
+ retry.async = asyncRetry;
1934
+ Object.defineProperty(retry, "async", { value: asyncRetry });
1935
+ //#endregion
1936
+ //#region src/internal/function/work.ts
1937
+ function asyncFlow(...fns) {
1938
+ assertFlowFunctions(fns);
1939
+ return (...args) => asyncWork(args.map((value) => {
1940
+ if (isError(value)) throw value.error;
1941
+ return isOk(value) ? value.value : value;
1942
+ }), fns, true);
1943
+ }
1944
+ function flow(...fns) {
1945
+ assertFlowFunctions(fns);
1946
+ return (...args) => work(args.map((value) => {
1947
+ if (isError(value)) throw value.error;
1948
+ return isOk(value) ? value.value : value;
1949
+ }), fns, true);
1950
+ }
1951
+ async function asyncPipe(value, ...pipes) {
1952
+ assertPipeFunctions(pipes);
1953
+ return asyncWork(value, pipes, false);
1954
+ }
1955
+ function pipe(value, ...pipes) {
1956
+ assertPipeFunctions(pipes);
1957
+ return work(value, pipes, false);
1958
+ }
1959
+ async function asyncWork(initial, functions, flow) {
1960
+ const { length } = functions;
1961
+ let transformed = unwrapValue(initial);
1962
+ for (let index = 0; index < length; index += 1) {
1963
+ const fn = functions[index];
1964
+ transformed = unwrapValue(flow && index === 0 && Array.isArray(initial) ? await fn(...initial) : await fn(transformed));
1965
+ }
1966
+ return transformed;
1967
+ }
1968
+ function unwrapValue(value, flow, nested) {
1969
+ if (typeof value === "function") {
1970
+ if (nested != null) throw new TypeError(WORK_MESSAGE_NESTING);
1971
+ return unwrapValue(value(), flow, true);
1972
+ }
1973
+ if (flow != null && value instanceof Promise) throw new TypeError(flow ? WORK_MESSAGE_FLOW_PROMISE : WORK_MESSAGE_PIPE_PROMISE);
1974
+ if (isError(value)) throw value.error;
1975
+ return isOk(value) ? value.value : value;
1976
+ }
1977
+ function work(initial, functions, flow) {
1978
+ const { length } = functions;
1979
+ let transformed = unwrapValue(initial, flow);
1980
+ for (let index = 0; index < length; index += 1) {
1981
+ const fn = functions[index];
1982
+ transformed = unwrapValue(flow && index === 0 && Array.isArray(initial) ? fn(...initial) : fn(transformed), flow);
1983
+ }
1984
+ return transformed;
1985
+ }
1986
+ const WORK_MESSAGE_FLOW_ARRAY = "Flow expected to receive an array of functions";
1987
+ const WORK_MESSAGE_FLOW_PROMISE = "Synchronous Flow received a promise. Use `flow.async` instead.";
1988
+ const WORK_MESSAGE_NESTING = "Return values are too deeply nested.";
1989
+ const WORK_MESSAGE_PIPE_ARRAY = "Pipe expected to receive an array of functions";
1990
+ const WORK_MESSAGE_PIPE_PROMISE = "Synchronous Pipe received a promise. Use `pipe.async` instead.";
1991
+ const assertFlowFunctions = assert.condition((value) => Array.isArray(value) && value.every((item) => typeof item === "function"), WORK_MESSAGE_FLOW_ARRAY, TypeError);
1992
+ const assertPipeFunctions = assert.condition((value) => Array.isArray(value) && value.every((item) => typeof item === "function"), WORK_MESSAGE_PIPE_ARRAY, TypeError);
1993
+ flow.async = asyncFlow;
1994
+ pipe.async = asyncPipe;
1995
+ Object.defineProperty(flow, "async", { value: asyncFlow });
1996
+ Object.defineProperty(pipe, "async", { value: asyncPipe });
1997
+ //#endregion
1998
+ //#region src/internal/number.ts
1999
+ /**
2000
+ * Is the number between a minimum and maximum value?
2001
+ *
2002
+ * @param value Value to check
2003
+ * @param minimum Minimum value
2004
+ * @param maximum Maximum value
2005
+ * @returns `true` if the value is between the minimum and maximum, otherwise `false`
2006
+ */
2007
+ function between(value, minimum, maximum) {
2008
+ if (![
2009
+ value,
2010
+ minimum,
2011
+ maximum
2012
+ ].every(isNumber)) return false;
2013
+ if (Object.is(minimum, maximum)) return Object.is(value, minimum);
2014
+ return value >= (maximum > minimum ? minimum : maximum) && value <= (maximum > minimum ? maximum : minimum);
2015
+ }
2016
+ /**
2017
+ * Clamp a number between a minimum and maximum value
2018
+ *
2019
+ * @param value Value to clamp
2020
+ * @param minimum Minimum value
2021
+ * @param maximum Maximum value
2022
+ * @param loop If `true`, the value will loop around when smaller than the minimum or larger than the maximum _(defaults to `false`)_
2023
+ * @returns Clamped value
2024
+ *
2025
+ * @example
2026
+ * ```typescript
2027
+ * clamp(10, 0, 5); // => 5
2028
+ * clamp(10, 0, 5, true); // => 0
2029
+ * ```
2030
+ */
2031
+ function clamp(value, minimum, maximum, loop) {
2032
+ if (![
2033
+ value,
2034
+ minimum,
2035
+ maximum
2036
+ ].every(isNumber)) return NaN;
1641
2037
  if (value < minimum) return loop === true ? maximum : minimum;
1642
2038
  return value > maximum ? loop === true ? minimum : maximum : value;
1643
2039
  }
@@ -1664,15 +2060,12 @@ function getNumber(value) {
1664
2060
  if (isBinary || NUMBER_EXPRESSION_OCTAL.test(trimmed)) return Number.parseInt(trimmed.slice(2), isBinary ? 2 : NUMBER_OCTAL_VALUE);
1665
2061
  return Number(trimmed);
1666
2062
  }
1667
- function getNumberOrDefault(value, defaultValue, minimum) {
1668
- return typeof value === "number" && !Number.isNaN(value) && value >= (minimum ?? 0) ? Math.floor(value) : defaultValue;
1669
- }
1670
2063
  const NUMBER_EXPRESSION_BINARY = /^0b[01]+$/i;
1671
2064
  const NUMBER_EXPRESSION_OCTAL = /^0o[0-7]+$/i;
1672
2065
  const NUMBER_EXPRESSION_ZEROISH = /^\s*0+\s*$/;
1673
2066
  const NUMBER_OCTAL_VALUE = 8;
1674
2067
  //#endregion
1675
- //#region src/internal/sized.ts
2068
+ //#region src/internal/sized/misc.ts
1676
2069
  function getSizedMaximum(first, second) {
1677
2070
  let actual;
1678
2071
  if (typeof first === "number") actual = first;
@@ -1682,7 +2075,7 @@ function getSizedMaximum(first, second) {
1682
2075
  const SIZED_MAXIMUM_ABSOLUTE = 16777216;
1683
2076
  const SIZED_MAXIMUM_DEFAULT = 1048576;
1684
2077
  //#endregion
1685
- //#region src/sized/map.ts
2078
+ //#region src/internal/sized/map.ts
1686
2079
  /**
1687
2080
  * A _Map_ with a maximum size
1688
2081
  *
@@ -1736,7 +2129,7 @@ var SizedMap = class extends Map {
1736
2129
  }
1737
2130
  };
1738
2131
  //#endregion
1739
- //#region src/function/memoize.ts
2132
+ //#region src/internal/function/memoize.ts
1740
2133
  function getMemoizationOptions(input) {
1741
2134
  const { cacheKey, cacheSize } = isPlainObject(input) ? input : {};
1742
2135
  return {
@@ -1789,1012 +2182,722 @@ const MEMOIZED_CACHE_SIZE_DEFAULT = 1024;
1789
2182
  const MEMOIZED_CALLBACK = "Memoized requires a callback function";
1790
2183
  const MEMOIZED_KEY_SEPARATOR = "_";
1791
2184
  //#endregion
1792
- //#region src/internal/function/timer.ts
1793
- function getAsyncTimer(type, callback, time) {
1794
- function cancel() {
1795
- clearTimer(id);
1796
- if (last != null && !last.running) {
1797
- last.reject();
1798
- last = void 0;
1799
- }
1800
- }
1801
- async function run(item) {
1802
- const now = performance.now();
1803
- start ??= now;
1804
- if (interval === 0 || now - start >= interval - TIMER_OFFSET) {
1805
- start = throttle ? now : void 0;
1806
- item.running = true;
1807
- try {
1808
- let result = callback(...item.parameters);
1809
- if (result instanceof Promise) result = await result;
1810
- item.resolve(result);
1811
- } catch (error) {
1812
- item.reject(error);
1813
- } finally {
1814
- item.running = false;
1815
- }
1816
- } else id = startTimer(() => run(item));
1817
- }
1818
- const interval = getInterval(time);
1819
- const throttle = type === TIMER_THROTTLE;
1820
- let id;
1821
- let last;
1822
- let start;
1823
- const timer = (...parameters) => {
1824
- cancel();
1825
- const next = {
1826
- parameters,
1827
- running: false
1828
- };
1829
- next.promise = new Promise((resolve, reject) => {
1830
- next.reject = reject;
1831
- next.resolve = resolve;
1832
- });
1833
- last = next;
1834
- if (throttle) run(next);
1835
- else id = startTimer(() => run(next));
1836
- return next.promise;
1837
- };
1838
- Object.defineProperty(timer, TIMER_CANCEL, { value: () => cancel() });
1839
- return timer;
1840
- }
1841
- function getInterval(value) {
1842
- return typeof value === "number" && value > 0 ? value : 0;
1843
- }
1844
- function getTimer(type, callback, time) {
1845
- function cancel() {
1846
- clearTimer(id);
1847
- }
1848
- function run() {
1849
- const now = performance.now();
1850
- start ??= now;
1851
- if (interval === 0 || now - start >= interval - TIMER_OFFSET) {
1852
- start = throttle ? now : void 0;
1853
- callback(...args);
1854
- } else id = startTimer(run);
1855
- }
1856
- const interval = getInterval(time);
1857
- const throttle = type === TIMER_THROTTLE;
1858
- let args;
1859
- let id;
1860
- let start;
1861
- const timer = (...parameters) => {
1862
- cancel();
1863
- args = parameters;
1864
- if (throttle) run();
1865
- else id = startTimer(run);
1866
- };
1867
- Object.defineProperty(timer, TIMER_CANCEL, { value: () => cancel() });
1868
- return timer;
1869
- }
1870
- const TIMER_CANCEL = "cancel";
1871
- const TIMER_DEBOUNCE = "debounce";
1872
- const TIMER_OFFSET = 5;
1873
- const TIMER_THROTTLE = "throttle";
1874
- const TIMER_WAIT = "wait";
1875
- // istanbul ignore next
1876
- const clearTimer = typeof cancelAnimationFrame === "function" ? cancelAnimationFrame : clearTimeout;
1877
- // istanbul ignore next
1878
- const startTimer = typeof requestAnimationFrame === "function" ? requestAnimationFrame : setTimeout;
1879
- //#endregion
1880
- //#region src/function/limit.ts
2185
+ //#region src/internal/string/case.ts
1881
2186
  /**
1882
- * Debounce a function, ensuring it is only called after `time` milliseconds have passed
1883
- *
1884
- * - When called, successful _(finished)_ results will resolve and errors will reject
1885
- * - On subsequent calls, existing calls will be canceled _(rejected)_, the timer reset, and will wait another `time` milliseconds before the new call is made _(and so on...)_
1886
- *
1887
- * _Available as `asyncDebounce` and `debounce.async`_
2187
+ * Convert a string to camel case _(thisIsCamelCase)_
1888
2188
  *
1889
- * @param callback Callback to debounce
1890
- * @param time Time in milliseconds to wait before calling the callback _(defaults to `0`; e.g., as soon as possible)_
1891
- * @returns Debounced callback handler with a `cancel` method
2189
+ * @param value String to convert
2190
+ * @returns Camel-cased string
1892
2191
  */
1893
- function asyncDebounce(callback, time) {
1894
- return getAsyncTimer(TIMER_DEBOUNCE, callback, time);
2192
+ function camelCase(value) {
2193
+ return toCase(STRING_CASE_CAMEL, value, true, false);
1895
2194
  }
1896
2195
  /**
1897
- * Throttle a function, ensuring it is only called once every `time` milliseconds
1898
- *
1899
- * - When called, successful _(finished)_ results will resolve and errors will reject
1900
- * - On subsequent calls, existing calls will be canceled _(rejected)_ and will wait until the next valid time to call the callback again _(and so on...)_
1901
- *
1902
- * _Available as `asyncThrottle` and `throttle.async`_
2196
+ * Capitalize the first letter of a string _(and lowercase the rest)_
1903
2197
  *
1904
- * @param callback Callback to throttle
1905
- * @param time Time in milliseconds to wait before calling the callback again _(defaults to `0`; e.g., as soon as possible)_
1906
- * @returns Throttled callback handler with a `cancel` method
2198
+ * @param value String to capitalize
2199
+ * @returns Capitalized string
1907
2200
  */
1908
- function asyncThrottle(callback, time) {
1909
- return getAsyncTimer(TIMER_THROTTLE, callback, time);
2201
+ function capitalize(value) {
2202
+ if (typeof value !== "string" || value.length === 0) return "";
2203
+ memoizedCapitalize ??= memoize((v) => v.length === 1 ? v.toLocaleUpperCase() : `${v.charAt(0).toLocaleUpperCase()}${v.slice(1).toLocaleLowerCase()}`);
2204
+ return memoizedCapitalize.run(value);
1910
2205
  }
1911
2206
  /**
1912
- * Debounce a function, ensuring it is only called after `time` milliseconds have passed
2207
+ * Convert a string to kebab case _(this-is-kebab-case)_
1913
2208
  *
1914
- * On subsequent calls, the timer is reset and will wait another `time` milliseconds _(and so on...)_
2209
+ * @param value String to convert
2210
+ * @returns Kebab-cased string
2211
+ */
2212
+ function kebabCase(value) {
2213
+ return toCase(STRING_CASE_KEBAB, value, false, false);
2214
+ }
2215
+ /**
2216
+ * Convert a string to lower case
1915
2217
  *
1916
- * @param callback Callback to debounce
1917
- * @param time Time in milliseconds to wait before calling the callback _(defaults to `0`; e.g., as soon as possible)_
1918
- * @returns Debounced callback handler with a `cancel` method
2218
+ * @param value String to convert
2219
+ * @returns Lower-cased string
1919
2220
  */
1920
- function debounce(callback, time) {
1921
- return getTimer(TIMER_DEBOUNCE, callback, time);
2221
+ function lowerCase(value) {
2222
+ if (typeof value !== "string") return "";
2223
+ memoizedLowerCase ??= memoize((v) => v.toLocaleLowerCase());
2224
+ return memoizedLowerCase.run(value);
1922
2225
  }
1923
2226
  /**
1924
- * Throttle a function, ensuring it is only called once every `time` milliseconds
2227
+ * Convert a string to pascal case _(ThisIsPascalCase)_
1925
2228
  *
1926
- * @param callback Callback to throttle
1927
- * @param time Time in milliseconds to wait before calling the callback again _(defaults to `0`; e.g., as soon as possible)_
1928
- * @returns Throttled callback handler with a `cancel` method
2229
+ * @param value String to convert
2230
+ * @returns Pascal-cased string
1929
2231
  */
1930
- function throttle(callback, time) {
1931
- return getTimer(TIMER_THROTTLE, callback, time);
2232
+ function pascalCase(value) {
2233
+ return toCase(STRING_CASE_PASCAL, value, true, true);
1932
2234
  }
1933
- Object.defineProperty(debounce, "async", { value: asyncDebounce });
1934
- Object.defineProperty(throttle, "async", { value: asyncThrottle });
1935
- //#endregion
1936
- //#region src/function/once.ts
1937
2235
  /**
1938
- * Create an asynchronous function that can only be called once, rejecting or resolving the same result on subsequent calls
2236
+ * Convert a string to snake case _(this_is_snake_case)_
1939
2237
  *
1940
- * _Available as `asyncOnce` and `once.async`_
2238
+ * @param value String to convert
2239
+ * @returns Snake-cased string
2240
+ */
2241
+ function snakeCase(value) {
2242
+ return toCase(STRING_CASE_SNAKE, value, false, false);
2243
+ }
2244
+ /**
2245
+ * Convert a string to title case _(Capitalizing Every Word)_
1941
2246
  *
1942
- * @param callback Callback to use once
1943
- * @returns _Once_ callback
2247
+ * @param value String to convert
2248
+ * @returns Title-cased string
1944
2249
  */
1945
- function asyncOnce(callback) {
1946
- assert(() => typeof callback === "function", ONCE_MESSAGE_EXPECTATION);
1947
- const state = {
1948
- called: false,
1949
- cleared: false,
1950
- error: false,
1951
- finished: false,
1952
- items: [],
1953
- value: void 0
1954
- };
1955
- const fn = (...parameters) => {
1956
- if (state.cleared) return Promise.reject(new Error(ONCE_MESSAGE_CLEARED));
1957
- if (state.finished) return state.error ? Promise.reject(state.value) : Promise.resolve(state.value);
1958
- if (state.called) return new Promise((resolve, reject) => {
1959
- state.items.push({
1960
- reject,
1961
- resolve
1962
- });
1963
- });
1964
- state.called = true;
1965
- return new Promise((resolve, reject) => {
1966
- state.items.push({
1967
- reject,
1968
- resolve
1969
- });
1970
- callback(...parameters).then((value) => {
1971
- handleOnceResult(state, value, false);
1972
- }).catch((error) => {
1973
- handleOnceResult(state, error, true);
1974
- });
1975
- });
1976
- };
1977
- Object.defineProperties(fn, {
1978
- called: {
1979
- enumerable: true,
1980
- get: () => state.called
1981
- },
1982
- clear: { value: () => clearState(state) },
1983
- cleared: {
1984
- enumerable: true,
1985
- get: () => state.cleared
1986
- },
1987
- error: {
1988
- enumerable: true,
1989
- get: () => state.error
1990
- },
1991
- finished: {
1992
- enumerable: true,
1993
- get: () => state.finished
1994
- }
1995
- });
1996
- return fn;
2250
+ function titleCase(value) {
2251
+ if (typeof value !== "string" || value.length === 0) return "";
2252
+ memoizedTitleCase ??= memoize((v) => v.length < 2 ? capitalize(v) : join(words(v).map(capitalize), " "));
2253
+ return memoizedTitleCase.run(value);
1997
2254
  }
1998
- function clearState(state) {
1999
- if (!state.called || state.cleared) return;
2000
- state.cleared = true;
2001
- state.value = void 0;
2255
+ function toCase(type, value, capitalizeAny, capitalizeFirst) {
2256
+ caseMemoizers[type] ??= memoize(toCaseCallback.bind({
2257
+ type,
2258
+ capitalizeAny,
2259
+ capitalizeFirst
2260
+ }));
2261
+ return caseMemoizers[type].run(value);
2002
2262
  }
2003
- function handleOnceResult(state, value, error) {
2004
- state.error = error;
2005
- state.finished = true;
2006
- state.value = value;
2007
- const items = state.items.splice(0);
2008
- const { length } = items;
2009
- for (let index = 0; index < length; index += 1) {
2010
- const { reject, resolve } = items[index];
2011
- if (error) reject(value);
2012
- else resolve(value);
2263
+ function toCaseCallback(value) {
2264
+ if (typeof value !== "string") return "";
2265
+ if (value.length < 1) return value;
2266
+ const { capitalizeAny, capitalizeFirst, type } = this;
2267
+ const parts = words(value);
2268
+ const partsLength = parts.length;
2269
+ const cased = [];
2270
+ for (let partIndex = 0; partIndex < partsLength; partIndex += 1) {
2271
+ const items = parts[partIndex].replace(STRING_EXPRESSION_ACRONYM, (full, one, two, three) => three === STRING_S ? full : `${one}-${two}${three}`).replace(STRING_EXPRESSION_CAMEL_CASE, STRING_REPLACEMENT_CAMEL_CASE).split("-");
2272
+ const itemsLength = items.length;
2273
+ const partResult = [];
2274
+ let itemCount = 0;
2275
+ for (let itemIndex = 0; itemIndex < itemsLength; itemIndex += 1) {
2276
+ const item = items[itemIndex];
2277
+ if (item.length === 0) continue;
2278
+ if (!capitalizeAny || itemCount === 0 && partIndex === 0 && !capitalizeFirst) partResult.push(item.toLocaleLowerCase());
2279
+ else partResult.push(capitalize(item));
2280
+ itemCount += 1;
2281
+ }
2282
+ cased.push(join(partResult, delimiters[type]));
2013
2283
  }
2284
+ return join(cased, delimiters[type]);
2014
2285
  }
2015
2286
  /**
2016
- * Create a function that can only be called once, returning the same value on subsequent calls
2287
+ * Convert a string to upper case
2017
2288
  *
2018
- * @param callback Callback to use once
2019
- * @returns _Once_ callback
2289
+ * @param value String to convert
2290
+ * @returns Upper-cased string
2020
2291
  */
2021
- function once(callback) {
2022
- assert(() => typeof callback === "function", ONCE_MESSAGE_EXPECTATION);
2023
- const state = {
2024
- called: false,
2025
- cleared: false,
2026
- value: void 0
2027
- };
2028
- const fn = (...parameters) => {
2029
- if (state.cleared) throw new Error(ONCE_MESSAGE_CLEARED);
2030
- if (state.called) return state.value;
2031
- state.called = true;
2032
- state.value = callback(...parameters);
2033
- return state.value;
2034
- };
2035
- Object.defineProperties(fn, {
2036
- called: {
2037
- enumerable: true,
2038
- get: () => state.called
2039
- },
2040
- clear: { value: () => clearState(state) },
2041
- cleared: {
2042
- enumerable: true,
2043
- get: () => state.cleared
2044
- }
2045
- });
2046
- return fn;
2292
+ function upperCase(value) {
2293
+ if (typeof value !== "string" || value.length === 0) return "";
2294
+ memoizedUpperCase ??= memoize((v) => v.toLocaleUpperCase());
2295
+ return memoizedUpperCase.run(value);
2047
2296
  }
2048
- const ONCE_MESSAGE_CLEARED = "Once has been cleared";
2049
- const ONCE_MESSAGE_EXPECTATION = "Once expected a function";
2050
- Object.defineProperty(once, "async", { value: asyncOnce });
2051
- //#endregion
2052
- //#region src/function/retry.ts
2053
- /**
2054
- * An error thrown when a retry fails
2055
- */
2056
- var RetryError = class extends Error {
2057
- original;
2058
- constructor(message, original) {
2059
- super(message);
2060
- this.original = original;
2061
- this.name = RETRY_ERROR_NAME;
2062
- }
2297
+ const STRING_CASE_CAMEL = "camel";
2298
+ const STRING_CASE_KEBAB = "kebab";
2299
+ const STRING_CASE_PASCAL = "pascal";
2300
+ const STRING_CASE_SNAKE = "snake";
2301
+ const STRING_DELIMTER_EMPTY = "";
2302
+ const STRING_DELIMITER_HYPHEN = "-";
2303
+ const STRING_DELIMITER_UNDERSCORE = "_";
2304
+ const STRING_EXPRESSION_CAMEL_CASE = /(\p{Ll})(\p{Lu})/gu;
2305
+ const STRING_EXPRESSION_ACRONYM = /(\p{Lu}*)(\p{Lu})(\p{Ll}+)/gu;
2306
+ const STRING_REPLACEMENT_CAMEL_CASE = "$1-$2";
2307
+ const STRING_S = "s";
2308
+ const caseMemoizers = {};
2309
+ const delimiters = {
2310
+ [STRING_CASE_CAMEL]: STRING_DELIMTER_EMPTY,
2311
+ [STRING_CASE_KEBAB]: STRING_DELIMITER_HYPHEN,
2312
+ [STRING_CASE_PASCAL]: STRING_DELIMTER_EMPTY,
2313
+ [STRING_CASE_SNAKE]: STRING_DELIMITER_UNDERSCORE
2063
2314
  };
2315
+ let memoizedCapitalize;
2316
+ let memoizedLowerCase;
2317
+ let memoizedTitleCase;
2318
+ let memoizedUpperCase;
2319
+ //#endregion
2320
+ //#region src/internal/value/equal.ts
2064
2321
  /**
2065
- * Retry a callback a specified number of times, with a delay between attempts
2322
+ * Deregister a equality comparison handler for a specific class
2066
2323
  *
2067
- * _Available as `asyncRetry` and `retry.async`_
2324
+ * _Available as `deregisterEqualizer` and `equal.deregister`_
2068
2325
  *
2069
- * @param callback Callback to retry
2070
- * @param options Retry options
2071
- * @returns Callback result
2326
+ * @param constructor Class constructor
2072
2327
  */
2073
- async function asyncRetry(callback, options) {
2074
- if (typeof callback !== "function") throw new TypeError(RETRY_MESSAGE_EXPECTATION);
2075
- async function handle() {
2076
- try {
2077
- const result = await callback();
2078
- resolver(result);
2079
- } catch (error) {
2080
- if (attempts >= times || !when(error)) rejector(new RetryError(RETRY_MESSAGE_FAILED, error));
2081
- else {
2082
- attempts += 1;
2083
- timer();
2084
- }
2085
- }
2086
- }
2087
- const { delay, times, when } = getRetryOptions(options);
2088
- const timer = getTimer(TIMER_WAIT, handle, delay);
2089
- let attempts = 0;
2090
- let rejector;
2091
- let resolver;
2092
- return new Promise((resolve, reject) => {
2093
- rejector = reject;
2094
- resolver = resolve;
2095
- handle();
2096
- });
2328
+ function deregisterEqualizer(constructor) {
2329
+ equal.handlers.deregister(constructor);
2097
2330
  }
2098
- function getRetryNumber(value) {
2099
- return typeof value === "number" && value > 0 ? value : 0;
2331
+ function filterKey(key, options) {
2332
+ if (typeof key !== "string") return true;
2333
+ if (options.ignoreExpressions.enabled && options.ignoreExpressions.values.some((expression) => expression.test(key))) return false;
2334
+ if (options.ignoreKeys.enabled && options.ignoreKeys.values.has(key)) return false;
2335
+ return true;
2100
2336
  }
2101
- function getRetryOptions(input) {
2102
- const options = isPlainObject(input) ? input : {};
2103
- return {
2104
- delay: getRetryNumber(options.delay),
2105
- times: getRetryNumber(options.times),
2106
- when: typeof options.when === "function" ? options.when : shouldRetry
2107
- };
2337
+ function equal(first, second, options) {
2338
+ return equalValue(first, second, getEqualOptions(options));
2108
2339
  }
2109
- /**
2110
- * Retry a callback a specified number of times
2111
- *
2112
- * @param callback Callback to retry
2113
- * @param options Retry options
2114
- * @returns Callback result
2115
- */
2116
- function retry(callback, options) {
2117
- if (typeof callback !== "function") throw new TypeError(RETRY_MESSAGE_EXPECTATION);
2118
- const { times, when } = getRetryOptions(options);
2119
- let last;
2120
- for (let index = 0; index <= times; index += 1) try {
2121
- return callback();
2122
- } catch (error) {
2123
- if (index >= times || !when(error)) {
2124
- last = error;
2125
- break;
2126
- }
2340
+ equal.handlers = getCompareHandlers(equal, { callback: Object.is });
2341
+ equal.deregister = deregisterEqualizer;
2342
+ equal.initialize = initializeEqualizer;
2343
+ equal.register = registerEqualizer;
2344
+ function equalArray(first, second, options) {
2345
+ const { length } = first;
2346
+ if (length !== second.length) return false;
2347
+ let offset = 0;
2348
+ if (length >= EQUAL_ARRAY_THRESHOLD) {
2349
+ offset = Math.round(length / EQUAL_ARRAY_PEEK_PERCENTAGE);
2350
+ offset = offset > EQUAL_ARRAY_THRESHOLD ? EQUAL_ARRAY_THRESHOLD : offset;
2351
+ for (let index = 0; index < offset; index += 1) if (!(equalValue(first[index], second[index], options) && equalValue(first[length - index - 1], second[length - index - 1], options))) return false;
2127
2352
  }
2128
- throw new RetryError(RETRY_MESSAGE_FAILED, last);
2129
- }
2130
- function shouldRetry() {
2353
+ const end = length - offset;
2354
+ for (let index = offset; index < end; index += 1) if (!equalValue(first[index], second[index], options)) return false;
2131
2355
  return true;
2132
2356
  }
2133
- const RETRY_ERROR_NAME = "RetryError";
2134
- const RETRY_MESSAGE_EXPECTATION = "Retry expected a function";
2135
- const RETRY_MESSAGE_FAILED = "Retry failed";
2136
- Object.defineProperty(retry, "async", { value: asyncRetry });
2137
- //#endregion
2138
- //#region src/function/work.ts
2139
- function asyncFlow(...fns) {
2140
- assertFlowFunctions(fns);
2141
- return (...args) => asyncWork(args.map((value) => {
2142
- if (isError(value)) throw value.error;
2143
- return isOk(value) ? value.value : value;
2144
- }), fns, true);
2145
- }
2146
- function flow(...fns) {
2147
- assertFlowFunctions(fns);
2148
- return (...args) => work(args.map((value) => {
2149
- if (isError(value)) throw value.error;
2150
- return isOk(value) ? value.value : value;
2151
- }), fns, true);
2357
+ function equalArrayBuffer(first, second, options) {
2358
+ return first.byteLength === second.byteLength ? equalArray(new Uint8Array(first), new Uint8Array(second), options) : false;
2152
2359
  }
2153
- async function asyncPipe(value, ...pipes) {
2154
- assertPipeFunctions(pipes);
2155
- return asyncWork(value, pipes, false);
2360
+ function equalDataView(first, second, options) {
2361
+ return first.byteOffset === second.byteOffset ? equalArrayBuffer(first.buffer, second.buffer, options) : false;
2156
2362
  }
2157
- function pipe(value, ...pipes) {
2158
- assertPipeFunctions(pipes);
2159
- return work(value, pipes, false);
2363
+ function equalMap(first, second, options) {
2364
+ const { size } = first;
2365
+ if (size !== second.size) return false;
2366
+ const firstKeys = [...first.keys()];
2367
+ for (let index = 0; index < size; index += 1) {
2368
+ const key = firstKeys[index];
2369
+ if (!second.has(key) || !equalValue(first.get(key), second.get(key), options)) return false;
2370
+ }
2371
+ return true;
2160
2372
  }
2161
- async function asyncWork(initial, functions, flow) {
2162
- const { length } = functions;
2163
- let transformed = unwrapValue(initial);
2373
+ function equalPlainObject(first, second, options) {
2374
+ let firstKeys = [...Object.keys(first), ...Object.getOwnPropertySymbols(first)];
2375
+ let secondKeys = [...Object.keys(second), ...Object.getOwnPropertySymbols(second)];
2376
+ if (options.ignoreKeys.enabled || options.ignoreExpressions.enabled) {
2377
+ firstKeys = firstKeys.filter((key) => filterKey(key, options));
2378
+ secondKeys = secondKeys.filter((key) => filterKey(key, options));
2379
+ }
2380
+ const secondSet = secondKeys.length >= EQUAL_MINIMUM_LENGTH_FOR_SET ? new Set(secondKeys) : void 0;
2381
+ const { length } = firstKeys;
2382
+ if (length !== secondKeys.length) return false;
2164
2383
  for (let index = 0; index < length; index += 1) {
2165
- const fn = functions[index];
2166
- transformed = unwrapValue(flow && index === 0 && Array.isArray(initial) ? await fn(...initial) : await fn(transformed));
2384
+ const key = firstKeys[index];
2385
+ if (!(secondSet?.has(key) ?? secondKeys.includes(key)) || !equalValue(first[key], second[key], options)) return false;
2167
2386
  }
2168
- return transformed;
2387
+ return true;
2169
2388
  }
2170
- function unwrapValue(value, flow, nested) {
2171
- if (typeof value === "function") {
2172
- if (nested != null) throw new TypeError(WORK_MESSAGE_NESTING);
2173
- return unwrapValue(value(), flow, true);
2389
+ function equalProperties(first, second, properties, options) {
2390
+ const { length } = properties;
2391
+ for (let index = 0; index < length; index += 1) {
2392
+ const property = properties[index];
2393
+ if (!equalValue(first[property], second[property], options)) return false;
2174
2394
  }
2175
- if (flow != null && value instanceof Promise) throw new TypeError(flow ? WORK_MESSAGE_FLOW_PROMISE : WORK_MESSAGE_PIPE_PROMISE);
2176
- if (isError(value)) throw value.error;
2177
- return isOk(value) ? value.value : value;
2395
+ return true;
2178
2396
  }
2179
- function work(initial, functions, flow) {
2180
- const { length } = functions;
2181
- let transformed = unwrapValue(initial, flow);
2182
- for (let index = 0; index < length; index += 1) {
2183
- const fn = functions[index];
2184
- transformed = unwrapValue(flow && index === 0 && Array.isArray(initial) ? fn(...initial) : fn(transformed), flow);
2397
+ function equalSet(first, second, options) {
2398
+ const { size } = first;
2399
+ if (size !== second.size) return false;
2400
+ const firstValues = [...first];
2401
+ const secondValues = [...second];
2402
+ for (let index = 0; index < size; index += 1) {
2403
+ const firstValue = firstValues[index];
2404
+ if (isPrimitive(firstValue) ? !second.has(firstValue) : !secondValues.some((secondValue) => equalValue(firstValue, secondValue, options))) return false;
2185
2405
  }
2186
- return transformed;
2406
+ return true;
2187
2407
  }
2188
- const WORK_MESSAGE_FLOW_ARRAY = "Flow expected to receive an array of functions";
2189
- const WORK_MESSAGE_FLOW_PROMISE = "Synchronous Flow received a promise. Use `flow.async` instead.";
2190
- const WORK_MESSAGE_NESTING = "Return values are too deeply nested.";
2191
- const WORK_MESSAGE_PIPE_ARRAY = "Pipe expected to receive an array of functions";
2192
- const WORK_MESSAGE_PIPE_PROMISE = "Synchronous Pipe received a promise. Use `pipe.async` instead.";
2193
- const assertFlowFunctions = assert.condition((value) => Array.isArray(value) && value.every((item) => typeof item === "function"), WORK_MESSAGE_FLOW_ARRAY, TypeError);
2194
- const assertPipeFunctions = assert.condition((value) => Array.isArray(value) && value.every((item) => typeof item === "function"), WORK_MESSAGE_PIPE_ARRAY, TypeError);
2195
- flow.async = asyncFlow;
2196
- pipe.async = asyncPipe;
2197
- Object.defineProperty(flow, "async", { value: asyncFlow });
2198
- Object.defineProperty(pipe, "async", { value: asyncPipe });
2199
- //#endregion
2200
- //#region src/internal/abort.ts
2201
- function createAborter(value, onAbort) {
2202
- if (!(value instanceof AbortSignal)) return;
2203
- value.addEventListener(ABORT_EVENT, onAbort, ABORT_OPTIONS);
2204
- return {
2205
- callback: onAbort,
2206
- signal: value,
2207
- cancel: () => value.removeEventListener(ABORT_EVENT, onAbort)
2208
- };
2408
+ function equalTypedArray(first, second) {
2409
+ if (first.constructor !== second.constructor) return false;
2410
+ if (first.byteLength !== second.byteLength) return false;
2411
+ const { length } = first;
2412
+ for (let index = 0; index < length; index += 1) if (first[index] !== second[index]) return false;
2413
+ return true;
2209
2414
  }
2210
- const ABORT_EVENT = "abort";
2211
- const ABORT_OPTIONS = { once: true };
2212
- //#endregion
2213
- //#region src/internal/subscription.ts
2214
- function addSubscription(subscriptions, subscription, state) {
2215
- const { key, value } = state.parameters;
2216
- const { items, values } = subscriptions.state;
2217
- if (!isKey(key)) {
2218
- items.any.add(subscription);
2219
- values.from.any.set(value, subscription);
2220
- values.to.any.set(subscription, value);
2221
- return;
2222
- }
2223
- /* istanbul ignore if */
2224
- if (items.keyed == null || values.from.keyed == null || values.to.keyed == null)
2225
- // istanbul ignore next
2226
- return;
2227
- let keyedItems = items.keyed.get(key);
2228
- if (keyedItems == null) {
2229
- keyedItems = /* @__PURE__ */ new Set();
2230
- items.keyed.set(key, keyedItems);
2231
- }
2232
- keyedItems.add(subscription);
2233
- let keyedFrom = values.from.keyed.get(key);
2234
- if (keyedFrom == null) {
2235
- keyedFrom = /* @__PURE__ */ new Map();
2236
- values.from.keyed.set(key, keyedFrom);
2237
- }
2238
- keyedFrom.set(value, subscription);
2239
- let keyedTo = values.to.keyed.get(key);
2240
- if (keyedTo == null) {
2241
- keyedTo = /* @__PURE__ */ new Map();
2242
- values.to.keyed.set(key, keyedTo);
2415
+ function equalValue(first, second, options) {
2416
+ if (options.relaxedNullish && first == null && second == null) return true;
2417
+ switch (true) {
2418
+ case Object.is(first, second): return true;
2419
+ case first == null || second == null: return first === second;
2420
+ case typeof first !== typeof second: return false;
2421
+ case typeof first === "string" && options.ignoreCase === true: return Object.is(first.toLocaleLowerCase(), second.toLocaleLowerCase());
2422
+ case first instanceof ArrayBuffer && second instanceof ArrayBuffer: return equalArrayBuffer(first, second, options);
2423
+ case first instanceof Date && second instanceof Date: return Object.is(first.getTime(), second.getTime());
2424
+ case first instanceof DataView && second instanceof DataView: return equalDataView(first, second, options);
2425
+ case first instanceof Error && second instanceof Error: return equalProperties(first, second, EQUAL_ERROR_PROPERTIES, options);
2426
+ case first instanceof Map && second instanceof Map: return equalMap(first, second, options);
2427
+ case first instanceof RegExp && second instanceof RegExp: return equalProperties(first, second, EQUAL_EXPRESSION_PROPERTIES, options);
2428
+ case first instanceof Set && second instanceof Set: return equalSet(first, second, options);
2429
+ case Array.isArray(first) && Array.isArray(second): return equalArray(first, second, options);
2430
+ case isPlainObject(first) && isPlainObject(second): return equalPlainObject(first, second, options);
2431
+ case isTypedArray(first) && isTypedArray(second): return equalTypedArray(first, second);
2432
+ default: return equal.handlers.handle(first, second, options);
2243
2433
  }
2244
- keyedTo.set(subscription, value);
2245
- }
2246
- function clearSubscriptions(store) {
2247
- for (const susbcription of store.values.to.any.keys()) susbcription.unsubscribe();
2248
- if (store.values.to.keyed != null) for (const values of store.values.to.keyed.values()) for (const susbcription of values.keys()) susbcription.unsubscribe();
2249
- }
2250
- function createSubscription(subscriptions, property, parameters) {
2251
- if (parameters.signal?.aborted ?? false) throw new Error(parameters.signal?.reason);
2252
- const state = {
2253
- parameters,
2254
- active: true
2255
- };
2256
- const existing = getExistingSubscription(subscriptions, state);
2257
- if (existing != null) return [existing, true];
2258
- if (subscriptions.state.keys != null && isKey(parameters.key) && !subscriptions.state.keys.has(parameters.key)) throw new Error(SUBSCRIPTION_INVALID_KEY);
2259
- state.aborter = createAborter(parameters.signal, () => unsubscribe(subscriptions, instance, state));
2260
- const instance = { unsubscribe: () => unsubscribe(subscriptions, instance, state) };
2261
- Object.defineProperties(instance, {
2262
- [SUBSCRIPTION_PROPERTY]: { value: true },
2263
- [property.key]: { value: property.value ?? "subscription" },
2264
- active: {
2265
- enumerable: true,
2266
- get: () => (parameters.isActive?.() ?? true) && state.active
2267
- }
2268
- });
2269
- addSubscription(subscriptions, instance, state);
2270
- return [Object.freeze(instance), false];
2271
2434
  }
2272
- function createSubscriptions(parameters) {
2273
- const { keys, property } = parameters;
2274
- const state = {
2275
- keys,
2276
- items: {
2277
- any: /* @__PURE__ */ new Set(),
2278
- keyed: keys == null ? void 0 : /* @__PURE__ */ new Map()
2435
+ function getEqualOptions(input) {
2436
+ const options = {
2437
+ ignoreCase: false,
2438
+ ignoreExpressions: {
2439
+ enabled: false,
2440
+ values: []
2279
2441
  },
2280
- values: {
2281
- from: {
2282
- any: /* @__PURE__ */ new Map(),
2283
- keyed: keys == null ? void 0 : /* @__PURE__ */ new Map()
2284
- },
2285
- to: {
2286
- any: /* @__PURE__ */ new Map(),
2287
- keyed: keys == null ? void 0 : /* @__PURE__ */ new Map()
2288
- }
2289
- }
2290
- };
2291
- const instance = {
2292
- state,
2293
- clear: () => clearSubscriptions(state),
2294
- create: (parameters) => createSubscription(instance, property, parameters)
2442
+ ignoreKeys: {
2443
+ enabled: false,
2444
+ values: /* @__PURE__ */ new Set()
2445
+ },
2446
+ relaxedNullish: false
2295
2447
  };
2296
- return instance;
2448
+ if (typeof input === "boolean") {
2449
+ options.ignoreCase = input;
2450
+ return options;
2451
+ }
2452
+ if (isNonPlainObject(input)) return options;
2453
+ options.ignoreCase = typeof input.ignoreCase === "boolean" ? input.ignoreCase : false;
2454
+ options.ignoreExpressions.values = (Array.isArray(input.ignoreKeys) ? input.ignoreKeys : [input.ignoreKeys]).filter((key) => key instanceof RegExp);
2455
+ options.ignoreKeys.values = new Set((Array.isArray(input.ignoreKeys) ? input.ignoreKeys : [input.ignoreKeys]).filter((key) => typeof key === "string"));
2456
+ options.ignoreExpressions.enabled = options.ignoreExpressions.values.length > 0;
2457
+ options.ignoreKeys.enabled = options.ignoreKeys.values.size > 0;
2458
+ options.relaxedNullish = input.relaxedNullish === true;
2459
+ return options;
2297
2460
  }
2298
- function getExistingSubscription(subscriptions, state) {
2299
- const { parameters } = state;
2300
- const { values } = subscriptions.state;
2301
- return isKey(parameters.key) ? values.from.keyed?.get(parameters.key)?.get(parameters.value) : values.from.any.get(parameters.value);
2461
+ /**
2462
+ * Create an equalizer with predefined options
2463
+ *
2464
+ * _Available as `initializeEqualizer` and `equal.initialize`_
2465
+ *
2466
+ * @param options Comparison options
2467
+ * @returns Equalizer function
2468
+ */
2469
+ function initializeEqualizer(options) {
2470
+ const actual = getEqualOptions(options);
2471
+ const equalizer = (first, second) => equalValue(first, second, actual);
2472
+ equalizer.deregister = deregisterEqualizer;
2473
+ equalizer.register = registerEqualizer;
2474
+ return equalizer;
2302
2475
  }
2303
2476
  /**
2304
- * Is the value a subscription?
2477
+ * Register a equality comparison function for a specific class
2305
2478
  *
2306
- * @param value Value to check
2307
- * @returns `true` if the value is a subscription, otherwise `false`
2479
+ * _Available as `registerEqualizer` and `equal.register`_
2480
+ *
2481
+ * @param constructor Class constructor
2482
+ * @param handler Comparison function
2308
2483
  */
2309
- function isSubscription(value) {
2310
- return isPlainObject(value) && SUBSCRIPTION_PROPERTY in value && value[SUBSCRIPTION_PROPERTY] === true;
2484
+ function registerEqualizer(constructor, handler) {
2485
+ equal.handlers.register(constructor, handler);
2311
2486
  }
2312
- function removeFromStore(items, values, subscription, value, key) {
2313
- items.delete(subscription);
2314
- if (key == null) {
2315
- values.from.any.delete(value);
2316
- values.to.any.delete(subscription);
2317
- } else {
2318
- values.from.keyed?.get(key)?.delete(value);
2319
- values.to.keyed?.get(key)?.delete(subscription);
2320
- }
2487
+ const EQUAL_ARRAY_PEEK_PERCENTAGE = 10;
2488
+ const EQUAL_ARRAY_THRESHOLD = 100;
2489
+ const EQUAL_ERROR_PROPERTIES = ["name", "message"];
2490
+ const EQUAL_EXPRESSION_PROPERTIES = ["source", "flags"];
2491
+ const EQUAL_MINIMUM_LENGTH_FOR_SET = 16;
2492
+ //#endregion
2493
+ //#region src/internal/value/get.ts
2494
+ function getValue(data, path, ignoreCase) {
2495
+ return getNestedValue(data, path, ignoreCase === true).value;
2321
2496
  }
2322
- function removeSubscription(subscriptions, subscription, state) {
2323
- if (!state.active) return;
2324
- state.aborter = void 0;
2325
- state.active = false;
2326
- state.parameters.isActive = void 0;
2327
- state.parameters.signal = void 0;
2328
- const { key, value } = state.parameters;
2329
- const { items, values } = subscriptions.state;
2330
- if (!isKey(key)) {
2331
- removeFromStore(items.any, values, subscription, value);
2332
- return;
2497
+ //#endregion
2498
+ //#region src/internal/value/set.ts
2499
+ function setValue(data, path, value, ignoreCase) {
2500
+ if (typeof data !== "object" || data === null || typeof path !== "string" || path.trim().length === 0) return data;
2501
+ const shouldIgnoreCase = ignoreCase === true;
2502
+ const paths = getPaths(path, shouldIgnoreCase);
2503
+ if (typeof paths === "string") {
2504
+ handleValue(data, paths, value, false, shouldIgnoreCase);
2505
+ return data;
2333
2506
  }
2334
- const keyed = items.keyed?.get(key);
2335
- /* istanbul ignore if */
2336
- if (items.keyed == null || keyed == null)
2337
- // istanbul ignore next
2338
- return;
2339
- removeFromStore(keyed, values, subscription, value, key);
2340
- if (keyed.size === 0) items.keyed.delete(key);
2341
- }
2342
- function unsubscribe(subscriptions, subscription, state) {
2343
- state.aborter?.cancel();
2344
- removeSubscription(subscriptions, subscription, state);
2507
+ const { length } = paths;
2508
+ const lastIndex = length - 1;
2509
+ let target = data;
2510
+ for (let index = 0; index < length; index += 1) {
2511
+ const currentPath = paths[index];
2512
+ if (index === lastIndex) {
2513
+ handleValue(target, currentPath, value, false, shouldIgnoreCase);
2514
+ break;
2515
+ }
2516
+ let next = handleValue(target, currentPath, null, true, shouldIgnoreCase).value;
2517
+ if (typeof next !== "object" || next === null) {
2518
+ const nextPath = paths[index + 1];
2519
+ if (SET_EXPRESSION_INDEX.test(nextPath)) next = Array.from({ length: Number(nextPath) + 1 }, () => void 0);
2520
+ else next = {};
2521
+ target[currentPath] = next;
2522
+ }
2523
+ target = next;
2524
+ }
2525
+ return data;
2345
2526
  }
2346
- const SUBSCRIPTION_INVALID_KEY = "Invalid key for subscription";
2347
- const SUBSCRIPTION_PROPERTY = "$subscription";
2527
+ const SET_EXPRESSION_INDEX = /^\d+$/;
2348
2528
  //#endregion
2349
- //#region src/herald.ts
2350
- function createEvents(herald, state) {
2351
- const events = {};
2352
- Object.defineProperty(events, HERALD_PROPERTY, { value: HERALD_NAME_EVENTS });
2353
- for (const key of state.keys) events[key] = (callback, signal) => herald.subscribe(key, callback, signal);
2354
- return Object.freeze(events);
2355
- }
2356
- function emitForHerald(state, event, ...parameters) {
2357
- const items = state.subscriptions.state.values.from.keyed?.get(event);
2358
- if (items == null || items.size === 0) return;
2359
- for (const [callback] of items) callback(...parameters);
2360
- }
2361
- function getHeraldSubscriptionProperty(input) {
2362
- if (input == null) return heraldSubscription;
2363
- const property = isPlainObject(input) ? input : {};
2364
- if (typeof property.key !== "string" || property.value != null && typeof property.value !== "string") throw new Error(HERALD_MESSAGE_PROPERTY);
2529
+ //#region src/internal/abort.ts
2530
+ function createAborter(value, onAbort) {
2531
+ if (!(value instanceof AbortSignal)) return;
2532
+ value.addEventListener(ABORT_EVENT, onAbort, ABORT_OPTIONS);
2365
2533
  return {
2366
- key: property.key,
2367
- value: property.value
2534
+ callback: onAbort,
2535
+ signal: value,
2536
+ cancel: () => value.removeEventListener(ABORT_EVENT, onAbort)
2368
2537
  };
2369
2538
  }
2370
- function getHeraldState(input) {
2371
- const options = isPlainObject(input) ? input : {};
2372
- if (!Array.isArray(options.names) || options.names.length === 0 || !options.names.every((name) => typeof name === "string")) throw new Error(HERALD_MESSAGE_ARRAY);
2373
- if (options.onCreate != null && typeof options.onCreate !== "function") throw new Error(HERALD_MESSAGE_ONCREATE);
2374
- const keys = new Set(options.names);
2375
- return {
2376
- keys,
2377
- subscriptions: createSubscriptions({
2378
- keys,
2379
- property: getHeraldSubscriptionProperty(options.property)
2380
- }),
2381
- onCreate: options.onCreate
2382
- };
2539
+ const ABORT_EVENT = "abort";
2540
+ const ABORT_OPTIONS = { once: true };
2541
+ //#endregion
2542
+ //#region src/internal/defaults.ts
2543
+ function getBooleanOrDefault(value, defaultValue) {
2544
+ return typeof value === "boolean" ? value : defaultValue;
2545
+ }
2546
+ function getNumberOrDefault(value, defaultValue, minimum) {
2547
+ return typeof value === "number" && !Number.isNaN(value) && value >= (minimum ?? 0) ? value : defaultValue;
2383
2548
  }
2549
+ //#endregion
2550
+ //#region src/promise/constants.ts
2551
+ const PROMISE_ERROR_NAME = "PromiseTimeoutError";
2552
+ const PROMISE_MESSAGE_EXPECTATION_ATTEMPT = "Attempt expected a function or a promise";
2553
+ const PROMISE_MESSAGE_EXPECTATION_RESULT = "toResult expected a Promise";
2554
+ const PROMISE_MESSAGE_EXPECTATION_TIMED = "Timed function expected a Promise";
2555
+ const PROMISE_MESSAGE_TIMEOUT = "Promise timed out";
2556
+ const PROMISE_STRATEGY_ALL = /* @__PURE__ */ new Set(["complete", "first"]);
2557
+ const PROMISE_STRATEGY_DEFAULT = "complete";
2558
+ const PROMISE_TYPE_FULFILLED = "fulfilled";
2559
+ const PROMISE_TYPE_REJECTED = "rejected";
2560
+ //#endregion
2561
+ //#region src/promise/models.ts
2384
2562
  /**
2385
- * Create a _Herald_ for announcing named events
2386
- *
2387
- * @param names Event names
2388
- * @param property Optional property for subscription identification _(defaults to `$herald`)_
2389
- * @returns _Herald_ instance
2563
+ * A _Promise_ that can be canceled
2390
2564
  */
2391
- function herald(options) {
2392
- const state = getHeraldState(options);
2393
- const instance = {
2394
- clear: () => state.subscriptions.clear(),
2395
- emit: (event, ...parameters) => emitForHerald(state, event, ...parameters),
2396
- observed: (event) => (state.subscriptions.state.items.keyed?.get(event)?.size ?? 0) > 0,
2397
- subscribe: (key, callback, signal) => subscribeToHerald(state, key, callback, signal)
2565
+ var CancelablePromise = class extends Promise {
2566
+ #rejector;
2567
+ constructor(executor) {
2568
+ let rejector;
2569
+ super((resolve, reject) => {
2570
+ rejector = reject;
2571
+ executor(resolve, reject);
2572
+ });
2573
+ this.#rejector = rejector;
2574
+ }
2575
+ /**
2576
+ * Cancel the _Promise_, rejecting it with an optional reason
2577
+ *
2578
+ * @param reason Optional reason for canceling the _Promise_
2579
+ */
2580
+ cancel(reason) {
2581
+ this.#rejector?.(reason);
2582
+ this.#rejector = void 0;
2583
+ }
2584
+ };
2585
+ /**
2586
+ * An error thrown when a promise times out
2587
+ */
2588
+ var PromiseTimeoutError = class extends Error {
2589
+ constructor() {
2590
+ super(PROMISE_MESSAGE_TIMEOUT);
2591
+ this.name = PROMISE_ERROR_NAME;
2592
+ }
2593
+ };
2594
+ //#endregion
2595
+ //#region src/promise/helpers.ts
2596
+ function getPromiseOptions(input) {
2597
+ if (typeof input === "number") return { time: getNumberOrDefault(input, 0) };
2598
+ if (input instanceof AbortSignal) return {
2599
+ signal: input,
2600
+ time: 0
2398
2601
  };
2399
- Object.defineProperties(instance, {
2400
- [HERALD_PROPERTY]: { value: HERALD_NAME_HERALD },
2401
- events: {
2402
- enumerable: true,
2403
- value: createEvents(instance, state)
2404
- }
2405
- });
2406
- return Object.freeze(instance);
2602
+ const options = typeof input === "object" && input !== null ? input : {};
2603
+ return {
2604
+ signal: options.signal instanceof AbortSignal ? options.signal : void 0,
2605
+ time: getNumberOrDefault(options.time, 0)
2606
+ };
2607
+ }
2608
+ function getPromisesOptions(input) {
2609
+ if (typeof input === "string") return { strategy: getStrategyOrDefault(input) };
2610
+ if (input instanceof AbortSignal) return {
2611
+ signal: input,
2612
+ strategy: PROMISE_STRATEGY_DEFAULT
2613
+ };
2614
+ const options = typeof input === "object" && input !== null ? input : {};
2615
+ return {
2616
+ signal: options.signal instanceof AbortSignal ? options.signal : void 0,
2617
+ strategy: getStrategyOrDefault(options.strategy)
2618
+ };
2619
+ }
2620
+ function getResultsFromPromises(promised) {
2621
+ return promised.map((result) => isFulfilled(result) ? ok(result.value) : error(result.reason));
2622
+ }
2623
+ function getStrategyOrDefault(value) {
2624
+ return PROMISE_STRATEGY_ALL.has(value) ? value : PROMISE_STRATEGY_DEFAULT;
2407
2625
  }
2408
2626
  /**
2409
- * Is the value events for a herald?
2627
+ * Is the value a fulfilled _Promise_ result?
2410
2628
  *
2411
2629
  * @param value Value to check
2412
- * @returns `true` if the value is events for a herald, otherwise `false`
2630
+ * @returns `true` if the value is a fulfilled _Promise_ result, otherwise `false`
2413
2631
  */
2414
- function isHeraldEvents(value) {
2415
- return isHeraldInstance(HERALD_NAME_EVENTS, value);
2632
+ function isFulfilled(value) {
2633
+ return isType(value, PROMISE_TYPE_FULFILLED);
2416
2634
  }
2417
2635
  /**
2418
- * Is the value a herald?
2636
+ * Is the value a rejected _Promise_ result?
2419
2637
  *
2420
2638
  * @param value Value to check
2421
- * @returns `true` if the value is a herald, otherwise `false`
2639
+ * @returns `true` if the value is a rejected _Promise_ result, otherwise `false`
2422
2640
  */
2423
- function isHerald(value) {
2424
- return isHeraldInstance(HERALD_NAME_HERALD, value);
2641
+ function isRejected(value) {
2642
+ return isType(value, PROMISE_TYPE_REJECTED);
2425
2643
  }
2426
- function isHeraldInstance(name, value) {
2427
- return isPlainObject(value) && HERALD_PROPERTY in value && value[HERALD_PROPERTY] === name;
2644
+ function isType(value, type) {
2645
+ return typeof value === "object" && value !== null && value.status === type;
2428
2646
  }
2647
+ //#endregion
2648
+ //#region src/result/misc.ts
2429
2649
  /**
2430
- * Is the value a herald subscription?
2650
+ * Converts a _Result_ to a _Promise_
2431
2651
  *
2432
- * @param value Value to check
2433
- * @returns `true` if the value is a herald subscription, otherwise `false`
2652
+ * Resolves if ok, rejects for error
2653
+ *
2654
+ * @param result _Result_ to convert
2655
+ * @returns Promised result
2434
2656
  */
2435
- function isHeraldSubscription(value) {
2436
- return isSubscription(value) && value[HERALD_PROPERTY] === "subscription";
2437
- }
2438
- function subscribeToHerald(state, key, callback, signal) {
2439
- const [subscription, existing] = state.subscriptions.create({
2440
- key,
2441
- signal,
2442
- value: callback
2443
- });
2444
- if (!existing) state.onCreate?.(key, callback, subscription);
2445
- return subscription;
2657
+ async function toPromise(result) {
2658
+ const actual = typeof result === "function" ? result() : result;
2659
+ if (!isResult(actual)) return Promise.reject(new Error(RESULT_MESSAGE_PROMISE));
2660
+ return isOk(actual) ? Promise.resolve(actual.value) : Promise.reject(actual.error);
2446
2661
  }
2447
- const HERALD_PROPERTY = "$herald";
2448
- const HERALD_MESSAGE_ARRAY = "Herald requires an array of event names.";
2449
- const HERALD_MESSAGE_ONCREATE = `Herald requires a valid onCreate callback for subscription creation`;
2450
- const HERALD_MESSAGE_PROPERTY = `Herald requires valid property information for subscription identification`;
2451
- const HERALD_NAME_EVENTS = "events";
2452
- const HERALD_NAME_HERALD = "herald";
2453
- const heraldSubscription = { key: HERALD_PROPERTY };
2662
+ const RESULT_MESSAGE_PROMISE = "toPromise expected to receive a Result";
2454
2663
  //#endregion
2455
- //#region src/internal/value/equal.ts
2664
+ //#region src/promise/misc.ts
2456
2665
  /**
2457
- * Deregister a equality comparison handler for a specific class
2458
- *
2459
- * _Available as `deregisterEqualizer` and `equal.deregister`_
2666
+ * Create a cancelable _Promise_
2460
2667
  *
2461
- * @param constructor Class constructor
2668
+ * @param executor Executor function for the _Promise_
2669
+ * @returns Cancelable _Promise_
2462
2670
  */
2463
- function deregisterEqualizer(constructor) {
2464
- equal.handlers.deregister(constructor);
2465
- }
2466
- function filterKey(key, options) {
2467
- if (typeof key !== "string") return true;
2468
- if (options.ignoreExpressions.enabled && options.ignoreExpressions.values.some((expression) => expression.test(key))) return false;
2469
- if (options.ignoreKeys.enabled && options.ignoreKeys.values.has(key)) return false;
2470
- return true;
2471
- }
2472
- function equal(first, second, options) {
2473
- return equalValue(first, second, getEqualOptions(options));
2671
+ function cancelable(executor) {
2672
+ return new CancelablePromise(executor);
2474
2673
  }
2475
- equal.handlers = getCompareHandlers(equal, { callback: Object.is });
2476
- equal.deregister = deregisterEqualizer;
2477
- equal.initialize = initializeEqualizer;
2478
- equal.register = registerEqualizer;
2479
- function equalArray(first, second, options) {
2480
- const { length } = first;
2481
- if (length !== second.length) return false;
2482
- let offset = 0;
2483
- if (length >= EQUAL_ARRAY_THRESHOLD) {
2484
- offset = Math.round(length / EQUAL_ARRAY_PEEK_PERCENTAGE);
2485
- offset = offset > EQUAL_ARRAY_THRESHOLD ? EQUAL_ARRAY_THRESHOLD : offset;
2486
- for (let index = 0; index < offset; index += 1) if (!(equalValue(first[index], second[index], options) && equalValue(first[length - index - 1], second[length - index - 1], options))) return false;
2674
+ function handleResult(status, parameters) {
2675
+ const { aborter, complete, data, handlers, index, value } = parameters;
2676
+ if (aborter?.signal.aborted ?? false) return;
2677
+ if (!complete && status === "rejected") {
2678
+ settlePromise(handlers.reject, value, aborter);
2679
+ return;
2487
2680
  }
2488
- const end = length - offset;
2489
- for (let index = offset; index < end; index += 1) if (!equalValue(first[index], second[index], options)) return false;
2490
- return true;
2681
+ data.result[index] = !complete ? value : status === "fulfilled" ? {
2682
+ status,
2683
+ value
2684
+ } : {
2685
+ status,
2686
+ reason: value
2687
+ };
2688
+ if (index === data.last) settlePromise(handlers.resolve, data.result, aborter);
2491
2689
  }
2492
- function equalArrayBuffer(first, second, options) {
2493
- return first.byteLength === second.byteLength ? equalArray(new Uint8Array(first), new Uint8Array(second), options) : false;
2690
+ function settlePromise(settler, value, aborter) {
2691
+ aborter?.cancel();
2692
+ settler(value);
2494
2693
  }
2495
- function equalDataView(first, second, options) {
2496
- return first.byteOffset === second.byteOffset ? equalArrayBuffer(first.buffer, second.buffer, options) : false;
2694
+ async function toResult(value) {
2695
+ const actual = typeof value === "function" ? value() : value;
2696
+ if (!(actual instanceof Promise)) return Promise.reject(/* @__PURE__ */ new TypeError(PROMISE_MESSAGE_EXPECTATION_RESULT));
2697
+ return actual.then((result) => ok(result)).catch((reason) => error(reason));
2497
2698
  }
2498
- function equalMap(first, second, options) {
2499
- const { size } = first;
2500
- if (size !== second.size) return false;
2501
- const firstKeys = [...first.keys()];
2502
- for (let index = 0; index < size; index += 1) {
2503
- const key = firstKeys[index];
2504
- if (!second.has(key) || !equalValue(first.get(key), second.get(key), options)) return false;
2505
- }
2506
- return true;
2699
+ //#endregion
2700
+ //#region src/promise/delay.ts
2701
+ function delay(options) {
2702
+ const { signal, time } = getPromiseOptions(options);
2703
+ if (signal?.aborted ?? false) return Promise.reject(signal?.reason);
2704
+ const aborter = createAborter(signal, () => {
2705
+ timer.cancel();
2706
+ rejector(signal?.reason);
2707
+ });
2708
+ const timer = getTimer(TIMER_WAIT, () => settlePromise(resolver, void 0, aborter), time);
2709
+ let rejector;
2710
+ let resolver;
2711
+ return new Promise((resolve, reject) => {
2712
+ rejector = reject;
2713
+ resolver = resolve;
2714
+ if (time === 0) settlePromise(resolver, void 0, aborter);
2715
+ else timer();
2716
+ });
2507
2717
  }
2508
- function equalPlainObject(first, second, options) {
2509
- let firstKeys = [...Object.keys(first), ...Object.getOwnPropertySymbols(first)];
2510
- let secondKeys = [...Object.keys(second), ...Object.getOwnPropertySymbols(second)];
2511
- if (options.ignoreKeys.enabled || options.ignoreExpressions.enabled) {
2512
- firstKeys = firstKeys.filter((key) => filterKey(key, options));
2513
- secondKeys = secondKeys.filter((key) => filterKey(key, options));
2514
- }
2515
- const secondSet = secondKeys.length >= EQUAL_MINIMUM_LENGTH_FOR_SET ? new Set(secondKeys) : void 0;
2516
- const { length } = firstKeys;
2517
- if (length !== secondKeys.length) return false;
2518
- for (let index = 0; index < length; index += 1) {
2519
- const key = firstKeys[index];
2520
- if (!(secondSet?.has(key) ?? secondKeys.includes(key)) || !equalValue(first[key], second[key], options)) return false;
2521
- }
2522
- return true;
2523
- }
2524
- function equalProperties(first, second, properties, options) {
2525
- const { length } = properties;
2526
- for (let index = 0; index < length; index += 1) {
2527
- const property = properties[index];
2528
- if (!equalValue(first[property], second[property], options)) return false;
2529
- }
2530
- return true;
2531
- }
2532
- function equalSet(first, second, options) {
2533
- const { size } = first;
2534
- if (size !== second.size) return false;
2535
- const firstValues = [...first];
2536
- const secondValues = [...second];
2537
- for (let index = 0; index < size; index += 1) {
2538
- const firstValue = firstValues[index];
2539
- if (isPrimitive(firstValue) ? !second.has(firstValue) : !secondValues.some((secondValue) => equalValue(firstValue, secondValue, options))) return false;
2540
- }
2541
- return true;
2718
+ //#endregion
2719
+ //#region src/promise/timed.ts
2720
+ async function getTimedPromise(promise, time, signal) {
2721
+ const aborter = createAborter(signal, () => {
2722
+ timer.cancel();
2723
+ rejector(signal?.reason);
2724
+ });
2725
+ const timer = getTimer(TIMER_WAIT, () => settlePromise(rejector, new PromiseTimeoutError(), aborter), time);
2726
+ let rejector;
2727
+ return Promise.race([promise, new Promise((_, reject) => {
2728
+ rejector = reject;
2729
+ timer();
2730
+ })]).then((value) => {
2731
+ aborter?.cancel();
2732
+ timer.cancel();
2733
+ rejector(void 0);
2734
+ return value;
2735
+ });
2542
2736
  }
2543
- function equalTypedArray(first, second) {
2544
- if (first.constructor !== second.constructor) return false;
2545
- if (first.byteLength !== second.byteLength) return false;
2546
- const { length } = first;
2547
- for (let index = 0; index < length; index += 1) if (first[index] !== second[index]) return false;
2548
- return true;
2737
+ async function timed(promise, options) {
2738
+ if (!(promise instanceof Promise)) return Promise.reject(/* @__PURE__ */ new TypeError(PROMISE_MESSAGE_EXPECTATION_TIMED));
2739
+ const { signal, time } = getPromiseOptions(options);
2740
+ if (signal?.aborted ?? false) return Promise.reject(signal?.reason);
2741
+ return time > 0 ? getTimedPromise(promise, time, signal) : promise;
2549
2742
  }
2550
- function equalValue(first, second, options) {
2551
- if (options.relaxedNullish && first == null && second == null) return true;
2552
- switch (true) {
2553
- case Object.is(first, second): return true;
2554
- case first == null || second == null: return first === second;
2555
- case typeof first !== typeof second: return false;
2556
- case typeof first === "string" && options.ignoreCase === true: return Object.is(first.toLocaleLowerCase(), second.toLocaleLowerCase());
2557
- case first instanceof ArrayBuffer && second instanceof ArrayBuffer: return equalArrayBuffer(first, second, options);
2558
- case first instanceof Date && second instanceof Date: return Object.is(first.getTime(), second.getTime());
2559
- case first instanceof DataView && second instanceof DataView: return equalDataView(first, second, options);
2560
- case first instanceof Error && second instanceof Error: return equalProperties(first, second, EQUAL_ERROR_PROPERTIES, options);
2561
- case first instanceof Map && second instanceof Map: return equalMap(first, second, options);
2562
- case first instanceof RegExp && second instanceof RegExp: return equalProperties(first, second, EQUAL_EXPRESSION_PROPERTIES, options);
2563
- case first instanceof Set && second instanceof Set: return equalSet(first, second, options);
2564
- case Array.isArray(first) && Array.isArray(second): return equalArray(first, second, options);
2565
- case isPlainObject(first) && isPlainObject(second): return equalPlainObject(first, second, options);
2566
- case isTypedArray(first) && isTypedArray(second): return equalTypedArray(first, second);
2567
- default: return equal.handlers.handle(first, second, options);
2743
+ //#endregion
2744
+ //#region src/promise/index.ts
2745
+ async function attemptPromise(value, options) {
2746
+ const isFunction = typeof value === "function";
2747
+ if (!isFunction && !(value instanceof Promise)) return Promise.reject(/* @__PURE__ */ new TypeError(PROMISE_MESSAGE_EXPECTATION_ATTEMPT));
2748
+ const { signal, time } = getPromiseOptions(options);
2749
+ if (signal?.aborted ?? false) return Promise.reject(signal?.reason);
2750
+ const aborter = createAborter(signal, () => {
2751
+ rejector(signal?.reason);
2752
+ });
2753
+ async function handler(resolve, reject) {
2754
+ try {
2755
+ let result = isFunction ? value() : await value;
2756
+ if (result instanceof Promise) result = await result;
2757
+ settlePromise(resolve, result, aborter);
2758
+ } catch (error) {
2759
+ settlePromise(reject, error, aborter);
2760
+ }
2568
2761
  }
2762
+ let rejector;
2763
+ const promise = new Promise((resolve, reject) => {
2764
+ rejector = reject;
2765
+ handler(resolve, reject);
2766
+ });
2767
+ return time > 0 ? getTimedPromise(promise, time, signal) : promise;
2569
2768
  }
2570
- function getEqualOptions(input) {
2571
- const options = {
2572
- ignoreCase: false,
2573
- ignoreExpressions: {
2574
- enabled: false,
2575
- values: []
2576
- },
2577
- ignoreKeys: {
2578
- enabled: false,
2579
- values: /* @__PURE__ */ new Set()
2580
- },
2581
- relaxedNullish: false
2769
+ async function promises(items, options) {
2770
+ const { signal, strategy } = getPromisesOptions(options);
2771
+ if (signal?.aborted ?? false) return Promise.reject(signal?.reason);
2772
+ if (!Array.isArray(items)) return Promise.resolve([]);
2773
+ const actual = items.map((item) => typeof item === "function" ? item() : item).filter((item) => item instanceof Promise);
2774
+ const { length } = actual;
2775
+ if (length === 0) return Promise.resolve([]);
2776
+ const complete = strategy === PROMISE_STRATEGY_DEFAULT;
2777
+ const aborter = createAborter(signal, () => {
2778
+ handlers.reject(signal?.reason);
2779
+ });
2780
+ const data = {
2781
+ last: length - 1,
2782
+ result: []
2582
2783
  };
2583
- if (typeof input === "boolean") {
2584
- options.ignoreCase = input;
2585
- return options;
2586
- }
2587
- if (isNonPlainObject(input)) return options;
2588
- options.ignoreCase = typeof input.ignoreCase === "boolean" ? input.ignoreCase : false;
2589
- options.ignoreExpressions.values = (Array.isArray(input.ignoreKeys) ? input.ignoreKeys : [input.ignoreKeys]).filter((key) => key instanceof RegExp);
2590
- options.ignoreKeys.values = new Set((Array.isArray(input.ignoreKeys) ? input.ignoreKeys : [input.ignoreKeys]).filter((key) => typeof key === "string"));
2591
- options.ignoreExpressions.enabled = options.ignoreExpressions.values.length > 0;
2592
- options.ignoreKeys.enabled = options.ignoreKeys.values.size > 0;
2593
- options.relaxedNullish = input.relaxedNullish === true;
2594
- return options;
2595
- }
2596
- /**
2597
- * Create an equalizer with predefined options
2598
- *
2599
- * _Available as `initializeEqualizer` and `equal.initialize`_
2600
- *
2601
- * @param options Comparison options
2602
- * @returns Equalizer function
2603
- */
2604
- function initializeEqualizer(options) {
2605
- const actual = getEqualOptions(options);
2606
- const equalizer = (first, second) => equalValue(first, second, actual);
2607
- equalizer.deregister = deregisterEqualizer;
2608
- equalizer.register = registerEqualizer;
2609
- return equalizer;
2610
- }
2611
- /**
2612
- * Register a equality comparison function for a specific class
2613
- *
2614
- * _Available as `registerEqualizer` and `equal.register`_
2615
- *
2616
- * @param constructor Class constructor
2617
- * @param handler Comparison function
2618
- */
2619
- function registerEqualizer(constructor, handler) {
2620
- equal.handlers.register(constructor, handler);
2784
+ let handlers;
2785
+ return new Promise((resolve, reject) => {
2786
+ handlers = {
2787
+ reject,
2788
+ resolve
2789
+ };
2790
+ for (let index = 0; index < length; index += 1) actual[index].then((value) => handleResult(PROMISE_TYPE_FULFILLED, {
2791
+ aborter,
2792
+ complete,
2793
+ data,
2794
+ handlers,
2795
+ index,
2796
+ value
2797
+ })).catch((reason) => handleResult(PROMISE_TYPE_REJECTED, {
2798
+ aborter,
2799
+ complete,
2800
+ data,
2801
+ handlers,
2802
+ index,
2803
+ value: reason
2804
+ }));
2805
+ });
2621
2806
  }
2622
- const EQUAL_ARRAY_PEEK_PERCENTAGE = 10;
2623
- const EQUAL_ARRAY_THRESHOLD = 100;
2624
- const EQUAL_ERROR_PROPERTIES = ["name", "message"];
2625
- const EQUAL_EXPRESSION_PROPERTIES = ["source", "flags"];
2626
- const EQUAL_MINIMUM_LENGTH_FOR_SET = 16;
2627
- //#endregion
2628
- //#region src/internal/value/get.ts
2629
- function getValue(data, path, ignoreCase) {
2630
- return getNestedValue(data, path, ignoreCase === true).value;
2807
+ promises.result = resultPromises;
2808
+ async function resultPromises(items, signal) {
2809
+ return promises(items, signal).then(getResultsFromPromises);
2631
2810
  }
2632
2811
  //#endregion
2633
- //#region src/internal/value/set.ts
2634
- function setValue(data, path, value, ignoreCase) {
2635
- if (typeof data !== "object" || data === null || typeof path !== "string" || path.trim().length === 0) return data;
2636
- const shouldIgnoreCase = ignoreCase === true;
2637
- const paths = getPaths(path, shouldIgnoreCase);
2638
- if (typeof paths === "string") {
2639
- handleValue(data, paths, value, false, shouldIgnoreCase);
2640
- return data;
2812
+ //#region src/result/index.ts
2813
+ async function asyncAttempt(value, err) {
2814
+ try {
2815
+ let result = typeof value === "function" ? value() : await value;
2816
+ if (result instanceof Promise) result = await result;
2817
+ return ok(result);
2818
+ } catch (thrown) {
2819
+ return getError(err ?? thrown, err == null ? void 0 : thrown);
2641
2820
  }
2642
- const { length } = paths;
2643
- const lastIndex = length - 1;
2644
- let target = data;
2645
- for (let index = 0; index < length; index += 1) {
2646
- const currentPath = paths[index];
2647
- if (index === lastIndex) {
2648
- handleValue(target, currentPath, value, false, shouldIgnoreCase);
2649
- break;
2650
- }
2651
- let next = handleValue(target, currentPath, null, true, shouldIgnoreCase).value;
2652
- if (typeof next !== "object" || next === null) {
2653
- const nextPath = paths[index + 1];
2654
- if (SET_EXPRESSION_INDEX.test(nextPath)) next = Array.from({ length: Number(nextPath) + 1 }, () => void 0);
2655
- else next = {};
2656
- target[currentPath] = next;
2657
- }
2658
- target = next;
2821
+ }
2822
+ function attempt(callback, err) {
2823
+ try {
2824
+ return ok(callback());
2825
+ } catch (thrown) {
2826
+ return getError(err ?? thrown, err == null ? void 0 : thrown);
2659
2827
  }
2660
- return data;
2661
2828
  }
2662
- const SET_EXPRESSION_INDEX = /^\d+$/;
2829
+ attempt.async = asyncAttempt;
2830
+ Object.defineProperty(attempt, "async", { value: asyncAttempt });
2663
2831
  //#endregion
2664
- //#region src/string/case.ts
2665
- /**
2666
- * Convert a string to camel case _(thisIsCamelCase)_
2667
- *
2668
- * @param value String to convert
2669
- * @returns Camel-cased string
2670
- */
2671
- function camelCase(value) {
2672
- return toCase(STRING_CASE_CAMEL, value, true, false);
2673
- }
2674
- /**
2675
- * Capitalize the first letter of a string _(and lowercase the rest)_
2676
- *
2677
- * @param value String to capitalize
2678
- * @returns Capitalized string
2679
- */
2680
- function capitalize(value) {
2681
- if (typeof value !== "string" || value.length === 0) return "";
2682
- memoizedCapitalize ??= memoize((v) => v.length === 1 ? v.toLocaleUpperCase() : `${v.charAt(0).toLocaleUpperCase()}${v.slice(1).toLocaleLowerCase()}`);
2683
- return memoizedCapitalize.run(value);
2684
- }
2685
- /**
2686
- * Convert a string to kebab case _(this-is-kebab-case)_
2687
- *
2688
- * @param value String to convert
2689
- * @returns Kebab-cased string
2690
- */
2691
- function kebabCase(value) {
2692
- return toCase(STRING_CASE_KEBAB, value, false, false);
2693
- }
2694
- /**
2695
- * Convert a string to lower case
2696
- *
2697
- * @param value String to convert
2698
- * @returns Lower-cased string
2699
- */
2700
- function lowerCase(value) {
2701
- if (typeof value !== "string") return "";
2702
- memoizedLowerCase ??= memoize((v) => v.toLocaleLowerCase());
2703
- return memoizedLowerCase.run(value);
2704
- }
2705
- /**
2706
- * Convert a string to pascal case _(ThisIsPascalCase)_
2707
- *
2708
- * @param value String to convert
2709
- * @returns Pascal-cased string
2710
- */
2711
- function pascalCase(value) {
2712
- return toCase(STRING_CASE_PASCAL, value, true, true);
2713
- }
2714
- /**
2715
- * Convert a string to snake case _(this_is_snake_case)_
2716
- *
2717
- * @param value String to convert
2718
- * @returns Snake-cased string
2719
- */
2720
- function snakeCase(value) {
2721
- return toCase(STRING_CASE_SNAKE, value, false, false);
2722
- }
2723
- /**
2724
- * Convert a string to title case _(Capitalizing Every Word)_
2725
- *
2726
- * @param value String to convert
2727
- * @returns Title-cased string
2728
- */
2729
- function titleCase(value) {
2730
- if (typeof value !== "string" || value.length === 0) return "";
2731
- memoizedTitleCase ??= memoize((v) => v.length < 2 ? capitalize(v) : join(words(v).map(capitalize), " "));
2732
- return memoizedTitleCase.run(value);
2832
+ //#region src/result/match.ts
2833
+ async function asyncMatchResult(result, first, error) {
2834
+ let value;
2835
+ if (typeof result === "function") value = await result();
2836
+ else if (result instanceof Promise) value = await result;
2837
+ else value = result;
2838
+ if (!isResult(value)) throw new Error(MATCH_MESSAGE);
2839
+ const hasObj = typeof first === "object" && first !== null;
2840
+ const okHandler = hasObj ? first.ok : first;
2841
+ const errorHandler = hasObj ? first.error : error;
2842
+ if (isOk(value)) return okHandler(value.value);
2843
+ return errorHandler(value.error, value.original);
2733
2844
  }
2734
- function toCase(type, value, capitalizeAny, capitalizeFirst) {
2735
- caseMemoizers[type] ??= memoize(toCaseCallback.bind({
2736
- type,
2737
- capitalizeAny,
2738
- capitalizeFirst
2739
- }));
2740
- return caseMemoizers[type].run(value);
2845
+ function matchResult(result, first, error) {
2846
+ const value = typeof result === "function" ? result() : result;
2847
+ if (!isResult(value)) throw new Error(MATCH_MESSAGE);
2848
+ const hasObj = typeof first === "object" && first !== null;
2849
+ const okHandler = hasObj ? first.ok : first;
2850
+ const errorHandler = hasObj ? first.error : error;
2851
+ if (isOk(value)) return okHandler(value.value);
2852
+ return errorHandler(value.error, value.original);
2741
2853
  }
2742
- function toCaseCallback(value) {
2743
- if (typeof value !== "string") return "";
2744
- if (value.length < 1) return value;
2745
- const { capitalizeAny, capitalizeFirst, type } = this;
2746
- const parts = words(value);
2747
- const partsLength = parts.length;
2748
- const cased = [];
2749
- for (let partIndex = 0; partIndex < partsLength; partIndex += 1) {
2750
- const items = parts[partIndex].replace(STRING_EXPRESSION_ACRONYM, (full, one, two, three) => three === STRING_S ? full : `${one}-${two}${three}`).replace(STRING_EXPRESSION_CAMEL_CASE, STRING_REPLACEMENT_CAMEL_CASE).split("-");
2751
- const itemsLength = items.length;
2752
- const partResult = [];
2753
- let itemCount = 0;
2754
- for (let itemIndex = 0; itemIndex < itemsLength; itemIndex += 1) {
2755
- const item = items[itemIndex];
2756
- if (item.length === 0) continue;
2757
- if (!capitalizeAny || itemCount === 0 && partIndex === 0 && !capitalizeFirst) partResult.push(item.toLocaleLowerCase());
2758
- else partResult.push(capitalize(item));
2759
- itemCount += 1;
2760
- }
2761
- cased.push(join(partResult, delimiters[type]));
2762
- }
2763
- return join(cased, delimiters[type]);
2854
+ const MATCH_MESSAGE = "`result.match` expected a Result or a function that returns a Result";
2855
+ matchResult.async = asyncMatchResult;
2856
+ Object.defineProperty(matchResult, "async", { value: asyncMatchResult });
2857
+ //#endregion
2858
+ //#region src/result/work/flow.ts
2859
+ function attemptAsyncFlow(...fns) {
2860
+ let Flow;
2861
+ return (...args) => asyncAttempt(() => {
2862
+ Flow ??= asyncFlow(...fns);
2863
+ return Flow(...args.map((value) => {
2864
+ if (isError(value)) throw value.error;
2865
+ return isOk(value) ? value.value : value;
2866
+ }));
2867
+ });
2764
2868
  }
2765
- /**
2766
- * Convert a string to upper case
2767
- *
2768
- * @param value String to convert
2769
- * @returns Upper-cased string
2770
- */
2771
- function upperCase(value) {
2772
- if (typeof value !== "string" || value.length === 0) return "";
2773
- memoizedUpperCase ??= memoize((v) => v.toLocaleUpperCase());
2774
- return memoizedUpperCase.run(value);
2869
+ function attemptFlow(...fns) {
2870
+ let Flow;
2871
+ return (...args) => attempt(() => {
2872
+ Flow ??= flow(...fns);
2873
+ return Flow(...args.map((value) => {
2874
+ if (isError(value)) throw value.error;
2875
+ return isOk(value) ? value.value : value;
2876
+ }));
2877
+ });
2775
2878
  }
2776
- const STRING_CASE_CAMEL = "camel";
2777
- const STRING_CASE_KEBAB = "kebab";
2778
- const STRING_CASE_PASCAL = "pascal";
2779
- const STRING_CASE_SNAKE = "snake";
2780
- const STRING_DELIMTER_EMPTY = "";
2781
- const STRING_DELIMITER_HYPHEN = "-";
2782
- const STRING_DELIMITER_UNDERSCORE = "_";
2783
- const STRING_EXPRESSION_CAMEL_CASE = /(\p{Ll})(\p{Lu})/gu;
2784
- const STRING_EXPRESSION_ACRONYM = /(\p{Lu}*)(\p{Lu})(\p{Ll}+)/gu;
2785
- const STRING_REPLACEMENT_CAMEL_CASE = "$1-$2";
2786
- const STRING_S = "s";
2787
- const caseMemoizers = {};
2788
- const delimiters = {
2789
- [STRING_CASE_CAMEL]: STRING_DELIMTER_EMPTY,
2790
- [STRING_CASE_KEBAB]: STRING_DELIMITER_HYPHEN,
2791
- [STRING_CASE_PASCAL]: STRING_DELIMTER_EMPTY,
2792
- [STRING_CASE_SNAKE]: STRING_DELIMITER_UNDERSCORE
2793
- };
2794
- let memoizedCapitalize;
2795
- let memoizedLowerCase;
2796
- let memoizedTitleCase;
2797
- let memoizedUpperCase;
2879
+ attemptFlow.async = attemptAsyncFlow;
2880
+ Object.defineProperty(attemptFlow, "async", { value: attemptAsyncFlow });
2881
+ //#endregion
2882
+ //#region src/result/work/pipe.ts
2883
+ async function attemptAsyncPipe(initial, first, ...seconds) {
2884
+ return asyncAttempt(() => {
2885
+ if (isError(initial)) throw initial.error;
2886
+ const value = typeof initial === "function" ? initial() : isOk(initial) ? initial.value : initial;
2887
+ if (first == null) return value;
2888
+ return asyncPipe(value, ...[first, ...seconds]);
2889
+ });
2890
+ }
2891
+ function attemptPipe(initial, first, ...seconds) {
2892
+ return attempt(() => {
2893
+ if (isError(initial)) throw initial.error;
2894
+ const value = typeof initial === "function" ? initial() : isOk(initial) ? initial.value : initial;
2895
+ if (first == null) return value;
2896
+ return pipe(value, ...[first, ...seconds]);
2897
+ });
2898
+ }
2899
+ attemptPipe.async = attemptAsyncPipe;
2900
+ Object.defineProperty(attemptPipe, "async", { value: attemptAsyncPipe });
2798
2901
  //#endregion
2799
2902
  //#region src/string/match.ts
2800
2903
  /**
@@ -3856,6 +3959,142 @@ function transformValue(value, transformer) {
3856
3959
  return value;
3857
3960
  }
3858
3961
  //#endregion
3962
+ //#region src/internal/subscription.ts
3963
+ function addSubscription(subscriptions, subscription, state) {
3964
+ const { key, value } = state.parameters;
3965
+ const { items, values } = subscriptions.state;
3966
+ if (!isKey(key)) {
3967
+ items.any.add(subscription);
3968
+ values.from.any.set(value, subscription);
3969
+ values.to.any.set(subscription, value);
3970
+ return;
3971
+ }
3972
+ /* istanbul ignore if */
3973
+ if (items.keyed == null || values.from.keyed == null || values.to.keyed == null)
3974
+ // istanbul ignore next
3975
+ return;
3976
+ let keyedItems = items.keyed.get(key);
3977
+ if (keyedItems == null) {
3978
+ keyedItems = /* @__PURE__ */ new Set();
3979
+ items.keyed.set(key, keyedItems);
3980
+ }
3981
+ keyedItems.add(subscription);
3982
+ let keyedFrom = values.from.keyed.get(key);
3983
+ if (keyedFrom == null) {
3984
+ keyedFrom = /* @__PURE__ */ new Map();
3985
+ values.from.keyed.set(key, keyedFrom);
3986
+ }
3987
+ keyedFrom.set(value, subscription);
3988
+ let keyedTo = values.to.keyed.get(key);
3989
+ if (keyedTo == null) {
3990
+ keyedTo = /* @__PURE__ */ new Map();
3991
+ values.to.keyed.set(key, keyedTo);
3992
+ }
3993
+ keyedTo.set(subscription, value);
3994
+ }
3995
+ function clearSubscriptions(store) {
3996
+ for (const susbcription of store.values.to.any.keys()) susbcription.unsubscribe();
3997
+ if (store.values.to.keyed != null) for (const values of store.values.to.keyed.values()) for (const susbcription of values.keys()) susbcription.unsubscribe();
3998
+ }
3999
+ function createSubscription(subscriptions, property, parameters) {
4000
+ if (parameters.signal?.aborted ?? false) throw new Error(parameters.signal?.reason);
4001
+ const state = {
4002
+ parameters,
4003
+ active: true
4004
+ };
4005
+ const existing = getExistingSubscription(subscriptions, state);
4006
+ if (existing != null) return [existing, true];
4007
+ if (subscriptions.state.keys != null && isKey(parameters.key) && !subscriptions.state.keys.has(parameters.key)) throw new Error(SUBSCRIPTION_INVALID_KEY);
4008
+ state.aborter = createAborter(parameters.signal, () => unsubscribe(subscriptions, instance, state));
4009
+ const instance = { unsubscribe: () => unsubscribe(subscriptions, instance, state) };
4010
+ Object.defineProperties(instance, {
4011
+ [SUBSCRIPTION_PROPERTY]: { value: true },
4012
+ [property.key]: { value: property.value ?? "subscription" },
4013
+ active: {
4014
+ enumerable: true,
4015
+ get: () => (parameters.isActive?.() ?? true) && state.active
4016
+ }
4017
+ });
4018
+ addSubscription(subscriptions, instance, state);
4019
+ return [Object.freeze(instance), false];
4020
+ }
4021
+ function createSubscriptions(parameters) {
4022
+ const { keys, property } = parameters;
4023
+ const state = {
4024
+ keys,
4025
+ items: {
4026
+ any: /* @__PURE__ */ new Set(),
4027
+ keyed: keys == null ? void 0 : /* @__PURE__ */ new Map()
4028
+ },
4029
+ values: {
4030
+ from: {
4031
+ any: /* @__PURE__ */ new Map(),
4032
+ keyed: keys == null ? void 0 : /* @__PURE__ */ new Map()
4033
+ },
4034
+ to: {
4035
+ any: /* @__PURE__ */ new Map(),
4036
+ keyed: keys == null ? void 0 : /* @__PURE__ */ new Map()
4037
+ }
4038
+ }
4039
+ };
4040
+ const instance = {
4041
+ state,
4042
+ clear: () => clearSubscriptions(state),
4043
+ create: (parameters) => createSubscription(instance, property, parameters)
4044
+ };
4045
+ return instance;
4046
+ }
4047
+ function getExistingSubscription(subscriptions, state) {
4048
+ const { parameters } = state;
4049
+ const { values } = subscriptions.state;
4050
+ return isKey(parameters.key) ? values.from.keyed?.get(parameters.key)?.get(parameters.value) : values.from.any.get(parameters.value);
4051
+ }
4052
+ /**
4053
+ * Is the value a subscription?
4054
+ *
4055
+ * @param value Value to check
4056
+ * @returns `true` if the value is a subscription, otherwise `false`
4057
+ */
4058
+ function isSubscription(value) {
4059
+ return isPlainObject(value) && SUBSCRIPTION_PROPERTY in value && value[SUBSCRIPTION_PROPERTY] === true;
4060
+ }
4061
+ function removeFromStore(items, values, subscription, value, key) {
4062
+ items.delete(subscription);
4063
+ if (key == null) {
4064
+ values.from.any.delete(value);
4065
+ values.to.any.delete(subscription);
4066
+ } else {
4067
+ values.from.keyed?.get(key)?.delete(value);
4068
+ values.to.keyed?.get(key)?.delete(subscription);
4069
+ }
4070
+ }
4071
+ function removeSubscription(subscriptions, subscription, state) {
4072
+ if (!state.active) return;
4073
+ state.aborter = void 0;
4074
+ state.active = false;
4075
+ state.parameters.isActive = void 0;
4076
+ state.parameters.signal = void 0;
4077
+ const { key, value } = state.parameters;
4078
+ const { items, values } = subscriptions.state;
4079
+ if (!isKey(key)) {
4080
+ removeFromStore(items.any, values, subscription, value);
4081
+ return;
4082
+ }
4083
+ const keyed = items.keyed?.get(key);
4084
+ /* istanbul ignore if */
4085
+ if (items.keyed == null || keyed == null)
4086
+ // istanbul ignore next
4087
+ return;
4088
+ removeFromStore(keyed, values, subscription, value, key);
4089
+ if (keyed.size === 0) items.keyed.delete(key);
4090
+ }
4091
+ function unsubscribe(subscriptions, subscription, state) {
4092
+ state.aborter?.cancel();
4093
+ removeSubscription(subscriptions, subscription, state);
4094
+ }
4095
+ const SUBSCRIPTION_INVALID_KEY = "Invalid key for subscription";
4096
+ const SUBSCRIPTION_PROPERTY = "$subscription";
4097
+ //#endregion
3859
4098
  //#region src/beacon.ts
3860
4099
  /**
3861
4100
  * Create a new beacon
@@ -3987,26 +4226,132 @@ function subscribeToObservable(state, first, second, third) {
3987
4226
  isActive: () => state.beacon.active && state.active,
3988
4227
  value: observer
3989
4228
  });
3990
- observer.next?.(state.beacon.value);
4229
+ observer.next?.(state.beacon.value);
4230
+ return subscription;
4231
+ }
4232
+ function updateBeacon(type, state, value, finish) {
4233
+ if (!state.active) return;
4234
+ if (type === BEACON_TYPE_NEXT) {
4235
+ if (state.options.equal(state.value, value)) return;
4236
+ state.value = value;
4237
+ }
4238
+ for (const [, observer] of state.subscriptions.state.values.to.any) observer[type]?.(value);
4239
+ if (finish === true) finishBeacon(state, true);
4240
+ }
4241
+ const BEACON_MESSAGE_RETRIEVE = "Cannot retrieve observable from a closed beacon";
4242
+ const BEACON_MESSAGE_SUBSCRIBE = "Cannot subscribe to a closed observable";
4243
+ const BEACON_PROPERTY = "$beacon";
4244
+ const BEACON_NAME = "beacon";
4245
+ const BEACON_OBSERVABLE = "observable";
4246
+ const BEACON_TYPE_ERROR = "error";
4247
+ const BEACON_TYPE_NEXT = "next";
4248
+ const beaconSubscription = { key: BEACON_PROPERTY };
4249
+ //#endregion
4250
+ //#region src/internal/herald.ts
4251
+ function createEvents(herald, state) {
4252
+ const events = {};
4253
+ Object.defineProperty(events, HERALD_PROPERTY, { value: HERALD_NAME_EVENTS });
4254
+ for (const key of state.keys) events[key] = (callback, signal) => herald.subscribe(key, callback, signal);
4255
+ return Object.freeze(events);
4256
+ }
4257
+ function emitForHerald(state, event, ...parameters) {
4258
+ const items = state.subscriptions.state.values.from.keyed?.get(event);
4259
+ if (items == null || items.size === 0) return;
4260
+ for (const [callback] of items) callback(...parameters);
4261
+ }
4262
+ function getHeraldSubscriptionProperty(input) {
4263
+ if (input == null) return heraldSubscription;
4264
+ const property = isPlainObject(input) ? input : {};
4265
+ if (typeof property.key !== "string" || property.value != null && typeof property.value !== "string") throw new Error(HERALD_MESSAGE_PROPERTY);
4266
+ return {
4267
+ key: property.key,
4268
+ value: property.value
4269
+ };
4270
+ }
4271
+ function getHeraldState(input) {
4272
+ const options = isPlainObject(input) ? input : {};
4273
+ if (!Array.isArray(options.names) || options.names.length === 0 || !options.names.every((name) => typeof name === "string")) throw new Error(HERALD_MESSAGE_ARRAY);
4274
+ if (options.onCreate != null && typeof options.onCreate !== "function") throw new Error(HERALD_MESSAGE_ONCREATE);
4275
+ const keys = new Set(options.names);
4276
+ return {
4277
+ keys,
4278
+ subscriptions: createSubscriptions({
4279
+ keys,
4280
+ property: getHeraldSubscriptionProperty(options.property)
4281
+ }),
4282
+ onCreate: options.onCreate
4283
+ };
4284
+ }
4285
+ /**
4286
+ * Create a _Herald_ for announcing named events
4287
+ *
4288
+ * @param names Event names
4289
+ * @param property Optional property for subscription identification _(defaults to `$herald`)_
4290
+ * @returns _Herald_ instance
4291
+ */
4292
+ function herald(options) {
4293
+ const state = getHeraldState(options);
4294
+ const instance = {
4295
+ clear: () => state.subscriptions.clear(),
4296
+ emit: (event, ...parameters) => emitForHerald(state, event, ...parameters),
4297
+ observed: (event) => (state.subscriptions.state.items.keyed?.get(event)?.size ?? 0) > 0,
4298
+ subscribe: (key, callback, signal) => subscribeToHerald(state, key, callback, signal)
4299
+ };
4300
+ Object.defineProperties(instance, {
4301
+ [HERALD_PROPERTY]: { value: HERALD_NAME_HERALD },
4302
+ events: {
4303
+ enumerable: true,
4304
+ value: createEvents(instance, state)
4305
+ }
4306
+ });
4307
+ return Object.freeze(instance);
4308
+ }
4309
+ /**
4310
+ * Is the value a herald?
4311
+ *
4312
+ * @param value Value to check
4313
+ * @returns `true` if the value is a herald, otherwise `false`
4314
+ */
4315
+ function isHerald(value) {
4316
+ return isHeraldInstance(HERALD_NAME_HERALD, value);
4317
+ }
4318
+ /**
4319
+ * Is the value events for a herald?
4320
+ *
4321
+ * @param value Value to check
4322
+ * @returns `true` if the value is events for a herald, otherwise `false`
4323
+ */
4324
+ function isHeraldEvents(value) {
4325
+ return isHeraldInstance(HERALD_NAME_EVENTS, value);
4326
+ }
4327
+ function isHeraldInstance(name, value) {
4328
+ return isPlainObject(value) && HERALD_PROPERTY in value && value[HERALD_PROPERTY] === name;
4329
+ }
4330
+ /**
4331
+ * Is the value a herald subscription?
4332
+ *
4333
+ * @param value Value to check
4334
+ * @returns `true` if the value is a herald subscription, otherwise `false`
4335
+ */
4336
+ function isHeraldSubscription(value) {
4337
+ return isSubscription(value) && value[HERALD_PROPERTY] === "subscription";
4338
+ }
4339
+ function subscribeToHerald(state, key, callback, signal) {
4340
+ const [subscription, existing] = state.subscriptions.create({
4341
+ key,
4342
+ signal,
4343
+ value: callback
4344
+ });
4345
+ if (!existing) state.onCreate?.(key, callback, subscription);
3991
4346
  return subscription;
3992
4347
  }
3993
- function updateBeacon(type, state, value, finish) {
3994
- if (!state.active) return;
3995
- if (type === BEACON_TYPE_NEXT) {
3996
- if (state.options.equal(state.value, value)) return;
3997
- state.value = value;
3998
- }
3999
- for (const [, observer] of state.subscriptions.state.values.to.any) observer[type]?.(value);
4000
- if (finish === true) finishBeacon(state, true);
4001
- }
4002
- const BEACON_MESSAGE_RETRIEVE = "Cannot retrieve observable from a closed beacon";
4003
- const BEACON_MESSAGE_SUBSCRIBE = "Cannot subscribe to a closed observable";
4004
- const BEACON_PROPERTY = "$beacon";
4005
- const BEACON_NAME = "beacon";
4006
- const BEACON_OBSERVABLE = "observable";
4007
- const BEACON_TYPE_ERROR = "error";
4008
- const BEACON_TYPE_NEXT = "next";
4009
- const beaconSubscription = { key: BEACON_PROPERTY };
4348
+ const HERALD_PROPERTY = "$herald";
4349
+ const HERALD_MESSAGE_ARRAY = "Herald requires an array of event names.";
4350
+ const HERALD_MESSAGE_ONCREATE = `Herald requires a valid onCreate callback for subscription creation`;
4351
+ const HERALD_MESSAGE_PROPERTY = `Herald requires valid property information for subscription identification`;
4352
+ const HERALD_NAME_EVENTS = "events";
4353
+ const HERALD_NAME_HERALD = "herald";
4354
+ const heraldSubscription = { key: HERALD_PROPERTY };
4010
4355
  //#endregion
4011
4356
  //#region src/color/constants.ts
4012
4357
  const COLOR_ALPHA = {
@@ -5333,332 +5678,86 @@ const methods = [
5333
5678
  * _(Logging can be enabled or disabled by setting the `enabled` property)_
5334
5679
  */
5335
5680
  const Logger = (() => {
5336
- const instance = {};
5337
- Object.defineProperties(instance, {
5338
- [LOGGER_PROPERTY]: { value: LOGGER_NAME },
5339
- enabled: {
5340
- enumerable: true,
5341
- get: () => enabled,
5342
- set: (value) => {
5343
- enabled = typeof value === "boolean" ? value : enabled;
5344
- }
5345
- },
5346
- time: { value: (label) => timedLogger(getString(label)) }
5347
- });
5348
- for (const method of methods) Object.defineProperty(instance, method, {
5349
- enumerable: true,
5350
- get() {
5351
- return enabled ? console[method].bind(console) : noop;
5352
- }
5353
- });
5354
- return Object.freeze(instance);
5355
- })();
5356
- let enabled = true;
5357
- //#endregion
5358
- //#region src/math.ts
5359
- function average(array, key) {
5360
- const aggregated = aggregate(AGGREGATION_AVERAGE, array, key);
5361
- return aggregated.count > 0 ? aggregated.value / aggregated.count : NaN;
5362
- }
5363
- /**
5364
- * Round a number up
5365
- *
5366
- * @param value Number to round up
5367
- * @param decimals Number of decimal places to round to _(defaults to `0`)_
5368
- * @returns Rounded number, or `Number.NaN` if the value if unable to be rounded
5369
- */
5370
- function ceil(value, decimals) {
5371
- return roundNumber(Math.ceil, value, decimals);
5372
- }
5373
- function count(array, key, value) {
5374
- if (!Array.isArray(array)) return NaN;
5375
- const { length } = array;
5376
- const callback = getAggregateCallback(key);
5377
- if (callback == null) return length;
5378
- let counted = 0;
5379
- for (let index = 0; index < length; index += 1) {
5380
- const item = array[index];
5381
- if (Object.is(callback(item, index, array), value)) counted += 1;
5382
- }
5383
- return counted;
5384
- }
5385
- /**
5386
- * Round a number down
5387
- *
5388
- * @param value Number to round down
5389
- * @param decimals Number of decimal places to round to _(defaults to `0`)_
5390
- * @returns Rounded number, or `Number.NaN` if the value if unable to be rounded
5391
- */
5392
- function floor(value, decimals) {
5393
- return roundNumber(Math.floor, value, decimals);
5394
- }
5395
- function median(array, key) {
5396
- let length = Array.isArray(array) ? array.length : 0;
5397
- if (!Array.isArray(array) || length === 0) return NaN;
5398
- let values = array;
5399
- const callback = getAggregateCallback(key);
5400
- if (callback != null) values = array.map((item, index) => callback(item, index, array));
5401
- const numbers = values.filter(isNumber).sort((first, second) => first - second);
5402
- length = numbers.length;
5403
- if (length === 1) return numbers[0];
5404
- if (length % 2 === 0) {
5405
- const first = length / 2 - 1;
5406
- const second = length / 2;
5407
- return (numbers[first] + numbers[second]) / 2;
5408
- }
5409
- return numbers[Math.floor(length / 2)];
5410
- }
5411
- function min(array, key) {
5412
- return getAggregated("min", array, key);
5413
- }
5414
- function sum(array, key) {
5415
- return getAggregated("sum", array, key);
5416
- }
5417
- //#endregion
5418
- //#region src/promise/constants.ts
5419
- const PROMISE_ERROR_NAME = "PromiseTimeoutError";
5420
- const PROMISE_MESSAGE_EXPECTATION_ATTEMPT = "Attempt expected a function or a promise";
5421
- const PROMISE_MESSAGE_EXPECTATION_RESULT = "toResult expected a Promise";
5422
- const PROMISE_MESSAGE_EXPECTATION_TIMED = "Timed function expected a Promise";
5423
- const PROMISE_MESSAGE_TIMEOUT = "Promise timed out";
5424
- const PROMISE_STRATEGY_ALL = /* @__PURE__ */ new Set(["complete", "first"]);
5425
- const PROMISE_STRATEGY_DEFAULT = "complete";
5426
- const PROMISE_TYPE_FULFILLED = "fulfilled";
5427
- const PROMISE_TYPE_REJECTED = "rejected";
5428
- //#endregion
5429
- //#region src/promise/models.ts
5430
- /**
5431
- * A _Promise_ that can be canceled
5432
- */
5433
- var CancelablePromise = class extends Promise {
5434
- #rejector;
5435
- constructor(executor) {
5436
- let rejector;
5437
- super((resolve, reject) => {
5438
- rejector = reject;
5439
- executor(resolve, reject);
5440
- });
5441
- this.#rejector = rejector;
5442
- }
5443
- /**
5444
- * Cancel the _Promise_, rejecting it with an optional reason
5445
- *
5446
- * @param reason Optional reason for canceling the _Promise_
5447
- */
5448
- cancel(reason) {
5449
- this.#rejector?.(reason);
5450
- this.#rejector = void 0;
5451
- }
5452
- };
5453
- /**
5454
- * An error thrown when a promise times out
5455
- */
5456
- var PromiseTimeoutError = class extends Error {
5457
- constructor() {
5458
- super(PROMISE_MESSAGE_TIMEOUT);
5459
- this.name = PROMISE_ERROR_NAME;
5460
- }
5461
- };
5462
- //#endregion
5463
- //#region src/promise/helpers.ts
5464
- function getPromiseOptions(input) {
5465
- if (typeof input === "number") return { time: getNumberOrDefault(input, 0) };
5466
- if (input instanceof AbortSignal) return {
5467
- signal: input,
5468
- time: 0
5469
- };
5470
- const options = typeof input === "object" && input !== null ? input : {};
5471
- return {
5472
- signal: options.signal instanceof AbortSignal ? options.signal : void 0,
5473
- time: getNumberOrDefault(options.time, 0)
5474
- };
5475
- }
5476
- function getPromisesOptions(input) {
5477
- if (typeof input === "string") return { strategy: getStrategyOrDefault(input) };
5478
- if (input instanceof AbortSignal) return {
5479
- signal: input,
5480
- strategy: PROMISE_STRATEGY_DEFAULT
5481
- };
5482
- const options = typeof input === "object" && input !== null ? input : {};
5483
- return {
5484
- signal: options.signal instanceof AbortSignal ? options.signal : void 0,
5485
- strategy: getStrategyOrDefault(options.strategy)
5486
- };
5487
- }
5488
- function getResultsFromPromises(promised) {
5489
- return promised.map((result) => isFulfilled(result) ? ok(result.value) : error(result.reason));
5490
- }
5491
- function getStrategyOrDefault(value) {
5492
- return PROMISE_STRATEGY_ALL.has(value) ? value : PROMISE_STRATEGY_DEFAULT;
5493
- }
5494
- /**
5495
- * Is the value a fulfilled _Promise_ result?
5496
- *
5497
- * @param value Value to check
5498
- * @returns `true` if the value is a fulfilled _Promise_ result, otherwise `false`
5499
- */
5500
- function isFulfilled(value) {
5501
- return isType(value, PROMISE_TYPE_FULFILLED);
5502
- }
5503
- /**
5504
- * Is the value a rejected _Promise_ result?
5505
- *
5506
- * @param value Value to check
5507
- * @returns `true` if the value is a rejected _Promise_ result, otherwise `false`
5508
- */
5509
- function isRejected(value) {
5510
- return isType(value, PROMISE_TYPE_REJECTED);
5511
- }
5512
- function isType(value, type) {
5513
- return typeof value === "object" && value !== null && value.status === type;
5514
- }
5515
- //#endregion
5516
- //#region src/promise/misc.ts
5517
- /**
5518
- * Create a cancelable _Promise_
5519
- *
5520
- * @param executor Executor function for the _Promise_
5521
- * @returns Cancelable _Promise_
5522
- */
5523
- function cancelable(executor) {
5524
- return new CancelablePromise(executor);
5525
- }
5526
- function handleResult(status, parameters) {
5527
- const { aborter, complete, data, handlers, index, value } = parameters;
5528
- if (aborter?.signal.aborted ?? false) return;
5529
- if (!complete && status === "rejected") {
5530
- settlePromise(handlers.reject, value, aborter);
5531
- return;
5532
- }
5533
- data.result[index] = !complete ? value : status === "fulfilled" ? {
5534
- status,
5535
- value
5536
- } : {
5537
- status,
5538
- reason: value
5539
- };
5540
- if (index === data.last) settlePromise(handlers.resolve, data.result, aborter);
5541
- }
5542
- function settlePromise(settler, value, aborter) {
5543
- aborter?.cancel();
5544
- settler(value);
5545
- }
5546
- async function toResult(value) {
5547
- const actual = typeof value === "function" ? value() : value;
5548
- if (!(actual instanceof Promise)) return Promise.reject(/* @__PURE__ */ new TypeError(PROMISE_MESSAGE_EXPECTATION_RESULT));
5549
- return actual.then((result) => ok(result)).catch((reason) => error(reason));
5550
- }
5551
- //#endregion
5552
- //#region src/promise/delay.ts
5553
- function delay(options) {
5554
- const { signal, time } = getPromiseOptions(options);
5555
- if (signal?.aborted ?? false) return Promise.reject(signal?.reason);
5556
- const aborter = createAborter(signal, () => {
5557
- timer.cancel();
5558
- rejector(signal?.reason);
5681
+ const instance = {};
5682
+ Object.defineProperties(instance, {
5683
+ [LOGGER_PROPERTY]: { value: LOGGER_NAME },
5684
+ enabled: {
5685
+ enumerable: true,
5686
+ get: () => enabled,
5687
+ set: (value) => {
5688
+ enabled = typeof value === "boolean" ? value : enabled;
5689
+ }
5690
+ },
5691
+ time: { value: (label) => timedLogger(getString(label)) }
5559
5692
  });
5560
- const timer = getTimer(TIMER_WAIT, () => settlePromise(resolver, void 0, aborter), time);
5561
- let rejector;
5562
- let resolver;
5563
- return new Promise((resolve, reject) => {
5564
- rejector = reject;
5565
- resolver = resolve;
5566
- if (time === 0) settlePromise(resolver, void 0, aborter);
5567
- else timer();
5693
+ for (const method of methods) Object.defineProperty(instance, method, {
5694
+ enumerable: true,
5695
+ get() {
5696
+ return enabled ? console[method].bind(console) : noop;
5697
+ }
5568
5698
  });
5569
- }
5699
+ return Object.freeze(instance);
5700
+ })();
5701
+ let enabled = true;
5570
5702
  //#endregion
5571
- //#region src/promise/timed.ts
5572
- async function getTimedPromise(promise, time, signal) {
5573
- const aborter = createAborter(signal, () => {
5574
- timer.cancel();
5575
- rejector(signal?.reason);
5576
- });
5577
- const timer = getTimer(TIMER_WAIT, () => settlePromise(rejector, new PromiseTimeoutError(), aborter), time);
5578
- let rejector;
5579
- return Promise.race([promise, new Promise((_, reject) => {
5580
- rejector = reject;
5581
- timer();
5582
- })]).then((value) => {
5583
- aborter?.cancel();
5584
- timer.cancel();
5585
- rejector(void 0);
5586
- return value;
5587
- });
5703
+ //#region src/math.ts
5704
+ function average(array, key) {
5705
+ const aggregated = aggregate(AGGREGATION_AVERAGE, array, key);
5706
+ return aggregated.count > 0 ? aggregated.value / aggregated.count : NaN;
5588
5707
  }
5589
- async function timed(promise, options) {
5590
- if (!(promise instanceof Promise)) return Promise.reject(/* @__PURE__ */ new TypeError(PROMISE_MESSAGE_EXPECTATION_TIMED));
5591
- const { signal, time } = getPromiseOptions(options);
5592
- if (signal?.aborted ?? false) return Promise.reject(signal?.reason);
5593
- return time > 0 ? getTimedPromise(promise, time, signal) : promise;
5708
+ /**
5709
+ * Round a number up
5710
+ *
5711
+ * @param value Number to round up
5712
+ * @param decimals Number of decimal places to round to _(defaults to `0`)_
5713
+ * @returns Rounded number, or `Number.NaN` if the value if unable to be rounded
5714
+ */
5715
+ function ceil(value, decimals) {
5716
+ return roundNumber(Math.ceil, value, decimals);
5594
5717
  }
5595
- //#endregion
5596
- //#region src/promise/index.ts
5597
- async function attemptPromise(value, options) {
5598
- const isFunction = typeof value === "function";
5599
- if (!isFunction && !(value instanceof Promise)) return Promise.reject(/* @__PURE__ */ new TypeError(PROMISE_MESSAGE_EXPECTATION_ATTEMPT));
5600
- const { signal, time } = getPromiseOptions(options);
5601
- if (signal?.aborted ?? false) return Promise.reject(signal?.reason);
5602
- const aborter = createAborter(signal, () => {
5603
- rejector(signal?.reason);
5604
- });
5605
- async function handler(resolve, reject) {
5606
- try {
5607
- let result = isFunction ? value() : await value;
5608
- if (result instanceof Promise) result = await result;
5609
- settlePromise(resolve, result, aborter);
5610
- } catch (error) {
5611
- settlePromise(reject, error, aborter);
5612
- }
5718
+ function count(array, key, value) {
5719
+ if (!Array.isArray(array)) return NaN;
5720
+ const { length } = array;
5721
+ const callback = getAggregateCallback(key);
5722
+ if (callback == null) return length;
5723
+ let counted = 0;
5724
+ for (let index = 0; index < length; index += 1) {
5725
+ const item = array[index];
5726
+ if (Object.is(callback(item, index, array), value)) counted += 1;
5613
5727
  }
5614
- let rejector;
5615
- const promise = new Promise((resolve, reject) => {
5616
- rejector = reject;
5617
- handler(resolve, reject);
5618
- });
5619
- return time > 0 ? getTimedPromise(promise, time, signal) : promise;
5728
+ return counted;
5620
5729
  }
5621
- async function promises(items, options) {
5622
- const { signal, strategy } = getPromisesOptions(options);
5623
- if (signal?.aborted ?? false) return Promise.reject(signal?.reason);
5624
- if (!Array.isArray(items)) return Promise.resolve([]);
5625
- const actual = items.map((item) => typeof item === "function" ? item() : item).filter((item) => item instanceof Promise);
5626
- const { length } = actual;
5627
- if (length === 0) return Promise.resolve([]);
5628
- const complete = strategy === PROMISE_STRATEGY_DEFAULT;
5629
- const aborter = createAborter(signal, () => {
5630
- handlers.reject(signal?.reason);
5631
- });
5632
- const data = {
5633
- last: length - 1,
5634
- result: []
5635
- };
5636
- let handlers;
5637
- return new Promise((resolve, reject) => {
5638
- handlers = {
5639
- reject,
5640
- resolve
5641
- };
5642
- for (let index = 0; index < length; index += 1) actual[index].then((value) => handleResult(PROMISE_TYPE_FULFILLED, {
5643
- aborter,
5644
- complete,
5645
- data,
5646
- handlers,
5647
- index,
5648
- value
5649
- })).catch((reason) => handleResult(PROMISE_TYPE_REJECTED, {
5650
- aborter,
5651
- complete,
5652
- data,
5653
- handlers,
5654
- index,
5655
- value: reason
5656
- }));
5657
- });
5730
+ /**
5731
+ * Round a number down
5732
+ *
5733
+ * @param value Number to round down
5734
+ * @param decimals Number of decimal places to round to _(defaults to `0`)_
5735
+ * @returns Rounded number, or `Number.NaN` if the value if unable to be rounded
5736
+ */
5737
+ function floor(value, decimals) {
5738
+ return roundNumber(Math.floor, value, decimals);
5658
5739
  }
5659
- promises.result = resultPromises;
5660
- async function resultPromises(items, signal) {
5661
- return promises(items, signal).then(getResultsFromPromises);
5740
+ function median(array, key) {
5741
+ let length = Array.isArray(array) ? array.length : 0;
5742
+ if (!Array.isArray(array) || length === 0) return NaN;
5743
+ let values = array;
5744
+ const callback = getAggregateCallback(key);
5745
+ if (callback != null) values = array.map((item, index) => callback(item, index, array));
5746
+ const numbers = values.filter(isNumber).sort((first, second) => first - second);
5747
+ length = numbers.length;
5748
+ if (length === 1) return numbers[0];
5749
+ if (length % 2 === 0) {
5750
+ const first = length / 2 - 1;
5751
+ const second = length / 2;
5752
+ return (numbers[first] + numbers[second]) / 2;
5753
+ }
5754
+ return numbers[Math.floor(length / 2)];
5755
+ }
5756
+ function min(array, key) {
5757
+ return getAggregated("min", array, key);
5758
+ }
5759
+ function sum(array, key) {
5760
+ return getAggregated("sum", array, key);
5662
5761
  }
5663
5762
  //#endregion
5664
5763
  //#region src/query.ts
@@ -5847,9 +5946,6 @@ function createQueue(callback, options, key) {
5847
5946
  });
5848
5947
  return Object.freeze(instance);
5849
5948
  }
5850
- function getBooleanOrDefault(value, defaultValue) {
5851
- return typeof value === "boolean" ? value : defaultValue;
5852
- }
5853
5949
  function getOptions(input) {
5854
5950
  const options = typeof input === "object" && input != null ? input : {};
5855
5951
  return {
@@ -6125,92 +6221,6 @@ const RANDOM_BOOLEAN_MODIFIER = .5;
6125
6221
  const RANDOM_HEX_CHARACTERS = "0123456789ABCDEF";
6126
6222
  const RANDOM_HEX_MAXIMUM = 15;
6127
6223
  //#endregion
6128
- //#region src/result/index.ts
6129
- async function asyncAttempt(value, err) {
6130
- try {
6131
- let result = typeof value === "function" ? value() : await value;
6132
- if (result instanceof Promise) result = await result;
6133
- return ok(result);
6134
- } catch (thrown) {
6135
- return getError(err ?? thrown, err == null ? void 0 : thrown);
6136
- }
6137
- }
6138
- function attempt(callback, err) {
6139
- try {
6140
- return ok(callback());
6141
- } catch (thrown) {
6142
- return getError(err ?? thrown, err == null ? void 0 : thrown);
6143
- }
6144
- }
6145
- Object.defineProperty(attempt, "async", { value: asyncAttempt });
6146
- //#endregion
6147
- //#region src/result/match.ts
6148
- async function asyncMatchResult(result, first, error) {
6149
- let value;
6150
- if (typeof result === "function") value = await result();
6151
- else if (result instanceof Promise) value = await result;
6152
- else value = result;
6153
- if (!isResult(value)) throw new Error(MATCH_MESSAGE);
6154
- const hasObj = typeof first === "object" && first !== null;
6155
- const okHandler = hasObj ? first.ok : first;
6156
- const errorHandler = hasObj ? first.error : error;
6157
- if (isOk(value)) return okHandler(value.value);
6158
- return errorHandler(value.error, value.original);
6159
- }
6160
- function matchResult(result, first, error) {
6161
- const value = typeof result === "function" ? result() : result;
6162
- if (!isResult(value)) throw new Error(MATCH_MESSAGE);
6163
- const hasObj = typeof first === "object" && first !== null;
6164
- const okHandler = hasObj ? first.ok : first;
6165
- const errorHandler = hasObj ? first.error : error;
6166
- if (isOk(value)) return okHandler(value.value);
6167
- return errorHandler(value.error, value.original);
6168
- }
6169
- const MATCH_MESSAGE = "`result.match` expected a Result or a function that returns a Result";
6170
- Object.defineProperty(matchResult, "async", { value: asyncMatchResult });
6171
- //#endregion
6172
- //#region src/result/work/flow.ts
6173
- function attemptAsyncFlow(...fns) {
6174
- let Flow;
6175
- return (...args) => asyncAttempt(() => {
6176
- Flow ??= asyncFlow(...fns);
6177
- return Flow(...args.map((value) => {
6178
- if (isError(value)) throw value.error;
6179
- return isOk(value) ? value.value : value;
6180
- }));
6181
- });
6182
- }
6183
- function attemptFlow(...fns) {
6184
- let Flow;
6185
- return (...args) => attempt(() => {
6186
- Flow ??= flow(...fns);
6187
- return Flow(...args.map((value) => {
6188
- if (isError(value)) throw value.error;
6189
- return isOk(value) ? value.value : value;
6190
- }));
6191
- });
6192
- }
6193
- Object.defineProperty(attemptFlow, "async", { value: attemptAsyncFlow });
6194
- //#endregion
6195
- //#region src/result/work/pipe.ts
6196
- async function attemptAsyncPipe(initial, first, ...seconds) {
6197
- return asyncAttempt(() => {
6198
- if (isError(initial)) throw initial.error;
6199
- const value = typeof initial === "function" ? initial() : isOk(initial) ? initial.value : initial;
6200
- if (first == null) return value;
6201
- return asyncPipe(value, ...[first, ...seconds]);
6202
- });
6203
- }
6204
- function attemptPipe(initial, first, ...seconds) {
6205
- return attempt(() => {
6206
- if (isError(initial)) throw initial.error;
6207
- const value = typeof initial === "function" ? initial() : isOk(initial) ? initial.value : initial;
6208
- if (first == null) return value;
6209
- return pipe(value, ...[first, ...seconds]);
6210
- });
6211
- }
6212
- Object.defineProperty(attemptPipe, "async", { value: attemptAsyncPipe });
6213
- //#endregion
6214
6224
  //#region src/sized/set.ts
6215
6225
  /**
6216
6226
  * A _Set_ with a maximum size
@@ -6267,4 +6277,4 @@ var SizedSet = class extends Set {
6267
6277
  }
6268
6278
  };
6269
6279
  //#endregion
6270
- export { CancelablePromise, Logger, PromiseTimeoutError, QueueError, RetryError, SORT_DIRECTION_ASCENDING, SORT_DIRECTION_DESCENDING, SizedMap, SizedSet, assert, assertCondition, assertDefined, assertInstanceOf, assertIs, assertProperty, assign, asyncAttempt, asyncDebounce, asyncFlow, asyncMatchResult, asyncOnce, asyncPipe, asyncThrottle, attempt, attemptAsyncFlow, attemptAsyncPipe, attemptFlow, attemptPipe, attemptPromise, average, beacon, between, camelCase, cancelable, capitalize, ceil, chunk, clamp, clone, compact, compare, copy, count, debounce, deburr, dedent, delay, deregisterCloner, deregisterComparator, deregisterEqualizer, diff, difference, drop, endsWith, endsWithArray, equal, error, exclude, exists, filter, find, findLast, first, firstOrDefault, flatFreeze, flatten, floor, flow, freeze, fromQuery, toPromise as fromResult, toPromise, fuzzy, fuzzyMatch, getArray, getArrayComparison, getColor, getError, getForegroundColor, getHexColor, getHexaColor, getHslColor, getHslaColor, getHwbColor, getHwbaColor, getNormalizedHex, getNumber, getRandomBoolean, getRandomCharacters, getRandomColor, getRandomFloatingNumber as getRandomFloat, getRandomHex, getRandomInteger, getRandomItem, getRandomItems, getRgbColor, getRgbaColor, getSortedIndex, getString, getTimedPromise, getUuid, getValue, groupArraysBy, groupBy, handleResult, hasValue, hasValueResult, herald, hexToHsl, hexToHsla, hexToHwb, hexToHwba, hexToRgb, hexToRgba, hslToHex, hslToHwb, hslToHwba, hslToRgb, hslToRgba, hwbToHex, hwbToHsl, hwbToHsla, hwbToRgb, hwbToRgba, ignoreKey, inMap, inSet, includes, includesArray, indexOf, indexOfArray, initializeAssigner, initializeEqualizer, initializeMerger, initializeNormalizer, initializeSorter, initializeTemplater, initializeTransformer, insert, interpolate, intersection, isArrayOrPlainObject, isBeacon, isBeaconSubscription, isColor, isConstructor, isEmpty, isError, isFrozen, isFulfilled, isHerald, isHeraldEvents, isHeraldSubscription, isHexColor, isHslColor, isHslaColor, isHwbColor, isHwbaColor, isInstanceOf, isKey, isKeyedQueue, isLogger, isNonArrayOrPlainObject, isNonConstructor, isNonEmpty, isNonInstanceOf, isNonKey, isNonNullable, isNonNullableOrEmpty, isNonNullableOrWhitespace, isNonNumber, isNonNumerical, isNonObject, isNonPlainObject, isNonPrimitive, isNonTypedArray, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isObservable, isOk, isPlainObject, isPrimitive, isQueue, isQueueInstance, isRejected, isResult, isRgbColor, isRgbaColor, isSorted, isSubscription, isTimedLogger, isTypedArray, join, kebabCase, keyedQueue, last, lastIndexOf, lastOrDefault, lowerCase, matchResult, max, median, memoize, merge, min, move, moveIndices, moveToIndex, noop, normalize, ok, omit, once, parse, partition, pascalCase, pick, pipe, promises, push, queue, range, registerCloner, registerComparator, registerEqualizer, resultPromises, retry, reverse, rgbToHex, rgbToHsl, rgbToHsla, rgbToHwb, rgbToHwba, round, select, setValue, settlePromise, shake, shuffle, single, slice, smush, snakeCase, sort, splice, startsWith, startsWithArray, sum, swap, take, template, throttle, timed, times, titleCase, toMap, toMapArrays, toQuery, toRecord, toRecordArrays, toResult, toSet, toggle, transform, trim, truncate, tryDecode, tryEncode, union, unique, unsmush, unwrap, update, upperCase, words };
6280
+ export { CancelablePromise, Logger, PromiseTimeoutError, QueueError, RetryError, SORT_DIRECTION_ASCENDING, SORT_DIRECTION_DESCENDING, SizedMap, SizedSet, assert, assertCondition, assertDefined, assertInstanceOf, assertIs, assertProperty, assign, asyncAttempt, asyncDebounce, asyncFlow, asyncMatchResult, asyncOnce, asyncPipe, asyncThrottle, attempt, attemptAsyncFlow, attemptAsyncPipe, attemptFlow, attemptPipe, attemptPromise, average, beacon, between, camelCase, cancelable, capitalize, ceil, chunk, clamp, clone, compact, compare, copy, count, debounce, deburr, dedent, delay, deregisterCloner, deregisterComparator, deregisterEqualizer, diff, difference, drop, endsWith, endsWithArray, equal, error, exclude, exists, filter, find, findLast, first, firstOrDefault, flatFreeze, flatten, floor, flow, freeze, fromQuery, toPromise as fromResult, toPromise, fuzzy, fuzzyMatch, getArray, getArrayComparison, getColor, getForegroundColor, getHexColor, getHexaColor, getHslColor, getHslaColor, getHwbColor, getHwbaColor, getNormalizedHex, getNumber, getRandomBoolean, getRandomCharacters, getRandomColor, getRandomFloatingNumber as getRandomFloat, getRandomHex, getRandomInteger, getRandomItem, getRandomItems, getRgbColor, getRgbaColor, getSortedIndex, getString, getTimedPromise, getUuid, getValue, groupArraysBy, groupBy, handleResult, hasValue, hasValueResult, herald, hexToHsl, hexToHsla, hexToHwb, hexToHwba, hexToRgb, hexToRgba, hslToHex, hslToHwb, hslToHwba, hslToRgb, hslToRgba, hwbToHex, hwbToHsl, hwbToHsla, hwbToRgb, hwbToRgba, ignoreKey, inMap, inSet, includes, includesArray, indexOf, indexOfArray, initializeAssigner, initializeEqualizer, initializeMerger, initializeNormalizer, initializeSorter, initializeTemplater, initializeTransformer, insert, interpolate, intersection, isArrayOrPlainObject, isBeacon, isBeaconSubscription, isColor, isConstructor, isEmpty, isError, isFrozen, isFulfilled, isHerald, isHeraldEvents, isHeraldSubscription, isHexColor, isHslColor, isHslaColor, isHwbColor, isHwbaColor, isInstanceOf, isKey, isKeyedQueue, isLogger, isNonArrayOrPlainObject, isNonConstructor, isNonEmpty, isNonInstanceOf, isNonKey, isNonNullable, isNonNullableOrEmpty, isNonNullableOrWhitespace, isNonNumber, isNonNumerical, isNonObject, isNonPlainObject, isNonPrimitive, isNonTypedArray, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isObservable, isOk, isPlainObject, isPrimitive, isQueue, isQueueInstance, isRejected, isResult, isRgbColor, isRgbaColor, isSorted, isSubscription, isTimedLogger, isTypedArray, join, kebabCase, keyedQueue, last, lastIndexOf, lastOrDefault, lowerCase, matchResult, max, median, memoize, merge, min, move, moveIndices, moveToIndex, noop, normalize, ok, omit, once, parse, partition, pascalCase, pick, pipe, promises, push, queue, range, registerCloner, registerComparator, registerEqualizer, resultPromises, retry, reverse, rgbToHex, rgbToHsl, rgbToHsla, rgbToHwb, rgbToHwba, round, select, setValue, settlePromise, shake, shuffle, single, slice, smush, snakeCase, sort, splice, startsWith, startsWithArray, sum, swap, take, template, throttle, timed, times, titleCase, toMap, toMapArrays, toQuery, toRecord, toRecordArrays, toResult, toSet, toggle, transform, trim, truncate, tryDecode, tryEncode, union, unique, unsmush, unwrap, update, upperCase, words };