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