@oscarpalmer/atoms 0.194.0 → 0.195.0

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 (81) 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/once.mjs +1 -1
  13. package/dist/herald.d.mts +2 -71
  14. package/dist/herald.mjs +1 -109
  15. package/dist/index.d.mts +3270 -3271
  16. package/dist/index.mjs +1500 -1498
  17. package/dist/{array → internal/array}/get.d.mts +2 -2
  18. package/dist/{array → internal/array}/get.mjs +2 -2
  19. package/dist/{array → internal/array}/match.d.mts +2 -2
  20. package/dist/{array → internal/array}/match.mjs +2 -2
  21. package/dist/internal/defaults.d.mts +5 -0
  22. package/dist/internal/defaults.mjs +9 -0
  23. package/dist/{function → internal/function}/assert.d.mts +2 -2
  24. package/dist/{function → internal/function}/assert.mjs +2 -2
  25. package/dist/{function → internal/function}/memoize.d.mts +2 -2
  26. package/dist/{function → internal/function}/memoize.mjs +3 -3
  27. package/dist/{function → internal/function}/work.d.mts +2 -2
  28. package/dist/{function → internal/function}/work.mjs +2 -2
  29. package/dist/internal/herald.d.mts +71 -0
  30. package/dist/internal/herald.mjs +110 -0
  31. package/dist/internal/number.d.mts +1 -2
  32. package/dist/internal/number.mjs +1 -4
  33. package/dist/internal/{result.d.mts → result/misc.d.mts} +42 -3
  34. package/dist/internal/{result.mjs → result/misc.mjs} +29 -3
  35. package/dist/{result → internal/result}/models.d.mts +2 -2
  36. package/dist/{sized → internal/sized}/map.d.mts +1 -1
  37. package/dist/{sized → internal/sized}/map.mjs +2 -2
  38. package/dist/internal/{sized.d.mts → sized/misc.d.mts} +1 -1
  39. package/dist/internal/{sized.mjs → sized/misc.mjs} +2 -2
  40. package/dist/{string → internal/string}/case.d.mts +1 -1
  41. package/dist/{string → internal/string}/case.mjs +2 -2
  42. package/dist/internal/{string.d.mts → string/misc.d.mts} +1 -1
  43. package/dist/internal/{string.mjs → string/misc.mjs} +1 -1
  44. package/dist/internal/value/compare.mjs +1 -1
  45. package/dist/internal/value/has.d.mts +1 -1
  46. package/dist/internal/value/misc.d.mts +1 -1
  47. package/dist/internal/value/misc.mjs +2 -2
  48. package/dist/is.mjs +2 -2
  49. package/dist/logger.mjs +1 -1
  50. package/dist/promise/helpers.d.mts +1 -1
  51. package/dist/promise/helpers.mjs +2 -2
  52. package/dist/promise/index.d.mts +1 -1
  53. package/dist/promise/misc.d.mts +1 -1
  54. package/dist/promise/misc.mjs +2 -1
  55. package/dist/promise/models.d.mts +1 -1
  56. package/dist/query.mjs +1 -1
  57. package/dist/queue.mjs +1 -4
  58. package/dist/random.mjs +1 -1
  59. package/dist/result/index.d.mts +1 -1
  60. package/dist/result/index.mjs +1 -1
  61. package/dist/result/match.d.mts +1 -1
  62. package/dist/result/match.mjs +1 -1
  63. package/dist/result/misc.d.mts +3 -42
  64. package/dist/result/misc.mjs +2 -28
  65. package/dist/result/work/flow.d.mts +1 -1
  66. package/dist/result/work/flow.mjs +2 -2
  67. package/dist/result/work/pipe.d.mts +1 -1
  68. package/dist/result/work/pipe.mjs +2 -2
  69. package/dist/sized/set.mjs +1 -1
  70. package/dist/string/fuzzy.mjs +2 -2
  71. package/dist/string/index.d.mts +1 -1
  72. package/dist/string/index.mjs +1 -1
  73. package/dist/string/match.mjs +1 -1
  74. package/dist/string/normalize.mjs +2 -2
  75. package/dist/string/template.mjs +1 -1
  76. package/dist/subscription.d.mts +2 -0
  77. package/dist/subscription.mjs +2 -0
  78. package/dist/value/diff.mjs +1 -1
  79. package/dist/value/smush.mjs +1 -1
  80. package/package.json +23 -11
  81. /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,204 @@ 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
+ Object.defineProperty(debounce, "async", { value: asyncDebounce });
1532
+ Object.defineProperty(throttle, "async", { value: asyncThrottle });
1533
+ //#endregion
1534
+ //#region src/internal/result/misc.ts
1535
+ function error(value, original) {
1536
+ return getError(value, original);
1537
+ }
1538
+ function getError(value, original) {
1539
+ const errorResult = {
1540
+ error: value,
1541
+ ok: false
1542
+ };
1543
+ if (original instanceof Error) errorResult.original = original;
1544
+ return errorResult;
1545
+ }
1546
+ function isError(value, extended) {
1547
+ return isResultValue(value, false) && (extended === true ? value.original instanceof Error : true);
1548
+ }
1549
+ function isOk(value) {
1550
+ return isResultValue(value, true);
1551
+ }
1552
+ /**
1553
+ * Is the value a _Result_?
1554
+ *
1555
+ * @param value Value to check
1556
+ * @returns `true` if the value is a _Result_, otherwise `false`
1557
+ */
1558
+ function isResult(value) {
1559
+ return isResultValue(value, true) || isResultValue(value, false);
1560
+ }
1561
+ function isResultValue(value, okValue) {
1562
+ if (isNonPlainObject(value)) return false;
1563
+ return value.ok === okValue && (okValue ? RESULT_PROPERTY_VALUE : RESULT_PROPERTY_ERROR) in value;
1564
+ }
1565
+ /**
1566
+ * Creates an ok result
1567
+ *
1568
+ * @param value Value
1569
+ * @returns Ok result
1570
+ */
1571
+ function ok(value) {
1572
+ return {
1573
+ ok: true,
1574
+ value
1575
+ };
1443
1576
  }
1444
1577
  function unwrap(value, defaultValue) {
1445
1578
  return isOk(value) ? value.value : defaultValue;
1446
1579
  }
1447
- const RESULT_MESSAGE_PROMISE = "toPromise expected to receive a Result";
1580
+ const RESULT_PROPERTY_ERROR = "error";
1581
+ const RESULT_PROPERTY_VALUE = "value";
1448
1582
  //#endregion
1449
1583
  //#region src/internal/value/misc.ts
1450
1584
  function findKey(needle, haystack) {
@@ -1499,7 +1633,7 @@ function hasValueResult(data, path, ignoreCase) {
1499
1633
  return getNestedValue(data, path, ignoreCase === true);
1500
1634
  }
1501
1635
  //#endregion
1502
- //#region src/function/assert.ts
1636
+ //#region src/internal/function/assert.ts
1503
1637
  /**
1504
1638
  * Asserts that a condition is true, throwing an error if it is not
1505
1639
  *
@@ -1593,51 +1727,309 @@ function assertProperty(path, condition, message, error) {
1593
1727
  }
1594
1728
  const ASSERT_MESSAGE_VALUE_DEFINED = "Expected value to be defined";
1595
1729
  //#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
1730
+ //#region src/function/once.ts
1603
1731
  /**
1604
- * Is the number between a minimum and maximum value?
1732
+ * Create an asynchronous function that can only be called once, rejecting or resolving the same result on subsequent calls
1605
1733
  *
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`
1734
+ * _Available as `asyncOnce` and `once.async`_
1735
+ *
1736
+ * @param callback Callback to use once
1737
+ * @returns _Once_ callback
1610
1738
  */
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);
1739
+ function asyncOnce(callback) {
1740
+ assert(() => typeof callback === "function", ONCE_MESSAGE_EXPECTATION);
1741
+ const state = {
1742
+ called: false,
1743
+ cleared: false,
1744
+ error: false,
1745
+ finished: false,
1746
+ items: [],
1747
+ value: void 0
1748
+ };
1749
+ const fn = (...parameters) => {
1750
+ if (state.cleared) return Promise.reject(new Error(ONCE_MESSAGE_CLEARED));
1751
+ if (state.finished) return state.error ? Promise.reject(state.value) : Promise.resolve(state.value);
1752
+ if (state.called) return new Promise((resolve, reject) => {
1753
+ state.items.push({
1754
+ reject,
1755
+ resolve
1756
+ });
1757
+ });
1758
+ state.called = true;
1759
+ return new Promise((resolve, reject) => {
1760
+ state.items.push({
1761
+ reject,
1762
+ resolve
1763
+ });
1764
+ callback(...parameters).then((value) => {
1765
+ handleOnceResult(state, value, false);
1766
+ }).catch((error) => {
1767
+ handleOnceResult(state, error, true);
1768
+ });
1769
+ });
1770
+ };
1771
+ Object.defineProperties(fn, {
1772
+ called: {
1773
+ enumerable: true,
1774
+ get: () => state.called
1775
+ },
1776
+ clear: { value: () => clearState(state) },
1777
+ cleared: {
1778
+ enumerable: true,
1779
+ get: () => state.cleared
1780
+ },
1781
+ error: {
1782
+ enumerable: true,
1783
+ get: () => state.error
1784
+ },
1785
+ finished: {
1786
+ enumerable: true,
1787
+ get: () => state.finished
1788
+ }
1789
+ });
1790
+ return fn;
1791
+ }
1792
+ function clearState(state) {
1793
+ if (!state.called || state.cleared) return;
1794
+ state.cleared = true;
1795
+ state.value = void 0;
1796
+ }
1797
+ function handleOnceResult(state, value, error) {
1798
+ state.error = error;
1799
+ state.finished = true;
1800
+ state.value = value;
1801
+ const items = state.items.splice(0);
1802
+ const { length } = items;
1803
+ for (let index = 0; index < length; index += 1) {
1804
+ const { reject, resolve } = items[index];
1805
+ if (error) reject(value);
1806
+ else resolve(value);
1807
+ }
1619
1808
  }
1620
1809
  /**
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
1810
+ * Create a function that can only be called once, returning the same value on subsequent calls
1628
1811
  *
1629
- * @example
1630
- * ```typescript
1631
- * clamp(10, 0, 5); // => 5
1632
- * clamp(10, 0, 5, true); // => 0
1633
- * ```
1812
+ * @param callback Callback to use once
1813
+ * @returns _Once_ callback
1634
1814
  */
1635
- function clamp(value, minimum, maximum, loop) {
1636
- if (![
1637
- value,
1638
- minimum,
1639
- maximum
1640
- ].every(isNumber)) return NaN;
1815
+ function once(callback) {
1816
+ assert(() => typeof callback === "function", ONCE_MESSAGE_EXPECTATION);
1817
+ const state = {
1818
+ called: false,
1819
+ cleared: false,
1820
+ value: void 0
1821
+ };
1822
+ const fn = (...parameters) => {
1823
+ if (state.cleared) throw new Error(ONCE_MESSAGE_CLEARED);
1824
+ if (state.called) return state.value;
1825
+ state.called = true;
1826
+ state.value = callback(...parameters);
1827
+ return state.value;
1828
+ };
1829
+ Object.defineProperties(fn, {
1830
+ called: {
1831
+ enumerable: true,
1832
+ get: () => state.called
1833
+ },
1834
+ clear: { value: () => clearState(state) },
1835
+ cleared: {
1836
+ enumerable: true,
1837
+ get: () => state.cleared
1838
+ }
1839
+ });
1840
+ return fn;
1841
+ }
1842
+ const ONCE_MESSAGE_CLEARED = "Once has been cleared";
1843
+ const ONCE_MESSAGE_EXPECTATION = "Once expected a function";
1844
+ Object.defineProperty(once, "async", { value: asyncOnce });
1845
+ //#endregion
1846
+ //#region src/function/retry.ts
1847
+ /**
1848
+ * An error thrown when a retry fails
1849
+ */
1850
+ var RetryError = class extends Error {
1851
+ original;
1852
+ constructor(message, original) {
1853
+ super(message);
1854
+ this.original = original;
1855
+ this.name = RETRY_ERROR_NAME;
1856
+ }
1857
+ };
1858
+ /**
1859
+ * Retry a callback a specified number of times, with a delay between attempts
1860
+ *
1861
+ * _Available as `asyncRetry` and `retry.async`_
1862
+ *
1863
+ * @param callback Callback to retry
1864
+ * @param options Retry options
1865
+ * @returns Callback result
1866
+ */
1867
+ async function asyncRetry(callback, options) {
1868
+ if (typeof callback !== "function") throw new TypeError(RETRY_MESSAGE_EXPECTATION);
1869
+ async function handle() {
1870
+ try {
1871
+ const result = await callback();
1872
+ resolver(result);
1873
+ } catch (error) {
1874
+ if (attempts >= times || !when(error)) rejector(new RetryError(RETRY_MESSAGE_FAILED, error));
1875
+ else {
1876
+ attempts += 1;
1877
+ timer();
1878
+ }
1879
+ }
1880
+ }
1881
+ const { delay, times, when } = getRetryOptions(options);
1882
+ const timer = getTimer(TIMER_WAIT, handle, delay);
1883
+ let attempts = 0;
1884
+ let rejector;
1885
+ let resolver;
1886
+ return new Promise((resolve, reject) => {
1887
+ rejector = reject;
1888
+ resolver = resolve;
1889
+ handle();
1890
+ });
1891
+ }
1892
+ function getRetryNumber(value) {
1893
+ return typeof value === "number" && value > 0 ? value : 0;
1894
+ }
1895
+ function getRetryOptions(input) {
1896
+ const options = isPlainObject(input) ? input : {};
1897
+ return {
1898
+ delay: getRetryNumber(options.delay),
1899
+ times: getRetryNumber(options.times),
1900
+ when: typeof options.when === "function" ? options.when : shouldRetry
1901
+ };
1902
+ }
1903
+ /**
1904
+ * Retry a callback a specified number of times
1905
+ *
1906
+ * @param callback Callback to retry
1907
+ * @param options Retry options
1908
+ * @returns Callback result
1909
+ */
1910
+ function retry(callback, options) {
1911
+ if (typeof callback !== "function") throw new TypeError(RETRY_MESSAGE_EXPECTATION);
1912
+ const { times, when } = getRetryOptions(options);
1913
+ let last;
1914
+ for (let index = 0; index <= times; index += 1) try {
1915
+ return callback();
1916
+ } catch (error) {
1917
+ if (index >= times || !when(error)) {
1918
+ last = error;
1919
+ break;
1920
+ }
1921
+ }
1922
+ throw new RetryError(RETRY_MESSAGE_FAILED, last);
1923
+ }
1924
+ function shouldRetry() {
1925
+ return true;
1926
+ }
1927
+ const RETRY_ERROR_NAME = "RetryError";
1928
+ const RETRY_MESSAGE_EXPECTATION = "Retry expected a function";
1929
+ const RETRY_MESSAGE_FAILED = "Retry failed";
1930
+ Object.defineProperty(retry, "async", { value: asyncRetry });
1931
+ //#endregion
1932
+ //#region src/internal/function/work.ts
1933
+ function asyncFlow(...fns) {
1934
+ assertFlowFunctions(fns);
1935
+ return (...args) => asyncWork(args.map((value) => {
1936
+ if (isError(value)) throw value.error;
1937
+ return isOk(value) ? value.value : value;
1938
+ }), fns, true);
1939
+ }
1940
+ function flow(...fns) {
1941
+ assertFlowFunctions(fns);
1942
+ return (...args) => work(args.map((value) => {
1943
+ if (isError(value)) throw value.error;
1944
+ return isOk(value) ? value.value : value;
1945
+ }), fns, true);
1946
+ }
1947
+ async function asyncPipe(value, ...pipes) {
1948
+ assertPipeFunctions(pipes);
1949
+ return asyncWork(value, pipes, false);
1950
+ }
1951
+ function pipe(value, ...pipes) {
1952
+ assertPipeFunctions(pipes);
1953
+ return work(value, pipes, false);
1954
+ }
1955
+ async function asyncWork(initial, functions, flow) {
1956
+ const { length } = functions;
1957
+ let transformed = unwrapValue(initial);
1958
+ for (let index = 0; index < length; index += 1) {
1959
+ const fn = functions[index];
1960
+ transformed = unwrapValue(flow && index === 0 && Array.isArray(initial) ? await fn(...initial) : await fn(transformed));
1961
+ }
1962
+ return transformed;
1963
+ }
1964
+ function unwrapValue(value, flow, nested) {
1965
+ if (typeof value === "function") {
1966
+ if (nested != null) throw new TypeError(WORK_MESSAGE_NESTING);
1967
+ return unwrapValue(value(), flow, true);
1968
+ }
1969
+ if (flow != null && value instanceof Promise) throw new TypeError(flow ? WORK_MESSAGE_FLOW_PROMISE : WORK_MESSAGE_PIPE_PROMISE);
1970
+ if (isError(value)) throw value.error;
1971
+ return isOk(value) ? value.value : value;
1972
+ }
1973
+ function work(initial, functions, flow) {
1974
+ const { length } = functions;
1975
+ let transformed = unwrapValue(initial, flow);
1976
+ for (let index = 0; index < length; index += 1) {
1977
+ const fn = functions[index];
1978
+ transformed = unwrapValue(flow && index === 0 && Array.isArray(initial) ? fn(...initial) : fn(transformed), flow);
1979
+ }
1980
+ return transformed;
1981
+ }
1982
+ const WORK_MESSAGE_FLOW_ARRAY = "Flow expected to receive an array of functions";
1983
+ const WORK_MESSAGE_FLOW_PROMISE = "Synchronous Flow received a promise. Use `flow.async` instead.";
1984
+ const WORK_MESSAGE_NESTING = "Return values are too deeply nested.";
1985
+ const WORK_MESSAGE_PIPE_ARRAY = "Pipe expected to receive an array of functions";
1986
+ const WORK_MESSAGE_PIPE_PROMISE = "Synchronous Pipe received a promise. Use `pipe.async` instead.";
1987
+ const assertFlowFunctions = assert.condition((value) => Array.isArray(value) && value.every((item) => typeof item === "function"), WORK_MESSAGE_FLOW_ARRAY, TypeError);
1988
+ const assertPipeFunctions = assert.condition((value) => Array.isArray(value) && value.every((item) => typeof item === "function"), WORK_MESSAGE_PIPE_ARRAY, TypeError);
1989
+ flow.async = asyncFlow;
1990
+ pipe.async = asyncPipe;
1991
+ Object.defineProperty(flow, "async", { value: asyncFlow });
1992
+ Object.defineProperty(pipe, "async", { value: asyncPipe });
1993
+ //#endregion
1994
+ //#region src/internal/number.ts
1995
+ /**
1996
+ * Is the number between a minimum and maximum value?
1997
+ *
1998
+ * @param value Value to check
1999
+ * @param minimum Minimum value
2000
+ * @param maximum Maximum value
2001
+ * @returns `true` if the value is between the minimum and maximum, otherwise `false`
2002
+ */
2003
+ function between(value, minimum, maximum) {
2004
+ if (![
2005
+ value,
2006
+ minimum,
2007
+ maximum
2008
+ ].every(isNumber)) return false;
2009
+ if (Object.is(minimum, maximum)) return Object.is(value, minimum);
2010
+ return value >= (maximum > minimum ? minimum : maximum) && value <= (maximum > minimum ? maximum : minimum);
2011
+ }
2012
+ /**
2013
+ * Clamp a number between a minimum and maximum value
2014
+ *
2015
+ * @param value Value to clamp
2016
+ * @param minimum Minimum value
2017
+ * @param maximum Maximum value
2018
+ * @param loop If `true`, the value will loop around when smaller than the minimum or larger than the maximum _(defaults to `false`)_
2019
+ * @returns Clamped value
2020
+ *
2021
+ * @example
2022
+ * ```typescript
2023
+ * clamp(10, 0, 5); // => 5
2024
+ * clamp(10, 0, 5, true); // => 0
2025
+ * ```
2026
+ */
2027
+ function clamp(value, minimum, maximum, loop) {
2028
+ if (![
2029
+ value,
2030
+ minimum,
2031
+ maximum
2032
+ ].every(isNumber)) return NaN;
1641
2033
  if (value < minimum) return loop === true ? maximum : minimum;
1642
2034
  return value > maximum ? loop === true ? minimum : maximum : value;
1643
2035
  }
@@ -1664,15 +2056,12 @@ function getNumber(value) {
1664
2056
  if (isBinary || NUMBER_EXPRESSION_OCTAL.test(trimmed)) return Number.parseInt(trimmed.slice(2), isBinary ? 2 : NUMBER_OCTAL_VALUE);
1665
2057
  return Number(trimmed);
1666
2058
  }
1667
- function getNumberOrDefault(value, defaultValue, minimum) {
1668
- return typeof value === "number" && !Number.isNaN(value) && value >= (minimum ?? 0) ? Math.floor(value) : defaultValue;
1669
- }
1670
2059
  const NUMBER_EXPRESSION_BINARY = /^0b[01]+$/i;
1671
2060
  const NUMBER_EXPRESSION_OCTAL = /^0o[0-7]+$/i;
1672
2061
  const NUMBER_EXPRESSION_ZEROISH = /^\s*0+\s*$/;
1673
2062
  const NUMBER_OCTAL_VALUE = 8;
1674
2063
  //#endregion
1675
- //#region src/internal/sized.ts
2064
+ //#region src/internal/sized/misc.ts
1676
2065
  function getSizedMaximum(first, second) {
1677
2066
  let actual;
1678
2067
  if (typeof first === "number") actual = first;
@@ -1682,7 +2071,7 @@ function getSizedMaximum(first, second) {
1682
2071
  const SIZED_MAXIMUM_ABSOLUTE = 16777216;
1683
2072
  const SIZED_MAXIMUM_DEFAULT = 1048576;
1684
2073
  //#endregion
1685
- //#region src/sized/map.ts
2074
+ //#region src/internal/sized/map.ts
1686
2075
  /**
1687
2076
  * A _Map_ with a maximum size
1688
2077
  *
@@ -1736,7 +2125,7 @@ var SizedMap = class extends Map {
1736
2125
  }
1737
2126
  };
1738
2127
  //#endregion
1739
- //#region src/function/memoize.ts
2128
+ //#region src/internal/function/memoize.ts
1740
2129
  function getMemoizationOptions(input) {
1741
2130
  const { cacheKey, cacheSize } = isPlainObject(input) ? input : {};
1742
2131
  return {
@@ -1789,1012 +2178,718 @@ const MEMOIZED_CACHE_SIZE_DEFAULT = 1024;
1789
2178
  const MEMOIZED_CALLBACK = "Memoized requires a callback function";
1790
2179
  const MEMOIZED_KEY_SEPARATOR = "_";
1791
2180
  //#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
2181
+ //#region src/internal/string/case.ts
1881
2182
  /**
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`_
2183
+ * Convert a string to camel case _(thisIsCamelCase)_
1888
2184
  *
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
2185
+ * @param value String to convert
2186
+ * @returns Camel-cased string
1892
2187
  */
1893
- function asyncDebounce(callback, time) {
1894
- return getAsyncTimer(TIMER_DEBOUNCE, callback, time);
2188
+ function camelCase(value) {
2189
+ return toCase(STRING_CASE_CAMEL, value, true, false);
1895
2190
  }
1896
2191
  /**
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`_
2192
+ * Capitalize the first letter of a string _(and lowercase the rest)_
1903
2193
  *
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
2194
+ * @param value String to capitalize
2195
+ * @returns Capitalized string
1907
2196
  */
1908
- function asyncThrottle(callback, time) {
1909
- return getAsyncTimer(TIMER_THROTTLE, callback, time);
2197
+ function capitalize(value) {
2198
+ if (typeof value !== "string" || value.length === 0) return "";
2199
+ memoizedCapitalize ??= memoize((v) => v.length === 1 ? v.toLocaleUpperCase() : `${v.charAt(0).toLocaleUpperCase()}${v.slice(1).toLocaleLowerCase()}`);
2200
+ return memoizedCapitalize.run(value);
1910
2201
  }
1911
2202
  /**
1912
- * Debounce a function, ensuring it is only called after `time` milliseconds have passed
2203
+ * Convert a string to kebab case _(this-is-kebab-case)_
1913
2204
  *
1914
- * On subsequent calls, the timer is reset and will wait another `time` milliseconds _(and so on...)_
2205
+ * @param value String to convert
2206
+ * @returns Kebab-cased string
2207
+ */
2208
+ function kebabCase(value) {
2209
+ return toCase(STRING_CASE_KEBAB, value, false, false);
2210
+ }
2211
+ /**
2212
+ * Convert a string to lower case
1915
2213
  *
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
2214
+ * @param value String to convert
2215
+ * @returns Lower-cased string
1919
2216
  */
1920
- function debounce(callback, time) {
1921
- return getTimer(TIMER_DEBOUNCE, callback, time);
2217
+ function lowerCase(value) {
2218
+ if (typeof value !== "string") return "";
2219
+ memoizedLowerCase ??= memoize((v) => v.toLocaleLowerCase());
2220
+ return memoizedLowerCase.run(value);
1922
2221
  }
1923
2222
  /**
1924
- * Throttle a function, ensuring it is only called once every `time` milliseconds
2223
+ * Convert a string to pascal case _(ThisIsPascalCase)_
1925
2224
  *
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
2225
+ * @param value String to convert
2226
+ * @returns Pascal-cased string
1929
2227
  */
1930
- function throttle(callback, time) {
1931
- return getTimer(TIMER_THROTTLE, callback, time);
2228
+ function pascalCase(value) {
2229
+ return toCase(STRING_CASE_PASCAL, value, true, true);
1932
2230
  }
1933
- Object.defineProperty(debounce, "async", { value: asyncDebounce });
1934
- Object.defineProperty(throttle, "async", { value: asyncThrottle });
1935
- //#endregion
1936
- //#region src/function/once.ts
1937
2231
  /**
1938
- * Create an asynchronous function that can only be called once, rejecting or resolving the same result on subsequent calls
2232
+ * Convert a string to snake case _(this_is_snake_case)_
1939
2233
  *
1940
- * _Available as `asyncOnce` and `once.async`_
2234
+ * @param value String to convert
2235
+ * @returns Snake-cased string
2236
+ */
2237
+ function snakeCase(value) {
2238
+ return toCase(STRING_CASE_SNAKE, value, false, false);
2239
+ }
2240
+ /**
2241
+ * Convert a string to title case _(Capitalizing Every Word)_
1941
2242
  *
1942
- * @param callback Callback to use once
1943
- * @returns _Once_ callback
2243
+ * @param value String to convert
2244
+ * @returns Title-cased string
1944
2245
  */
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;
2246
+ function titleCase(value) {
2247
+ if (typeof value !== "string" || value.length === 0) return "";
2248
+ memoizedTitleCase ??= memoize((v) => v.length < 2 ? capitalize(v) : join(words(v).map(capitalize), " "));
2249
+ return memoizedTitleCase.run(value);
1997
2250
  }
1998
- function clearState(state) {
1999
- if (!state.called || state.cleared) return;
2000
- state.cleared = true;
2001
- state.value = void 0;
2251
+ function toCase(type, value, capitalizeAny, capitalizeFirst) {
2252
+ caseMemoizers[type] ??= memoize(toCaseCallback.bind({
2253
+ type,
2254
+ capitalizeAny,
2255
+ capitalizeFirst
2256
+ }));
2257
+ return caseMemoizers[type].run(value);
2002
2258
  }
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);
2259
+ function toCaseCallback(value) {
2260
+ if (typeof value !== "string") return "";
2261
+ if (value.length < 1) return value;
2262
+ const { capitalizeAny, capitalizeFirst, type } = this;
2263
+ const parts = words(value);
2264
+ const partsLength = parts.length;
2265
+ const cased = [];
2266
+ for (let partIndex = 0; partIndex < partsLength; partIndex += 1) {
2267
+ 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("-");
2268
+ const itemsLength = items.length;
2269
+ const partResult = [];
2270
+ let itemCount = 0;
2271
+ for (let itemIndex = 0; itemIndex < itemsLength; itemIndex += 1) {
2272
+ const item = items[itemIndex];
2273
+ if (item.length === 0) continue;
2274
+ if (!capitalizeAny || itemCount === 0 && partIndex === 0 && !capitalizeFirst) partResult.push(item.toLocaleLowerCase());
2275
+ else partResult.push(capitalize(item));
2276
+ itemCount += 1;
2277
+ }
2278
+ cased.push(join(partResult, delimiters[type]));
2013
2279
  }
2280
+ return join(cased, delimiters[type]);
2014
2281
  }
2015
2282
  /**
2016
- * Create a function that can only be called once, returning the same value on subsequent calls
2283
+ * Convert a string to upper case
2017
2284
  *
2018
- * @param callback Callback to use once
2019
- * @returns _Once_ callback
2285
+ * @param value String to convert
2286
+ * @returns Upper-cased string
2020
2287
  */
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;
2288
+ function upperCase(value) {
2289
+ if (typeof value !== "string" || value.length === 0) return "";
2290
+ memoizedUpperCase ??= memoize((v) => v.toLocaleUpperCase());
2291
+ return memoizedUpperCase.run(value);
2047
2292
  }
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
- }
2293
+ const STRING_CASE_CAMEL = "camel";
2294
+ const STRING_CASE_KEBAB = "kebab";
2295
+ const STRING_CASE_PASCAL = "pascal";
2296
+ const STRING_CASE_SNAKE = "snake";
2297
+ const STRING_DELIMTER_EMPTY = "";
2298
+ const STRING_DELIMITER_HYPHEN = "-";
2299
+ const STRING_DELIMITER_UNDERSCORE = "_";
2300
+ const STRING_EXPRESSION_CAMEL_CASE = /(\p{Ll})(\p{Lu})/gu;
2301
+ const STRING_EXPRESSION_ACRONYM = /(\p{Lu}*)(\p{Lu})(\p{Ll}+)/gu;
2302
+ const STRING_REPLACEMENT_CAMEL_CASE = "$1-$2";
2303
+ const STRING_S = "s";
2304
+ const caseMemoizers = {};
2305
+ const delimiters = {
2306
+ [STRING_CASE_CAMEL]: STRING_DELIMTER_EMPTY,
2307
+ [STRING_CASE_KEBAB]: STRING_DELIMITER_HYPHEN,
2308
+ [STRING_CASE_PASCAL]: STRING_DELIMTER_EMPTY,
2309
+ [STRING_CASE_SNAKE]: STRING_DELIMITER_UNDERSCORE
2063
2310
  };
2311
+ let memoizedCapitalize;
2312
+ let memoizedLowerCase;
2313
+ let memoizedTitleCase;
2314
+ let memoizedUpperCase;
2315
+ //#endregion
2316
+ //#region src/internal/value/equal.ts
2064
2317
  /**
2065
- * Retry a callback a specified number of times, with a delay between attempts
2318
+ * Deregister a equality comparison handler for a specific class
2066
2319
  *
2067
- * _Available as `asyncRetry` and `retry.async`_
2320
+ * _Available as `deregisterEqualizer` and `equal.deregister`_
2068
2321
  *
2069
- * @param callback Callback to retry
2070
- * @param options Retry options
2071
- * @returns Callback result
2322
+ * @param constructor Class constructor
2072
2323
  */
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
- });
2324
+ function deregisterEqualizer(constructor) {
2325
+ equal.handlers.deregister(constructor);
2097
2326
  }
2098
- function getRetryNumber(value) {
2099
- return typeof value === "number" && value > 0 ? value : 0;
2327
+ function filterKey(key, options) {
2328
+ if (typeof key !== "string") return true;
2329
+ if (options.ignoreExpressions.enabled && options.ignoreExpressions.values.some((expression) => expression.test(key))) return false;
2330
+ if (options.ignoreKeys.enabled && options.ignoreKeys.values.has(key)) return false;
2331
+ return true;
2100
2332
  }
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
- };
2333
+ function equal(first, second, options) {
2334
+ return equalValue(first, second, getEqualOptions(options));
2108
2335
  }
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
- }
2336
+ equal.handlers = getCompareHandlers(equal, { callback: Object.is });
2337
+ equal.deregister = deregisterEqualizer;
2338
+ equal.initialize = initializeEqualizer;
2339
+ equal.register = registerEqualizer;
2340
+ function equalArray(first, second, options) {
2341
+ const { length } = first;
2342
+ if (length !== second.length) return false;
2343
+ let offset = 0;
2344
+ if (length >= EQUAL_ARRAY_THRESHOLD) {
2345
+ offset = Math.round(length / EQUAL_ARRAY_PEEK_PERCENTAGE);
2346
+ offset = offset > EQUAL_ARRAY_THRESHOLD ? EQUAL_ARRAY_THRESHOLD : offset;
2347
+ 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
2348
  }
2128
- throw new RetryError(RETRY_MESSAGE_FAILED, last);
2129
- }
2130
- function shouldRetry() {
2349
+ const end = length - offset;
2350
+ for (let index = offset; index < end; index += 1) if (!equalValue(first[index], second[index], options)) return false;
2131
2351
  return true;
2132
2352
  }
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);
2353
+ function equalArrayBuffer(first, second, options) {
2354
+ return first.byteLength === second.byteLength ? equalArray(new Uint8Array(first), new Uint8Array(second), options) : false;
2152
2355
  }
2153
- async function asyncPipe(value, ...pipes) {
2154
- assertPipeFunctions(pipes);
2155
- return asyncWork(value, pipes, false);
2356
+ function equalDataView(first, second, options) {
2357
+ return first.byteOffset === second.byteOffset ? equalArrayBuffer(first.buffer, second.buffer, options) : false;
2156
2358
  }
2157
- function pipe(value, ...pipes) {
2158
- assertPipeFunctions(pipes);
2159
- return work(value, pipes, false);
2359
+ function equalMap(first, second, options) {
2360
+ const { size } = first;
2361
+ if (size !== second.size) return false;
2362
+ const firstKeys = [...first.keys()];
2363
+ for (let index = 0; index < size; index += 1) {
2364
+ const key = firstKeys[index];
2365
+ if (!second.has(key) || !equalValue(first.get(key), second.get(key), options)) return false;
2366
+ }
2367
+ return true;
2160
2368
  }
2161
- async function asyncWork(initial, functions, flow) {
2162
- const { length } = functions;
2163
- let transformed = unwrapValue(initial);
2369
+ function equalPlainObject(first, second, options) {
2370
+ let firstKeys = [...Object.keys(first), ...Object.getOwnPropertySymbols(first)];
2371
+ let secondKeys = [...Object.keys(second), ...Object.getOwnPropertySymbols(second)];
2372
+ if (options.ignoreKeys.enabled || options.ignoreExpressions.enabled) {
2373
+ firstKeys = firstKeys.filter((key) => filterKey(key, options));
2374
+ secondKeys = secondKeys.filter((key) => filterKey(key, options));
2375
+ }
2376
+ const secondSet = secondKeys.length >= EQUAL_MINIMUM_LENGTH_FOR_SET ? new Set(secondKeys) : void 0;
2377
+ const { length } = firstKeys;
2378
+ if (length !== secondKeys.length) return false;
2164
2379
  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));
2380
+ const key = firstKeys[index];
2381
+ if (!(secondSet?.has(key) ?? secondKeys.includes(key)) || !equalValue(first[key], second[key], options)) return false;
2167
2382
  }
2168
- return transformed;
2383
+ return true;
2169
2384
  }
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);
2385
+ function equalProperties(first, second, properties, options) {
2386
+ const { length } = properties;
2387
+ for (let index = 0; index < length; index += 1) {
2388
+ const property = properties[index];
2389
+ if (!equalValue(first[property], second[property], options)) return false;
2174
2390
  }
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;
2391
+ return true;
2178
2392
  }
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);
2393
+ function equalSet(first, second, options) {
2394
+ const { size } = first;
2395
+ if (size !== second.size) return false;
2396
+ const firstValues = [...first];
2397
+ const secondValues = [...second];
2398
+ for (let index = 0; index < size; index += 1) {
2399
+ const firstValue = firstValues[index];
2400
+ if (isPrimitive(firstValue) ? !second.has(firstValue) : !secondValues.some((secondValue) => equalValue(firstValue, secondValue, options))) return false;
2185
2401
  }
2186
- return transformed;
2402
+ return true;
2187
2403
  }
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
- };
2404
+ function equalTypedArray(first, second) {
2405
+ if (first.constructor !== second.constructor) return false;
2406
+ if (first.byteLength !== second.byteLength) return false;
2407
+ const { length } = first;
2408
+ for (let index = 0; index < length; index += 1) if (first[index] !== second[index]) return false;
2409
+ return true;
2209
2410
  }
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);
2411
+ function equalValue(first, second, options) {
2412
+ if (options.relaxedNullish && first == null && second == null) return true;
2413
+ switch (true) {
2414
+ case Object.is(first, second): return true;
2415
+ case first == null || second == null: return first === second;
2416
+ case typeof first !== typeof second: return false;
2417
+ case typeof first === "string" && options.ignoreCase === true: return Object.is(first.toLocaleLowerCase(), second.toLocaleLowerCase());
2418
+ case first instanceof ArrayBuffer && second instanceof ArrayBuffer: return equalArrayBuffer(first, second, options);
2419
+ case first instanceof Date && second instanceof Date: return Object.is(first.getTime(), second.getTime());
2420
+ case first instanceof DataView && second instanceof DataView: return equalDataView(first, second, options);
2421
+ case first instanceof Error && second instanceof Error: return equalProperties(first, second, EQUAL_ERROR_PROPERTIES, options);
2422
+ case first instanceof Map && second instanceof Map: return equalMap(first, second, options);
2423
+ case first instanceof RegExp && second instanceof RegExp: return equalProperties(first, second, EQUAL_EXPRESSION_PROPERTIES, options);
2424
+ case first instanceof Set && second instanceof Set: return equalSet(first, second, options);
2425
+ case Array.isArray(first) && Array.isArray(second): return equalArray(first, second, options);
2426
+ case isPlainObject(first) && isPlainObject(second): return equalPlainObject(first, second, options);
2427
+ case isTypedArray(first) && isTypedArray(second): return equalTypedArray(first, second);
2428
+ default: return equal.handlers.handle(first, second, options);
2243
2429
  }
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
2430
  }
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()
2431
+ function getEqualOptions(input) {
2432
+ const options = {
2433
+ ignoreCase: false,
2434
+ ignoreExpressions: {
2435
+ enabled: false,
2436
+ values: []
2279
2437
  },
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)
2438
+ ignoreKeys: {
2439
+ enabled: false,
2440
+ values: /* @__PURE__ */ new Set()
2441
+ },
2442
+ relaxedNullish: false
2295
2443
  };
2296
- return instance;
2444
+ if (typeof input === "boolean") {
2445
+ options.ignoreCase = input;
2446
+ return options;
2447
+ }
2448
+ if (isNonPlainObject(input)) return options;
2449
+ options.ignoreCase = typeof input.ignoreCase === "boolean" ? input.ignoreCase : false;
2450
+ options.ignoreExpressions.values = (Array.isArray(input.ignoreKeys) ? input.ignoreKeys : [input.ignoreKeys]).filter((key) => key instanceof RegExp);
2451
+ options.ignoreKeys.values = new Set((Array.isArray(input.ignoreKeys) ? input.ignoreKeys : [input.ignoreKeys]).filter((key) => typeof key === "string"));
2452
+ options.ignoreExpressions.enabled = options.ignoreExpressions.values.length > 0;
2453
+ options.ignoreKeys.enabled = options.ignoreKeys.values.size > 0;
2454
+ options.relaxedNullish = input.relaxedNullish === true;
2455
+ return options;
2297
2456
  }
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);
2457
+ /**
2458
+ * Create an equalizer with predefined options
2459
+ *
2460
+ * _Available as `initializeEqualizer` and `equal.initialize`_
2461
+ *
2462
+ * @param options Comparison options
2463
+ * @returns Equalizer function
2464
+ */
2465
+ function initializeEqualizer(options) {
2466
+ const actual = getEqualOptions(options);
2467
+ const equalizer = (first, second) => equalValue(first, second, actual);
2468
+ equalizer.deregister = deregisterEqualizer;
2469
+ equalizer.register = registerEqualizer;
2470
+ return equalizer;
2302
2471
  }
2303
2472
  /**
2304
- * Is the value a subscription?
2473
+ * Register a equality comparison function for a specific class
2305
2474
  *
2306
- * @param value Value to check
2307
- * @returns `true` if the value is a subscription, otherwise `false`
2475
+ * _Available as `registerEqualizer` and `equal.register`_
2476
+ *
2477
+ * @param constructor Class constructor
2478
+ * @param handler Comparison function
2308
2479
  */
2309
- function isSubscription(value) {
2310
- return isPlainObject(value) && SUBSCRIPTION_PROPERTY in value && value[SUBSCRIPTION_PROPERTY] === true;
2480
+ function registerEqualizer(constructor, handler) {
2481
+ equal.handlers.register(constructor, handler);
2311
2482
  }
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
- }
2483
+ const EQUAL_ARRAY_PEEK_PERCENTAGE = 10;
2484
+ const EQUAL_ARRAY_THRESHOLD = 100;
2485
+ const EQUAL_ERROR_PROPERTIES = ["name", "message"];
2486
+ const EQUAL_EXPRESSION_PROPERTIES = ["source", "flags"];
2487
+ const EQUAL_MINIMUM_LENGTH_FOR_SET = 16;
2488
+ //#endregion
2489
+ //#region src/internal/value/get.ts
2490
+ function getValue(data, path, ignoreCase) {
2491
+ return getNestedValue(data, path, ignoreCase === true).value;
2321
2492
  }
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;
2493
+ //#endregion
2494
+ //#region src/internal/value/set.ts
2495
+ function setValue(data, path, value, ignoreCase) {
2496
+ if (typeof data !== "object" || data === null || typeof path !== "string" || path.trim().length === 0) return data;
2497
+ const shouldIgnoreCase = ignoreCase === true;
2498
+ const paths = getPaths(path, shouldIgnoreCase);
2499
+ if (typeof paths === "string") {
2500
+ handleValue(data, paths, value, false, shouldIgnoreCase);
2501
+ return data;
2333
2502
  }
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);
2503
+ const { length } = paths;
2504
+ const lastIndex = length - 1;
2505
+ let target = data;
2506
+ for (let index = 0; index < length; index += 1) {
2507
+ const currentPath = paths[index];
2508
+ if (index === lastIndex) {
2509
+ handleValue(target, currentPath, value, false, shouldIgnoreCase);
2510
+ break;
2511
+ }
2512
+ let next = handleValue(target, currentPath, null, true, shouldIgnoreCase).value;
2513
+ if (typeof next !== "object" || next === null) {
2514
+ const nextPath = paths[index + 1];
2515
+ if (SET_EXPRESSION_INDEX.test(nextPath)) next = Array.from({ length: Number(nextPath) + 1 }, () => void 0);
2516
+ else next = {};
2517
+ target[currentPath] = next;
2518
+ }
2519
+ target = next;
2520
+ }
2521
+ return data;
2345
2522
  }
2346
- const SUBSCRIPTION_INVALID_KEY = "Invalid key for subscription";
2347
- const SUBSCRIPTION_PROPERTY = "$subscription";
2523
+ const SET_EXPRESSION_INDEX = /^\d+$/;
2348
2524
  //#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);
2525
+ //#region src/internal/abort.ts
2526
+ function createAborter(value, onAbort) {
2527
+ if (!(value instanceof AbortSignal)) return;
2528
+ value.addEventListener(ABORT_EVENT, onAbort, ABORT_OPTIONS);
2365
2529
  return {
2366
- key: property.key,
2367
- value: property.value
2530
+ callback: onAbort,
2531
+ signal: value,
2532
+ cancel: () => value.removeEventListener(ABORT_EVENT, onAbort)
2368
2533
  };
2369
2534
  }
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
- };
2535
+ const ABORT_EVENT = "abort";
2536
+ const ABORT_OPTIONS = { once: true };
2537
+ //#endregion
2538
+ //#region src/internal/defaults.ts
2539
+ function getBooleanOrDefault(value, defaultValue) {
2540
+ return typeof value === "boolean" ? value : defaultValue;
2541
+ }
2542
+ function getNumberOrDefault(value, defaultValue, minimum) {
2543
+ return typeof value === "number" && !Number.isNaN(value) && value >= (minimum ?? 0) ? value : defaultValue;
2383
2544
  }
2545
+ //#endregion
2546
+ //#region src/promise/constants.ts
2547
+ const PROMISE_ERROR_NAME = "PromiseTimeoutError";
2548
+ const PROMISE_MESSAGE_EXPECTATION_ATTEMPT = "Attempt expected a function or a promise";
2549
+ const PROMISE_MESSAGE_EXPECTATION_RESULT = "toResult expected a Promise";
2550
+ const PROMISE_MESSAGE_EXPECTATION_TIMED = "Timed function expected a Promise";
2551
+ const PROMISE_MESSAGE_TIMEOUT = "Promise timed out";
2552
+ const PROMISE_STRATEGY_ALL = /* @__PURE__ */ new Set(["complete", "first"]);
2553
+ const PROMISE_STRATEGY_DEFAULT = "complete";
2554
+ const PROMISE_TYPE_FULFILLED = "fulfilled";
2555
+ const PROMISE_TYPE_REJECTED = "rejected";
2556
+ //#endregion
2557
+ //#region src/promise/models.ts
2384
2558
  /**
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
2559
+ * A _Promise_ that can be canceled
2390
2560
  */
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)
2561
+ var CancelablePromise = class extends Promise {
2562
+ #rejector;
2563
+ constructor(executor) {
2564
+ let rejector;
2565
+ super((resolve, reject) => {
2566
+ rejector = reject;
2567
+ executor(resolve, reject);
2568
+ });
2569
+ this.#rejector = rejector;
2570
+ }
2571
+ /**
2572
+ * Cancel the _Promise_, rejecting it with an optional reason
2573
+ *
2574
+ * @param reason Optional reason for canceling the _Promise_
2575
+ */
2576
+ cancel(reason) {
2577
+ this.#rejector?.(reason);
2578
+ this.#rejector = void 0;
2579
+ }
2580
+ };
2581
+ /**
2582
+ * An error thrown when a promise times out
2583
+ */
2584
+ var PromiseTimeoutError = class extends Error {
2585
+ constructor() {
2586
+ super(PROMISE_MESSAGE_TIMEOUT);
2587
+ this.name = PROMISE_ERROR_NAME;
2588
+ }
2589
+ };
2590
+ //#endregion
2591
+ //#region src/promise/helpers.ts
2592
+ function getPromiseOptions(input) {
2593
+ if (typeof input === "number") return { time: getNumberOrDefault(input, 0) };
2594
+ if (input instanceof AbortSignal) return {
2595
+ signal: input,
2596
+ time: 0
2398
2597
  };
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);
2598
+ const options = typeof input === "object" && input !== null ? input : {};
2599
+ return {
2600
+ signal: options.signal instanceof AbortSignal ? options.signal : void 0,
2601
+ time: getNumberOrDefault(options.time, 0)
2602
+ };
2603
+ }
2604
+ function getPromisesOptions(input) {
2605
+ if (typeof input === "string") return { strategy: getStrategyOrDefault(input) };
2606
+ if (input instanceof AbortSignal) return {
2607
+ signal: input,
2608
+ strategy: PROMISE_STRATEGY_DEFAULT
2609
+ };
2610
+ const options = typeof input === "object" && input !== null ? input : {};
2611
+ return {
2612
+ signal: options.signal instanceof AbortSignal ? options.signal : void 0,
2613
+ strategy: getStrategyOrDefault(options.strategy)
2614
+ };
2615
+ }
2616
+ function getResultsFromPromises(promised) {
2617
+ return promised.map((result) => isFulfilled(result) ? ok(result.value) : error(result.reason));
2618
+ }
2619
+ function getStrategyOrDefault(value) {
2620
+ return PROMISE_STRATEGY_ALL.has(value) ? value : PROMISE_STRATEGY_DEFAULT;
2407
2621
  }
2408
2622
  /**
2409
- * Is the value events for a herald?
2623
+ * Is the value a fulfilled _Promise_ result?
2410
2624
  *
2411
2625
  * @param value Value to check
2412
- * @returns `true` if the value is events for a herald, otherwise `false`
2626
+ * @returns `true` if the value is a fulfilled _Promise_ result, otherwise `false`
2413
2627
  */
2414
- function isHeraldEvents(value) {
2415
- return isHeraldInstance(HERALD_NAME_EVENTS, value);
2628
+ function isFulfilled(value) {
2629
+ return isType(value, PROMISE_TYPE_FULFILLED);
2416
2630
  }
2417
2631
  /**
2418
- * Is the value a herald?
2632
+ * Is the value a rejected _Promise_ result?
2419
2633
  *
2420
2634
  * @param value Value to check
2421
- * @returns `true` if the value is a herald, otherwise `false`
2635
+ * @returns `true` if the value is a rejected _Promise_ result, otherwise `false`
2422
2636
  */
2423
- function isHerald(value) {
2424
- return isHeraldInstance(HERALD_NAME_HERALD, value);
2637
+ function isRejected(value) {
2638
+ return isType(value, PROMISE_TYPE_REJECTED);
2425
2639
  }
2426
- function isHeraldInstance(name, value) {
2427
- return isPlainObject(value) && HERALD_PROPERTY in value && value[HERALD_PROPERTY] === name;
2640
+ function isType(value, type) {
2641
+ return typeof value === "object" && value !== null && value.status === type;
2428
2642
  }
2643
+ //#endregion
2644
+ //#region src/result/misc.ts
2429
2645
  /**
2430
- * Is the value a herald subscription?
2646
+ * Converts a _Result_ to a _Promise_
2431
2647
  *
2432
- * @param value Value to check
2433
- * @returns `true` if the value is a herald subscription, otherwise `false`
2648
+ * Resolves if ok, rejects for error
2649
+ *
2650
+ * @param result _Result_ to convert
2651
+ * @returns Promised result
2434
2652
  */
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;
2653
+ async function toPromise(result) {
2654
+ const actual = typeof result === "function" ? result() : result;
2655
+ if (!isResult(actual)) return Promise.reject(new Error(RESULT_MESSAGE_PROMISE));
2656
+ return isOk(actual) ? Promise.resolve(actual.value) : Promise.reject(actual.error);
2446
2657
  }
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 };
2658
+ const RESULT_MESSAGE_PROMISE = "toPromise expected to receive a Result";
2454
2659
  //#endregion
2455
- //#region src/internal/value/equal.ts
2660
+ //#region src/promise/misc.ts
2456
2661
  /**
2457
- * Deregister a equality comparison handler for a specific class
2458
- *
2459
- * _Available as `deregisterEqualizer` and `equal.deregister`_
2662
+ * Create a cancelable _Promise_
2460
2663
  *
2461
- * @param constructor Class constructor
2664
+ * @param executor Executor function for the _Promise_
2665
+ * @returns Cancelable _Promise_
2462
2666
  */
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));
2667
+ function cancelable(executor) {
2668
+ return new CancelablePromise(executor);
2474
2669
  }
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;
2670
+ function handleResult(status, parameters) {
2671
+ const { aborter, complete, data, handlers, index, value } = parameters;
2672
+ if (aborter?.signal.aborted ?? false) return;
2673
+ if (!complete && status === "rejected") {
2674
+ settlePromise(handlers.reject, value, aborter);
2675
+ return;
2487
2676
  }
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;
2677
+ data.result[index] = !complete ? value : status === "fulfilled" ? {
2678
+ status,
2679
+ value
2680
+ } : {
2681
+ status,
2682
+ reason: value
2683
+ };
2684
+ if (index === data.last) settlePromise(handlers.resolve, data.result, aborter);
2491
2685
  }
2492
- function equalArrayBuffer(first, second, options) {
2493
- return first.byteLength === second.byteLength ? equalArray(new Uint8Array(first), new Uint8Array(second), options) : false;
2686
+ function settlePromise(settler, value, aborter) {
2687
+ aborter?.cancel();
2688
+ settler(value);
2494
2689
  }
2495
- function equalDataView(first, second, options) {
2496
- return first.byteOffset === second.byteOffset ? equalArrayBuffer(first.buffer, second.buffer, options) : false;
2690
+ async function toResult(value) {
2691
+ const actual = typeof value === "function" ? value() : value;
2692
+ if (!(actual instanceof Promise)) return Promise.reject(/* @__PURE__ */ new TypeError(PROMISE_MESSAGE_EXPECTATION_RESULT));
2693
+ return actual.then((result) => ok(result)).catch((reason) => error(reason));
2497
2694
  }
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;
2695
+ //#endregion
2696
+ //#region src/promise/delay.ts
2697
+ function delay(options) {
2698
+ const { signal, time } = getPromiseOptions(options);
2699
+ if (signal?.aborted ?? false) return Promise.reject(signal?.reason);
2700
+ const aborter = createAborter(signal, () => {
2701
+ timer.cancel();
2702
+ rejector(signal?.reason);
2703
+ });
2704
+ const timer = getTimer(TIMER_WAIT, () => settlePromise(resolver, void 0, aborter), time);
2705
+ let rejector;
2706
+ let resolver;
2707
+ return new Promise((resolve, reject) => {
2708
+ rejector = reject;
2709
+ resolver = resolve;
2710
+ if (time === 0) settlePromise(resolver, void 0, aborter);
2711
+ else timer();
2712
+ });
2507
2713
  }
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;
2714
+ //#endregion
2715
+ //#region src/promise/timed.ts
2716
+ async function getTimedPromise(promise, time, signal) {
2717
+ const aborter = createAborter(signal, () => {
2718
+ timer.cancel();
2719
+ rejector(signal?.reason);
2720
+ });
2721
+ const timer = getTimer(TIMER_WAIT, () => settlePromise(rejector, new PromiseTimeoutError(), aborter), time);
2722
+ let rejector;
2723
+ return Promise.race([promise, new Promise((_, reject) => {
2724
+ rejector = reject;
2725
+ timer();
2726
+ })]).then((value) => {
2727
+ aborter?.cancel();
2728
+ timer.cancel();
2729
+ rejector(void 0);
2730
+ return value;
2731
+ });
2542
2732
  }
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;
2733
+ async function timed(promise, options) {
2734
+ if (!(promise instanceof Promise)) return Promise.reject(/* @__PURE__ */ new TypeError(PROMISE_MESSAGE_EXPECTATION_TIMED));
2735
+ const { signal, time } = getPromiseOptions(options);
2736
+ if (signal?.aborted ?? false) return Promise.reject(signal?.reason);
2737
+ return time > 0 ? getTimedPromise(promise, time, signal) : promise;
2549
2738
  }
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);
2739
+ //#endregion
2740
+ //#region src/promise/index.ts
2741
+ async function attemptPromise(value, options) {
2742
+ const isFunction = typeof value === "function";
2743
+ if (!isFunction && !(value instanceof Promise)) return Promise.reject(/* @__PURE__ */ new TypeError(PROMISE_MESSAGE_EXPECTATION_ATTEMPT));
2744
+ const { signal, time } = getPromiseOptions(options);
2745
+ if (signal?.aborted ?? false) return Promise.reject(signal?.reason);
2746
+ const aborter = createAborter(signal, () => {
2747
+ rejector(signal?.reason);
2748
+ });
2749
+ async function handler(resolve, reject) {
2750
+ try {
2751
+ let result = isFunction ? value() : await value;
2752
+ if (result instanceof Promise) result = await result;
2753
+ settlePromise(resolve, result, aborter);
2754
+ } catch (error) {
2755
+ settlePromise(reject, error, aborter);
2756
+ }
2568
2757
  }
2758
+ let rejector;
2759
+ const promise = new Promise((resolve, reject) => {
2760
+ rejector = reject;
2761
+ handler(resolve, reject);
2762
+ });
2763
+ return time > 0 ? getTimedPromise(promise, time, signal) : promise;
2569
2764
  }
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
2765
+ async function promises(items, options) {
2766
+ const { signal, strategy } = getPromisesOptions(options);
2767
+ if (signal?.aborted ?? false) return Promise.reject(signal?.reason);
2768
+ if (!Array.isArray(items)) return Promise.resolve([]);
2769
+ const actual = items.map((item) => typeof item === "function" ? item() : item).filter((item) => item instanceof Promise);
2770
+ const { length } = actual;
2771
+ if (length === 0) return Promise.resolve([]);
2772
+ const complete = strategy === PROMISE_STRATEGY_DEFAULT;
2773
+ const aborter = createAborter(signal, () => {
2774
+ handlers.reject(signal?.reason);
2775
+ });
2776
+ const data = {
2777
+ last: length - 1,
2778
+ result: []
2582
2779
  };
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);
2780
+ let handlers;
2781
+ return new Promise((resolve, reject) => {
2782
+ handlers = {
2783
+ reject,
2784
+ resolve
2785
+ };
2786
+ for (let index = 0; index < length; index += 1) actual[index].then((value) => handleResult(PROMISE_TYPE_FULFILLED, {
2787
+ aborter,
2788
+ complete,
2789
+ data,
2790
+ handlers,
2791
+ index,
2792
+ value
2793
+ })).catch((reason) => handleResult(PROMISE_TYPE_REJECTED, {
2794
+ aborter,
2795
+ complete,
2796
+ data,
2797
+ handlers,
2798
+ index,
2799
+ value: reason
2800
+ }));
2801
+ });
2621
2802
  }
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;
2803
+ promises.result = resultPromises;
2804
+ async function resultPromises(items, signal) {
2805
+ return promises(items, signal).then(getResultsFromPromises);
2631
2806
  }
2632
2807
  //#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;
2808
+ //#region src/result/index.ts
2809
+ async function asyncAttempt(value, err) {
2810
+ try {
2811
+ let result = typeof value === "function" ? value() : await value;
2812
+ if (result instanceof Promise) result = await result;
2813
+ return ok(result);
2814
+ } catch (thrown) {
2815
+ return getError(err ?? thrown, err == null ? void 0 : thrown);
2641
2816
  }
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;
2817
+ }
2818
+ function attempt(callback, err) {
2819
+ try {
2820
+ return ok(callback());
2821
+ } catch (thrown) {
2822
+ return getError(err ?? thrown, err == null ? void 0 : thrown);
2659
2823
  }
2660
- return data;
2661
2824
  }
2662
- const SET_EXPRESSION_INDEX = /^\d+$/;
2825
+ Object.defineProperty(attempt, "async", { value: asyncAttempt });
2663
2826
  //#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);
2827
+ //#region src/result/match.ts
2828
+ async function asyncMatchResult(result, first, error) {
2829
+ let value;
2830
+ if (typeof result === "function") value = await result();
2831
+ else if (result instanceof Promise) value = await result;
2832
+ else value = result;
2833
+ if (!isResult(value)) throw new Error(MATCH_MESSAGE);
2834
+ const hasObj = typeof first === "object" && first !== null;
2835
+ const okHandler = hasObj ? first.ok : first;
2836
+ const errorHandler = hasObj ? first.error : error;
2837
+ if (isOk(value)) return okHandler(value.value);
2838
+ return errorHandler(value.error, value.original);
2733
2839
  }
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);
2840
+ function matchResult(result, first, error) {
2841
+ const value = typeof result === "function" ? result() : result;
2842
+ if (!isResult(value)) throw new Error(MATCH_MESSAGE);
2843
+ const hasObj = typeof first === "object" && first !== null;
2844
+ const okHandler = hasObj ? first.ok : first;
2845
+ const errorHandler = hasObj ? first.error : error;
2846
+ if (isOk(value)) return okHandler(value.value);
2847
+ return errorHandler(value.error, value.original);
2741
2848
  }
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]);
2849
+ const MATCH_MESSAGE = "`result.match` expected a Result or a function that returns a Result";
2850
+ Object.defineProperty(matchResult, "async", { value: asyncMatchResult });
2851
+ //#endregion
2852
+ //#region src/result/work/flow.ts
2853
+ function attemptAsyncFlow(...fns) {
2854
+ let Flow;
2855
+ return (...args) => asyncAttempt(() => {
2856
+ Flow ??= asyncFlow(...fns);
2857
+ return Flow(...args.map((value) => {
2858
+ if (isError(value)) throw value.error;
2859
+ return isOk(value) ? value.value : value;
2860
+ }));
2861
+ });
2764
2862
  }
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);
2863
+ function attemptFlow(...fns) {
2864
+ let Flow;
2865
+ return (...args) => attempt(() => {
2866
+ Flow ??= flow(...fns);
2867
+ return Flow(...args.map((value) => {
2868
+ if (isError(value)) throw value.error;
2869
+ return isOk(value) ? value.value : value;
2870
+ }));
2871
+ });
2775
2872
  }
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;
2873
+ Object.defineProperty(attemptFlow, "async", { value: attemptAsyncFlow });
2874
+ //#endregion
2875
+ //#region src/result/work/pipe.ts
2876
+ async function attemptAsyncPipe(initial, first, ...seconds) {
2877
+ return asyncAttempt(() => {
2878
+ if (isError(initial)) throw initial.error;
2879
+ const value = typeof initial === "function" ? initial() : isOk(initial) ? initial.value : initial;
2880
+ if (first == null) return value;
2881
+ return asyncPipe(value, ...[first, ...seconds]);
2882
+ });
2883
+ }
2884
+ function attemptPipe(initial, first, ...seconds) {
2885
+ return attempt(() => {
2886
+ if (isError(initial)) throw initial.error;
2887
+ const value = typeof initial === "function" ? initial() : isOk(initial) ? initial.value : initial;
2888
+ if (first == null) return value;
2889
+ return pipe(value, ...[first, ...seconds]);
2890
+ });
2891
+ }
2892
+ Object.defineProperty(attemptPipe, "async", { value: attemptAsyncPipe });
2798
2893
  //#endregion
2799
2894
  //#region src/string/match.ts
2800
2895
  /**
@@ -3856,6 +3951,142 @@ function transformValue(value, transformer) {
3856
3951
  return value;
3857
3952
  }
3858
3953
  //#endregion
3954
+ //#region src/internal/subscription.ts
3955
+ function addSubscription(subscriptions, subscription, state) {
3956
+ const { key, value } = state.parameters;
3957
+ const { items, values } = subscriptions.state;
3958
+ if (!isKey(key)) {
3959
+ items.any.add(subscription);
3960
+ values.from.any.set(value, subscription);
3961
+ values.to.any.set(subscription, value);
3962
+ return;
3963
+ }
3964
+ /* istanbul ignore if */
3965
+ if (items.keyed == null || values.from.keyed == null || values.to.keyed == null)
3966
+ // istanbul ignore next
3967
+ return;
3968
+ let keyedItems = items.keyed.get(key);
3969
+ if (keyedItems == null) {
3970
+ keyedItems = /* @__PURE__ */ new Set();
3971
+ items.keyed.set(key, keyedItems);
3972
+ }
3973
+ keyedItems.add(subscription);
3974
+ let keyedFrom = values.from.keyed.get(key);
3975
+ if (keyedFrom == null) {
3976
+ keyedFrom = /* @__PURE__ */ new Map();
3977
+ values.from.keyed.set(key, keyedFrom);
3978
+ }
3979
+ keyedFrom.set(value, subscription);
3980
+ let keyedTo = values.to.keyed.get(key);
3981
+ if (keyedTo == null) {
3982
+ keyedTo = /* @__PURE__ */ new Map();
3983
+ values.to.keyed.set(key, keyedTo);
3984
+ }
3985
+ keyedTo.set(subscription, value);
3986
+ }
3987
+ function clearSubscriptions(store) {
3988
+ for (const susbcription of store.values.to.any.keys()) susbcription.unsubscribe();
3989
+ if (store.values.to.keyed != null) for (const values of store.values.to.keyed.values()) for (const susbcription of values.keys()) susbcription.unsubscribe();
3990
+ }
3991
+ function createSubscription(subscriptions, property, parameters) {
3992
+ if (parameters.signal?.aborted ?? false) throw new Error(parameters.signal?.reason);
3993
+ const state = {
3994
+ parameters,
3995
+ active: true
3996
+ };
3997
+ const existing = getExistingSubscription(subscriptions, state);
3998
+ if (existing != null) return [existing, true];
3999
+ if (subscriptions.state.keys != null && isKey(parameters.key) && !subscriptions.state.keys.has(parameters.key)) throw new Error(SUBSCRIPTION_INVALID_KEY);
4000
+ state.aborter = createAborter(parameters.signal, () => unsubscribe(subscriptions, instance, state));
4001
+ const instance = { unsubscribe: () => unsubscribe(subscriptions, instance, state) };
4002
+ Object.defineProperties(instance, {
4003
+ [SUBSCRIPTION_PROPERTY]: { value: true },
4004
+ [property.key]: { value: property.value ?? "subscription" },
4005
+ active: {
4006
+ enumerable: true,
4007
+ get: () => (parameters.isActive?.() ?? true) && state.active
4008
+ }
4009
+ });
4010
+ addSubscription(subscriptions, instance, state);
4011
+ return [Object.freeze(instance), false];
4012
+ }
4013
+ function createSubscriptions(parameters) {
4014
+ const { keys, property } = parameters;
4015
+ const state = {
4016
+ keys,
4017
+ items: {
4018
+ any: /* @__PURE__ */ new Set(),
4019
+ keyed: keys == null ? void 0 : /* @__PURE__ */ new Map()
4020
+ },
4021
+ values: {
4022
+ from: {
4023
+ any: /* @__PURE__ */ new Map(),
4024
+ keyed: keys == null ? void 0 : /* @__PURE__ */ new Map()
4025
+ },
4026
+ to: {
4027
+ any: /* @__PURE__ */ new Map(),
4028
+ keyed: keys == null ? void 0 : /* @__PURE__ */ new Map()
4029
+ }
4030
+ }
4031
+ };
4032
+ const instance = {
4033
+ state,
4034
+ clear: () => clearSubscriptions(state),
4035
+ create: (parameters) => createSubscription(instance, property, parameters)
4036
+ };
4037
+ return instance;
4038
+ }
4039
+ function getExistingSubscription(subscriptions, state) {
4040
+ const { parameters } = state;
4041
+ const { values } = subscriptions.state;
4042
+ return isKey(parameters.key) ? values.from.keyed?.get(parameters.key)?.get(parameters.value) : values.from.any.get(parameters.value);
4043
+ }
4044
+ /**
4045
+ * Is the value a subscription?
4046
+ *
4047
+ * @param value Value to check
4048
+ * @returns `true` if the value is a subscription, otherwise `false`
4049
+ */
4050
+ function isSubscription(value) {
4051
+ return isPlainObject(value) && SUBSCRIPTION_PROPERTY in value && value[SUBSCRIPTION_PROPERTY] === true;
4052
+ }
4053
+ function removeFromStore(items, values, subscription, value, key) {
4054
+ items.delete(subscription);
4055
+ if (key == null) {
4056
+ values.from.any.delete(value);
4057
+ values.to.any.delete(subscription);
4058
+ } else {
4059
+ values.from.keyed?.get(key)?.delete(value);
4060
+ values.to.keyed?.get(key)?.delete(subscription);
4061
+ }
4062
+ }
4063
+ function removeSubscription(subscriptions, subscription, state) {
4064
+ if (!state.active) return;
4065
+ state.aborter = void 0;
4066
+ state.active = false;
4067
+ state.parameters.isActive = void 0;
4068
+ state.parameters.signal = void 0;
4069
+ const { key, value } = state.parameters;
4070
+ const { items, values } = subscriptions.state;
4071
+ if (!isKey(key)) {
4072
+ removeFromStore(items.any, values, subscription, value);
4073
+ return;
4074
+ }
4075
+ const keyed = items.keyed?.get(key);
4076
+ /* istanbul ignore if */
4077
+ if (items.keyed == null || keyed == null)
4078
+ // istanbul ignore next
4079
+ return;
4080
+ removeFromStore(keyed, values, subscription, value, key);
4081
+ if (keyed.size === 0) items.keyed.delete(key);
4082
+ }
4083
+ function unsubscribe(subscriptions, subscription, state) {
4084
+ state.aborter?.cancel();
4085
+ removeSubscription(subscriptions, subscription, state);
4086
+ }
4087
+ const SUBSCRIPTION_INVALID_KEY = "Invalid key for subscription";
4088
+ const SUBSCRIPTION_PROPERTY = "$subscription";
4089
+ //#endregion
3859
4090
  //#region src/beacon.ts
3860
4091
  /**
3861
4092
  * Create a new beacon
@@ -3987,26 +4218,132 @@ function subscribeToObservable(state, first, second, third) {
3987
4218
  isActive: () => state.beacon.active && state.active,
3988
4219
  value: observer
3989
4220
  });
3990
- observer.next?.(state.beacon.value);
4221
+ observer.next?.(state.beacon.value);
4222
+ return subscription;
4223
+ }
4224
+ function updateBeacon(type, state, value, finish) {
4225
+ if (!state.active) return;
4226
+ if (type === BEACON_TYPE_NEXT) {
4227
+ if (state.options.equal(state.value, value)) return;
4228
+ state.value = value;
4229
+ }
4230
+ for (const [, observer] of state.subscriptions.state.values.to.any) observer[type]?.(value);
4231
+ if (finish === true) finishBeacon(state, true);
4232
+ }
4233
+ const BEACON_MESSAGE_RETRIEVE = "Cannot retrieve observable from a closed beacon";
4234
+ const BEACON_MESSAGE_SUBSCRIBE = "Cannot subscribe to a closed observable";
4235
+ const BEACON_PROPERTY = "$beacon";
4236
+ const BEACON_NAME = "beacon";
4237
+ const BEACON_OBSERVABLE = "observable";
4238
+ const BEACON_TYPE_ERROR = "error";
4239
+ const BEACON_TYPE_NEXT = "next";
4240
+ const beaconSubscription = { key: BEACON_PROPERTY };
4241
+ //#endregion
4242
+ //#region src/internal/herald.ts
4243
+ function createEvents(herald, state) {
4244
+ const events = {};
4245
+ Object.defineProperty(events, HERALD_PROPERTY, { value: HERALD_NAME_EVENTS });
4246
+ for (const key of state.keys) events[key] = (callback, signal) => herald.subscribe(key, callback, signal);
4247
+ return Object.freeze(events);
4248
+ }
4249
+ function emitForHerald(state, event, ...parameters) {
4250
+ const items = state.subscriptions.state.values.from.keyed?.get(event);
4251
+ if (items == null || items.size === 0) return;
4252
+ for (const [callback] of items) callback(...parameters);
4253
+ }
4254
+ function getHeraldSubscriptionProperty(input) {
4255
+ if (input == null) return heraldSubscription;
4256
+ const property = isPlainObject(input) ? input : {};
4257
+ if (typeof property.key !== "string" || property.value != null && typeof property.value !== "string") throw new Error(HERALD_MESSAGE_PROPERTY);
4258
+ return {
4259
+ key: property.key,
4260
+ value: property.value
4261
+ };
4262
+ }
4263
+ function getHeraldState(input) {
4264
+ const options = isPlainObject(input) ? input : {};
4265
+ if (!Array.isArray(options.names) || options.names.length === 0 || !options.names.every((name) => typeof name === "string")) throw new Error(HERALD_MESSAGE_ARRAY);
4266
+ if (options.onCreate != null && typeof options.onCreate !== "function") throw new Error(HERALD_MESSAGE_ONCREATE);
4267
+ const keys = new Set(options.names);
4268
+ return {
4269
+ keys,
4270
+ subscriptions: createSubscriptions({
4271
+ keys,
4272
+ property: getHeraldSubscriptionProperty(options.property)
4273
+ }),
4274
+ onCreate: options.onCreate
4275
+ };
4276
+ }
4277
+ /**
4278
+ * Create a _Herald_ for announcing named events
4279
+ *
4280
+ * @param names Event names
4281
+ * @param property Optional property for subscription identification _(defaults to `$herald`)_
4282
+ * @returns _Herald_ instance
4283
+ */
4284
+ function herald(options) {
4285
+ const state = getHeraldState(options);
4286
+ const instance = {
4287
+ clear: () => state.subscriptions.clear(),
4288
+ emit: (event, ...parameters) => emitForHerald(state, event, ...parameters),
4289
+ observed: (event) => (state.subscriptions.state.items.keyed?.get(event)?.size ?? 0) > 0,
4290
+ subscribe: (key, callback, signal) => subscribeToHerald(state, key, callback, signal)
4291
+ };
4292
+ Object.defineProperties(instance, {
4293
+ [HERALD_PROPERTY]: { value: HERALD_NAME_HERALD },
4294
+ events: {
4295
+ enumerable: true,
4296
+ value: createEvents(instance, state)
4297
+ }
4298
+ });
4299
+ return Object.freeze(instance);
4300
+ }
4301
+ /**
4302
+ * Is the value a herald?
4303
+ *
4304
+ * @param value Value to check
4305
+ * @returns `true` if the value is a herald, otherwise `false`
4306
+ */
4307
+ function isHerald(value) {
4308
+ return isHeraldInstance(HERALD_NAME_HERALD, value);
4309
+ }
4310
+ /**
4311
+ * Is the value events for a herald?
4312
+ *
4313
+ * @param value Value to check
4314
+ * @returns `true` if the value is events for a herald, otherwise `false`
4315
+ */
4316
+ function isHeraldEvents(value) {
4317
+ return isHeraldInstance(HERALD_NAME_EVENTS, value);
4318
+ }
4319
+ function isHeraldInstance(name, value) {
4320
+ return isPlainObject(value) && HERALD_PROPERTY in value && value[HERALD_PROPERTY] === name;
4321
+ }
4322
+ /**
4323
+ * Is the value a herald subscription?
4324
+ *
4325
+ * @param value Value to check
4326
+ * @returns `true` if the value is a herald subscription, otherwise `false`
4327
+ */
4328
+ function isHeraldSubscription(value) {
4329
+ return isSubscription(value) && value[HERALD_PROPERTY] === "subscription";
4330
+ }
4331
+ function subscribeToHerald(state, key, callback, signal) {
4332
+ const [subscription, existing] = state.subscriptions.create({
4333
+ key,
4334
+ signal,
4335
+ value: callback
4336
+ });
4337
+ if (!existing) state.onCreate?.(key, callback, subscription);
3991
4338
  return subscription;
3992
4339
  }
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 };
4340
+ const HERALD_PROPERTY = "$herald";
4341
+ const HERALD_MESSAGE_ARRAY = "Herald requires an array of event names.";
4342
+ const HERALD_MESSAGE_ONCREATE = `Herald requires a valid onCreate callback for subscription creation`;
4343
+ const HERALD_MESSAGE_PROPERTY = `Herald requires valid property information for subscription identification`;
4344
+ const HERALD_NAME_EVENTS = "events";
4345
+ const HERALD_NAME_HERALD = "herald";
4346
+ const heraldSubscription = { key: HERALD_PROPERTY };
4010
4347
  //#endregion
4011
4348
  //#region src/color/constants.ts
4012
4349
  const COLOR_ALPHA = {
@@ -5333,332 +5670,86 @@ const methods = [
5333
5670
  * _(Logging can be enabled or disabled by setting the `enabled` property)_
5334
5671
  */
5335
5672
  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);
5673
+ const instance = {};
5674
+ Object.defineProperties(instance, {
5675
+ [LOGGER_PROPERTY]: { value: LOGGER_NAME },
5676
+ enabled: {
5677
+ enumerable: true,
5678
+ get: () => enabled,
5679
+ set: (value) => {
5680
+ enabled = typeof value === "boolean" ? value : enabled;
5681
+ }
5682
+ },
5683
+ time: { value: (label) => timedLogger(getString(label)) }
5559
5684
  });
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();
5685
+ for (const method of methods) Object.defineProperty(instance, method, {
5686
+ enumerable: true,
5687
+ get() {
5688
+ return enabled ? console[method].bind(console) : noop;
5689
+ }
5568
5690
  });
5569
- }
5691
+ return Object.freeze(instance);
5692
+ })();
5693
+ let enabled = true;
5570
5694
  //#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
- });
5695
+ //#region src/math.ts
5696
+ function average(array, key) {
5697
+ const aggregated = aggregate(AGGREGATION_AVERAGE, array, key);
5698
+ return aggregated.count > 0 ? aggregated.value / aggregated.count : NaN;
5588
5699
  }
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;
5700
+ /**
5701
+ * Round a number up
5702
+ *
5703
+ * @param value Number to round up
5704
+ * @param decimals Number of decimal places to round to _(defaults to `0`)_
5705
+ * @returns Rounded number, or `Number.NaN` if the value if unable to be rounded
5706
+ */
5707
+ function ceil(value, decimals) {
5708
+ return roundNumber(Math.ceil, value, decimals);
5594
5709
  }
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
- }
5710
+ function count(array, key, value) {
5711
+ if (!Array.isArray(array)) return NaN;
5712
+ const { length } = array;
5713
+ const callback = getAggregateCallback(key);
5714
+ if (callback == null) return length;
5715
+ let counted = 0;
5716
+ for (let index = 0; index < length; index += 1) {
5717
+ const item = array[index];
5718
+ if (Object.is(callback(item, index, array), value)) counted += 1;
5613
5719
  }
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;
5720
+ return counted;
5620
5721
  }
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
- });
5722
+ /**
5723
+ * Round a number down
5724
+ *
5725
+ * @param value Number to round down
5726
+ * @param decimals Number of decimal places to round to _(defaults to `0`)_
5727
+ * @returns Rounded number, or `Number.NaN` if the value if unable to be rounded
5728
+ */
5729
+ function floor(value, decimals) {
5730
+ return roundNumber(Math.floor, value, decimals);
5658
5731
  }
5659
- promises.result = resultPromises;
5660
- async function resultPromises(items, signal) {
5661
- return promises(items, signal).then(getResultsFromPromises);
5732
+ function median(array, key) {
5733
+ let length = Array.isArray(array) ? array.length : 0;
5734
+ if (!Array.isArray(array) || length === 0) return NaN;
5735
+ let values = array;
5736
+ const callback = getAggregateCallback(key);
5737
+ if (callback != null) values = array.map((item, index) => callback(item, index, array));
5738
+ const numbers = values.filter(isNumber).sort((first, second) => first - second);
5739
+ length = numbers.length;
5740
+ if (length === 1) return numbers[0];
5741
+ if (length % 2 === 0) {
5742
+ const first = length / 2 - 1;
5743
+ const second = length / 2;
5744
+ return (numbers[first] + numbers[second]) / 2;
5745
+ }
5746
+ return numbers[Math.floor(length / 2)];
5747
+ }
5748
+ function min(array, key) {
5749
+ return getAggregated("min", array, key);
5750
+ }
5751
+ function sum(array, key) {
5752
+ return getAggregated("sum", array, key);
5662
5753
  }
5663
5754
  //#endregion
5664
5755
  //#region src/query.ts
@@ -5847,9 +5938,6 @@ function createQueue(callback, options, key) {
5847
5938
  });
5848
5939
  return Object.freeze(instance);
5849
5940
  }
5850
- function getBooleanOrDefault(value, defaultValue) {
5851
- return typeof value === "boolean" ? value : defaultValue;
5852
- }
5853
5941
  function getOptions(input) {
5854
5942
  const options = typeof input === "object" && input != null ? input : {};
5855
5943
  return {
@@ -6125,92 +6213,6 @@ const RANDOM_BOOLEAN_MODIFIER = .5;
6125
6213
  const RANDOM_HEX_CHARACTERS = "0123456789ABCDEF";
6126
6214
  const RANDOM_HEX_MAXIMUM = 15;
6127
6215
  //#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
6216
  //#region src/sized/set.ts
6215
6217
  /**
6216
6218
  * A _Set_ with a maximum size
@@ -6267,4 +6269,4 @@ var SizedSet = class extends Set {
6267
6269
  }
6268
6270
  };
6269
6271
  //#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 };
6272
+ 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 };