@oscarpalmer/atoms 0.141.2 → 0.143.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.
Files changed (61) hide show
  1. package/dist/atoms.full.js +185 -72
  2. package/dist/color/misc/is.js +6 -6
  3. package/dist/function/memoize.js +1 -1
  4. package/dist/index.js +7 -6
  5. package/dist/internal/math/aggregate.js +12 -8
  6. package/dist/internal/number.js +1 -1
  7. package/dist/internal/value/partial.js +14 -0
  8. package/dist/is.js +11 -3
  9. package/dist/math.js +21 -5
  10. package/dist/promise.js +107 -36
  11. package/dist/result.js +7 -5
  12. package/dist/sized/map.js +1 -1
  13. package/dist/sized/set.js +2 -2
  14. package/dist/value/misc.js +3 -2
  15. package/dist/value/omit.js +11 -0
  16. package/dist/value/pick.js +11 -0
  17. package/package.json +5 -5
  18. package/src/color/misc/is.ts +6 -6
  19. package/src/function/debounce.ts +2 -2
  20. package/src/function/memoize.ts +1 -1
  21. package/src/function/throttle.ts +2 -2
  22. package/src/index.ts +2 -1
  23. package/src/internal/function/limiter.ts +3 -3
  24. package/src/internal/math/aggregate.ts +19 -10
  25. package/src/internal/number.ts +1 -1
  26. package/src/internal/value/partial.ts +46 -0
  27. package/src/is.ts +11 -2
  28. package/src/math.ts +67 -9
  29. package/src/models.ts +2 -2
  30. package/src/promise.ts +249 -57
  31. package/src/random.ts +2 -2
  32. package/src/result.ts +31 -11
  33. package/src/sized/map.ts +1 -1
  34. package/src/sized/set.ts +2 -2
  35. package/src/value/get-set.ts +1 -1
  36. package/src/value/merge.ts +1 -1
  37. package/src/value/misc.ts +2 -1
  38. package/src/value/omit.ts +19 -0
  39. package/src/value/pick.ts +19 -0
  40. package/types/color/misc/is.d.ts +6 -6
  41. package/types/function/debounce.d.ts +2 -2
  42. package/types/function/memoize.d.ts +1 -1
  43. package/types/function/throttle.d.ts +2 -2
  44. package/types/index.d.ts +2 -1
  45. package/types/internal/function/limiter.d.ts +2 -2
  46. package/types/internal/math/aggregate.d.ts +1 -0
  47. package/types/internal/number.d.ts +1 -1
  48. package/types/internal/value/partial.d.ts +2 -0
  49. package/types/is.d.ts +8 -2
  50. package/types/math.d.ts +20 -0
  51. package/types/models.d.ts +2 -2
  52. package/types/promise.d.ts +68 -11
  53. package/types/random.d.ts +2 -2
  54. package/types/result.d.ts +21 -6
  55. package/types/sized/map.d.ts +1 -1
  56. package/types/sized/set.d.ts +2 -2
  57. package/types/value/misc.d.ts +2 -1
  58. package/types/value/omit.d.ts +8 -0
  59. package/types/value/{partial.d.ts → pick.d.ts} +1 -1
  60. package/dist/value/partial.js +0 -17
  61. package/src/value/partial.ts +0 -39
package/dist/is.js CHANGED
@@ -3,8 +3,8 @@ import { getArray } from "./array/get.js";
3
3
  import { getString } from "./internal/string.js";
4
4
  /**
5
5
  * Is the value empty, or only containing `null` or `undefined` values?
6
- * @param value Object to check
7
- * @returns `true` if the object is considered empty, otherwise `false`
6
+ * @param value Value to check
7
+ * @returns `true` if the value is considered empty, otherwise `false`
8
8
  */
9
9
  function isEmpty(value) {
10
10
  if (value == null) return true;
@@ -15,6 +15,14 @@ function isEmpty(value) {
15
15
  return true;
16
16
  }
17
17
  /**
18
+ * Is the value not `undefined` or `null`?
19
+ * @param value Value to check
20
+ * @returns `true` if the value is not `undefined` or `null`, otherwise `false`
21
+ */
22
+ function isNonNullable(value) {
23
+ return value != null;
24
+ }
25
+ /**
18
26
  * Is the value `undefined` or `null`?
19
27
  * @param value Value to check
20
28
  * @returns `true` if the value is `undefined` or `null`, otherwise `false`
@@ -64,4 +72,4 @@ function isPrimitive(value) {
64
72
  }
65
73
  var EXPRESSION_PRIMITIVE = /^(bigint|boolean|number|string|symbol)$/;
66
74
  var EXPRESSION_WHITESPACE = /^\s*$/;
67
- export { isArrayOrPlainObject, isConstructor, isEmpty, isKey, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isPlainObject, isPrimitive, isTypedArray };
75
+ export { isArrayOrPlainObject, isConstructor, isEmpty, isKey, isNonNullable, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isPlainObject, isPrimitive, isTypedArray };
package/dist/math.js CHANGED
@@ -1,4 +1,5 @@
1
- import { aggregate, getAggregated, max } from "./internal/math/aggregate.js";
1
+ import { isNumber } from "./internal/is.js";
2
+ import { aggregate, getAggregateCallback, getAggregated, max } from "./internal/math/aggregate.js";
2
3
  function average(array, key) {
3
4
  const aggregated = aggregate("average", array, key);
4
5
  return aggregated.count > 0 ? aggregated.value / aggregated.count : NaN;
@@ -6,9 +7,8 @@ function average(array, key) {
6
7
  function count(array, key, value) {
7
8
  if (!Array.isArray(array)) return NaN;
8
9
  const { length } = array;
9
- if (key == null) return length;
10
- if (typeof key !== "string" && typeof key !== "function") return NaN;
11
- const callback = typeof key === "function" ? key : (item) => item[key];
10
+ const callback = getAggregateCallback(key);
11
+ if (callback == null) return length;
12
12
  let counted = 0;
13
13
  for (let index = 0; index < length; index += 1) {
14
14
  const item = array[index];
@@ -16,6 +16,22 @@ function count(array, key, value) {
16
16
  }
17
17
  return counted;
18
18
  }
19
+ function median(array, key) {
20
+ let length = Array.isArray(array) ? array.length : 0;
21
+ if (!Array.isArray(array) || length === 0) return NaN;
22
+ if (length === 1) return isNumber(array[0]) ? array[0] : NaN;
23
+ let values = array;
24
+ const callback = getAggregateCallback(key);
25
+ if (callback != null) values = array.map((item, index) => callback(item, index, array));
26
+ const numbers = values.filter(isNumber).sort((first, second) => first - second);
27
+ length = numbers.length;
28
+ if (length % 2 === 0) {
29
+ const first = length / 2 - 1;
30
+ const second = length / 2;
31
+ return (numbers[first] + numbers[second]) / 2;
32
+ }
33
+ return numbers[Math.floor(length / 2)];
34
+ }
19
35
  function min(array, key) {
20
36
  return getAggregated("min", array, key);
21
37
  }
@@ -34,4 +50,4 @@ function round(value, decimals) {
34
50
  function sum(array, key) {
35
51
  return getAggregated("sum", array, key);
36
52
  }
37
- export { average, count, max, min, round, sum };
53
+ export { average, count, max, median, min, round, sum };
package/dist/promise.js CHANGED
@@ -1,9 +1,35 @@
1
+ var CancelablePromise = class extends Promise {
2
+ #rejector;
3
+ constructor(executor) {
4
+ let rejector;
5
+ super((resolve, reject) => {
6
+ rejector = reject;
7
+ executor(resolve, reject);
8
+ });
9
+ this.#rejector = rejector;
10
+ }
11
+ /**
12
+ * Cancel the promise, rejecting it with an optional reason
13
+ * @param reason Optional reason for canceling the promise
14
+ */
15
+ cancel(reason) {
16
+ this.#rejector(reason);
17
+ }
18
+ };
1
19
  var PromiseTimeoutError = class extends Error {
2
20
  constructor() {
3
21
  super(MESSAGE_TIMEOUT);
4
22
  this.name = ERROR_NAME;
5
23
  }
6
24
  };
25
+ /**
26
+ * Create a cancelable promise
27
+ * @param executor Executor function for the promise
28
+ * @returns Cancelable promise
29
+ */
30
+ function cancelable(executor) {
31
+ return new CancelablePromise(executor);
32
+ }
7
33
  function delay(options) {
8
34
  const { signal, time } = getPromiseOptions(options);
9
35
  if (signal?.aborted ?? false) return Promise.reject(signal.reason);
@@ -11,25 +37,25 @@ function delay(options) {
11
37
  clearTimeout(timeout);
12
38
  rejector(signal.reason);
13
39
  }
14
- signal?.addEventListener("abort", abort, abortOptions);
40
+ signal?.addEventListener("abort", abort, ABORT_OPTIONS);
15
41
  let rejector;
16
42
  let timeout;
17
43
  return new Promise((resolve, reject) => {
18
44
  rejector = reject;
19
45
  timeout = setTimeout(() => {
20
- signal?.removeEventListener("abort", abort);
21
- resolve();
46
+ settlePromise(abort, resolve, void 0, signal);
22
47
  }, time);
23
48
  });
24
49
  }
25
- function getBooleanOrDefault(value, defaultValue) {
26
- return typeof value === "boolean" ? value : defaultValue;
27
- }
28
50
  function getNumberOrDefault(value) {
29
51
  return typeof value === "number" && value > 0 ? value : 0;
30
52
  }
31
53
  function getPromiseOptions(input) {
32
54
  if (typeof input === "number") return { time: getNumberOrDefault(input) };
55
+ if (input instanceof AbortSignal) return {
56
+ signal: input,
57
+ time: 0
58
+ };
33
59
  const options = typeof input === "object" && input !== null ? input : {};
34
60
  return {
35
61
  signal: options.signal instanceof AbortSignal ? options.signal : void 0,
@@ -37,32 +63,54 @@ function getPromiseOptions(input) {
37
63
  };
38
64
  }
39
65
  function getPromisesOptions(input) {
40
- if (typeof input === "boolean") return { eager: input };
66
+ if (typeof input === "string") return { strategy: getStrategyOrDefault(input) };
41
67
  if (input instanceof AbortSignal) return {
42
- eager: false,
43
- signal: input
68
+ signal: input,
69
+ strategy: DEFAULT_STRATEGY
44
70
  };
45
71
  const options = typeof input === "object" && input !== null ? input : {};
46
72
  return {
47
- eager: getBooleanOrDefault(options.eager, false),
48
- signal: options.signal instanceof AbortSignal ? options.signal : void 0
73
+ signal: options.signal instanceof AbortSignal ? options.signal : void 0,
74
+ strategy: getStrategyOrDefault(options.strategy)
49
75
  };
50
76
  }
77
+ function getStrategyOrDefault(value) {
78
+ return strategies.has(value) ? value : DEFAULT_STRATEGY;
79
+ }
80
+ async function getTimed(promise, time, signal) {
81
+ function abort() {
82
+ clearTimeout(timeout);
83
+ rejector(signal.reason);
84
+ }
85
+ signal?.addEventListener(EVENT_NAME, abort, ABORT_OPTIONS);
86
+ let rejector;
87
+ let timeout;
88
+ return Promise.race([promise, new Promise((_, reject) => {
89
+ rejector = reject;
90
+ timeout = setTimeout(() => {
91
+ settlePromise(abort, reject, new PromiseTimeoutError(), signal);
92
+ }, time);
93
+ })]).then((value) => {
94
+ clearTimeout(timeout);
95
+ signal?.removeEventListener(EVENT_NAME, abort);
96
+ return value;
97
+ });
98
+ }
51
99
  function handleResult(status, parameters) {
52
- const { data, eager, handlers, index, signal, value } = parameters;
100
+ const { abort, complete, data, handlers, index, signal, value } = parameters;
53
101
  if (signal?.aborted ?? false) return;
54
- if (eager && status === TYPE_REJECTED) {
55
- handlers.reject(value);
102
+ if (!complete && status === TYPE_REJECTED) {
103
+ settlePromise(abort, handlers.reject, value, signal);
56
104
  return;
57
105
  }
58
- data.result[index] = eager ? value : status === TYPE_FULFILLED ? {
106
+ data.result[index] = !complete ? value : status === TYPE_FULFILLED ? {
59
107
  status,
60
108
  value
61
109
  } : {
62
110
  status,
63
111
  reason: value
64
112
  };
65
- if (index === data.last) handlers.resolve(data.result);
113
+ if (index === data.last) settlePromise(abort, handlers.resolve, data.result, signal);
66
114
  }
67
115
  /**
68
116
  * Is the value a fulfilled promise result?
@@ -84,15 +132,17 @@ function isType(value, type) {
84
132
  return typeof value === "object" && value !== null && value.status === type;
85
133
  }
86
134
  async function promises(items, options) {
135
+ const { signal, strategy } = getPromisesOptions(options);
136
+ if (signal?.aborted ?? false) return Promise.reject(signal.reason);
137
+ if (!Array.isArray(items)) return Promise.reject(new TypeError(MESSAGE_EXPECTATION_PROMISES));
87
138
  const actual = items.filter((item) => item instanceof Promise);
88
139
  const { length } = actual;
89
- const { eager, signal } = getPromisesOptions(options);
90
- if (signal?.aborted ?? false) return Promise.reject(signal.reason);
91
140
  if (length === 0) return actual;
141
+ const complete = strategy === DEFAULT_STRATEGY;
92
142
  function abort() {
93
143
  handlers.reject(signal.reason);
94
144
  }
95
- signal?.addEventListener("abort", abort, abortOptions);
145
+ signal?.addEventListener("abort", abort, ABORT_OPTIONS);
96
146
  const data = {
97
147
  last: length - 1,
98
148
  result: []
@@ -104,15 +154,17 @@ async function promises(items, options) {
104
154
  resolve
105
155
  };
106
156
  for (let index = 0; index < length; index += 1) actual[index].then((value) => handleResult(TYPE_FULFILLED, {
157
+ abort,
158
+ complete,
107
159
  data,
108
- eager,
109
160
  handlers,
110
161
  index,
111
162
  signal,
112
163
  value
113
164
  })).catch((reason) => handleResult(TYPE_REJECTED, {
165
+ abort,
166
+ complete,
114
167
  data,
115
- eager,
116
168
  handlers,
117
169
  index,
118
170
  signal,
@@ -120,31 +172,50 @@ async function promises(items, options) {
120
172
  }));
121
173
  });
122
174
  }
123
- function timed(promise, options) {
124
- if (!(promise instanceof Promise)) throw new TypeError(MESSAGE_EXPECTATION);
175
+ function settlePromise(aborter, settler, value, signal) {
176
+ signal?.removeEventListener(EVENT_NAME, aborter);
177
+ settler(value);
178
+ }
179
+ async function timed(promise, options) {
180
+ if (!(promise instanceof Promise)) return Promise.reject(new TypeError(MESSAGE_EXPECTATION_TIMED));
181
+ const { signal, time } = getPromiseOptions(options);
182
+ if (signal?.aborted ?? false) return Promise.reject(signal.reason);
183
+ return time > 0 ? getTimed(promise, time, signal) : promise;
184
+ }
185
+ async function attemptPromise(value, options) {
186
+ const isFunction = typeof value === "function";
187
+ if (!isFunction && !(value instanceof Promise)) return Promise.reject(new TypeError(MESSAGE_EXPECTATION_ATTEMPT));
125
188
  const { signal, time } = getPromiseOptions(options);
126
189
  if (signal?.aborted ?? false) return Promise.reject(signal.reason);
127
- if (time <= 0) return promise;
128
190
  function abort() {
129
- clearTimeout(timeout);
130
191
  rejector(signal.reason);
131
192
  }
132
- signal?.addEventListener(EVENT_NAME, abort, abortOptions);
193
+ async function handler(resolve, reject) {
194
+ try {
195
+ let result = isFunction ? value() : await value;
196
+ if (result instanceof Promise) result = await result;
197
+ settlePromise(abort, resolve, result, signal);
198
+ } catch (error) {
199
+ settlePromise(abort, reject, error, signal);
200
+ }
201
+ }
133
202
  let rejector;
134
- let timeout;
135
- return Promise.race([promise, new Promise((_, reject) => {
203
+ signal?.addEventListener(EVENT_NAME, abort, ABORT_OPTIONS);
204
+ const promise = new Promise((resolve, reject) => {
136
205
  rejector = reject;
137
- timeout = setTimeout(() => {
138
- signal?.removeEventListener(EVENT_NAME, abort);
139
- reject(new PromiseTimeoutError());
140
- }, time);
141
- })]);
206
+ handler(resolve, reject);
207
+ });
208
+ return time > 0 ? getTimed(promise, time, signal) : promise;
142
209
  }
143
- var abortOptions = { once: true };
210
+ var ABORT_OPTIONS = { once: true };
211
+ var DEFAULT_STRATEGY = "complete";
144
212
  var ERROR_NAME = "PromiseTimeoutError";
145
213
  var EVENT_NAME = "abort";
146
- var MESSAGE_EXPECTATION = "Timed function expected a Promise";
214
+ var MESSAGE_EXPECTATION_ATTEMPT = "Attempt expected a function or a promise";
215
+ var MESSAGE_EXPECTATION_PROMISES = "Promises expected an array of promises";
216
+ var MESSAGE_EXPECTATION_TIMED = "Timed function expected a Promise";
147
217
  var MESSAGE_TIMEOUT = "Promise timed out";
218
+ var strategies = new Set(["complete", "first"]);
148
219
  var TYPE_FULFILLED = "fulfilled";
149
220
  var TYPE_REJECTED = "rejected";
150
- export { PromiseTimeoutError, delay, isFulfilled, isRejected, promises, timed };
221
+ export { CancelablePromise, PromiseTimeoutError, attemptPromise, cancelable, delay, isFulfilled, isRejected, promises, timed };
package/dist/result.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { isPlainObject } from "./internal/is.js";
2
+ import { attemptPromise } from "./promise.js";
2
3
  function _isResult(value, okValue) {
3
4
  if (!isPlainObject(value)) return false;
4
5
  return value.ok === okValue && (okValue ? "value" : "error") in value;
@@ -44,17 +45,18 @@ function ok(value) {
44
45
  value
45
46
  };
46
47
  }
47
- function result(callback, err) {
48
+ function attempt(callback, err) {
48
49
  try {
49
50
  return ok(callback());
50
51
  } catch (thrown) {
51
52
  return getError(err ?? thrown, err == null ? void 0 : thrown);
52
53
  }
53
54
  }
54
- result.async = asyncResult;
55
- async function asyncResult(callback, err) {
55
+ attempt.async = asyncAttempt;
56
+ attempt.promise = attemptPromise;
57
+ async function asyncAttempt(value, err) {
56
58
  try {
57
- return ok(await callback());
59
+ return ok(await (typeof value === "function" ? value() : value));
58
60
  } catch (thrown) {
59
61
  return getError(err ?? thrown, err == null ? void 0 : thrown);
60
62
  }
@@ -62,4 +64,4 @@ async function asyncResult(callback, err) {
62
64
  function unwrap(value, defaultValue) {
63
65
  return isOk(value) ? value.value : defaultValue;
64
66
  }
65
- export { error, isError, isOk, isResult, ok, result, unwrap };
67
+ export { attempt, error, isError, isOk, isResult, ok, unwrap };
package/dist/sized/map.js CHANGED
@@ -2,7 +2,7 @@ import { getSizedMaximum } from "../internal/sized.js";
2
2
  /**
3
3
  * A Map with a maximum size
4
4
  *
5
- * Behaviour is similar to a _LRU_-cache, where the least recently used entries are removed
5
+ * Behavior is similar to a _LRU_-cache, where the least recently used entries are removed
6
6
  */
7
7
  var SizedMap = class extends Map {
8
8
  /**
package/dist/sized/set.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { getSizedMaximum } from "../internal/sized.js";
2
2
  /**
3
3
  * - A Set with a maximum size
4
- * - Behaviour is similar to a _LRU_-cache, where the oldest values are removed
4
+ * - Behavior is similar to a _LRU_-cache, where the oldest values are removed
5
5
  */
6
6
  var SizedSet = class extends Set {
7
7
  /**
@@ -39,7 +39,7 @@ var SizedSet = class extends Set {
39
39
  * Get a value from the SizedSet, if it exists _(and move it to the end)_
40
40
  * @param value Value to get from the SizedSet
41
41
  * @param update Update the value's position in the SizedSet? _(defaults to `false`)_
42
- * @returns The value if it exists, otherwise `undefined`
42
+ * @returns Found value if it exists, otherwise `undefined`
43
43
  */
44
44
  get(value, update) {
45
45
  if (this.has(value)) {
@@ -1,4 +1,5 @@
1
- import { partial } from "./partial.js";
1
+ import { omit } from "./omit.js";
2
+ import { pick } from "./pick.js";
2
3
  import { smush } from "./smush.js";
3
4
  import { unsmush } from "./unsmush.js";
4
- export { partial, smush, unsmush };
5
+ export { omit, pick, smush, unsmush };
@@ -0,0 +1,11 @@
1
+ import { partial } from "../internal/value/partial.js";
2
+ /**
3
+ * Create a new object without the specified keys
4
+ * @param value Original object
5
+ * @param keys Keys to omit
6
+ * @returns Partial object without the specified keys
7
+ */
8
+ function omit(value, keys) {
9
+ return partial(value, keys, true);
10
+ }
11
+ export { omit };
@@ -0,0 +1,11 @@
1
+ import { partial } from "../internal/value/partial.js";
2
+ /**
3
+ * Create a new object with only the specified keys
4
+ * @param value Original object
5
+ * @param keys Keys to use
6
+ * @returns Partial object with only the specified keys
7
+ */
8
+ function pick(value, keys) {
9
+ return partial(value, keys, false);
10
+ }
11
+ export { pick };
package/package.json CHANGED
@@ -8,12 +8,12 @@
8
8
  "@types/node": "^25.3",
9
9
  "@vitest/coverage-istanbul": "^4",
10
10
  "jsdom": "^28.1",
11
- "oxfmt": "^0.34",
12
- "oxlint": "^1.49",
13
- "rolldown": "1.0.0-rc.5",
11
+ "oxfmt": "^0.35",
12
+ "oxlint": "^1.50",
13
+ "rolldown": "1.0.0-rc.6",
14
14
  "tslib": "^2.8",
15
15
  "typescript": "^5.9",
16
- "vite": "8.0.0-beta.15",
16
+ "vite": "8.0.0-beta.16",
17
17
  "vitest": "^4"
18
18
  },
19
19
  "exports": {
@@ -236,5 +236,5 @@
236
236
  },
237
237
  "type": "module",
238
238
  "types": "./types/index.d.ts",
239
- "version": "0.141.2"
239
+ "version": "0.143.0"
240
240
  }
@@ -34,7 +34,7 @@ function isBytey(value: unknown): value is number {
34
34
 
35
35
  /**
36
36
  * Is the value a Color?
37
- * @param value The value to check
37
+ * @param value Value to check
38
38
  * @returns `true` if the value is a Color, otherwise `false`
39
39
  */
40
40
  export function isColor(value: unknown): value is Color {
@@ -75,7 +75,7 @@ function isDegree(value: unknown): value is number {
75
75
 
76
76
  /**
77
77
  * Is the value a hex color?
78
- * @param value The value to check
78
+ * @param value Value to check
79
79
  * @param alpha Allow alpha channel? _(defaults to `true`)_
80
80
  * @returns `true` if the value is a hex color, otherwise `false`
81
81
  */
@@ -97,7 +97,7 @@ export function isHexColor(value: unknown, alpha?: boolean): value is string {
97
97
 
98
98
  /**
99
99
  * Is the value an HSLA color?
100
- * @param value The value to check
100
+ * @param value Value to check
101
101
  * @returns `true` if the value is an HSLA color, otherwise `false`
102
102
  */
103
103
  export function isHslaColor(value: unknown): value is HSLAColor {
@@ -106,7 +106,7 @@ export function isHslaColor(value: unknown): value is HSLAColor {
106
106
 
107
107
  /**
108
108
  * Is the value an HSL color?
109
- * @param value The value to check
109
+ * @param value Value to check
110
110
  * @returns `true` if the value is an HSL color, otherwise `false`
111
111
  */
112
112
  export function isHslColor(value: unknown): value is HSLColor {
@@ -119,7 +119,7 @@ export function isHslLike(value: unknown): value is Record<keyof HSLColor, unkno
119
119
 
120
120
  /**
121
121
  * Is the value an RGBA color?
122
- * @param value The value to check
122
+ * @param value Value to check
123
123
  * @returns `true` if the value is an RGBA color, otherwise `false`
124
124
  */
125
125
  export function isRgbaColor(value: unknown): value is RGBAColor {
@@ -128,7 +128,7 @@ export function isRgbaColor(value: unknown): value is RGBAColor {
128
128
 
129
129
  /**
130
130
  * Is the value an RGB color?
131
- * @param value The value to check
131
+ * @param value Value to check
132
132
  * @returns `true` if the value is an RGB color, otherwise `false`
133
133
  */
134
134
  export function isRgbColor(value: unknown): value is RGBColor {
@@ -1,5 +1,5 @@
1
1
  import {getLimiter} from '../internal/function/limiter';
2
- import type {CancellableCallback, GenericCallback} from '../models';
2
+ import type {CancelableCallback, GenericCallback} from '../models';
3
3
 
4
4
  // #region Functions
5
5
 
@@ -14,7 +14,7 @@ import type {CancellableCallback, GenericCallback} from '../models';
14
14
  export function debounce<Callback extends GenericCallback>(
15
15
  callback: Callback,
16
16
  time?: number,
17
- ): CancellableCallback<Callback> {
17
+ ): CancelableCallback<Callback> {
18
18
  return getLimiter(callback, false, time);
19
19
  }
20
20
 
@@ -73,7 +73,7 @@ class Memoized<Callback extends GenericCallback> {
73
73
  /**
74
74
  * Get a result from the cache
75
75
  * @param key Key to get
76
- * @returns The cached result or `undefined` if it does not exist
76
+ * @returns Cached result or `undefined` if it does not exist
77
77
  */
78
78
  get(key: unknown): ReturnType<Callback> | undefined {
79
79
  return this.#state.cache?.get(key);
@@ -1,5 +1,5 @@
1
1
  import {getLimiter} from '../internal/function/limiter';
2
- import type {CancellableCallback, GenericCallback} from '../models';
2
+ import type {CancelableCallback, GenericCallback} from '../models';
3
3
 
4
4
  // #region Functions
5
5
 
@@ -12,7 +12,7 @@ import type {CancellableCallback, GenericCallback} from '../models';
12
12
  export function throttle<Callback extends GenericCallback>(
13
13
  callback: Callback,
14
14
  time?: number,
15
- ): CancellableCallback<Callback> {
15
+ ): CancelableCallback<Callback> {
16
16
  return getLimiter(callback, true, time);
17
17
  }
18
18
 
package/src/index.ts CHANGED
@@ -38,7 +38,8 @@ export * from './string/template';
38
38
  export * from './value/clone';
39
39
  export * from './value/diff';
40
40
  export * from './value/merge';
41
- export * from './value/partial';
41
+ export * from './value/omit';
42
+ export * from './value/pick';
42
43
  export * from './value/smush';
43
44
  export * from './value/unsmush';
44
45
 
@@ -1,4 +1,4 @@
1
- import type {CancellableCallback} from '../../models';
1
+ import type {CancelableCallback} from '../../models';
2
2
  import type {GenericCallback} from '../../models';
3
3
  import FRAME_RATE_MS from '../frame-rate';
4
4
 
@@ -8,7 +8,7 @@ export function getLimiter<Callback extends GenericCallback>(
8
8
  callback: Callback,
9
9
  throttler: boolean,
10
10
  time?: number,
11
- ): CancellableCallback<Callback> {
11
+ ): CancelableCallback<Callback> {
12
12
  const interval = typeof time === 'number' && time >= FRAME_RATE_MS ? time : FRAME_RATE_MS;
13
13
 
14
14
  function step(now: DOMHighResTimeStamp, parameters: Parameters<Callback>): void {
@@ -46,7 +46,7 @@ export function getLimiter<Callback extends GenericCallback>(
46
46
  }
47
47
  };
48
48
 
49
- return limiter as CancellableCallback<Callback>;
49
+ return limiter as CancelableCallback<Callback>;
50
50
  }
51
51
 
52
52
  // #endregion
@@ -1,4 +1,5 @@
1
- import type {GenericCallback, NumericalValues, PlainObject} from '../../models';
1
+ import type {NumericalValues, PlainObject} from '../../models';
2
+ import {isNumber} from '../is';
2
3
 
3
4
  // #region Types
4
5
 
@@ -26,7 +27,7 @@ export function aggregate(type: AggregationType, array: unknown[], key: unknown)
26
27
  }
27
28
 
28
29
  const aggregator = aggregators[type];
29
- const isCallback = typeof key === 'function';
30
+ const callback = getAggregateCallback(key);
30
31
 
31
32
  let counted = 0;
32
33
  let aggregated = Number.NaN;
@@ -35,16 +36,16 @@ export function aggregate(type: AggregationType, array: unknown[], key: unknown)
35
36
  for (let index = 0; index < length; index += 1) {
36
37
  const item = array[index];
37
38
 
38
- const value = isCallback
39
- ? (key as GenericCallback)(item, index, array)
40
- : ((item as PlainObject)[key as never] ?? item);
39
+ const value = callback == null ? item : callback(item as never, index, array);
41
40
 
42
- if (typeof value === 'number' && !Number.isNaN(value)) {
43
- aggregated = aggregator(aggregated, value, notNumber);
44
-
45
- counted += 1;
46
- notNumber = false;
41
+ if (!isNumber(value)) {
42
+ continue;
47
43
  }
44
+
45
+ aggregated = aggregator(aggregated, value, notNumber);
46
+
47
+ counted += 1;
48
+ notNumber = false;
48
49
  }
49
50
 
50
51
  return {
@@ -53,6 +54,14 @@ export function aggregate(type: AggregationType, array: unknown[], key: unknown)
53
54
  };
54
55
  }
55
56
 
57
+ export function getAggregateCallback(key: unknown): Function | undefined {
58
+ if (key == null) {
59
+ return;
60
+ }
61
+
62
+ return typeof key === 'function' ? key : (item: PlainObject): unknown => item[key as never];
63
+ }
64
+
56
65
  /**
57
66
  * Get the maximum value from a list of items
58
67
  * @param items List of items
@@ -49,7 +49,7 @@ export function clamp(value: number, minimum: number, maximum: number, loop?: bo
49
49
  /**
50
50
  * Get the number value from an unknown value _(based on Lodash)_
51
51
  * @param value Original value
52
- * @returns The value as a number, or `NaN` if the value is unable to be parsed
52
+ * @returns Original value as a number, or `NaN` if the value is unable to be parsed
53
53
  */
54
54
  export function getNumber(value: unknown): number {
55
55
  if (typeof value === 'number') {