@tim-code/my-util 0.4.8 → 0.4.9

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tim-code/my-util",
3
- "version": "0.4.8",
3
+ "version": "0.4.9",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "author": "Tim Sprowl",
package/src/find.js CHANGED
@@ -271,39 +271,83 @@ export function findMax(array, { key, cutoff = -Infinity } = {}) {
271
271
 
272
272
  /**
273
273
  * Find the first truthy value in an array.
274
- * Supports "from" and "to" being reversed to "find last truthy".
274
+ * Supports "from" and "to"/"until" being reversed to "find last truthy" if "reverse" is true.
275
275
  * @template T
276
276
  * @param {Array<T>} array
277
277
  * @param {Object} $1
278
278
  * @param {string|Function=} $1.key Specifies an alternative to using each element as the value.
279
279
  * If string, then accesses each element at that key to get value.
280
280
  * If function, then calls the callback on each element to get value.
281
- * @param {number=} $1.from Numeric index to start from: inclusive, defaults to 0
281
+ * @param {number=} $1.from Numeric index to start from: inclusive, defaults to `0`
282
282
  * @param {number=} $1.until Numeric index to end at: exclusive, defaults to `array.length`
283
+ * @param {number=} $1.to Numeric index to end at: inclusive, defaults to `array.length - 1`; takes precedence over "until"
284
+ * @param {boolean=} $1.reverse If true, looks through the array in reverse. Default is false.
285
+ * When true, findTruthy() will still start from "from" and end at "to"/"until".
286
+ * When true, changes the default values of "from", "until", "to" to `array.length - 1`, `-1`, `0`.
283
287
  * @returns {T}
284
288
  */
285
- export function findTruthy(array, { key, from = 0, until = array.length } = {}) {
289
+ // eslint-disable-next-line complexity
290
+ export function findTruthy(
291
+ array,
292
+ {
293
+ key,
294
+ reverse = false,
295
+ from = reverse ? array.length - 1 : 0,
296
+ until = reverse ? -1 : array.length,
297
+ to = reverse ? until + 1 : until - 1,
298
+ } = {}
299
+ ) {
286
300
  if (typeof key === "function") {
287
- for (let i = from; i < until; i++) {
288
- const element = array[i]
289
- const value = key(element, i, array)
290
- if (value) {
291
- return element
301
+ if (reverse) {
302
+ for (let i = from; i >= to; i--) {
303
+ const element = array[i]
304
+ const value = key(element, i, array)
305
+ if (value) {
306
+ return element
307
+ }
308
+ }
309
+ } else {
310
+ for (let i = from; i <= to; i++) {
311
+ const element = array[i]
312
+ const value = key(element, i, array)
313
+ if (value) {
314
+ return element
315
+ }
292
316
  }
293
317
  }
294
318
  } else if (typeof key === "number" || typeof key === "string") {
295
- for (let i = from; i < until; i++) {
296
- const element = array[i]
297
- const value = element[key]
298
- if (value) {
299
- return element
319
+ if (reverse) {
320
+ for (let i = from; i >= to; i--) {
321
+ const element = array[i]
322
+ const value = element[key]
323
+ if (value) {
324
+ return element
325
+ }
326
+ }
327
+ } else {
328
+ for (let i = from; i <= to; i++) {
329
+ const element = array[i]
330
+ const value = element[key]
331
+ if (value) {
332
+ return element
333
+ }
300
334
  }
301
335
  }
302
336
  } else {
303
- for (let i = from; i < until; i++) {
304
- const value = array[i]
305
- if (value) {
306
- return value
337
+ // eslint-disable-next-line no-lonely-if
338
+ if (reverse) {
339
+ for (let i = from; i >= to; i--) {
340
+ const value = array[i]
341
+ if (value) {
342
+ return value
343
+ }
344
+ }
345
+ } else {
346
+ for (let i = from; i <= to; i++) {
347
+ const value = array[i]
348
+ if (value) {
349
+ return value
350
+ }
307
351
  }
308
352
  }
309
353
  }
package/src/find.test.js CHANGED
@@ -323,4 +323,116 @@ describe("findTruthy", () => {
323
323
  expect(findTruthy([0, 1, 2], { from: 2, until: 2 })).toBeUndefined()
324
324
  expect(findTruthy([0, 1, 2], { from: 3, until: 2 })).toBeUndefined()
325
325
  })
326
+
327
+ it("respects the new 'to' option (inclusive end)", () => {
328
+ const arr = [0, 1, 2, 3]
329
+ expect(findTruthy(arr, { from: 1, to: 2 })).toBe(1)
330
+ expect(findTruthy(arr, { from: 2, to: 3 })).toBe(2)
331
+ expect(findTruthy(arr, { from: 2, to: 2 })).toBe(2)
332
+ expect(findTruthy(arr, { from: 2, to: 1 })).toBeUndefined()
333
+ expect(findTruthy(arr, { from: 0, to: 0 })).toBeUndefined()
334
+ expect(findTruthy(arr, { from: 1, to: 1 })).toBe(1)
335
+ })
336
+
337
+ it("prefers 'to' over 'until' if both are given", () => {
338
+ const arr = [0, 1, 2, 3]
339
+ // 'to' = 1, so only index 1 is checked, even though until=4
340
+ expect(findTruthy(arr, { from: 1, until: 4, to: 1 })).toBe(1)
341
+ // 'to' = 2, so indices 1 and 2 checked, even though until=2 (which would skip 2)
342
+ expect(findTruthy(arr, { from: 1, until: 2, to: 2 })).toBe(1)
343
+ })
344
+
345
+ it("works with key as function and 'to'", () => {
346
+ const arr = [{ v: 0 }, { v: 0 }, { v: 2 }, { v: 3 }]
347
+ expect(findTruthy(arr, { key: (e) => e.v, from: 1, to: 2 })).toEqual({ v: 2 })
348
+ expect(findTruthy(arr, { key: (e) => e.v, from: 1, to: 1 })).toBeUndefined()
349
+ })
350
+
351
+ it("works with key as string and 'to'", () => {
352
+ const arr = [{ x: 0 }, { x: 2 }, { x: 0 }]
353
+ expect(findTruthy(arr, { key: "x", from: 0, to: 1 })).toEqual({ x: 2 })
354
+ expect(findTruthy(arr, { key: "x", from: 1, to: 1 })).toEqual({ x: 2 })
355
+ expect(findTruthy(arr, { key: "x", from: 2, to: 1 })).toBeUndefined()
356
+ })
357
+
358
+ it("works with key as number and 'to'", () => {
359
+ const arr = [[0], [2], [0]]
360
+ expect(findTruthy(arr, { key: 0, from: 0, to: 1 })).toEqual([2])
361
+ expect(findTruthy(arr, { key: 0, from: 1, to: 1 })).toEqual([2])
362
+ expect(findTruthy(arr, { key: 0, from: 2, to: 1 })).toBeUndefined()
363
+ })
364
+
365
+ // New tests for reverse mode and its interaction with from, to, until
366
+ it("finds last truthy value with reverse=true and default from/to", () => {
367
+ const arr = [0, 1, 2, 3, 0]
368
+ expect(findTruthy(arr, { reverse: true })).toBe(3)
369
+ })
370
+
371
+ it("finds last truthy value with reverse=true and custom from/to", () => {
372
+ const arr = [0, 1, 2, 3, 4]
373
+ // from=3, to=1 (reverse), should check indices 3,2,1
374
+ expect(findTruthy(arr, { reverse: true, from: 3, to: 1 })).toBe(3)
375
+ // from=4, to=2, should check 4,3,2
376
+ expect(findTruthy(arr, { reverse: true, from: 4, to: 2 })).toBe(4)
377
+ // from=2, to=0, should check 2,1,0
378
+ expect(findTruthy(arr, { reverse: true, from: 2, to: 0 })).toBe(2)
379
+ // from=2, to=2, should check only 2
380
+ expect(findTruthy(arr, { reverse: true, from: 2, to: 2 })).toBe(2)
381
+ // from=2, to=3, should check 2,1,0 (since to > from, loop doesn't run)
382
+ expect(findTruthy(arr, { reverse: true, from: 2, to: 3 })).toBeUndefined()
383
+ })
384
+
385
+ it("finds last truthy value with reverse=true and until", () => {
386
+ const arr = [0, 1, 2, 3, 0]
387
+ // until=1, so to=until+1=2, from=4, should check 4,3,2
388
+ expect(findTruthy(arr, { reverse: true, until: 1 })).toBe(3)
389
+ expect(findTruthy(arr, { reverse: true, until: 2 })).toBe(3)
390
+ expect(findTruthy(arr, { reverse: true, until: 3 })).toBe(undefined)
391
+ })
392
+
393
+ it("finds last truthy value with reverse=true and key as function", () => {
394
+ const arr = [{ v: 0 }, { v: 2 }, { v: 0 }]
395
+ expect(findTruthy(arr, { key: (e) => e.v, reverse: true })).toEqual({ v: 2 })
396
+ })
397
+
398
+ it("finds last truthy value with reverse=true and key as string", () => {
399
+ const arr = [{ x: 0 }, { x: 2 }, { x: 0 }]
400
+ expect(findTruthy(arr, { key: "x", reverse: true })).toEqual({ x: 2 })
401
+ })
402
+
403
+ it("finds last truthy value with reverse=true and key as number", () => {
404
+ const arr = [[0], [2], [0]]
405
+ expect(findTruthy(arr, { key: 0, reverse: true })).toEqual([2])
406
+ })
407
+
408
+ it("returns undefined if no truthy value in reverse mode", () => {
409
+ expect(findTruthy([0, 0, 0], { reverse: true })).toBeUndefined()
410
+ })
411
+
412
+ it("returns undefined if reverse=true and from < to", () => {
413
+ expect(findTruthy([0, 1, 2], { reverse: true, from: 0, to: 2 })).toBeUndefined()
414
+ })
415
+
416
+ it("reverse=true with custom from/to and key as function", () => {
417
+ const arr = [{ v: 0 }, { v: 2 }, { v: 0 }, { v: 3 }]
418
+ expect(findTruthy(arr, { key: (e) => e.v, reverse: true, from: 2, to: 1 })).toEqual({
419
+ v: 2,
420
+ })
421
+ expect(findTruthy(arr, { key: (e) => e.v, reverse: true, from: 1, to: 1 })).toEqual({
422
+ v: 2,
423
+ })
424
+ expect(findTruthy(arr, { key: (e) => e.v, reverse: true, from: 1, to: 2 })).toBeUndefined()
425
+ })
426
+
427
+ it("reverse=true with custom from/to and key as string", () => {
428
+ const arr = [{ x: 0 }, { x: 2 }, { x: 0 }]
429
+ expect(findTruthy(arr, { key: "x", reverse: true, from: 1, to: 1 })).toEqual({ x: 2 })
430
+ expect(findTruthy(arr, { key: "x", reverse: true, from: 1, to: 2 })).toBeUndefined()
431
+ })
432
+
433
+ it("reverse=true with custom from/to and key as number", () => {
434
+ const arr = [[0], [2], [0]]
435
+ expect(findTruthy(arr, { key: 0, reverse: true, from: 1, to: 1 })).toEqual([2])
436
+ expect(findTruthy(arr, { key: 0, reverse: true, from: 1, to: 2 })).toBeUndefined()
437
+ })
326
438
  })