@naturalcycles/js-lib 14.224.0 → 14.226.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -103,26 +103,30 @@ export declare function _sortBy<T>(items: T[], mapper: Mapper<T, any>, mutate?:
103
103
  */
104
104
  export declare function _sortDescBy<T>(items: T[], mapper: Mapper<T, any>, mutate?: boolean): T[];
105
105
  /**
106
- * Like items.find(), but it tries to find from the END of the array.
106
+ * Similar to `Array.find`, but the `predicate` may return `END` to stop the iteration early.
107
107
  *
108
- * Node 18+ supports native array.findLast() - use that.
109
- * iOS Safari only has it since 15.4
108
+ * Use `Array.find` if you don't need to stop the iteration early.
110
109
  */
111
- export declare function _findLast<T>(items: T[], predicate: Predicate<T>): T | undefined;
112
- export declare function _takeWhile<T>(items: T[], predicate: Predicate<T>): T[];
113
- export declare function _takeRightWhile<T>(items: T[], predicate: Predicate<T>): T[];
114
- export declare function _dropWhile<T>(items: T[], predicate: Predicate<T>): T[];
115
- export declare function _dropRightWhile<T>(items: T[], predicate: Predicate<T>): T[];
110
+ export declare function _find<T>(items: readonly T[], predicate: AbortablePredicate<T>): T | undefined;
116
111
  /**
117
- * Counts how many items match the predicate.
112
+ * Similar to `Array.findLast`, but the `predicate` may return `END` to stop the iteration early.
118
113
  *
119
- * `limit` allows to exit early when limit count is reached, skipping further iterations (perf optimization).
114
+ * Use `Array.findLast` if you don't need to stop the iteration early, which is supported:
115
+ * - in Node since 18+
116
+ * - in iOS Safari since 15.4
120
117
  */
121
- export declare function _count<T>(items: T[], predicate: AbortablePredicate<T>, limit?: number): number;
118
+ export declare function _findLast<T>(items: readonly T[], predicate: AbortablePredicate<T>): T | undefined;
119
+ export declare function _takeWhile<T>(items: readonly T[], predicate: Predicate<T>): T[];
120
+ export declare function _takeRightWhile<T>(items: readonly T[], predicate: Predicate<T>): T[];
121
+ export declare function _dropWhile<T>(items: readonly T[], predicate: Predicate<T>): T[];
122
+ export declare function _dropRightWhile<T>(items: readonly T[], predicate: Predicate<T>): T[];
122
123
  /**
124
+ * Counts how many items match the predicate.
125
+ *
123
126
  * `limit` allows to exit early when limit count is reached, skipping further iterations (perf optimization).
124
127
  */
125
- export declare function _countBy<T>(items: T[], mapper: Mapper<T, any>): StringMap<number>;
128
+ export declare function _count<T>(items: Iterable<T>, predicate: AbortablePredicate<T>, limit?: number): number;
129
+ export declare function _countBy<T>(items: Iterable<T>, mapper: Mapper<T, any>): StringMap<number>;
126
130
  /**
127
131
  * Returns an intersection between 2 arrays.
128
132
  *
@@ -153,8 +157,8 @@ export declare function _difference<T>(source: T[], ...diffs: T[][]): T[];
153
157
  /**
154
158
  * Returns the sum of items, or 0 for empty array.
155
159
  */
156
- export declare function _sum(items: number[]): number;
157
- export declare function _sumBy<T>(items: T[], mapper: Mapper<T, number | undefined>): number;
160
+ export declare function _sum(items: Iterable<number>): number;
161
+ export declare function _sumBy<T>(items: Iterable<T>, mapper: Mapper<T, number | undefined>): number;
158
162
  /**
159
163
  * Map an array of T to a StringMap<V>,
160
164
  * by returning a tuple of [key, value] from a mapper function.
@@ -168,7 +172,7 @@ export declare function _sumBy<T>(items: T[], mapper: Mapper<T, number | undefin
168
172
  * _mapToObject([1, 2, 3], n => [n, `id${n}`])
169
173
  * // { '1': 'id1, '2': 'id2', '3': 'id3' }
170
174
  */
171
- export declare function _mapToObject<T, V>(array: T[], mapper: (item: T) => [key: any, value: V] | FalsyValue): StringMap<V>;
175
+ export declare function _mapToObject<T, V>(array: Iterable<T>, mapper: (item: T) => [key: any, value: V] | FalsyValue): StringMap<V>;
172
176
  /**
173
177
  * Randomly shuffle an array values.
174
178
  * Fisher–Yates algorithm.
@@ -179,28 +183,28 @@ export declare function _shuffle<T>(array: T[], mutate?: boolean): T[];
179
183
  * Returns last item of non-empty array.
180
184
  * Throws if array is empty.
181
185
  */
182
- export declare function _last<T>(array: T[]): T;
186
+ export declare function _last<T>(array: readonly T[]): T;
183
187
  /**
184
188
  * Returns last item of the array (or undefined if array is empty).
185
189
  */
186
- export declare function _lastOrUndefined<T>(array: T[]): T | undefined;
190
+ export declare function _lastOrUndefined<T>(array: readonly T[]): T | undefined;
187
191
  /**
188
192
  * Returns the first item of non-empty array.
189
193
  * Throws if array is empty.
190
194
  */
191
- export declare function _first<T>(array: T[]): T;
192
- export declare function _minOrUndefined<T>(array: T[]): NonNullable<T> | undefined;
195
+ export declare function _first<T>(array: readonly T[]): T;
196
+ export declare function _minOrUndefined<T>(array: readonly T[]): NonNullable<T> | undefined;
193
197
  /**
194
198
  * Filters out nullish values (undefined and null).
195
199
  */
196
- export declare function _min<T>(array: T[]): NonNullable<T>;
197
- export declare function _maxOrUndefined<T>(array: T[]): NonNullable<T> | undefined;
200
+ export declare function _min<T>(array: readonly T[]): NonNullable<T>;
201
+ export declare function _maxOrUndefined<T>(array: readonly T[]): NonNullable<T> | undefined;
198
202
  /**
199
203
  * Filters out nullish values (undefined and null).
200
204
  */
201
- export declare function _max<T>(array: T[]): NonNullable<T>;
202
- export declare function _maxBy<T>(array: T[], mapper: Mapper<T, number | string | undefined>): T;
203
- export declare function _minBy<T>(array: T[], mapper: Mapper<T, number | string | undefined>): T;
204
- export declare function _maxByOrUndefined<T>(array: T[], mapper: Mapper<T, number | string | undefined>): T | undefined;
205
- export declare function _minByOrUndefined<T>(array: T[], mapper: Mapper<T, number | string | undefined>): T | undefined;
206
- export declare function _zip<T1, T2>(array1: T1[], array2: T2[]): [T1, T2][];
205
+ export declare function _max<T>(array: readonly T[]): NonNullable<T>;
206
+ export declare function _maxBy<T>(array: readonly T[], mapper: Mapper<T, number | string | undefined>): T;
207
+ export declare function _minBy<T>(array: readonly T[], mapper: Mapper<T, number | string | undefined>): T;
208
+ export declare function _maxByOrUndefined<T>(array: readonly T[], mapper: Mapper<T, number | string | undefined>): T | undefined;
209
+ export declare function _minByOrUndefined<T>(array: readonly T[], mapper: Mapper<T, number | string | undefined>): T | undefined;
210
+ export declare function _zip<T1, T2>(array1: readonly T1[], array2: readonly T2[]): [T1, T2][];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports._zip = exports._minByOrUndefined = exports._maxByOrUndefined = exports._minBy = exports._maxBy = exports._max = exports._maxOrUndefined = exports._min = exports._minOrUndefined = exports._first = exports._lastOrUndefined = exports._last = exports._shuffle = exports._mapToObject = exports._sumBy = exports._sum = exports._difference = exports._intersectsWith = exports._intersection = exports._countBy = exports._count = exports._dropRightWhile = exports._dropWhile = exports._takeRightWhile = exports._takeWhile = exports._findLast = exports._sortDescBy = exports._sortBy = exports._groupBy = exports._mapBy = exports._by = exports._uniqBy = exports._pushUniqBy = exports._pushUniq = exports._uniq = exports._chunk = void 0;
3
+ exports._zip = exports._minByOrUndefined = exports._maxByOrUndefined = exports._minBy = exports._maxBy = exports._max = exports._maxOrUndefined = exports._min = exports._minOrUndefined = exports._first = exports._lastOrUndefined = exports._last = exports._shuffle = exports._mapToObject = exports._sumBy = exports._sum = exports._difference = exports._intersectsWith = exports._intersection = exports._countBy = exports._count = exports._dropRightWhile = exports._dropWhile = exports._takeRightWhile = exports._takeWhile = exports._findLast = exports._find = exports._sortDescBy = exports._sortBy = exports._groupBy = exports._mapBy = exports._by = exports._uniqBy = exports._pushUniqBy = exports._pushUniq = exports._uniq = exports._chunk = void 0;
4
4
  const is_util_1 = require("../is.util");
5
5
  const types_1 = require("../types");
6
6
  /**
@@ -172,13 +172,29 @@ function _sortDescBy(items, mapper, mutate = false) {
172
172
  }
173
173
  exports._sortDescBy = _sortDescBy;
174
174
  /**
175
- * Like items.find(), but it tries to find from the END of the array.
175
+ * Similar to `Array.find`, but the `predicate` may return `END` to stop the iteration early.
176
176
  *
177
- * Node 18+ supports native array.findLast() - use that.
178
- * iOS Safari only has it since 15.4
177
+ * Use `Array.find` if you don't need to stop the iteration early.
178
+ */
179
+ function _find(items, predicate) {
180
+ for (const [i, item] of items.entries()) {
181
+ const result = predicate(item, i);
182
+ if (result === types_1.END)
183
+ return;
184
+ if (result)
185
+ return item;
186
+ }
187
+ }
188
+ exports._find = _find;
189
+ /**
190
+ * Similar to `Array.findLast`, but the `predicate` may return `END` to stop the iteration early.
191
+ *
192
+ * Use `Array.findLast` if you don't need to stop the iteration early, which is supported:
193
+ * - in Node since 18+
194
+ * - in iOS Safari since 15.4
179
195
  */
180
196
  function _findLast(items, predicate) {
181
- return [...items].reverse().find(predicate);
197
+ return _find(items.slice().reverse(), predicate);
182
198
  }
183
199
  exports._findLast = _findLast;
184
200
  function _takeWhile(items, predicate) {
@@ -213,8 +229,9 @@ function _count(items, predicate, limit) {
213
229
  if (limit === 0)
214
230
  return 0;
215
231
  let count = 0;
216
- for (const [i, item] of items.entries()) {
217
- const r = predicate(item, i);
232
+ let i = 0;
233
+ for (const item of items) {
234
+ const r = predicate(item, i++);
218
235
  if (r === types_1.END)
219
236
  break;
220
237
  if (r) {
@@ -226,15 +243,13 @@ function _count(items, predicate, limit) {
226
243
  return count;
227
244
  }
228
245
  exports._count = _count;
229
- /**
230
- * `limit` allows to exit early when limit count is reached, skipping further iterations (perf optimization).
231
- */
232
246
  function _countBy(items, mapper) {
233
247
  const map = {};
234
- items.forEach((item, i) => {
235
- const key = mapper(item, i);
248
+ let i = 0;
249
+ for (const item of items) {
250
+ const key = mapper(item, i++);
236
251
  map[key] = (map[key] || 0) + 1;
237
- });
252
+ }
238
253
  return map;
239
254
  }
240
255
  exports._countBy = _countBy;
@@ -281,14 +296,24 @@ exports._difference = _difference;
281
296
  * Returns the sum of items, or 0 for empty array.
282
297
  */
283
298
  function _sum(items) {
284
- return items.reduce((sum, n) => sum + n, 0);
299
+ let sum = 0;
300
+ for (const n of items) {
301
+ sum += n;
302
+ }
303
+ return sum;
285
304
  }
286
305
  exports._sum = _sum;
287
306
  function _sumBy(items, mapper) {
288
- return items
289
- .map((v, i) => mapper(v, i))
290
- .filter(i => typeof i === 'number') // count only numbers, nothing else
291
- .reduce((sum, n) => sum + n, 0);
307
+ let sum = 0;
308
+ let i = 0;
309
+ for (const n of items) {
310
+ const v = mapper(n, i++);
311
+ if (typeof v === 'number') {
312
+ // count only numbers, nothing else
313
+ sum += v;
314
+ }
315
+ }
316
+ return sum;
292
317
  }
293
318
  exports._sumBy = _sumBy;
294
319
  /**
@@ -360,7 +385,7 @@ function _minOrUndefined(array) {
360
385
  const a = array.filter(is_util_1._isNotNullish);
361
386
  if (!a.length)
362
387
  return;
363
- return _min(a);
388
+ return a.reduce((min, item) => (min <= item ? min : item));
364
389
  }
365
390
  exports._minOrUndefined = _minOrUndefined;
366
391
  /**
@@ -377,7 +402,7 @@ function _maxOrUndefined(array) {
377
402
  const a = array.filter(is_util_1._isNotNullish);
378
403
  if (!a.length)
379
404
  return;
380
- return _max(a);
405
+ return a.reduce((max, item) => (max >= item ? max : item));
381
406
  }
382
407
  exports._maxOrUndefined = _maxOrUndefined;
383
408
  /**
@@ -159,13 +159,28 @@ export function _sortDescBy(items, mapper, mutate = false) {
159
159
  return _sortBy(items, mapper, mutate, 'desc');
160
160
  }
161
161
  /**
162
- * Like items.find(), but it tries to find from the END of the array.
162
+ * Similar to `Array.find`, but the `predicate` may return `END` to stop the iteration early.
163
163
  *
164
- * Node 18+ supports native array.findLast() - use that.
165
- * iOS Safari only has it since 15.4
164
+ * Use `Array.find` if you don't need to stop the iteration early.
165
+ */
166
+ export function _find(items, predicate) {
167
+ for (const [i, item] of items.entries()) {
168
+ const result = predicate(item, i);
169
+ if (result === END)
170
+ return;
171
+ if (result)
172
+ return item;
173
+ }
174
+ }
175
+ /**
176
+ * Similar to `Array.findLast`, but the `predicate` may return `END` to stop the iteration early.
177
+ *
178
+ * Use `Array.findLast` if you don't need to stop the iteration early, which is supported:
179
+ * - in Node since 18+
180
+ * - in iOS Safari since 15.4
166
181
  */
167
182
  export function _findLast(items, predicate) {
168
- return [...items].reverse().find(predicate);
183
+ return _find(items.slice().reverse(), predicate);
169
184
  }
170
185
  export function _takeWhile(items, predicate) {
171
186
  let proceed = true;
@@ -195,8 +210,9 @@ export function _count(items, predicate, limit) {
195
210
  if (limit === 0)
196
211
  return 0;
197
212
  let count = 0;
198
- for (const [i, item] of items.entries()) {
199
- const r = predicate(item, i);
213
+ let i = 0;
214
+ for (const item of items) {
215
+ const r = predicate(item, i++);
200
216
  if (r === END)
201
217
  break;
202
218
  if (r) {
@@ -207,15 +223,13 @@ export function _count(items, predicate, limit) {
207
223
  }
208
224
  return count;
209
225
  }
210
- /**
211
- * `limit` allows to exit early when limit count is reached, skipping further iterations (perf optimization).
212
- */
213
226
  export function _countBy(items, mapper) {
214
227
  const map = {};
215
- items.forEach((item, i) => {
216
- const key = mapper(item, i);
228
+ let i = 0;
229
+ for (const item of items) {
230
+ const key = mapper(item, i++);
217
231
  map[key] = (map[key] || 0) + 1;
218
- });
232
+ }
219
233
  return map;
220
234
  }
221
235
  // investigate: _groupBy
@@ -258,13 +272,23 @@ export function _difference(source, ...diffs) {
258
272
  * Returns the sum of items, or 0 for empty array.
259
273
  */
260
274
  export function _sum(items) {
261
- return items.reduce((sum, n) => sum + n, 0);
275
+ let sum = 0;
276
+ for (const n of items) {
277
+ sum += n;
278
+ }
279
+ return sum;
262
280
  }
263
281
  export function _sumBy(items, mapper) {
264
- return items
265
- .map((v, i) => mapper(v, i))
266
- .filter(i => typeof i === 'number') // count only numbers, nothing else
267
- .reduce((sum, n) => sum + n, 0);
282
+ let sum = 0;
283
+ let i = 0;
284
+ for (const n of items) {
285
+ const v = mapper(n, i++);
286
+ if (typeof v === 'number') {
287
+ // count only numbers, nothing else
288
+ sum += v;
289
+ }
290
+ }
291
+ return sum;
268
292
  }
269
293
  /**
270
294
  * Map an array of T to a StringMap<V>,
@@ -330,7 +354,7 @@ export function _minOrUndefined(array) {
330
354
  const a = array.filter(_isNotNullish);
331
355
  if (!a.length)
332
356
  return;
333
- return _min(a);
357
+ return a.reduce((min, item) => (min <= item ? min : item));
334
358
  }
335
359
  /**
336
360
  * Filters out nullish values (undefined and null).
@@ -345,7 +369,7 @@ export function _maxOrUndefined(array) {
345
369
  const a = array.filter(_isNotNullish);
346
370
  if (!a.length)
347
371
  return;
348
- return _max(a);
372
+ return a.reduce((max, item) => (max >= item ? max : item));
349
373
  }
350
374
  /**
351
375
  * Filters out nullish values (undefined and null).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/js-lib",
3
- "version": "14.224.0",
3
+ "version": "14.226.0",
4
4
  "scripts": {
5
5
  "prepare": "husky",
6
6
  "build-prod": "build-prod-esm-cjs",
@@ -195,31 +195,45 @@ export function _sortDescBy<T>(items: T[], mapper: Mapper<T, any>, mutate = fals
195
195
  }
196
196
 
197
197
  /**
198
- * Like items.find(), but it tries to find from the END of the array.
198
+ * Similar to `Array.find`, but the `predicate` may return `END` to stop the iteration early.
199
199
  *
200
- * Node 18+ supports native array.findLast() - use that.
201
- * iOS Safari only has it since 15.4
200
+ * Use `Array.find` if you don't need to stop the iteration early.
202
201
  */
203
- export function _findLast<T>(items: T[], predicate: Predicate<T>): T | undefined {
204
- return [...items].reverse().find(predicate)
202
+ export function _find<T>(items: readonly T[], predicate: AbortablePredicate<T>): T | undefined {
203
+ for (const [i, item] of items.entries()) {
204
+ const result = predicate(item, i)
205
+ if (result === END) return
206
+ if (result) return item
207
+ }
208
+ }
209
+
210
+ /**
211
+ * Similar to `Array.findLast`, but the `predicate` may return `END` to stop the iteration early.
212
+ *
213
+ * Use `Array.findLast` if you don't need to stop the iteration early, which is supported:
214
+ * - in Node since 18+
215
+ * - in iOS Safari since 15.4
216
+ */
217
+ export function _findLast<T>(items: readonly T[], predicate: AbortablePredicate<T>): T | undefined {
218
+ return _find(items.slice().reverse(), predicate)
205
219
  }
206
220
 
207
- export function _takeWhile<T>(items: T[], predicate: Predicate<T>): T[] {
221
+ export function _takeWhile<T>(items: readonly T[], predicate: Predicate<T>): T[] {
208
222
  let proceed = true
209
223
  return items.filter((v, index) => (proceed &&= predicate(v, index)))
210
224
  }
211
225
 
212
- export function _takeRightWhile<T>(items: T[], predicate: Predicate<T>): T[] {
226
+ export function _takeRightWhile<T>(items: readonly T[], predicate: Predicate<T>): T[] {
213
227
  let proceed = true
214
228
  return [...items].reverse().filter((v, index) => (proceed &&= predicate(v, index)))
215
229
  }
216
230
 
217
- export function _dropWhile<T>(items: T[], predicate: Predicate<T>): T[] {
231
+ export function _dropWhile<T>(items: readonly T[], predicate: Predicate<T>): T[] {
218
232
  let proceed = false
219
233
  return items.filter((v, index) => (proceed ||= !predicate(v, index)))
220
234
  }
221
235
 
222
- export function _dropRightWhile<T>(items: T[], predicate: Predicate<T>): T[] {
236
+ export function _dropRightWhile<T>(items: readonly T[], predicate: Predicate<T>): T[] {
223
237
  let proceed = false
224
238
  return [...items]
225
239
  .reverse()
@@ -232,12 +246,17 @@ export function _dropRightWhile<T>(items: T[], predicate: Predicate<T>): T[] {
232
246
  *
233
247
  * `limit` allows to exit early when limit count is reached, skipping further iterations (perf optimization).
234
248
  */
235
- export function _count<T>(items: T[], predicate: AbortablePredicate<T>, limit?: number): number {
249
+ export function _count<T>(
250
+ items: Iterable<T>,
251
+ predicate: AbortablePredicate<T>,
252
+ limit?: number,
253
+ ): number {
236
254
  if (limit === 0) return 0
237
255
  let count = 0
256
+ let i = 0
238
257
 
239
- for (const [i, item] of items.entries()) {
240
- const r = predicate(item, i)
258
+ for (const item of items) {
259
+ const r = predicate(item, i++)
241
260
  if (r === END) break
242
261
  if (r) {
243
262
  count++
@@ -248,16 +267,14 @@ export function _count<T>(items: T[], predicate: AbortablePredicate<T>, limit?:
248
267
  return count
249
268
  }
250
269
 
251
- /**
252
- * `limit` allows to exit early when limit count is reached, skipping further iterations (perf optimization).
253
- */
254
- export function _countBy<T>(items: T[], mapper: Mapper<T, any>): StringMap<number> {
270
+ export function _countBy<T>(items: Iterable<T>, mapper: Mapper<T, any>): StringMap<number> {
255
271
  const map: StringMap<number> = {}
256
272
 
257
- items.forEach((item, i) => {
258
- const key = mapper(item, i)
273
+ let i = 0
274
+ for (const item of items) {
275
+ const key = mapper(item, i++)
259
276
  map[key] = (map[key] || 0) + 1
260
- })
277
+ }
261
278
 
262
279
  return map
263
280
  }
@@ -305,15 +322,27 @@ export function _difference<T>(source: T[], ...diffs: T[][]): T[] {
305
322
  /**
306
323
  * Returns the sum of items, or 0 for empty array.
307
324
  */
308
- export function _sum(items: number[]): number {
309
- return items.reduce((sum, n) => sum + n, 0)
325
+ export function _sum(items: Iterable<number>): number {
326
+ let sum = 0
327
+ for (const n of items) {
328
+ sum += n
329
+ }
330
+ return sum
310
331
  }
311
332
 
312
- export function _sumBy<T>(items: T[], mapper: Mapper<T, number | undefined>): number {
313
- return items
314
- .map((v, i) => mapper(v, i)!)
315
- .filter(i => typeof i === 'number') // count only numbers, nothing else
316
- .reduce((sum, n) => sum + n, 0)
333
+ export function _sumBy<T>(items: Iterable<T>, mapper: Mapper<T, number | undefined>): number {
334
+ let sum = 0
335
+ let i = 0
336
+
337
+ for (const n of items) {
338
+ const v = mapper(n, i++)
339
+ if (typeof v === 'number') {
340
+ // count only numbers, nothing else
341
+ sum += v
342
+ }
343
+ }
344
+
345
+ return sum
317
346
  }
318
347
 
319
348
  /**
@@ -330,7 +359,7 @@ export function _sumBy<T>(items: T[], mapper: Mapper<T, number | undefined>): nu
330
359
  * // { '1': 'id1, '2': 'id2', '3': 'id3' }
331
360
  */
332
361
  export function _mapToObject<T, V>(
333
- array: T[],
362
+ array: Iterable<T>,
334
363
  mapper: (item: T) => [key: any, value: V] | FalsyValue,
335
364
  ): StringMap<V> {
336
365
  const m: StringMap<V> = {}
@@ -365,7 +394,7 @@ export function _shuffle<T>(array: T[], mutate = false): T[] {
365
394
  * Returns last item of non-empty array.
366
395
  * Throws if array is empty.
367
396
  */
368
- export function _last<T>(array: T[]): T {
397
+ export function _last<T>(array: readonly T[]): T {
369
398
  if (!array.length) throw new Error('_last called on empty array')
370
399
  return array[array.length - 1]!
371
400
  }
@@ -373,7 +402,7 @@ export function _last<T>(array: T[]): T {
373
402
  /**
374
403
  * Returns last item of the array (or undefined if array is empty).
375
404
  */
376
- export function _lastOrUndefined<T>(array: T[]): T | undefined {
405
+ export function _lastOrUndefined<T>(array: readonly T[]): T | undefined {
377
406
  return array[array.length - 1]
378
407
  }
379
408
 
@@ -381,48 +410,48 @@ export function _lastOrUndefined<T>(array: T[]): T | undefined {
381
410
  * Returns the first item of non-empty array.
382
411
  * Throws if array is empty.
383
412
  */
384
- export function _first<T>(array: T[]): T {
413
+ export function _first<T>(array: readonly T[]): T {
385
414
  if (!array.length) throw new Error('_first called on empty array')
386
415
  return array[0]!
387
416
  }
388
417
 
389
- export function _minOrUndefined<T>(array: T[]): NonNullable<T> | undefined {
418
+ export function _minOrUndefined<T>(array: readonly T[]): NonNullable<T> | undefined {
390
419
  const a = array.filter(_isNotNullish)
391
420
  if (!a.length) return
392
- return _min(a)
421
+ return a.reduce((min, item) => (min <= item ? min : item))
393
422
  }
394
423
 
395
424
  /**
396
425
  * Filters out nullish values (undefined and null).
397
426
  */
398
- export function _min<T>(array: T[]): NonNullable<T> {
427
+ export function _min<T>(array: readonly T[]): NonNullable<T> {
399
428
  const a = array.filter(_isNotNullish)
400
429
  if (!a.length) throw new Error('_min called on empty array')
401
430
  return a.reduce((min, item) => (min <= item ? min : item))
402
431
  }
403
432
 
404
- export function _maxOrUndefined<T>(array: T[]): NonNullable<T> | undefined {
433
+ export function _maxOrUndefined<T>(array: readonly T[]): NonNullable<T> | undefined {
405
434
  const a = array.filter(_isNotNullish)
406
435
  if (!a.length) return
407
- return _max(a)
436
+ return a.reduce((max, item) => (max >= item ? max : item))
408
437
  }
409
438
 
410
439
  /**
411
440
  * Filters out nullish values (undefined and null).
412
441
  */
413
- export function _max<T>(array: T[]): NonNullable<T> {
442
+ export function _max<T>(array: readonly T[]): NonNullable<T> {
414
443
  const a = array.filter(_isNotNullish)
415
444
  if (!a.length) throw new Error('_max called on empty array')
416
445
  return a.reduce((max, item) => (max >= item ? max : item))
417
446
  }
418
447
 
419
- export function _maxBy<T>(array: T[], mapper: Mapper<T, number | string | undefined>): T {
448
+ export function _maxBy<T>(array: readonly T[], mapper: Mapper<T, number | string | undefined>): T {
420
449
  const max = _maxByOrUndefined(array, mapper)
421
450
  if (max === undefined) throw new Error(`_maxBy returned undefined`)
422
451
  return max
423
452
  }
424
453
 
425
- export function _minBy<T>(array: T[], mapper: Mapper<T, number | string | undefined>): T {
454
+ export function _minBy<T>(array: readonly T[], mapper: Mapper<T, number | string | undefined>): T {
426
455
  const min = _minByOrUndefined(array, mapper)
427
456
  if (min === undefined) throw new Error(`_minBy returned undefined`)
428
457
  return min
@@ -431,7 +460,7 @@ export function _minBy<T>(array: T[], mapper: Mapper<T, number | string | undefi
431
460
  // todo: looks like it _maxByOrUndefined/_minByOrUndefined can be DRYer
432
461
 
433
462
  export function _maxByOrUndefined<T>(
434
- array: T[],
463
+ array: readonly T[],
435
464
  mapper: Mapper<T, number | string | undefined>,
436
465
  ): T | undefined {
437
466
  if (!array.length) return
@@ -450,7 +479,7 @@ export function _maxByOrUndefined<T>(
450
479
  }
451
480
 
452
481
  export function _minByOrUndefined<T>(
453
- array: T[],
482
+ array: readonly T[],
454
483
  mapper: Mapper<T, number | string | undefined>,
455
484
  ): T | undefined {
456
485
  if (!array.length) return
@@ -468,7 +497,7 @@ export function _minByOrUndefined<T>(
468
497
  return minItem
469
498
  }
470
499
 
471
- export function _zip<T1, T2>(array1: T1[], array2: T2[]): [T1, T2][] {
500
+ export function _zip<T1, T2>(array1: readonly T1[], array2: readonly T2[]): [T1, T2][] {
472
501
  const len = Math.min(array1.length, array2.length)
473
502
  const res: [T1, T2][] = []
474
503