@tim-code/my-util 0.5.0 → 0.5.2

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.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "author": "Tim Sprowl",
package/src/find.js CHANGED
@@ -1,4 +1,30 @@
1
- export function findClosestAbs(array, desired, { key, cutoff = Infinity } = {}) {
1
+ export function findEq(array, desired, { key } = {}) {
2
+ if (typeof key === "function") {
3
+ for (let i = 0; i < array.length; i++) {
4
+ const element = array[i]
5
+ const value = key(element, i, array)
6
+ if (value === desired) {
7
+ return value
8
+ }
9
+ }
10
+ } else if (typeof key === "number" || typeof key === "string") {
11
+ for (const element of array) {
12
+ const value = element[key]
13
+ if (value === desired) {
14
+ return value
15
+ }
16
+ }
17
+ } else {
18
+ for (const value of array) {
19
+ if (value === desired) {
20
+ return value
21
+ }
22
+ }
23
+ }
24
+ return undefined
25
+ }
26
+
27
+ export function findSmallestDiff(array, desired, { key, cutoff = Infinity } = {}) {
2
28
  let closest
3
29
  if (typeof key === "function") {
4
30
  for (let i = 0; i < array.length; i++) {
@@ -163,14 +189,16 @@ export function findClosestGTE(array, desired, { key, cutoff = Infinity } = {})
163
189
  * @param {string|number|Function=} options.key
164
190
  * If specified, will consider the value for each element's key instead of the element itself.
165
191
  * If a function, called with the element, index and array (same as .map() callback) to produce the value to sort on.
166
- * @param {string=} options.comparator "abs", "lt", "lte", "gt", "gte", "abs". Default is "abs" which implies T is number.
192
+ * @param {string=} options.comparator "diff", "lt", "lte", "gt", "gte", "eq". Default is "diff" which implies T is number.
167
193
  * @param {V=} options.cutoff If specified, sets a initial constraint on how close the found value must be.
168
- * For example, if used with "lt", the found element would need to be greater than or equal to the cutoff but still less than the desired value.
169
- * If used with "abs", the found element would need to have a difference with the desired value less than the cutoff.
194
+ * If used with lt, lte, value must be greater than or equal to cutoff.
195
+ * If used with gt, gte, value must be less than or equal to cutoff.
196
+ * If used with diff, value's difference with desired must be less than or equal to cutoff.
197
+ * No effect with eq.
170
198
  * @returns {T|undefined}
171
199
  */
172
200
  export function findClosest(array, value, options = {}) {
173
- const { comparator = "abs" } = options
201
+ const { comparator = "diff" } = options
174
202
  switch (comparator) {
175
203
  case "lt":
176
204
  return findClosestLT(array, value, options)
@@ -180,15 +208,17 @@ export function findClosest(array, value, options = {}) {
180
208
  return findClosestGT(array, value, options)
181
209
  case "gte":
182
210
  return findClosestGTE(array, value, options)
183
- case "abs":
184
- return findClosestAbs(array, value, options)
211
+ case "diff":
212
+ return findSmallestDiff(array, value, options)
213
+ case "eq":
214
+ return findEq(array, value, options)
185
215
  default:
186
216
  throw new Error(`unknown comparator: ${comparator}`)
187
217
  }
188
218
  }
189
219
 
190
220
  /**
191
- * Find the minimum value in an array.
221
+ * Find the minimum value in an array. undefined or null values are ignored.
192
222
  * @template T, V
193
223
  * @param {Array<T>} array
194
224
  * @param {Object} $1
@@ -196,7 +226,7 @@ export function findClosest(array, value, options = {}) {
196
226
  * If string, then accesses each element at that key to get value.
197
227
  * If function, then calls the callback on each element to get value.
198
228
  * @param {V=} $1.cutoff Only values below cutoff will be considered.
199
- * @returns {T}
229
+ * @returns {T|undefined}
200
230
  */
201
231
  export function findMin(array, { key, cutoff = Infinity } = {}) {
202
232
  let closest
@@ -229,7 +259,7 @@ export function findMin(array, { key, cutoff = Infinity } = {}) {
229
259
  }
230
260
 
231
261
  /**
232
- * Find the maximum value in an array.
262
+ * Find the maximum value in an array. undefined or null values are ignored.
233
263
  * @template T, V
234
264
  * @param {Array<T>} array
235
265
  * @param {Object} $1
@@ -237,7 +267,7 @@ export function findMin(array, { key, cutoff = Infinity } = {}) {
237
267
  * If string, then accesses each element at that key to get value.
238
268
  * If function, then calls the callback on each element to get value.
239
269
  * @param {V=} $1.cutoff Only values above cutoff will be considered.
240
- * @returns {T}
270
+ * @returns {T|undefined}
241
271
  */
242
272
  export function findMax(array, { key, cutoff = -Infinity } = {}) {
243
273
  let closest
package/src/find.test.js CHANGED
@@ -2,7 +2,8 @@
2
2
  import { describe, expect, it } from "@jest/globals"
3
3
 
4
4
  const {
5
- findClosestAbs,
5
+ findEq,
6
+ findSmallestDiff,
6
7
  findClosestLT,
7
8
  findClosestLTE,
8
9
  findClosestGT,
@@ -13,40 +14,75 @@ const {
13
14
  findTruthy,
14
15
  } = await import("./find.js")
15
16
 
16
- describe("findClosestAbs", () => {
17
+ describe("findEq", () => {
18
+ it("returns the first element equal to desired (no key)", () => {
19
+ expect(findEq([1, 2, 3, 2], 2)).toBe(2)
20
+ expect(findEq([1, 2, 3], 4)).toBeUndefined()
21
+ })
22
+
23
+ it("returns the first value from key function equal to desired", () => {
24
+ const arr = [{ v: 1 }, { v: 2 }, { v: 3 }]
25
+ expect(findEq(arr, 2, { key: (e) => e.v })).toBe(2)
26
+ expect(findEq(arr, 4, { key: (e) => e.v })).toBeUndefined()
27
+ })
28
+
29
+ it("returns the first value from key string equal to desired", () => {
30
+ const arr = [{ x: 1 }, { x: 2 }, { x: 3 }]
31
+ expect(findEq(arr, 2, { key: "x" })).toBe(2)
32
+ expect(findEq(arr, 4, { key: "x" })).toBeUndefined()
33
+ })
34
+
35
+ it("returns the first value from key number equal to desired", () => {
36
+ const arr = [[1], [2], [3]]
37
+ expect(findEq(arr, 2, { key: 0 })).toBe(2)
38
+ expect(findEq(arr, 4, { key: 0 })).toBeUndefined()
39
+ })
40
+
41
+ it("returns undefined for empty array", () => {
42
+ expect(findEq([], 1)).toBeUndefined()
43
+ })
44
+
45
+ it("returns first matching value if there are duplicates", () => {
46
+ expect(findEq([2, 2, 3], 2)).toBe(2)
47
+ const arr = [{ v: 2 }, { v: 2 }]
48
+ expect(findEq(arr, 2, { key: (e) => e.v })).toBe(2)
49
+ })
50
+ })
51
+
52
+ describe("findSmallestDiff", () => {
17
53
  it("returns the element closest in absolute value to desired", () => {
18
- expect(findClosestAbs([1, 5, 9], 6)).toBe(5)
19
- expect(findClosestAbs([1, 5, 9], 8)).toBe(9)
20
- expect(findClosestAbs([1, 5, 9], 1)).toBe(1)
54
+ expect(findSmallestDiff([1, 5, 9], 6)).toBe(5)
55
+ expect(findSmallestDiff([1, 5, 9], 8)).toBe(9)
56
+ expect(findSmallestDiff([1, 5, 9], 1)).toBe(1)
21
57
  })
22
58
 
23
59
  it("returns the first element in case of tie", () => {
24
- expect(findClosestAbs([4, 8], 6)).toBe(4)
60
+ expect(findSmallestDiff([4, 8], 6)).toBe(4)
25
61
  })
26
62
 
27
63
  it("returns undefined for empty array", () => {
28
- expect(findClosestAbs([], 10)).toBeUndefined()
64
+ expect(findSmallestDiff([], 10)).toBeUndefined()
29
65
  })
30
66
 
31
67
  it("supports key as function", () => {
32
68
  const arr = [{ v: 2 }, { v: 8 }]
33
- expect(findClosestAbs(arr, 5, { key: (e) => e.v })).toEqual({ v: 2 })
69
+ expect(findSmallestDiff(arr, 5, { key: (e) => e.v })).toEqual({ v: 2 })
34
70
  })
35
71
 
36
72
  it("supports key as string", () => {
37
73
  const arr = [{ x: 1 }, { x: 10 }]
38
- expect(findClosestAbs(arr, 8, { key: "x" })).toEqual({ x: 10 })
74
+ expect(findSmallestDiff(arr, 8, { key: "x" })).toEqual({ x: 10 })
39
75
  })
40
76
 
41
77
  it("supports key as number", () => {
42
78
  const arr = [[2], [8]]
43
- expect(findClosestAbs(arr, 7, { key: 0 })).toEqual([8])
79
+ expect(findSmallestDiff(arr, 7, { key: 0 })).toEqual([8])
44
80
  })
45
81
 
46
82
  it("respects cutoff", () => {
47
- expect(findClosestAbs([1, 5, 9], 6, { cutoff: 2 })).toBe(5)
48
- expect(findClosestAbs([1, 5, 9], 6, { cutoff: 1 })).toBe(5)
49
- expect(findClosestAbs([1, 5, 9], 6, { cutoff: 0 })).toBeUndefined()
83
+ expect(findSmallestDiff([1, 5, 9], 6, { cutoff: 2 })).toBe(5)
84
+ expect(findSmallestDiff([1, 5, 9], 6, { cutoff: 1 })).toBe(5)
85
+ expect(findSmallestDiff([1, 5, 9], 6, { cutoff: 0 })).toBeUndefined()
50
86
  })
51
87
  })
52
88
 
@@ -200,7 +236,7 @@ describe("findClosestGTE", () => {
200
236
  })
201
237
 
202
238
  describe("findClosest", () => {
203
- it("defaults to abs comparator", () => {
239
+ it("defaults to diff comparator", () => {
204
240
  expect(findClosest([1, 5, 9], 6)).toBe(5)
205
241
  })
206
242
 
@@ -209,7 +245,9 @@ describe("findClosest", () => {
209
245
  expect(findClosest([1, 5, 9], 6, { comparator: "lte" })).toBe(5)
210
246
  expect(findClosest([1, 5, 9], 6, { comparator: "gt" })).toBe(9)
211
247
  expect(findClosest([1, 5, 9], 6, { comparator: "gte" })).toBe(9)
212
- expect(findClosest([1, 5, 9], 6, { comparator: "abs" })).toBe(5)
248
+ expect(findClosest([1, 5, 9], 6, { comparator: "diff" })).toBe(5)
249
+ expect(findClosest([1, 5, 9], 6, { comparator: "eq" })).toBeUndefined()
250
+ expect(findClosest([1, 5, 9], 5, { comparator: "eq" })).toBe(5)
213
251
  })
214
252
 
215
253
  it("throws on unknown comparator", () => {
@@ -220,7 +258,8 @@ describe("findClosest", () => {
220
258
 
221
259
  it("passes options to underlying function", () => {
222
260
  const arr = [{ x: 1 }, { x: 10 }]
223
- expect(findClosest(arr, 8, { comparator: "abs", key: "x" })).toEqual({ x: 10 })
261
+ expect(findClosest(arr, 8, { comparator: "diff", key: "x" })).toEqual({ x: 10 })
262
+ expect(findClosest(arr, 10, { comparator: "eq", key: "x" })).toBe(10)
224
263
  })
225
264
  })
226
265
 
package/src/math.js CHANGED
@@ -148,5 +148,5 @@ export function range(start, end, increment = 1) {
148
148
  * @returns {boolean}
149
149
  */
150
150
  export function isNumber(number) {
151
- return typeof number === "number" && !isNaN(number)
151
+ return Number.isFinite(number)
152
152
  }
package/src/math.test.js CHANGED
@@ -311,9 +311,9 @@ describe("isNumber", () => {
311
311
  expect(isNumber(Number.MIN_SAFE_INTEGER)).toBe(true)
312
312
  })
313
313
 
314
- it("returns true for Infinity and -Infinity", () => {
315
- expect(isNumber(Infinity)).toBe(true)
316
- expect(isNumber(-Infinity)).toBe(true)
314
+ it("returns false for Infinity and -Infinity", () => {
315
+ expect(isNumber(Infinity)).toBe(false)
316
+ expect(isNumber(-Infinity)).toBe(false)
317
317
  })
318
318
 
319
319
  it("returns false for NaN", () => {