@daiso-tech/core 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/.changeset/README.md +8 -0
  2. package/.changeset/config.json +11 -0
  3. package/.changeset/sweet-peas-beg.md +5 -0
  4. package/.eslintignore +3 -0
  5. package/.eslintrc.json +50 -0
  6. package/.gitattributes +6 -0
  7. package/.github/workflows/main.yaml +54 -0
  8. package/.github/workflows/release.yaml +31 -0
  9. package/.prettierignore +4 -0
  10. package/.prettierrc.json +4 -0
  11. package/.vscode/settings.json +46 -0
  12. package/LICENSE.md +194 -0
  13. package/docs-api/.nojekyll +1 -0
  14. package/docs-api/assets/highlight.css +92 -0
  15. package/docs-api/assets/icons.js +18 -0
  16. package/docs-api/assets/icons.svg +1 -0
  17. package/docs-api/assets/main.js +60 -0
  18. package/docs-api/assets/navigation.js +1 -0
  19. package/docs-api/assets/search.js +1 -0
  20. package/docs-api/assets/style.css +1448 -0
  21. package/docs-api/classes/AsyncIterableCollection.html +437 -0
  22. package/docs-api/classes/CollectionError.html +12 -0
  23. package/docs-api/classes/IndexOverflowError.html +12 -0
  24. package/docs-api/classes/ItemNotFoundError.html +12 -0
  25. package/docs-api/classes/IterableCollection.html +434 -0
  26. package/docs-api/classes/ListCollection.html +434 -0
  27. package/docs-api/classes/MultipleItemsFoundError.html +12 -0
  28. package/docs-api/classes/UnexpectedCollectionError.html +12 -0
  29. package/docs-api/functions/isAsyncIterable.html +1 -0
  30. package/docs-api/functions/isIterable.html +1 -0
  31. package/docs-api/functions/range.html +4 -0
  32. package/docs-api/hierarchy.html +1 -0
  33. package/docs-api/index.html +1 -0
  34. package/docs-api/modules.html +60 -0
  35. package/docs-api/types/AsyncCollapse.html +1 -0
  36. package/docs-api/types/AsyncFilter.html +1 -0
  37. package/docs-api/types/AsyncFilter_.html +1 -0
  38. package/docs-api/types/AsyncFindOrSettings.html +1 -0
  39. package/docs-api/types/AsyncFindSettings.html +1 -0
  40. package/docs-api/types/AsyncForEach.html +1 -0
  41. package/docs-api/types/AsyncForEach_.html +1 -0
  42. package/docs-api/types/AsyncGroupBySettings.html +1 -0
  43. package/docs-api/types/AsyncIterableValue.html +1 -0
  44. package/docs-api/types/AsyncLazyable.html +1 -0
  45. package/docs-api/types/AsyncLazyable_.html +1 -0
  46. package/docs-api/types/AsyncMap.html +1 -0
  47. package/docs-api/types/AsyncMap_.html +1 -0
  48. package/docs-api/types/AsyncModifier.html +1 -0
  49. package/docs-api/types/AsyncModifier_.html +1 -0
  50. package/docs-api/types/AsyncReduce.html +1 -0
  51. package/docs-api/types/AsyncReduceSettings.html +1 -0
  52. package/docs-api/types/AsyncReduce_.html +1 -0
  53. package/docs-api/types/AsyncTap.html +1 -0
  54. package/docs-api/types/AsyncTap_.html +1 -0
  55. package/docs-api/types/AsyncTransform.html +1 -0
  56. package/docs-api/types/AsyncTransform_.html +1 -0
  57. package/docs-api/types/Collapse.html +1 -0
  58. package/docs-api/types/Comparator.html +1 -0
  59. package/docs-api/types/EnsureType.html +1 -0
  60. package/docs-api/types/Filter.html +1 -0
  61. package/docs-api/types/FilterGuard.html +1 -0
  62. package/docs-api/types/Filter_.html +1 -0
  63. package/docs-api/types/FindOrSettings.html +1 -0
  64. package/docs-api/types/FindSettings.html +1 -0
  65. package/docs-api/types/ForEach.html +1 -0
  66. package/docs-api/types/GroupBySettings.html +1 -0
  67. package/docs-api/types/IAsyncCollection.html +357 -0
  68. package/docs-api/types/ICollection.html +357 -0
  69. package/docs-api/types/JoinSettings.html +1 -0
  70. package/docs-api/types/Lazyable.html +1 -0
  71. package/docs-api/types/Map.html +1 -0
  72. package/docs-api/types/Modifier.html +1 -0
  73. package/docs-api/types/PageSettings.html +1 -0
  74. package/docs-api/types/RecordItem.html +1 -0
  75. package/docs-api/types/Reduce.html +1 -0
  76. package/docs-api/types/ReduceSettings.html +1 -0
  77. package/docs-api/types/ReverseSettings.html +1 -0
  78. package/docs-api/types/SliceSettings.html +1 -0
  79. package/docs-api/types/SlidingSettings.html +1 -0
  80. package/docs-api/types/Tap.html +1 -0
  81. package/docs-api/types/Transform.html +1 -0
  82. package/docs-api/types/UpdatedItem.html +1 -0
  83. package/package.json +47 -0
  84. package/src/_module.ts +2 -0
  85. package/src/collection/_module.ts +4 -0
  86. package/src/collection/_shared.ts +45 -0
  87. package/src/collection/async-iterable-collection/_module.ts +1 -0
  88. package/src/collection/async-iterable-collection/async-iterable-collection.test.ts +3195 -0
  89. package/src/collection/async-iterable-collection/async-iterable-collection.ts +1276 -0
  90. package/src/collection/async-iterable-collection/async-iterable-helpers/_module.ts +35 -0
  91. package/src/collection/async-iterable-collection/async-iterable-helpers/async-abort-iterable.ts +25 -0
  92. package/src/collection/async-iterable-collection/async-iterable-helpers/async-chunk-iterable.ts +57 -0
  93. package/src/collection/async-iterable-collection/async-iterable-helpers/async-chunk-whilte-iterable.ts +54 -0
  94. package/src/collection/async-iterable-collection/async-iterable-helpers/async-collapse-iterable.ts +40 -0
  95. package/src/collection/async-iterable-collection/async-iterable-helpers/async-count-by-iterable.ts +58 -0
  96. package/src/collection/async-iterable-collection/async-iterable-helpers/async-cross-join-iterable.ts +69 -0
  97. package/src/collection/async-iterable-collection/async-iterable-helpers/async-delay-iterable.ts +19 -0
  98. package/src/collection/async-iterable-collection/async-iterable-helpers/async-entries-iterable.ts +28 -0
  99. package/src/collection/async-iterable-collection/async-iterable-helpers/async-filter-iterable.ts +42 -0
  100. package/src/collection/async-iterable-collection/async-iterable-helpers/async-flat-map-iterable.ts +44 -0
  101. package/src/collection/async-iterable-collection/async-iterable-helpers/async-group-by-iterable.ts +48 -0
  102. package/src/collection/async-iterable-collection/async-iterable-helpers/async-insert-after-iterable.ts +57 -0
  103. package/src/collection/async-iterable-collection/async-iterable-helpers/async-insert-before-iterable.ts +57 -0
  104. package/src/collection/async-iterable-collection/async-iterable-helpers/async-map-iterable.ts +40 -0
  105. package/src/collection/async-iterable-collection/async-iterable-helpers/async-merge-iterable.ts +35 -0
  106. package/src/collection/async-iterable-collection/async-iterable-helpers/async-pad-end-iterable.ts +41 -0
  107. package/src/collection/async-iterable-collection/async-iterable-helpers/async-pad-start-iterable.ts +41 -0
  108. package/src/collection/async-iterable-collection/async-iterable-helpers/async-partion-iterable.ts +63 -0
  109. package/src/collection/async-iterable-collection/async-iterable-helpers/async-repeat-iterable.ts +40 -0
  110. package/src/collection/async-iterable-collection/async-iterable-helpers/async-reverse-iterable.ts +35 -0
  111. package/src/collection/async-iterable-collection/async-iterable-helpers/async-shuffle-iterable.ts +23 -0
  112. package/src/collection/async-iterable-collection/async-iterable-helpers/async-skip-iterable.ts +41 -0
  113. package/src/collection/async-iterable-collection/async-iterable-helpers/async-skip-until-iterable.ts +55 -0
  114. package/src/collection/async-iterable-collection/async-iterable-helpers/async-slice-iterable.ts +33 -0
  115. package/src/collection/async-iterable-collection/async-iterable-helpers/async-sliding-iterable.ts +54 -0
  116. package/src/collection/async-iterable-collection/async-iterable-helpers/async-sort-iterable.ts +18 -0
  117. package/src/collection/async-iterable-collection/async-iterable-helpers/async-split-iterable.ts +64 -0
  118. package/src/collection/async-iterable-collection/async-iterable-helpers/async-take-iterable.ts +41 -0
  119. package/src/collection/async-iterable-collection/async-iterable-helpers/async-take-until-iterable.ts +41 -0
  120. package/src/collection/async-iterable-collection/async-iterable-helpers/async-tap-iterable.ts +34 -0
  121. package/src/collection/async-iterable-collection/async-iterable-helpers/async-timeout-iterable.ts +20 -0
  122. package/src/collection/async-iterable-collection/async-iterable-helpers/async-unique-iterable.ts +49 -0
  123. package/src/collection/async-iterable-collection/async-iterable-helpers/async-update-iterable.ts +64 -0
  124. package/src/collection/async-iterable-collection/async-iterable-helpers/async-when-iterable.ts +43 -0
  125. package/src/collection/async-iterable-collection/async-iterable-helpers/async-zip-iterable.ts +45 -0
  126. package/src/collection/iterable-collection/_module.ts +1 -0
  127. package/src/collection/iterable-collection/iterable-collection.test.ts +2379 -0
  128. package/src/collection/iterable-collection/iterable-collection.ts +1317 -0
  129. package/src/collection/iterable-collection/iterable-helpers/_module.ts +32 -0
  130. package/src/collection/iterable-collection/iterable-helpers/chunk-iterable.ts +49 -0
  131. package/src/collection/iterable-collection/iterable-helpers/chunk-whilte-iterable.ts +51 -0
  132. package/src/collection/iterable-collection/iterable-helpers/collapse-iterable.ts +35 -0
  133. package/src/collection/iterable-collection/iterable-helpers/count-by-iterable.ts +49 -0
  134. package/src/collection/iterable-collection/iterable-helpers/cross-join-iterable.ts +57 -0
  135. package/src/collection/iterable-collection/iterable-helpers/entries-iterable.ts +42 -0
  136. package/src/collection/iterable-collection/iterable-helpers/filter-iterable.ts +39 -0
  137. package/src/collection/iterable-collection/iterable-helpers/flat-map-iterable.ts +35 -0
  138. package/src/collection/iterable-collection/iterable-helpers/group-by-iterable.ts +52 -0
  139. package/src/collection/iterable-collection/iterable-helpers/insert-after-iterable.ts +43 -0
  140. package/src/collection/iterable-collection/iterable-helpers/insert-before-iterable.ts +43 -0
  141. package/src/collection/iterable-collection/iterable-helpers/map-iterable.ts +35 -0
  142. package/src/collection/iterable-collection/iterable-helpers/merge-iterable.ts +31 -0
  143. package/src/collection/iterable-collection/iterable-helpers/pad-end-iterable.ts +52 -0
  144. package/src/collection/iterable-collection/iterable-helpers/pad-start-iterable.ts +52 -0
  145. package/src/collection/iterable-collection/iterable-helpers/partion-iterable.ts +46 -0
  146. package/src/collection/iterable-collection/iterable-helpers/repeat-iterable.ts +36 -0
  147. package/src/collection/iterable-collection/iterable-helpers/reverse-iterable.ts +46 -0
  148. package/src/collection/iterable-collection/iterable-helpers/shuffle-iterable.ts +36 -0
  149. package/src/collection/iterable-collection/iterable-helpers/skip-iterable.ts +37 -0
  150. package/src/collection/iterable-collection/iterable-helpers/skip-until-iterable.ts +41 -0
  151. package/src/collection/iterable-collection/iterable-helpers/slice-iterable.ts +47 -0
  152. package/src/collection/iterable-collection/iterable-helpers/sliding-iterable.ts +49 -0
  153. package/src/collection/iterable-collection/iterable-helpers/sort-iterable.ts +29 -0
  154. package/src/collection/iterable-collection/iterable-helpers/split-iterable.ts +58 -0
  155. package/src/collection/iterable-collection/iterable-helpers/take-iterable.ts +37 -0
  156. package/src/collection/iterable-collection/iterable-helpers/take-until-iterable.ts +38 -0
  157. package/src/collection/iterable-collection/iterable-helpers/tap-iterable.ts +31 -0
  158. package/src/collection/iterable-collection/iterable-helpers/unique-iterable.ts +43 -0
  159. package/src/collection/iterable-collection/iterable-helpers/update-iterable.ts +50 -0
  160. package/src/collection/iterable-collection/iterable-helpers/when-iterable.ts +37 -0
  161. package/src/collection/iterable-collection/iterable-helpers/zip-iterable.ts +41 -0
  162. package/src/collection/list-collection/_module.ts +1 -0
  163. package/src/collection/list-collection/list-collection.test.ts +2280 -0
  164. package/src/collection/list-collection/list-collection.ts +1883 -0
  165. package/src/contracts/_module.ts +1 -0
  166. package/src/contracts/collection/_module.ts +3 -0
  167. package/src/contracts/collection/_shared.ts +346 -0
  168. package/src/contracts/collection/async-collection.contract.ts +1028 -0
  169. package/src/contracts/collection/collection.contract.ts +978 -0
  170. package/src/types.ts +2 -0
  171. package/tsconfig.base.json +31 -0
  172. package/tsconfig.cjs.json +12 -0
  173. package/tsconfig.esm.json +12 -0
  174. package/tsconfig.json +10 -0
  175. package/tsconfig.types.json +12 -0
  176. package/vite.config.ts +6 -0
@@ -0,0 +1,1276 @@
1
+ import {
2
+ type AsyncCollapse,
3
+ type AsyncFilter,
4
+ type AsyncFindOrSettings,
5
+ type AsyncFindSettings,
6
+ type AsyncForEach,
7
+ type AsyncGroupBySettings,
8
+ type AsyncIterableValue,
9
+ type AsyncLazyable,
10
+ type AsyncMap,
11
+ type AsyncModifier,
12
+ type AsyncReduceSettings,
13
+ type AsyncTap,
14
+ type AsyncTransform,
15
+ CollectionError,
16
+ type Comparator,
17
+ type IAsyncCollection,
18
+ ItemNotFoundError,
19
+ type JoinSettings,
20
+ MultipleItemsFoundError,
21
+ IndexOverflowError,
22
+ type PageSettings,
23
+ type RecordItem,
24
+ type ReverseSettings,
25
+ type SliceSettings,
26
+ type SlidingSettings,
27
+ UnexpectedCollectionError,
28
+ type UpdatedItem,
29
+ } from "@/contracts/collection/_module";
30
+ import {
31
+ AsyncCrossJoinIterable,
32
+ AsyncSlidingIteralbe,
33
+ AsyncShuffleIterable,
34
+ AsyncEntriesIterable,
35
+ AsyncFilterIterable,
36
+ AsyncChunkIterable,
37
+ AsyncChunkWhileIterable,
38
+ AsyncCollapseIterable,
39
+ AsyncCountByIterable,
40
+ AsyncFlatMapIterable,
41
+ AsyncGroupByIterable,
42
+ AsyncInsertAfterIterable,
43
+ AsyncInsertBeforeIterable,
44
+ AsyncMapIterable,
45
+ AsyncMergeIterable,
46
+ AsyncPadEndIterable,
47
+ AsyncPadStartIterable,
48
+ AsyncPartionIterable,
49
+ AsyncSkipIterable,
50
+ AsyncSkipUntilIterable,
51
+ AsyncSortIterable,
52
+ AsyncSplitIterable,
53
+ AsyncTakeIterable,
54
+ AsyncTakeUntilIterable,
55
+ AsyncTapIterable,
56
+ AsyncUniqueIterable,
57
+ AsyncUpdateIterable,
58
+ AsyncWhenIterable,
59
+ AsyncZipIterable,
60
+ AsyncReverseIterable,
61
+ AsyncSliceIterable,
62
+ AsyncRepeatIterable,
63
+ AsyncAbortIterable,
64
+ AsyncDelayIterable,
65
+ AsyncTimeoutIterable,
66
+ } from "@/collection/async-iterable-collection/async-iterable-helpers/_module";
67
+ import { EnsureType } from "@/types";
68
+
69
+ /**
70
+ * Most methods in AsyncIterableCollection are lazy and will only execute when calling methods return values or iterating through an IterableCollection by using for of loop
71
+ * @group Collections
72
+ */
73
+ export class AsyncIterableCollection<TInput>
74
+ implements IAsyncCollection<TInput>
75
+ {
76
+ private static THROW_ON_NUMBER_LIMIT = false;
77
+
78
+ private static DEFAULT_CHUNK_SIZE = 1024;
79
+
80
+ private static makeCollection = <TInput>(
81
+ iterable: AsyncIterableValue<TInput>,
82
+ ): IAsyncCollection<TInput> => {
83
+ return new AsyncIterableCollection<TInput>(iterable);
84
+ };
85
+
86
+ constructor(private iterable: AsyncIterableValue<TInput>) {}
87
+
88
+ async *[Symbol.asyncIterator](): AsyncIterator<TInput> {
89
+ yield* this.iterable;
90
+ }
91
+
92
+ iterator(): AsyncIterator<TInput, void> {
93
+ return this[Symbol.asyncIterator]() as AsyncIterator<TInput, void>;
94
+ }
95
+
96
+ entries(
97
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
98
+ ): IAsyncCollection<RecordItem<number, TInput>> {
99
+ return new AsyncIterableCollection(
100
+ new AsyncEntriesIterable(this, throwOnNumberLimit),
101
+ );
102
+ }
103
+
104
+ keys(
105
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
106
+ ): IAsyncCollection<number> {
107
+ return this.entries(throwOnNumberLimit).map(([key]) => key);
108
+ }
109
+
110
+ values(): IAsyncCollection<TInput> {
111
+ return this.entries().map(([_key, value]) => value);
112
+ }
113
+
114
+ filter<TOutput extends TInput>(
115
+ filter: AsyncFilter<TInput, IAsyncCollection<TInput>, TOutput>,
116
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
117
+ ): IAsyncCollection<TOutput> {
118
+ return new AsyncIterableCollection<TOutput>(
119
+ new AsyncFilterIterable(this, filter, throwOnNumberLimit),
120
+ );
121
+ }
122
+
123
+ map<TOutput>(
124
+ map: AsyncMap<TInput, IAsyncCollection<TInput>, TOutput>,
125
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
126
+ ): IAsyncCollection<TOutput> {
127
+ return new AsyncIterableCollection(
128
+ new AsyncMapIterable(this, map, throwOnNumberLimit),
129
+ );
130
+ }
131
+
132
+ async reduce<TOutput = TInput>(
133
+ settings: AsyncReduceSettings<
134
+ TInput,
135
+ IAsyncCollection<TInput>,
136
+ TOutput
137
+ >,
138
+ ): Promise<TOutput> {
139
+ const { reduceFn: reduce, initialValue, throwOnNumberLimit } = settings;
140
+ if (initialValue === undefined && (await this.empty())) {
141
+ throw new TypeError(
142
+ "Reduce of empty array must be inputed a initial value",
143
+ );
144
+ }
145
+ if (initialValue !== undefined) {
146
+ let output = initialValue as TOutput;
147
+
148
+ for await (const [index, item] of this.entries()) {
149
+ output = await reduce(output, item, index, this);
150
+ }
151
+ return output;
152
+ }
153
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment
154
+ let output: TOutput = (await this.firstOrFail()) as any,
155
+ index = 0,
156
+ isFirstIteration = true;
157
+ for await (const item of this) {
158
+ if (!isFirstIteration) {
159
+ if (throwOnNumberLimit && index === Number.MAX_SAFE_INTEGER) {
160
+ throw new IndexOverflowError("Index has overflowed");
161
+ }
162
+ output = await reduce(output, item, index, this);
163
+ }
164
+ isFirstIteration = false;
165
+ index++;
166
+ }
167
+ return output;
168
+ }
169
+
170
+ async join(settings?: JoinSettings): Promise<string> {
171
+ return this.reduce({
172
+ reduceFn(str, item) {
173
+ if (typeof item !== "string") {
174
+ throw new TypeError("Item type is invalid must be string");
175
+ }
176
+ const separator = settings?.seperator ?? ",";
177
+ return str + separator + item;
178
+ },
179
+ throwOnNumberLimit:
180
+ settings?.throwOnNumberLimit ??
181
+ AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
182
+ });
183
+ }
184
+
185
+ collapse(): IAsyncCollection<AsyncCollapse<TInput>> {
186
+ return new AsyncIterableCollection(new AsyncCollapseIterable(this));
187
+ }
188
+
189
+ flatMap<TOutput>(
190
+ map: AsyncMap<TInput, IAsyncCollection<TInput>, Iterable<TOutput>>,
191
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
192
+ ): IAsyncCollection<TOutput> {
193
+ return new AsyncIterableCollection(
194
+ new AsyncFlatMapIterable(this, map, throwOnNumberLimit),
195
+ );
196
+ }
197
+
198
+ update<TFilterOutput extends TInput, TMapOutput>(
199
+ filter: AsyncFilter<TInput, IAsyncCollection<TInput>, TFilterOutput>,
200
+ map: AsyncMap<TFilterOutput, IAsyncCollection<TInput>, TMapOutput>,
201
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
202
+ ): IAsyncCollection<UpdatedItem<TInput, TFilterOutput, TMapOutput>> {
203
+ return new AsyncIterableCollection(
204
+ new AsyncUpdateIterable(this, filter, map, throwOnNumberLimit),
205
+ );
206
+ }
207
+
208
+ page(settings: PageSettings): IAsyncCollection<TInput> {
209
+ const { page, pageSize, throwOnNumberLimit } = settings;
210
+ if (page < 0) {
211
+ return this.skip(page * pageSize, throwOnNumberLimit).take(
212
+ pageSize,
213
+ throwOnNumberLimit,
214
+ );
215
+ }
216
+ return this.skip((page - 1) * pageSize, throwOnNumberLimit).take(
217
+ page * pageSize,
218
+ throwOnNumberLimit,
219
+ );
220
+ }
221
+
222
+ async sum(
223
+ throwOnNumberLimit?: boolean,
224
+ ): Promise<EnsureType<TInput, number>> {
225
+ try {
226
+ let sum = 0;
227
+ for await (const item of this) {
228
+ if (throwOnNumberLimit && sum === Number.MAX_SAFE_INTEGER) {
229
+ throw new IndexOverflowError("Sum has overflowed");
230
+ }
231
+ if (typeof item !== "number") {
232
+ throw new TypeError("Item type is invalid must be number");
233
+ }
234
+ sum += item;
235
+ }
236
+ return sum as EnsureType<TInput, number>;
237
+ } catch (error: unknown) {
238
+ if (
239
+ error instanceof CollectionError ||
240
+ error instanceof TypeError
241
+ ) {
242
+ throw error;
243
+ }
244
+ throw new UnexpectedCollectionError(
245
+ `Unexpected error "${String(error)}" occured`,
246
+ error,
247
+ );
248
+ }
249
+ }
250
+
251
+ async average(
252
+ throwOnNumberLimit?: boolean,
253
+ ): Promise<EnsureType<TInput, number>> {
254
+ try {
255
+ let size = 0,
256
+ sum = 0;
257
+ for await (const item of this) {
258
+ if (throwOnNumberLimit && sum === Number.MAX_SAFE_INTEGER) {
259
+ throw new IndexOverflowError("The sum has overflowed");
260
+ }
261
+ if (throwOnNumberLimit && size === Number.MAX_SAFE_INTEGER) {
262
+ throw new IndexOverflowError("The size has overflowed");
263
+ }
264
+ if (typeof item !== "number") {
265
+ throw new TypeError("Item type is invalid must be number");
266
+ }
267
+ size++;
268
+ sum += item;
269
+ }
270
+ return (sum / size) as EnsureType<TInput, number>;
271
+ } catch (error: unknown) {
272
+ if (
273
+ error instanceof CollectionError ||
274
+ error instanceof TypeError
275
+ ) {
276
+ throw error;
277
+ }
278
+ throw new UnexpectedCollectionError(
279
+ `Unexpected error "${String(error)}" occured`,
280
+ error,
281
+ );
282
+ }
283
+ }
284
+
285
+ async median(
286
+ throwOnNumberLimit?: boolean,
287
+ ): Promise<EnsureType<TInput, number>> {
288
+ if (await this.empty()) {
289
+ return 0 as EnsureType<TInput, number>;
290
+ }
291
+ const size = await this.size(throwOnNumberLimit);
292
+ if (size === 0) {
293
+ return 0 as EnsureType<TInput, number>;
294
+ }
295
+ const isEven = size % 2 === 0,
296
+ items = await this.map((item) => {
297
+ if (typeof item !== "number") {
298
+ throw new TypeError("Item type is invalid must be number");
299
+ }
300
+ return item;
301
+ }, throwOnNumberLimit)
302
+ .filter((_item, index) => {
303
+ if (isEven) {
304
+ return index === size / 2 || index === size / 2 - 1;
305
+ }
306
+ return index === Math.floor(size / 2);
307
+ }, throwOnNumberLimit)
308
+
309
+ .toArray();
310
+ if (isEven) {
311
+ const [a, b] = items;
312
+ if (a === undefined) {
313
+ throw new UnexpectedCollectionError("Is in invalid state");
314
+ }
315
+ if (b === undefined) {
316
+ throw new UnexpectedCollectionError("Is in invalid state");
317
+ }
318
+ return ((a + b) / 2) as EnsureType<TInput, number>;
319
+ }
320
+ const [median] = items;
321
+ if (median === undefined) {
322
+ throw new UnexpectedCollectionError("Is in invalid state");
323
+ }
324
+ return median as EnsureType<TInput, number>;
325
+ }
326
+
327
+ async min(): Promise<EnsureType<TInput, number>> {
328
+ try {
329
+ let min = 0;
330
+ for await (const item of this) {
331
+ if (typeof item !== "number") {
332
+ throw new TypeError("Item type is invalid must be number");
333
+ }
334
+ if (min === 0) {
335
+ min = item;
336
+ } else if (min > item) {
337
+ min = item;
338
+ }
339
+ }
340
+ return min as EnsureType<TInput, number>;
341
+ } catch (error: unknown) {
342
+ if (
343
+ error instanceof CollectionError ||
344
+ error instanceof TypeError
345
+ ) {
346
+ throw error;
347
+ }
348
+ throw new UnexpectedCollectionError(
349
+ `Unexpected error "${String(error)}" occured`,
350
+ error,
351
+ );
352
+ }
353
+ }
354
+
355
+ async max(): Promise<EnsureType<TInput, number>> {
356
+ try {
357
+ let max = 0;
358
+ for await (const item of this) {
359
+ if (typeof item !== "number") {
360
+ throw new TypeError("Item type is invalid must be number");
361
+ }
362
+ if (max === 0) {
363
+ max = item;
364
+ } else if (max < item) {
365
+ max = item;
366
+ }
367
+ }
368
+ return max as EnsureType<TInput, number>;
369
+ } catch (error: unknown) {
370
+ if (
371
+ error instanceof CollectionError ||
372
+ error instanceof TypeError
373
+ ) {
374
+ throw error;
375
+ }
376
+ throw new UnexpectedCollectionError(
377
+ `Unexpected error "${String(error)}" occured`,
378
+ error,
379
+ );
380
+ }
381
+ }
382
+
383
+ async percentage(
384
+ filter: AsyncFilter<TInput, IAsyncCollection<TInput>>,
385
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
386
+ ): Promise<number> {
387
+ try {
388
+ if (await this.empty()) {
389
+ return 0;
390
+ }
391
+ let part = 0,
392
+ total = 0;
393
+ for await (const item of this) {
394
+ if (throwOnNumberLimit && total === Number.MAX_SAFE_INTEGER) {
395
+ throw new IndexOverflowError(
396
+ "The total amount has overflowed",
397
+ );
398
+ }
399
+ if (await filter(item, total, this)) {
400
+ part++;
401
+ }
402
+ total++;
403
+ }
404
+ return (part / total) * 100;
405
+ } catch (error: unknown) {
406
+ if (
407
+ error instanceof CollectionError ||
408
+ error instanceof TypeError
409
+ ) {
410
+ throw error;
411
+ }
412
+ throw new UnexpectedCollectionError(
413
+ `Unexpected error "${String(error)}" occured`,
414
+ error,
415
+ );
416
+ }
417
+ }
418
+
419
+ async some<TOutput extends TInput>(
420
+ filter: AsyncFilter<TInput, IAsyncCollection<TInput>, TOutput>,
421
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
422
+ ): Promise<boolean> {
423
+ try {
424
+ for await (const [index, item] of this.entries(
425
+ throwOnNumberLimit,
426
+ )) {
427
+ if (await filter(item, index, this)) {
428
+ return true;
429
+ }
430
+ }
431
+ return false;
432
+ } catch (error: unknown) {
433
+ if (
434
+ error instanceof CollectionError ||
435
+ error instanceof TypeError
436
+ ) {
437
+ throw error;
438
+ }
439
+ throw new UnexpectedCollectionError(
440
+ `Unexpected error "${String(error)}" occured`,
441
+ error,
442
+ );
443
+ }
444
+ }
445
+
446
+ async every<TOutput extends TInput>(
447
+ filter: AsyncFilter<TInput, IAsyncCollection<TInput>, TOutput>,
448
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
449
+ ): Promise<boolean> {
450
+ try {
451
+ let isTrue = true;
452
+ for await (const [index, item] of this.entries(
453
+ throwOnNumberLimit,
454
+ )) {
455
+ isTrue &&= await filter(item, index, this);
456
+ if (!isTrue) {
457
+ break;
458
+ }
459
+ }
460
+ return isTrue;
461
+ } catch (error: unknown) {
462
+ if (
463
+ error instanceof CollectionError ||
464
+ error instanceof TypeError
465
+ ) {
466
+ throw error;
467
+ }
468
+ throw new UnexpectedCollectionError(
469
+ `Unexpected error "${String(error)}" occured`,
470
+ error,
471
+ );
472
+ }
473
+ }
474
+
475
+ take(
476
+ limit: number,
477
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
478
+ ): IAsyncCollection<TInput> {
479
+ return new AsyncIterableCollection(
480
+ new AsyncTakeIterable(this, limit, throwOnNumberLimit),
481
+ );
482
+ }
483
+
484
+ takeUntil(
485
+ filter: AsyncFilter<TInput, IAsyncCollection<TInput>>,
486
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
487
+ ): IAsyncCollection<TInput> {
488
+ return new AsyncIterableCollection(
489
+ new AsyncTakeUntilIterable(this, filter, throwOnNumberLimit),
490
+ );
491
+ }
492
+
493
+ takeWhile(
494
+ filter: AsyncFilter<TInput, IAsyncCollection<TInput>>,
495
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
496
+ ): IAsyncCollection<TInput> {
497
+ return this.takeUntil(
498
+ async (...arguments_) => !(await filter(...arguments_)),
499
+ throwOnNumberLimit,
500
+ );
501
+ }
502
+
503
+ skip(
504
+ offset: number,
505
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
506
+ ): IAsyncCollection<TInput> {
507
+ return new AsyncIterableCollection(
508
+ new AsyncSkipIterable(this, offset, throwOnNumberLimit),
509
+ );
510
+ }
511
+
512
+ skipUntil(
513
+ filter: AsyncFilter<TInput, IAsyncCollection<TInput>>,
514
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
515
+ ): IAsyncCollection<TInput> {
516
+ return new AsyncIterableCollection(
517
+ new AsyncSkipUntilIterable(this, filter, throwOnNumberLimit),
518
+ );
519
+ }
520
+
521
+ skipWhile(
522
+ filter: AsyncFilter<TInput, IAsyncCollection<TInput>>,
523
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
524
+ ): IAsyncCollection<TInput> {
525
+ return this.skipUntil(
526
+ async (...arguments_) => !(await filter(...arguments_)),
527
+ throwOnNumberLimit,
528
+ );
529
+ }
530
+
531
+ when<TExtended = TInput>(
532
+ condition: boolean,
533
+ callback: AsyncModifier<
534
+ IAsyncCollection<TInput>,
535
+ IAsyncCollection<TExtended>
536
+ >,
537
+ ): IAsyncCollection<TInput | TExtended> {
538
+ return new AsyncIterableCollection(
539
+ new AsyncWhenIterable(this, () => condition, callback),
540
+ );
541
+ }
542
+
543
+ whenEmpty<TExtended = TInput>(
544
+ callback: AsyncModifier<
545
+ IAsyncCollection<TInput>,
546
+ IAsyncCollection<TExtended>
547
+ >,
548
+ ): IAsyncCollection<TInput | TExtended> {
549
+ return new AsyncIterableCollection(
550
+ new AsyncWhenIterable(this, () => this.empty(), callback),
551
+ );
552
+ }
553
+
554
+ whenNot<TExtended = TInput>(
555
+ condition: boolean,
556
+ callback: AsyncModifier<
557
+ IAsyncCollection<TInput>,
558
+ IAsyncCollection<TExtended>
559
+ >,
560
+ ): IAsyncCollection<TInput | TExtended> {
561
+ return new AsyncIterableCollection(
562
+ new AsyncWhenIterable(this, () => !condition, callback),
563
+ );
564
+ }
565
+
566
+ whenNotEmpty<TExtended = TInput>(
567
+ callback: AsyncModifier<
568
+ IAsyncCollection<TInput>,
569
+ IAsyncCollection<TExtended>
570
+ >,
571
+ ): IAsyncCollection<TInput | TExtended> {
572
+ return new AsyncIterableCollection(
573
+ new AsyncWhenIterable(this, () => this.notEmpty(), callback),
574
+ );
575
+ }
576
+
577
+ async pipe<TOutput = TInput>(
578
+ callback: AsyncTransform<IAsyncCollection<TInput>, TOutput>,
579
+ ): Promise<TOutput> {
580
+ try {
581
+ return await callback(this);
582
+ } catch (error: unknown) {
583
+ if (
584
+ error instanceof CollectionError ||
585
+ error instanceof TypeError
586
+ ) {
587
+ throw error;
588
+ }
589
+ throw new UnexpectedCollectionError(
590
+ `Unexpected error "${String(error)}" occured`,
591
+ error,
592
+ );
593
+ }
594
+ }
595
+
596
+ tap(
597
+ callback: AsyncTap<IAsyncCollection<TInput>>,
598
+ ): IAsyncCollection<TInput> {
599
+ return new AsyncIterableCollection(
600
+ new AsyncTapIterable(this, callback),
601
+ );
602
+ }
603
+
604
+ chunk(chunkSize: number): IAsyncCollection<IAsyncCollection<TInput>> {
605
+ return new AsyncIterableCollection(
606
+ new AsyncChunkIterable(
607
+ this,
608
+ chunkSize,
609
+ AsyncIterableCollection.makeCollection,
610
+ ),
611
+ );
612
+ }
613
+
614
+ chunkWhile(
615
+ filter: AsyncFilter<TInput, IAsyncCollection<TInput>>,
616
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
617
+ ): IAsyncCollection<IAsyncCollection<TInput>> {
618
+ return new AsyncIterableCollection(
619
+ new AsyncChunkWhileIterable(
620
+ this,
621
+ filter,
622
+ throwOnNumberLimit,
623
+ AsyncIterableCollection.makeCollection,
624
+ ),
625
+ );
626
+ }
627
+
628
+ split(
629
+ chunkAmount: number,
630
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
631
+ ): IAsyncCollection<IAsyncCollection<TInput>> {
632
+ return new AsyncIterableCollection(
633
+ new AsyncSplitIterable(
634
+ this,
635
+ chunkAmount,
636
+ throwOnNumberLimit,
637
+ AsyncIterableCollection.makeCollection,
638
+ ),
639
+ );
640
+ }
641
+
642
+ partition(
643
+ filter: AsyncFilter<TInput, IAsyncCollection<TInput>>,
644
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
645
+ ): IAsyncCollection<IAsyncCollection<TInput>> {
646
+ return new AsyncIterableCollection(
647
+ new AsyncPartionIterable(
648
+ this,
649
+ filter,
650
+ throwOnNumberLimit,
651
+ AsyncIterableCollection.makeCollection,
652
+ ),
653
+ );
654
+ }
655
+
656
+ sliding(
657
+ settings: SlidingSettings,
658
+ ): IAsyncCollection<IAsyncCollection<TInput>> {
659
+ const {
660
+ chunkSize,
661
+ step = chunkSize - 1,
662
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
663
+ } = settings;
664
+ return new AsyncIterableCollection(
665
+ new AsyncSlidingIteralbe(this, chunkSize, step, throwOnNumberLimit),
666
+ );
667
+ }
668
+
669
+ groupBy<TOutput = TInput>(
670
+ settings?: AsyncGroupBySettings<
671
+ TInput,
672
+ IAsyncCollection<TInput>,
673
+ TOutput
674
+ >,
675
+ ): IAsyncCollection<RecordItem<TOutput, IAsyncCollection<TInput>>> {
676
+ return new AsyncIterableCollection(
677
+ new AsyncGroupByIterable(
678
+ this,
679
+ settings?.mapFn,
680
+ settings?.throwOnNumberLimit ??
681
+ AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
682
+ AsyncIterableCollection.makeCollection,
683
+ ),
684
+ );
685
+ }
686
+
687
+ countBy<TOutput = TInput>(
688
+ settings?: AsyncGroupBySettings<
689
+ TInput,
690
+ IAsyncCollection<TInput>,
691
+ TOutput
692
+ >,
693
+ ): IAsyncCollection<RecordItem<TOutput, number>> {
694
+ return new AsyncIterableCollection(
695
+ new AsyncCountByIterable(
696
+ this,
697
+ settings?.mapFn,
698
+ settings?.throwOnNumberLimit ??
699
+ AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
700
+ ),
701
+ );
702
+ }
703
+
704
+ unique<TOutput = TInput>(
705
+ settings?: AsyncGroupBySettings<
706
+ TInput,
707
+ IAsyncCollection<TInput>,
708
+ TOutput
709
+ >,
710
+ ): IAsyncCollection<TInput> {
711
+ return new AsyncIterableCollection(
712
+ new AsyncUniqueIterable(
713
+ this,
714
+ settings?.mapFn,
715
+ settings?.throwOnNumberLimit ??
716
+ AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
717
+ ),
718
+ );
719
+ }
720
+
721
+ difference<TOutput = TInput>(
722
+ iterable: AsyncIterableValue<TInput>,
723
+ map: AsyncMap<TInput, IAsyncCollection<TInput>, TOutput> = (item) =>
724
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-explicit-any
725
+ item as any,
726
+ ): IAsyncCollection<TInput> {
727
+ const differenceCollection = new AsyncIterableCollection(iterable);
728
+ return this.filter(async (item, index, collection) => {
729
+ return !(await differenceCollection.some(
730
+ async (matchItem, matchIndex, matchCollection) => {
731
+ return (
732
+ (await map(item, index, collection)) ===
733
+ (await map(matchItem, matchIndex, matchCollection))
734
+ );
735
+ },
736
+ ));
737
+ });
738
+ }
739
+
740
+ repeat(amount: number): IAsyncCollection<TInput> {
741
+ return new AsyncIterableCollection(
742
+ new AsyncRepeatIterable(
743
+ this,
744
+ amount,
745
+ AsyncIterableCollection.makeCollection,
746
+ ),
747
+ );
748
+ }
749
+
750
+ padStart<TExtended = TInput>(
751
+ maxLength: number,
752
+ fillItems: AsyncIterableValue<TExtended>,
753
+ ): IAsyncCollection<TInput | TExtended> {
754
+ return new AsyncIterableCollection(
755
+ new AsyncPadStartIterable(
756
+ this,
757
+ maxLength,
758
+ fillItems,
759
+ AsyncIterableCollection.makeCollection,
760
+ ),
761
+ );
762
+ }
763
+
764
+ padEnd<TExtended = TInput>(
765
+ maxLength: number,
766
+ fillItems: AsyncIterableValue<TExtended>,
767
+ ): IAsyncCollection<TInput | TExtended> {
768
+ return new AsyncIterableCollection(
769
+ new AsyncPadEndIterable(
770
+ this,
771
+ maxLength,
772
+ fillItems,
773
+ AsyncIterableCollection.makeCollection,
774
+ ),
775
+ );
776
+ }
777
+
778
+ slice(settings?: SliceSettings): IAsyncCollection<TInput> {
779
+ return new AsyncIterableCollection(
780
+ new AsyncSliceIterable(
781
+ this,
782
+ settings?.start,
783
+ settings?.end,
784
+ settings?.throwOnNumberLimit ??
785
+ AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
786
+ ),
787
+ );
788
+ }
789
+
790
+ prepend<TExtended = TInput>(
791
+ iterable: AsyncIterableValue<TInput | TExtended>,
792
+ ): IAsyncCollection<TInput | TExtended> {
793
+ return new AsyncIterableCollection(
794
+ new AsyncMergeIterable(iterable, this),
795
+ );
796
+ }
797
+
798
+ append<TExtended = TInput>(
799
+ iterable: AsyncIterableValue<TInput | TExtended>,
800
+ ): IAsyncCollection<TInput | TExtended> {
801
+ return new AsyncIterableCollection(
802
+ new AsyncMergeIterable(this, iterable),
803
+ );
804
+ }
805
+
806
+ insertBefore<TExtended = TInput>(
807
+ filter: AsyncFilter<TInput, IAsyncCollection<TInput>>,
808
+ iterable: AsyncIterableValue<TInput | TExtended>,
809
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
810
+ ): IAsyncCollection<TInput | TExtended> {
811
+ return new AsyncIterableCollection(
812
+ new AsyncInsertBeforeIterable(
813
+ this,
814
+ filter,
815
+ iterable,
816
+ throwOnNumberLimit,
817
+ ),
818
+ );
819
+ }
820
+
821
+ insertAfter<TExtended = TInput>(
822
+ filter: AsyncFilter<TInput, IAsyncCollection<TInput>>,
823
+ iterable: AsyncIterableValue<TInput | TExtended>,
824
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
825
+ ): IAsyncCollection<TInput | TExtended> {
826
+ return new AsyncIterableCollection(
827
+ new AsyncInsertAfterIterable(
828
+ this,
829
+ filter,
830
+ iterable,
831
+ throwOnNumberLimit,
832
+ ),
833
+ );
834
+ }
835
+
836
+ crossJoin<TExtended = TInput>(
837
+ ...iterables: Array<AsyncIterableValue<TExtended>>
838
+ ): IAsyncCollection<IAsyncCollection<TInput | TExtended>> {
839
+ return new AsyncIterableCollection(
840
+ new AsyncCrossJoinIterable(
841
+ this as IAsyncCollection<TInput>,
842
+ iterables,
843
+ AsyncIterableCollection.makeCollection,
844
+ ),
845
+ );
846
+ }
847
+
848
+ zip<TExtended>(
849
+ iterable: AsyncIterableValue<TExtended>,
850
+ ): IAsyncCollection<RecordItem<TInput, TExtended>> {
851
+ return new AsyncIterableCollection(
852
+ new AsyncZipIterable(this, iterable),
853
+ );
854
+ }
855
+
856
+ sort(compare?: Comparator<TInput> | undefined): IAsyncCollection<TInput> {
857
+ return new AsyncIterableCollection(
858
+ new AsyncSortIterable(this, compare),
859
+ );
860
+ }
861
+
862
+ reverse(settings?: ReverseSettings): IAsyncCollection<TInput> {
863
+ return new AsyncIterableCollection(
864
+ new AsyncReverseIterable(
865
+ this,
866
+ settings?.chunkSize ??
867
+ AsyncIterableCollection.DEFAULT_CHUNK_SIZE,
868
+ settings?.throwOnNumberLimit ??
869
+ AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
870
+ AsyncIterableCollection.makeCollection,
871
+ ),
872
+ );
873
+ }
874
+
875
+ shuffle(): IAsyncCollection<TInput> {
876
+ return new AsyncIterableCollection(new AsyncShuffleIterable(this));
877
+ }
878
+
879
+ async first<TOutput extends TInput>(
880
+ settings?: AsyncFindSettings<TInput, IAsyncCollection<TInput>, TOutput>,
881
+ ): Promise<TOutput | null> {
882
+ return this.firstOr({
883
+ ...settings,
884
+ defaultValue: null,
885
+ });
886
+ }
887
+
888
+ async firstOr<TOutput extends TInput, TExtended = TInput>(
889
+ settings: AsyncFindOrSettings<
890
+ TInput,
891
+ IAsyncCollection<TInput>,
892
+ TOutput,
893
+ TExtended
894
+ >,
895
+ ): Promise<TOutput | TExtended> {
896
+ try {
897
+ const throwOnNumberLimit =
898
+ settings.throwOnNumberLimit ??
899
+ AsyncIterableCollection.THROW_ON_NUMBER_LIMIT;
900
+
901
+ const filter = settings.filterFn ?? (() => true);
902
+ for await (const [index, item] of this.entries(
903
+ throwOnNumberLimit,
904
+ )) {
905
+ if (await filter(item, index, this)) {
906
+ return item as TOutput;
907
+ }
908
+ }
909
+ if (typeof settings.defaultValue === "function") {
910
+ const defaultFn = settings.defaultValue as () => TOutput;
911
+ return defaultFn();
912
+ }
913
+ return settings.defaultValue;
914
+ } catch (error: unknown) {
915
+ if (
916
+ error instanceof CollectionError ||
917
+ error instanceof TypeError
918
+ ) {
919
+ throw error;
920
+ }
921
+ throw new UnexpectedCollectionError(
922
+ `Unexpected error "${String(error)}" occured`,
923
+ error,
924
+ );
925
+ }
926
+ }
927
+
928
+ async firstOrFail<TOutput extends TInput>(
929
+ settings?: AsyncFindSettings<TInput, IAsyncCollection<TInput>, TOutput>,
930
+ ): Promise<TOutput> {
931
+ const item = await this.first(settings);
932
+ if (item === null) {
933
+ throw new ItemNotFoundError("Item was not found");
934
+ }
935
+ return item;
936
+ }
937
+
938
+ async last<TOutput extends TInput>(
939
+ settings?: AsyncFindSettings<TInput, IAsyncCollection<TInput>, TOutput>,
940
+ ): Promise<TOutput | null> {
941
+ return this.lastOr({
942
+ ...settings,
943
+ defaultValue: null,
944
+ });
945
+ }
946
+
947
+ async lastOr<TOutput extends TInput, TExtended = TInput>(
948
+ settings: AsyncFindOrSettings<
949
+ TInput,
950
+ IAsyncCollection<TInput>,
951
+ TOutput,
952
+ TExtended
953
+ >,
954
+ ): Promise<TOutput | TExtended> {
955
+ try {
956
+ const throwOnNumberLimit =
957
+ settings.throwOnNumberLimit ??
958
+ AsyncIterableCollection.THROW_ON_NUMBER_LIMIT;
959
+
960
+ const filter = settings.filterFn ?? (() => true);
961
+ let matchedItem: TOutput | null = null;
962
+ for await (const [index, item] of this.entries(
963
+ throwOnNumberLimit,
964
+ )) {
965
+ if (await filter(item, index, this)) {
966
+ matchedItem = item as TOutput;
967
+ }
968
+ }
969
+ if (matchedItem) {
970
+ return matchedItem;
971
+ }
972
+ if (typeof settings.defaultValue === "function") {
973
+ const defaultFn = settings.defaultValue as () => TOutput;
974
+ return defaultFn();
975
+ }
976
+ return settings.defaultValue;
977
+ } catch (error: unknown) {
978
+ if (
979
+ error instanceof CollectionError ||
980
+ error instanceof TypeError
981
+ ) {
982
+ throw error;
983
+ }
984
+ throw new UnexpectedCollectionError(
985
+ `Unexpected error "${String(error)}" occured`,
986
+ error,
987
+ );
988
+ }
989
+ }
990
+
991
+ async lastOrFail<TOutput extends TInput>(
992
+ settings?: AsyncFindSettings<TInput, IAsyncCollection<TInput>, TOutput>,
993
+ ): Promise<TOutput> {
994
+ const item = await this.last(settings);
995
+ if (item === null) {
996
+ throw new ItemNotFoundError("Item was not found");
997
+ }
998
+ return item;
999
+ }
1000
+
1001
+ async before(
1002
+ filter: AsyncFilter<TInput, IAsyncCollection<TInput>>,
1003
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
1004
+ ): Promise<TInput | null> {
1005
+ return this.beforeOr(null, filter, throwOnNumberLimit);
1006
+ }
1007
+
1008
+ async beforeOr<TExtended = TInput>(
1009
+ defaultValue: AsyncLazyable<TExtended>,
1010
+ filter: AsyncFilter<TInput, IAsyncCollection<TInput>>,
1011
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
1012
+ ): Promise<TInput | TExtended> {
1013
+ try {
1014
+ let beforeItem: TInput | null = null,
1015
+ index = 0;
1016
+ for await (const item of this) {
1017
+ if (throwOnNumberLimit && index === Number.MAX_SAFE_INTEGER) {
1018
+ throw new IndexOverflowError("Index has overflowed");
1019
+ }
1020
+ if ((await filter(item, index, this)) && beforeItem) {
1021
+ return beforeItem;
1022
+ }
1023
+ index++;
1024
+ beforeItem = item;
1025
+ }
1026
+ if (typeof defaultValue === "function") {
1027
+ const defaultFn = defaultValue as () => TExtended;
1028
+ return defaultFn();
1029
+ }
1030
+ return defaultValue;
1031
+ } catch (error: unknown) {
1032
+ if (
1033
+ error instanceof CollectionError ||
1034
+ error instanceof TypeError
1035
+ ) {
1036
+ throw error;
1037
+ }
1038
+ throw new UnexpectedCollectionError(
1039
+ `Unexpected error "${String(error)}" occured`,
1040
+ error,
1041
+ );
1042
+ }
1043
+ }
1044
+
1045
+ async beforeOrFail(
1046
+ filter: AsyncFilter<TInput, IAsyncCollection<TInput>>,
1047
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
1048
+ ): Promise<TInput> {
1049
+ const item = await this.before(filter, throwOnNumberLimit);
1050
+ if (item === null) {
1051
+ throw new ItemNotFoundError("Item was not found");
1052
+ }
1053
+ return item;
1054
+ }
1055
+
1056
+ async after(
1057
+ filter: AsyncFilter<TInput, IAsyncCollection<TInput>>,
1058
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
1059
+ ): Promise<TInput | null> {
1060
+ return this.afterOr(null, filter, throwOnNumberLimit);
1061
+ }
1062
+
1063
+ async afterOr<TExtended = TInput>(
1064
+ defaultValue: AsyncLazyable<TExtended>,
1065
+ filter: AsyncFilter<TInput, IAsyncCollection<TInput>>,
1066
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
1067
+ ): Promise<TInput | TExtended> {
1068
+ try {
1069
+ let hasMatched = false,
1070
+ index = 0;
1071
+ for await (const item of this) {
1072
+ if (hasMatched) {
1073
+ return item;
1074
+ }
1075
+ if (throwOnNumberLimit && index === Number.MAX_SAFE_INTEGER) {
1076
+ throw new IndexOverflowError("Index has overflowed");
1077
+ }
1078
+ hasMatched = await filter(item, index, this);
1079
+ index++;
1080
+ }
1081
+ if (typeof defaultValue === "function") {
1082
+ const defaultFn = defaultValue as () => TExtended;
1083
+ return defaultFn();
1084
+ }
1085
+ return defaultValue;
1086
+ } catch (error: unknown) {
1087
+ if (error instanceof CollectionError) {
1088
+ throw error;
1089
+ }
1090
+ throw new UnexpectedCollectionError("!!__messge__!!", error);
1091
+ }
1092
+ }
1093
+
1094
+ async afterOrFail(
1095
+ filter: AsyncFilter<TInput, IAsyncCollection<TInput>>,
1096
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
1097
+ ): Promise<TInput> {
1098
+ const item = await this.after(filter, throwOnNumberLimit);
1099
+ if (item === null) {
1100
+ throw new ItemNotFoundError("Item was not found");
1101
+ }
1102
+ return item;
1103
+ }
1104
+
1105
+ async sole<TOutput extends TInput>(
1106
+ filter: AsyncFilter<TInput, IAsyncCollection<TInput>, TOutput>,
1107
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
1108
+ ): Promise<TOutput> {
1109
+ try {
1110
+ let matchedItem: TOutput | null = null;
1111
+ for await (const [index, item] of this.entries(
1112
+ throwOnNumberLimit,
1113
+ )) {
1114
+ if (await filter(item, index, this)) {
1115
+ if (matchedItem !== null) {
1116
+ throw new MultipleItemsFoundError(
1117
+ "Multiple items were found",
1118
+ );
1119
+ }
1120
+ matchedItem = item as TOutput;
1121
+ }
1122
+ }
1123
+ if (matchedItem === null) {
1124
+ throw new ItemNotFoundError("Item was not found");
1125
+ }
1126
+ return matchedItem;
1127
+ } catch (error: unknown) {
1128
+ if (
1129
+ error instanceof CollectionError ||
1130
+ error instanceof TypeError
1131
+ ) {
1132
+ throw error;
1133
+ }
1134
+ throw new UnexpectedCollectionError(
1135
+ `Unexpected error "${String(error)}" occured`,
1136
+ error,
1137
+ );
1138
+ }
1139
+ }
1140
+
1141
+ nth(step: number): IAsyncCollection<TInput> {
1142
+ return this.filter((_item, index) => index % step === 0);
1143
+ }
1144
+
1145
+ delay(timeInMs: number): IAsyncCollection<TInput> {
1146
+ return new AsyncIterableCollection(
1147
+ new AsyncDelayIterable(this, timeInMs),
1148
+ );
1149
+ }
1150
+
1151
+ abort(signal: AbortSignal): IAsyncCollection<TInput> {
1152
+ return new AsyncIterableCollection(
1153
+ new AsyncAbortIterable(this, signal),
1154
+ );
1155
+ }
1156
+
1157
+ timeout(timeInMs: number): IAsyncCollection<TInput> {
1158
+ return new AsyncIterableCollection(
1159
+ new AsyncTimeoutIterable(this, timeInMs),
1160
+ );
1161
+ }
1162
+
1163
+ async count(
1164
+ filter: AsyncFilter<TInput, IAsyncCollection<TInput>>,
1165
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
1166
+ ): Promise<number> {
1167
+ try {
1168
+ let size = 0;
1169
+ for await (const item of this) {
1170
+ if (throwOnNumberLimit && size === Number.MAX_SAFE_INTEGER) {
1171
+ throw new IndexOverflowError("Size has overflowed");
1172
+ }
1173
+ if (await filter(item, size, this)) {
1174
+ size++;
1175
+ }
1176
+ }
1177
+ return size;
1178
+ } catch (error: unknown) {
1179
+ if (
1180
+ error instanceof CollectionError ||
1181
+ error instanceof TypeError
1182
+ ) {
1183
+ throw error;
1184
+ }
1185
+ throw new UnexpectedCollectionError(
1186
+ `Unexpected error "${String(error)}" occured`,
1187
+ error,
1188
+ );
1189
+ }
1190
+ }
1191
+
1192
+ async size(throwOnNumberLimit?: boolean): Promise<number> {
1193
+ return this.count(() => true, throwOnNumberLimit);
1194
+ }
1195
+
1196
+ async empty(): Promise<boolean> {
1197
+ try {
1198
+ for await (const _ of this) {
1199
+ return false;
1200
+ }
1201
+ return true;
1202
+ } catch (error: unknown) {
1203
+ if (
1204
+ error instanceof CollectionError ||
1205
+ error instanceof TypeError
1206
+ ) {
1207
+ throw error;
1208
+ }
1209
+ throw new UnexpectedCollectionError(
1210
+ `Unexpected error "${String(error)}" occured`,
1211
+ error,
1212
+ );
1213
+ }
1214
+ }
1215
+
1216
+ async notEmpty(): Promise<boolean> {
1217
+ return !(await this.empty());
1218
+ }
1219
+
1220
+ async search(
1221
+ filter: AsyncFilter<TInput, IAsyncCollection<TInput>>,
1222
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
1223
+ ): Promise<number> {
1224
+ try {
1225
+ for await (const [index, item] of this.entries(
1226
+ throwOnNumberLimit,
1227
+ )) {
1228
+ if (await filter(item, index, this)) {
1229
+ return index;
1230
+ }
1231
+ }
1232
+ return -1;
1233
+ } catch (error: unknown) {
1234
+ if (
1235
+ error instanceof CollectionError ||
1236
+ error instanceof TypeError
1237
+ ) {
1238
+ throw error;
1239
+ }
1240
+ throw new UnexpectedCollectionError(
1241
+ `Unexpected error "${String(error)}" occured`,
1242
+ error,
1243
+ );
1244
+ }
1245
+ }
1246
+
1247
+ async forEach(
1248
+ callback: AsyncForEach<TInput, IAsyncCollection<TInput>>,
1249
+ throwOnNumberLimit = AsyncIterableCollection.THROW_ON_NUMBER_LIMIT,
1250
+ ): Promise<void> {
1251
+ for await (const [index, item] of this.entries(throwOnNumberLimit)) {
1252
+ await callback(item, index, this);
1253
+ }
1254
+ }
1255
+
1256
+ async toArray(): Promise<TInput[]> {
1257
+ try {
1258
+ const items: TInput[] = [];
1259
+ for await (const item of this) {
1260
+ items.push(item);
1261
+ }
1262
+ return items;
1263
+ } catch (error: unknown) {
1264
+ if (
1265
+ error instanceof CollectionError ||
1266
+ error instanceof TypeError
1267
+ ) {
1268
+ throw error;
1269
+ }
1270
+ throw new UnexpectedCollectionError(
1271
+ `Unexpected error "${String(error)}" occured`,
1272
+ error,
1273
+ );
1274
+ }
1275
+ }
1276
+ }