atomic-fns 1.1.7 → 2.0.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 (216) hide show
  1. package/README.md +405 -60
  2. package/dist/array/index.d.ts +9 -0
  3. package/dist/array/index.js +9 -0
  4. package/dist/array/list.d.ts +99 -0
  5. package/dist/array/list.js +133 -0
  6. package/dist/array/sets.d.ts +130 -0
  7. package/dist/array/sets.js +213 -0
  8. package/dist/async/index.d.ts +6 -0
  9. package/dist/async/index.js +6 -0
  10. package/dist/async/retry.d.ts +38 -0
  11. package/dist/async/retry.js +56 -0
  12. package/dist/async/sleep.d.ts +42 -0
  13. package/dist/async/sleep.js +76 -0
  14. package/dist/collections/bisect.d.ts +103 -0
  15. package/dist/collections/bisect.js +157 -0
  16. package/dist/collections/deque.d.ts +67 -97
  17. package/dist/collections/deque.js +197 -249
  18. package/dist/collections/entries.d.ts +89 -0
  19. package/dist/collections/entries.js +131 -0
  20. package/dist/collections/frozen-set.d.ts +42 -0
  21. package/dist/collections/frozen-set.js +64 -0
  22. package/dist/collections/group.d.ts +141 -0
  23. package/dist/collections/group.js +241 -0
  24. package/dist/collections/heap.d.ts +64 -0
  25. package/dist/collections/heap.js +205 -0
  26. package/dist/collections/index.d.ts +15 -642
  27. package/dist/collections/index.js +14 -716
  28. package/dist/collections/internal/arrayKeys.d.ts +19 -0
  29. package/dist/collections/internal/arrayKeys.js +83 -0
  30. package/dist/collections/internal/invariants.d.ts +4 -0
  31. package/dist/collections/internal/invariants.js +12 -0
  32. package/dist/collections/internal/iterable.d.ts +25 -0
  33. package/dist/collections/internal/iterable.js +62 -0
  34. package/dist/collections/iterate.d.ts +162 -0
  35. package/dist/collections/iterate.js +188 -0
  36. package/dist/collections/lru-cache.d.ts +58 -0
  37. package/dist/collections/lru-cache.js +164 -0
  38. package/dist/collections/order.d.ts +19 -0
  39. package/dist/collections/order.js +38 -0
  40. package/dist/collections/shape.d.ts +32 -0
  41. package/dist/collections/shape.js +86 -0
  42. package/dist/collections/sorted-map.d.ts +171 -0
  43. package/dist/collections/sorted-map.js +845 -0
  44. package/dist/collections/sorted-set.d.ts +103 -0
  45. package/dist/collections/sorted-set.js +147 -0
  46. package/dist/collections/splay-tree.d.ts +82 -0
  47. package/dist/collections/splay-tree.js +354 -0
  48. package/dist/collections/trie.d.ts +58 -0
  49. package/dist/collections/trie.js +196 -0
  50. package/dist/decimal/currency.d.ts +211 -0
  51. package/dist/decimal/currency.js +321 -0
  52. package/dist/decimal/decimal.d.ts +299 -0
  53. package/dist/decimal/decimal.js +660 -0
  54. package/dist/decimal/index.d.ts +11 -145
  55. package/dist/decimal/index.js +10 -374
  56. package/dist/decimal/internal/bits.d.ts +2 -0
  57. package/dist/decimal/internal/bits.js +7 -0
  58. package/dist/decimal/internal/echo.d.ts +4 -0
  59. package/dist/decimal/internal/echo.js +6 -0
  60. package/dist/decimal/internal/isqrt.d.ts +9 -0
  61. package/dist/decimal/internal/isqrt.js +34 -0
  62. package/dist/decimal/internal/locale.d.ts +7 -0
  63. package/dist/decimal/internal/locale.js +24 -0
  64. package/dist/decimal/internal/minor-units.d.ts +2 -0
  65. package/dist/decimal/internal/minor-units.js +33 -0
  66. package/dist/decimal/internal/pow10.d.ts +24 -0
  67. package/dist/decimal/internal/pow10.js +96 -0
  68. package/dist/encoding/base64.d.ts +39 -0
  69. package/dist/encoding/base64.js +53 -0
  70. package/dist/encoding/hex.d.ts +23 -0
  71. package/dist/encoding/hex.js +34 -0
  72. package/dist/encoding/index.d.ts +6 -0
  73. package/dist/encoding/index.js +6 -0
  74. package/dist/function/debounce.d.ts +68 -0
  75. package/dist/function/debounce.js +203 -0
  76. package/dist/function/index.d.ts +6 -0
  77. package/dist/function/index.js +6 -0
  78. package/dist/function/shared.d.ts +2 -0
  79. package/dist/function/shared.js +5 -0
  80. package/dist/function/wrap.d.ts +130 -0
  81. package/dist/function/wrap.js +113 -0
  82. package/dist/hash/digest.d.ts +18 -0
  83. package/dist/hash/digest.js +26 -0
  84. package/dist/hash/hash.d.ts +22 -0
  85. package/dist/hash/hash.js +252 -0
  86. package/dist/hash/hashString.d.ts +13 -0
  87. package/dist/hash/hashString.js +53 -0
  88. package/dist/hash/index.d.ts +8 -0
  89. package/dist/hash/index.js +8 -0
  90. package/dist/hash/stableStringify.d.ts +19 -0
  91. package/dist/hash/stableStringify.js +102 -0
  92. package/dist/id/index.d.ts +7 -0
  93. package/dist/id/index.js +7 -0
  94. package/dist/id/nanoid.d.ts +16 -0
  95. package/dist/id/nanoid.js +65 -0
  96. package/dist/id/uniqueId.d.ts +14 -0
  97. package/dist/id/uniqueId.js +20 -0
  98. package/dist/id/uuid.d.ts +25 -0
  99. package/dist/id/uuid.js +64 -0
  100. package/dist/index.d.ts +15 -8
  101. package/dist/index.js +15 -8
  102. package/dist/internal/bytes.d.ts +11 -0
  103. package/dist/internal/bytes.js +33 -0
  104. package/dist/internal/codec.d.ts +11 -0
  105. package/dist/internal/codec.js +84 -0
  106. package/dist/internal/compare.d.ts +10 -0
  107. package/dist/internal/compare.js +26 -0
  108. package/dist/internal/crypto.d.ts +5 -0
  109. package/dist/internal/crypto.js +11 -0
  110. package/dist/internal/keys.d.ts +12 -0
  111. package/dist/internal/keys.js +23 -0
  112. package/dist/internal/kind.d.ts +44 -0
  113. package/dist/internal/kind.js +139 -0
  114. package/dist/internal/sparse.d.ts +51 -0
  115. package/dist/internal/sparse.js +104 -0
  116. package/dist/internal/text.d.ts +7 -0
  117. package/dist/internal/text.js +15 -0
  118. package/dist/internal/timer.d.ts +10 -0
  119. package/dist/internal/timer.js +17 -0
  120. package/dist/internal/truncate.d.ts +10 -0
  121. package/dist/internal/truncate.js +22 -0
  122. package/dist/internal/walk.d.ts +47 -0
  123. package/dist/internal/walk.js +100 -0
  124. package/dist/is/index.d.ts +8 -0
  125. package/dist/is/index.js +8 -0
  126. package/dist/is/isArrayLike.d.ts +18 -0
  127. package/dist/is/isArrayLike.js +25 -0
  128. package/dist/is/isError.d.ts +13 -0
  129. package/dist/is/isError.js +18 -0
  130. package/dist/is/isNil.d.ts +12 -0
  131. package/dist/is/isNil.js +14 -0
  132. package/dist/is/isPlainObject.d.ts +15 -0
  133. package/dist/is/isPlainObject.js +34 -0
  134. package/dist/number/index.d.ts +7 -0
  135. package/dist/number/index.js +7 -0
  136. package/dist/number/round.d.ts +86 -0
  137. package/dist/number/round.js +130 -0
  138. package/dist/number/stats.d.ts +52 -0
  139. package/dist/number/stats.js +115 -0
  140. package/dist/object/cloneDeep.d.ts +28 -0
  141. package/dist/object/cloneDeep.js +200 -0
  142. package/dist/object/index.d.ts +14 -0
  143. package/dist/object/index.js +13 -0
  144. package/dist/object/isEqual.d.ts +64 -0
  145. package/dist/object/isEqual.js +289 -0
  146. package/dist/object/matches.d.ts +40 -0
  147. package/dist/object/matches.js +284 -0
  148. package/dist/object/merge.d.ts +66 -0
  149. package/dist/object/merge.js +272 -0
  150. package/dist/object/parsePath.d.ts +22 -0
  151. package/dist/object/parsePath.js +111 -0
  152. package/dist/object/path.d.ts +85 -0
  153. package/dist/object/path.js +208 -0
  154. package/dist/object/pick.d.ts +91 -0
  155. package/dist/object/pick.js +180 -0
  156. package/dist/object/reshape.d.ts +73 -0
  157. package/dist/object/reshape.js +144 -0
  158. package/dist/random/index.d.ts +96 -32
  159. package/dist/random/index.js +215 -50
  160. package/dist/string/case.d.ts +71 -0
  161. package/dist/string/case.js +152 -0
  162. package/dist/string/fold.d.ts +35 -0
  163. package/dist/string/fold.js +100 -0
  164. package/dist/string/index.d.ts +6 -187
  165. package/dist/string/index.js +6 -226
  166. package/dist/string/truncate.d.ts +25 -0
  167. package/dist/string/truncate.js +44 -0
  168. package/dist/string/words.d.ts +27 -0
  169. package/dist/string/words.js +241 -0
  170. package/package.json +101 -58
  171. package/dist/collections/BTree.d.ts +0 -229
  172. package/dist/collections/BTree.js +0 -1165
  173. package/dist/collections/Heap.d.ts +0 -69
  174. package/dist/collections/Heap.js +0 -181
  175. package/dist/collections/LRUCache.d.ts +0 -80
  176. package/dist/collections/LRUCache.js +0 -126
  177. package/dist/collections/SortedMap.d.ts +0 -92
  178. package/dist/collections/SortedMap.js +0 -131
  179. package/dist/collections/SortedSet.d.ts +0 -69
  180. package/dist/collections/SortedSet.js +0 -99
  181. package/dist/collections/SortedTree.d.ts +0 -103
  182. package/dist/collections/SortedTree.js +0 -141
  183. package/dist/collections/SplayTree.d.ts +0 -105
  184. package/dist/collections/SplayTree.js +0 -338
  185. package/dist/collections/Trie.d.ts +0 -42
  186. package/dist/collections/Trie.js +0 -104
  187. package/dist/collections/abc.d.ts +0 -152
  188. package/dist/collections/abc.js +0 -39
  189. package/dist/collections/frozenset.d.ts +0 -19
  190. package/dist/collections/frozenset.js +0 -30
  191. package/dist/functools/index.d.ts +0 -130
  192. package/dist/functools/index.js +0 -235
  193. package/dist/globals/index.d.ts +0 -285
  194. package/dist/globals/index.js +0 -463
  195. package/dist/i18n/currency.d.ts +0 -24
  196. package/dist/i18n/currency.js +0 -85
  197. package/dist/i18n/date/index.d.ts +0 -203
  198. package/dist/i18n/date/index.js +0 -531
  199. package/dist/i18n/date/utils.d.ts +0 -65
  200. package/dist/i18n/date/utils.js +0 -290
  201. package/dist/i18n/duration.d.ts +0 -112
  202. package/dist/i18n/duration.js +0 -392
  203. package/dist/i18n/format.d.ts +0 -31
  204. package/dist/i18n/format.js +0 -506
  205. package/dist/i18n/index.d.ts +0 -8
  206. package/dist/i18n/index.js +0 -8
  207. package/dist/itertools/index.d.ts +0 -255
  208. package/dist/itertools/index.js +0 -437
  209. package/dist/math/index.d.ts +0 -96
  210. package/dist/math/index.js +0 -98
  211. package/dist/mod.d.ts +0 -1
  212. package/dist/mod.js +0 -1
  213. package/dist/operators/index.d.ts +0 -152
  214. package/dist/operators/index.js +0 -305
  215. package/dist/types.d.ts +0 -19
  216. package/dist/types.js +0 -1
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Array building blocks: `chunk`, `zip`, `range`, `remove`, `dropWhile`, `takeWhile`.
3
+ */
4
+ import { assertNotHugeSparse, walkArray } from '../internal/sparse.js';
5
+ /** The longest array the platform can build. */
6
+ const MAX_LENGTH = 2 ** 32 - 1;
7
+ /**
8
+ * `array` split into consecutive pieces of `size` elements; the last piece holds the rest.
9
+ * @param array The array to split.
10
+ * @param size The length of each piece, a positive integer.
11
+ * @returns A new array of new arrays.
12
+ * @throws {RangeError} when `size` is not a positive integer, or `array` is a huge sparse array.
13
+ * @example
14
+ * ```ts
15
+ * chunk([1, 2, 3, 4, 5], 2) // [[1, 2], [3, 4], [5]]
16
+ * ```
17
+ */
18
+ export function chunk(array, size) {
19
+ if (!Number.isInteger(size) || size < 1) {
20
+ throw new RangeError(`chunk size must be a positive integer, got ${String(size)}`);
21
+ }
22
+ assertNotHugeSparse(array);
23
+ const out = [];
24
+ for (let i = 0; i < array.length; i += size)
25
+ out.push(array.slice(i, i + size));
26
+ return out;
27
+ }
28
+ /**
29
+ * Rows built from the elements at each index of `arrays`: `zip(a, b)[i]` is `[a[i], b[i]]`. The
30
+ * result is as long as the longest input, and shorter inputs give `undefined`, as lodash does, so
31
+ * `zip(...zip(a, b))` restores `a` and `b` padded to one length.
32
+ * @param arrays The arrays to combine.
33
+ * @returns A new array of rows.
34
+ * @throws {RangeError} when an input is a huge sparse array.
35
+ * @example
36
+ * ```ts
37
+ * zip(['a', 'b'], [1, 2]) // [['a', 1], ['b', 2]]
38
+ * zip(...[['a', 1], ['b', 2]]) // [['a', 'b'], [1, 2]]
39
+ * ```
40
+ */
41
+ export function zip(...arrays) {
42
+ let length = 0;
43
+ for (const arr of arrays) {
44
+ assertNotHugeSparse(arr);
45
+ length = Math.max(length, arr.length);
46
+ }
47
+ return Array.from({ length }, (_, i) => arrays.map((arr) => arr[i]));
48
+ }
49
+ export function range(first, last, by) {
50
+ const [start, stop, step] = last === undefined ? [0, first, 1] : [first, last, by ?? 1];
51
+ for (const n of [start, stop, step]) {
52
+ if (typeof n !== 'number')
53
+ throw new TypeError(`range bounds must be numbers, got ${typeof n}`);
54
+ if (!Number.isFinite(n))
55
+ throw new RangeError('range bounds and step must be finite');
56
+ }
57
+ if (step === 0)
58
+ throw new RangeError('range step must not be zero');
59
+ const count = Math.max(0, Math.ceil((stop - start) / step));
60
+ if (count > MAX_LENGTH)
61
+ throw new RangeError(`range of ${String(count)} numbers is too long`);
62
+ const out = [];
63
+ for (let i = 0; i < count; i++) {
64
+ const value = start + i * step;
65
+ if (step > 0 ? !(value < stop) : !(value > stop))
66
+ break;
67
+ out.push(value);
68
+ }
69
+ return out;
70
+ }
71
+ export function remove(array, predicate) {
72
+ const removed = [];
73
+ const kept = [];
74
+ walkArray(array, (event) => {
75
+ if (event.kind !== 'value')
76
+ return;
77
+ const value = event.value;
78
+ if (predicate(value, event.index, array))
79
+ removed.push(value);
80
+ else
81
+ kept.push([event.index - removed.length, value]);
82
+ });
83
+ if (removed.length === 0)
84
+ return [];
85
+ const length = array.length - removed.length;
86
+ array.length = 0;
87
+ for (const [index, value] of kept)
88
+ array[index] = value;
89
+ array.length = length;
90
+ return removed;
91
+ }
92
+ function splitWhile(array, predicate, take) {
93
+ const out = [];
94
+ const length = array.length;
95
+ let boundary = length;
96
+ let matching = true;
97
+ walkArray(array, (event) => {
98
+ if (event.kind !== 'value')
99
+ return;
100
+ const value = event.value;
101
+ if (matching) {
102
+ if (predicate(value, event.index, array)) {
103
+ if (take)
104
+ out[event.index] = value;
105
+ return;
106
+ }
107
+ matching = false;
108
+ boundary = event.index;
109
+ }
110
+ if (take)
111
+ return false;
112
+ out[event.index - boundary] = value;
113
+ });
114
+ out.length = take ? boundary : length - boundary;
115
+ return out;
116
+ }
117
+ /**
118
+ * `array` without its leading elements for which `predicate` is truthy. Holes are skipped, as
119
+ * {@link remove} skips them, and keep their place in the result.
120
+ * @param array The array to read.
121
+ * @param predicate Tests one element present; gets `(value, index, array)`.
122
+ * @returns A new array from the first element that fails.
123
+ * @example
124
+ * ```ts
125
+ * dropWhile([1, 2, 3, 1], (n) => n < 3) // [3, 1]
126
+ * ```
127
+ */
128
+ export function dropWhile(array, predicate) {
129
+ return splitWhile(array, predicate, false);
130
+ }
131
+ export function takeWhile(array, predicate) {
132
+ return splitWhile(array, predicate, true);
133
+ }
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Set operations on arrays: values in order of first appearance, duplicates removed, compared
3
+ * with SameValueZero (as `Set` and `includes` do) unless a key or equality function is given.
4
+ */
5
+ /**
6
+ * `array` with the later elements that give the same key as an earlier one removed.
7
+ * `[...new Set(array)]` is the plain `uniq`.
8
+ * @param array The array to read.
9
+ * @param keyOf Returns the key of one element, compared with SameValueZero.
10
+ * @returns A new array of the first element for each key.
11
+ * @example
12
+ * ```ts
13
+ * uniqBy([2.1, 1.2, 2.3], Math.floor) // [2.1, 1.2]
14
+ * ```
15
+ */
16
+ export declare function uniqBy<T>(array: Iterable<T>, keyOf: (value: T) => unknown): T[];
17
+ /**
18
+ * `array` with the later elements that `equals` matches to an earlier one removed. It costs one
19
+ * comparison per pair of kept elements.
20
+ * @param array The array to read.
21
+ * @param equals Returns truthy when two elements count as the same; it gets the element under test
22
+ * first and the kept element second.
23
+ * @returns A new array of the first element of each group.
24
+ * @example
25
+ * ```ts
26
+ * uniqWith([{ x: 1 }, { x: 1 }], (a, b) => a.x === b.x) // [{ x: 1 }]
27
+ * ```
28
+ */
29
+ export declare function uniqWith<T>(array: Iterable<T>, equals: (a: T, b: T) => unknown): T[];
30
+ /**
31
+ * The distinct values of `array` that none of `others` holds.
32
+ * @param array The array to keep values from.
33
+ * @param others The arrays whose values to leave out.
34
+ * @returns A new array, in the order of `array`.
35
+ * @example
36
+ * ```ts
37
+ * difference([2, 1, 2, 3], [2]) // [1, 3]
38
+ * ```
39
+ */
40
+ export declare function difference<T>(array: Iterable<T>, ...others: Iterable<T>[]): T[];
41
+ /**
42
+ * {@link difference} by the key `keyOf` gives each value; the key function comes last.
43
+ * @param array The array to keep values from.
44
+ * @param rest The arrays to leave out, then the key function.
45
+ * @returns A new array, in the order of `array`.
46
+ * @throws {TypeError} when the last argument is not a function.
47
+ * @example
48
+ * ```ts
49
+ * differenceBy([2.1, 1.2], [2.3], Math.floor) // [1.2]
50
+ * ```
51
+ */
52
+ export declare function differenceBy<T>(array: Iterable<T>, ...rest: [...others: Iterable<T>[], keyOf: (value: T) => unknown]): T[];
53
+ /**
54
+ * {@link difference} with `equals` deciding which values match; the function comes last.
55
+ * @param array The array to keep values from.
56
+ * @param rest The arrays to leave out, then the equality function, which gets the element under
57
+ * test first and the kept or excluded element second.
58
+ * @returns A new array, in the order of `array`.
59
+ * @throws {TypeError} when the last argument is not a function.
60
+ * @example
61
+ * ```ts
62
+ * differenceWith([{ x: 1 }, { x: 2 }], [{ x: 1 }], (a, b) => a.x === b.x) // [{ x: 2 }]
63
+ * ```
64
+ */
65
+ export declare function differenceWith<T>(array: Iterable<T>, ...rest: [...others: Iterable<T>[], equals: (a: T, b: T) => unknown]): T[];
66
+ /**
67
+ * The distinct values of the first array that every other array holds.
68
+ * @param arrays The arrays to intersect.
69
+ * @returns A new array, in the order of the first array; `[]` with no arrays.
70
+ * @example
71
+ * ```ts
72
+ * intersection([2, 1, 2], [2, 3], [4, 2]) // [2]
73
+ * ```
74
+ */
75
+ export declare function intersection<T>(...arrays: Iterable<T>[]): T[];
76
+ /**
77
+ * {@link intersection} by the key `keyOf` gives each value; the key function comes last.
78
+ * @param rest The arrays to intersect, then the key function.
79
+ * @returns A new array, in the order of the first array.
80
+ * @throws {TypeError} when the last argument is not a function.
81
+ * @example
82
+ * ```ts
83
+ * intersectionBy([2.1, 1.2], [2.3], Math.floor) // [2.1]
84
+ * ```
85
+ */
86
+ export declare function intersectionBy<T>(...rest: [...arrays: Iterable<T>[], keyOf: (value: T) => unknown]): T[];
87
+ /**
88
+ * The distinct values of all `arrays`, in order of first appearance.
89
+ * @param arrays The arrays to join.
90
+ * @returns A new array.
91
+ * @example
92
+ * ```ts
93
+ * union([2], [1, 2], [3]) // [2, 1, 3]
94
+ * ```
95
+ */
96
+ export declare function union<T>(...arrays: Iterable<T>[]): T[];
97
+ /**
98
+ * {@link union} by the key `keyOf` gives each value; the key function comes last.
99
+ * @param rest The arrays to join, then the key function.
100
+ * @returns A new array of the first value for each key.
101
+ * @throws {TypeError} when the last argument is not a function.
102
+ * @example
103
+ * ```ts
104
+ * unionBy([2.1], [1.2, 2.3], Math.floor) // [2.1, 1.2]
105
+ * ```
106
+ */
107
+ export declare function unionBy<T>(...rest: [...arrays: Iterable<T>[], keyOf: (value: T) => unknown]): T[];
108
+ /**
109
+ * The distinct values that exactly one of `arrays` holds (for two arrays, the symmetric
110
+ * difference), in order of first appearance.
111
+ * @param arrays The arrays to compare.
112
+ * @returns A new array.
113
+ * @example
114
+ * ```ts
115
+ * xor([2, 1], [2, 3]) // [1, 3]
116
+ * xor([1], [1], [1]) // []
117
+ * ```
118
+ */
119
+ export declare function xor<T>(...arrays: Iterable<T>[]): T[];
120
+ /**
121
+ * {@link xor} by the key `keyOf` gives each value; the key function comes last.
122
+ * @param rest The arrays to compare, then the key function.
123
+ * @returns A new array of the first value for each key only one array holds.
124
+ * @throws {TypeError} when the last argument is not a function.
125
+ * @example
126
+ * ```ts
127
+ * xorBy([2.1, 1.2], [2.3], Math.floor) // [1.2]
128
+ * ```
129
+ */
130
+ export declare function xorBy<T>(...rest: [...arrays: Iterable<T>[], keyOf: (value: T) => unknown]): T[];
@@ -0,0 +1,213 @@
1
+ /**
2
+ * Set operations on arrays: values in order of first appearance, duplicates removed, compared
3
+ * with SameValueZero (as `Set` and `includes` do) unless a key or equality function is given.
4
+ */
5
+ const same = (value) => value;
6
+ function splitLast(rest, what) {
7
+ const fn = rest[rest.length - 1];
8
+ if (typeof fn !== 'function') {
9
+ throw new TypeError(`the last argument must be ${what}, got ${typeof fn}`);
10
+ }
11
+ // TypeScript cannot split a tuple whose rest element comes first, so the halves are cast.
12
+ return [rest.slice(0, -1), fn];
13
+ }
14
+ function uniqueBy(lists, keyOf, keep) {
15
+ const seen = new Set();
16
+ const out = [];
17
+ for (const list of lists) {
18
+ for (const value of list) {
19
+ const key = keyOf(value);
20
+ if (seen.has(key))
21
+ continue;
22
+ seen.add(key);
23
+ if (keep(key))
24
+ out.push(value);
25
+ }
26
+ }
27
+ return out;
28
+ }
29
+ function keySet(list, keyOf) {
30
+ const keys = new Set();
31
+ for (const value of list)
32
+ keys.add(keyOf(value));
33
+ return keys;
34
+ }
35
+ function uniqueWith(lists, equals, keep) {
36
+ const out = [];
37
+ for (const list of lists) {
38
+ for (const value of list) {
39
+ if (out.some((kept) => equals(value, kept)) || !keep(value))
40
+ continue;
41
+ out.push(value);
42
+ }
43
+ }
44
+ return out;
45
+ }
46
+ /**
47
+ * `array` with the later elements that give the same key as an earlier one removed.
48
+ * `[...new Set(array)]` is the plain `uniq`.
49
+ * @param array The array to read.
50
+ * @param keyOf Returns the key of one element, compared with SameValueZero.
51
+ * @returns A new array of the first element for each key.
52
+ * @example
53
+ * ```ts
54
+ * uniqBy([2.1, 1.2, 2.3], Math.floor) // [2.1, 1.2]
55
+ * ```
56
+ */
57
+ export function uniqBy(array, keyOf) {
58
+ return uniqueBy([array], keyOf, () => true);
59
+ }
60
+ /**
61
+ * `array` with the later elements that `equals` matches to an earlier one removed. It costs one
62
+ * comparison per pair of kept elements.
63
+ * @param array The array to read.
64
+ * @param equals Returns truthy when two elements count as the same; it gets the element under test
65
+ * first and the kept element second.
66
+ * @returns A new array of the first element of each group.
67
+ * @example
68
+ * ```ts
69
+ * uniqWith([{ x: 1 }, { x: 1 }], (a, b) => a.x === b.x) // [{ x: 1 }]
70
+ * ```
71
+ */
72
+ export function uniqWith(array, equals) {
73
+ return uniqueWith([array], equals, () => true);
74
+ }
75
+ /**
76
+ * The distinct values of `array` that none of `others` holds.
77
+ * @param array The array to keep values from.
78
+ * @param others The arrays whose values to leave out.
79
+ * @returns A new array, in the order of `array`.
80
+ * @example
81
+ * ```ts
82
+ * difference([2, 1, 2, 3], [2]) // [1, 3]
83
+ * ```
84
+ */
85
+ export function difference(array, ...others) {
86
+ return differenceBy(array, ...others, same);
87
+ }
88
+ /**
89
+ * {@link difference} by the key `keyOf` gives each value; the key function comes last.
90
+ * @param array The array to keep values from.
91
+ * @param rest The arrays to leave out, then the key function.
92
+ * @returns A new array, in the order of `array`.
93
+ * @throws {TypeError} when the last argument is not a function.
94
+ * @example
95
+ * ```ts
96
+ * differenceBy([2.1, 1.2], [2.3], Math.floor) // [1.2]
97
+ * ```
98
+ */
99
+ export function differenceBy(array, ...rest) {
100
+ const [others, keyOf] = splitLast(rest, 'a key function');
101
+ const excluded = new Set();
102
+ for (const other of others)
103
+ for (const value of other)
104
+ excluded.add(keyOf(value));
105
+ return uniqueBy([array], keyOf, (key) => !excluded.has(key));
106
+ }
107
+ /**
108
+ * {@link difference} with `equals` deciding which values match; the function comes last.
109
+ * @param array The array to keep values from.
110
+ * @param rest The arrays to leave out, then the equality function, which gets the element under
111
+ * test first and the kept or excluded element second.
112
+ * @returns A new array, in the order of `array`.
113
+ * @throws {TypeError} when the last argument is not a function.
114
+ * @example
115
+ * ```ts
116
+ * differenceWith([{ x: 1 }, { x: 2 }], [{ x: 1 }], (a, b) => a.x === b.x) // [{ x: 2 }]
117
+ * ```
118
+ */
119
+ export function differenceWith(array, ...rest) {
120
+ const [others, equals] = splitLast(rest, 'an equality function');
121
+ const excluded = others.flatMap((other) => [...other]);
122
+ return uniqueWith([array], equals, (value) => !excluded.some((other) => equals(value, other)));
123
+ }
124
+ /**
125
+ * The distinct values of the first array that every other array holds.
126
+ * @param arrays The arrays to intersect.
127
+ * @returns A new array, in the order of the first array; `[]` with no arrays.
128
+ * @example
129
+ * ```ts
130
+ * intersection([2, 1, 2], [2, 3], [4, 2]) // [2]
131
+ * ```
132
+ */
133
+ export function intersection(...arrays) {
134
+ return intersectionBy(...arrays, same);
135
+ }
136
+ /**
137
+ * {@link intersection} by the key `keyOf` gives each value; the key function comes last.
138
+ * @param rest The arrays to intersect, then the key function.
139
+ * @returns A new array, in the order of the first array.
140
+ * @throws {TypeError} when the last argument is not a function.
141
+ * @example
142
+ * ```ts
143
+ * intersectionBy([2.1, 1.2], [2.3], Math.floor) // [2.1]
144
+ * ```
145
+ */
146
+ export function intersectionBy(...rest) {
147
+ const [arrays, keyOf] = splitLast(rest, 'a key function');
148
+ if (arrays.length === 0)
149
+ return [];
150
+ const others = arrays.slice(1).map((other) => keySet(other, keyOf));
151
+ return uniqueBy([arrays[0]], keyOf, (key) => others.every((keys) => keys.has(key)));
152
+ }
153
+ /**
154
+ * The distinct values of all `arrays`, in order of first appearance.
155
+ * @param arrays The arrays to join.
156
+ * @returns A new array.
157
+ * @example
158
+ * ```ts
159
+ * union([2], [1, 2], [3]) // [2, 1, 3]
160
+ * ```
161
+ */
162
+ export function union(...arrays) {
163
+ return uniqueBy(arrays, same, () => true);
164
+ }
165
+ /**
166
+ * {@link union} by the key `keyOf` gives each value; the key function comes last.
167
+ * @param rest The arrays to join, then the key function.
168
+ * @returns A new array of the first value for each key.
169
+ * @throws {TypeError} when the last argument is not a function.
170
+ * @example
171
+ * ```ts
172
+ * unionBy([2.1], [1.2, 2.3], Math.floor) // [2.1, 1.2]
173
+ * ```
174
+ */
175
+ export function unionBy(...rest) {
176
+ const [arrays, keyOf] = splitLast(rest, 'a key function');
177
+ return uniqueBy(arrays, keyOf, () => true);
178
+ }
179
+ /**
180
+ * The distinct values that exactly one of `arrays` holds (for two arrays, the symmetric
181
+ * difference), in order of first appearance.
182
+ * @param arrays The arrays to compare.
183
+ * @returns A new array.
184
+ * @example
185
+ * ```ts
186
+ * xor([2, 1], [2, 3]) // [1, 3]
187
+ * xor([1], [1], [1]) // []
188
+ * ```
189
+ */
190
+ export function xor(...arrays) {
191
+ return xorBy(...arrays, same);
192
+ }
193
+ /**
194
+ * {@link xor} by the key `keyOf` gives each value; the key function comes last.
195
+ * @param rest The arrays to compare, then the key function.
196
+ * @returns A new array of the first value for each key only one array holds.
197
+ * @throws {TypeError} when the last argument is not a function.
198
+ * @example
199
+ * ```ts
200
+ * xorBy([2.1, 1.2], [2.3], Math.floor) // [1.2]
201
+ * ```
202
+ */
203
+ export function xorBy(...rest) {
204
+ const [arrays, keyOf] = splitLast(rest, 'a key function');
205
+ const lists = arrays.map((array) => Array.from(array, (value) => [value, keyOf(value)]));
206
+ const keyOfPair = ([, key]) => key;
207
+ const holders = new Map();
208
+ for (const list of lists) {
209
+ for (const key of keySet(list, keyOfPair))
210
+ holders.set(key, (holders.get(key) ?? 0) + 1);
211
+ }
212
+ return uniqueBy(lists, keyOfPair, (key) => holders.get(key) === 1).map(([value]) => value);
213
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Async helpers: `sleep`, `timeout` and `retry`.
3
+ * @module async
4
+ */
5
+ export { type RetryOptions, retry } from './retry.js';
6
+ export { type SleepOptions, sleep, type TimeoutOptions, timeout } from './sleep.js';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Async helpers: `sleep`, `timeout` and `retry`.
3
+ * @module async
4
+ */
5
+ export { retry } from './retry.js';
6
+ export { sleep, timeout } from './sleep.js';
@@ -0,0 +1,38 @@
1
+ /** Options for {@link retry}. */
2
+ export interface RetryOptions {
3
+ /** Retries after the first attempt (default 3); `Infinity` retries until success or abort. */
4
+ retries?: number;
5
+ /** Delay before the first retry, in milliseconds (default 100). */
6
+ minDelay?: number;
7
+ /** Longest delay between attempts, in milliseconds (default 10000, or `minDelay` when larger). */
8
+ maxDelay?: number;
9
+ /** Growth of the delay per retry (default 2). */
10
+ factor?: number;
11
+ /** Scale each delay by a random factor in [0.5, 1) so callers spread out (default `true`). */
12
+ jitter?: boolean;
13
+ /**
14
+ * Stops retrying and rejects with the signal's `reason` when it aborts. A running attempt is
15
+ * not interrupted, so pass the same signal to the work in `fn` to stop it too.
16
+ */
17
+ signal?: AbortSignal;
18
+ /** Decides whether an error is worth another attempt (default: every error is). */
19
+ shouldRetry?: (error: unknown, attempt: number) => boolean | PromiseLike<boolean>;
20
+ }
21
+ /**
22
+ * Calls `fn` until it succeeds, waiting between attempts with exponential backoff:
23
+ * `min(maxDelay, minDelay * factor ** (retry - 1))`, scaled into [0.5, 1) of that when `jitter`
24
+ * is on. `fn` receives the attempt number, from 1. After the last retry, or when `shouldRetry`
25
+ * returns `false`, the promise rejects with the error `fn` threw. An aborted `signal` rejects with
26
+ * its `reason` once the running attempt settles, before `shouldRetry` and the next attempt, or
27
+ * during a wait. Delays are checked as in {@link sleep}: negative ones clamp to 0.
28
+ * @param fn The work to try; may return a value or a promise.
29
+ * @param options Backoff, `signal` and `shouldRetry`.
30
+ * @returns A promise for the first successful result.
31
+ * @throws {TypeError} when `fn` is not a function, or a delay is not a number.
32
+ * @throws {RangeError} when an option is out of range, or `maxDelay` is below `minDelay`.
33
+ * @example
34
+ * ```ts
35
+ * const data = await retry(() => fetch('/api').then((r) => r.json()), { retries: 5 })
36
+ * ```
37
+ */
38
+ export declare function retry<T>(fn: (attempt: number) => T | PromiseLike<T>, options?: RetryOptions): Promise<T>;
@@ -0,0 +1,56 @@
1
+ import { assertFunction } from '../function/shared.js';
2
+ import { timerWait } from '../internal/timer.js';
3
+ import { sleep } from './sleep.js';
4
+ /**
5
+ * Calls `fn` until it succeeds, waiting between attempts with exponential backoff:
6
+ * `min(maxDelay, minDelay * factor ** (retry - 1))`, scaled into [0.5, 1) of that when `jitter`
7
+ * is on. `fn` receives the attempt number, from 1. After the last retry, or when `shouldRetry`
8
+ * returns `false`, the promise rejects with the error `fn` threw. An aborted `signal` rejects with
9
+ * its `reason` once the running attempt settles, before `shouldRetry` and the next attempt, or
10
+ * during a wait. Delays are checked as in {@link sleep}: negative ones clamp to 0.
11
+ * @param fn The work to try; may return a value or a promise.
12
+ * @param options Backoff, `signal` and `shouldRetry`.
13
+ * @returns A promise for the first successful result.
14
+ * @throws {TypeError} when `fn` is not a function, or a delay is not a number.
15
+ * @throws {RangeError} when an option is out of range, or `maxDelay` is below `minDelay`.
16
+ * @example
17
+ * ```ts
18
+ * const data = await retry(() => fetch('/api').then((r) => r.json()), { retries: 5 })
19
+ * ```
20
+ */
21
+ export function retry(fn, options = {}) {
22
+ assertFunction(fn, 'fn');
23
+ const retries = options.retries ?? 3;
24
+ if (!(Number.isInteger(retries) || retries === Number.POSITIVE_INFINITY) || retries < 0) {
25
+ throw new RangeError('retries must be a non-negative integer or Infinity');
26
+ }
27
+ const minDelay = timerWait(options.minDelay ?? 100, 'minDelay');
28
+ const maxDelay = options.maxDelay == null ? Math.max(10_000, minDelay) : timerWait(options.maxDelay, 'maxDelay');
29
+ if (maxDelay < minDelay)
30
+ throw new RangeError('maxDelay must be >= minDelay');
31
+ const factor = options.factor ?? 2;
32
+ if (typeof factor !== 'number' || !(factor >= 1 && Number.isFinite(factor))) {
33
+ throw new RangeError('factor must be a finite number >= 1');
34
+ }
35
+ const jitter = options.jitter ?? true;
36
+ const { signal, shouldRetry } = options;
37
+ return (async () => {
38
+ let backoff = minDelay;
39
+ for (let attempt = 1;; attempt++) {
40
+ signal?.throwIfAborted();
41
+ try {
42
+ return await fn(attempt);
43
+ }
44
+ catch (error) {
45
+ signal?.throwIfAborted();
46
+ if (attempt > retries)
47
+ throw error;
48
+ if (shouldRetry && !(await shouldRetry(error, attempt)))
49
+ throw error;
50
+ await sleep(jitter ? backoff * (0.5 + Math.random() / 2) : backoff, { signal });
51
+ // Grown one step at a time, so it stays capped instead of overflowing to Infinity or NaN.
52
+ backoff = Math.min(maxDelay, backoff * factor);
53
+ }
54
+ }
55
+ })();
56
+ }
@@ -0,0 +1,42 @@
1
+ /** Options for {@link sleep}. */
2
+ export interface SleepOptions {
3
+ /** Rejects the wait with the signal's `reason` when it aborts. */
4
+ signal?: AbortSignal;
5
+ }
6
+ /** Options for {@link timeout}. */
7
+ export interface TimeoutOptions {
8
+ /** Rejects with the signal's `reason` when it aborts before the promise settles. */
9
+ signal?: AbortSignal;
10
+ }
11
+ /**
12
+ * Resolves after `ms` milliseconds. An aborted `signal` rejects with its `reason`, at once when it
13
+ * is already aborted. Negative waits clamp to 0; NaN, infinite or past-2147483647 waits reject with
14
+ * `RangeError`.
15
+ * @param ms Milliseconds to wait.
16
+ * @param options `signal` to cancel the wait.
17
+ * @returns A promise that resolves to `undefined`.
18
+ * @example
19
+ * ```ts
20
+ * await sleep(100)
21
+ * const controller = new AbortController()
22
+ * const nap = sleep(1000, { signal: controller.signal })
23
+ * controller.abort()
24
+ * await nap.catch((reason) => console.log(reason)) // the abort reason
25
+ * ```
26
+ */
27
+ export declare function sleep(ms: number, options?: SleepOptions): Promise<void>;
28
+ /**
29
+ * Settles as `promise` does, or rejects with a `DOMException` named `TimeoutError` when `ms`
30
+ * milliseconds pass first, as `AbortSignal.timeout` does. An aborted `signal` rejects with its
31
+ * `reason`. The timer and the abort listener are removed once the result is known; `promise`
32
+ * itself keeps running, so pass the same `signal` to the work to stop it too.
33
+ * @param promise The promise to wait for.
34
+ * @param ms Milliseconds before it times out; checked as in {@link sleep}.
35
+ * @param options `signal` to cancel the wait.
36
+ * @returns A promise that settles with `promise`, or rejects on timeout or abort.
37
+ * @example
38
+ * ```ts
39
+ * const response = await timeout(fetch('/api'), 5000)
40
+ * ```
41
+ */
42
+ export declare function timeout<T>(promise: PromiseLike<T> | T, ms: number, options?: TimeoutOptions): Promise<T>;