@valkyriestudios/utils 12.42.0 → 12.43.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.
package/README.md CHANGED
@@ -239,7 +239,7 @@ const group = groupBy([
239
239
  **Take note**: any object without the key will be added to a fallback group called '_'
240
240
 
241
241
 
242
- ### array/dedupe(val:Array, opts?:{filter_fn})
242
+ ### array/dedupe(val:Array, opts?:{key:string; filter_fn})
243
243
  Remove all duplicates from an array, behind the scenes it uses the fnv 1A hash algorithm to performantly do comparisons.
244
244
  ```typescript
245
245
  import dedupe from '@valkyriestudios/utils/array/dedupe';
@@ -251,6 +251,22 @@ dedupe(['hello', 'hello', 'world']); // ['hello', 'world']
251
251
  dedupe(['hello', 'hello', 'world', false, 'world'], {filter_fn: el => isNotEmptyString(el)}); // ['hello', 'world']
252
252
  ```
253
253
 
254
+ Also supports deduping according to a specific `key`:
255
+ ```typescript
256
+ import dedupe from '@valkyriestudios/utils/array/dedupe';
257
+
258
+ const users = [
259
+ { id: 1, name: 'Alice' },
260
+ { id: 2, name: 'Bob' },
261
+ { id: 1, name: 'Alicia' }, // duplicate id
262
+ ];
263
+
264
+ // Deduplicate by `id`
265
+ const uniqueUsers = dedupe(users, { key: 'id' });
266
+ console.log(uniqueUsers);
267
+ // => [ { id: 1, name: "Alice" }, { id: 2, name: "Bob" } ]
268
+ ```
269
+
254
270
  Take Note: The filtering is applied while deduping, ensuring O(n) performance, as such this is faster than dedupe(arr.filter(...))
255
271
 
256
272
  ### array/join(val:Array, opts:object={delim:' ',trim:true,valtrim:true,innertrim:true,valround:false,dedupe:false})
@@ -978,15 +994,18 @@ import guid from '@valkyriestudios/utils/hash/guid';
978
994
  guid(); // 245caf1a-86af-11e7-bb31-be2e44b06b34
979
995
  ```
980
996
 
997
+ ### hash/djb2(val:unknown)
998
+ Generate a djb2 hash from an object/array/primitive/...
999
+ ```typescript
1000
+ import djb2 from '@valkyriestudios/utils/hash/djb2';
1001
+ djb2('hello world');
1002
+ ```
1003
+
981
1004
  ### hash/fnv1A(val:unknown)
982
- Generate a fnv1A hash from an object, using a 32-bit prime/offset
1005
+ Generate a fnv1A hash from an object/array/primitive/...
983
1006
  ```typescript
984
1007
  import fnv1A from '@valkyriestudios/utils/hash/fnv1A';
985
- fnv1A('hello world'); // -2023343616
986
- fnv1A({a:1,b:2}); // 361168128
987
- fnv1A(4); // 1630425728
988
- fnv1A(new RegExp(/ab+c/, 'i')); // 2131692544
989
- fnv1A(new Date('2012-02-02')); // 1655579136
1008
+ fnv1A('hello world');
990
1009
  ```
991
1010
 
992
1011
  ### Is
package/array/dedupe.d.ts CHANGED
@@ -1,14 +1,16 @@
1
- type DedupeOptions<T> = {
1
+ type DedupeOptionsBase<T> = {
2
2
  /**
3
3
  * Pass a custom filter function which will be run in O(n) while deduping is going on
4
4
  */
5
5
  filter_fn?: (el: T) => boolean;
6
6
  };
7
- /**
8
- * Dedupes the provided array
9
- *
10
- * @param {Array} val - Array to dedupe
11
- * @param {DedupeOptions?} opts - Dedupe options
12
- */
13
- declare function dedupe<T>(val: T[], opts?: DedupeOptions<T>): T[];
7
+ type DedupeOptionsWithKey<T extends Record<string, unknown>> = DedupeOptionsBase<T> & {
8
+ /**
9
+ * Deduplicate based on a single property key of T
10
+ */
11
+ key: keyof T;
12
+ };
13
+ type DedupeOptionsNoKey<T> = DedupeOptionsBase<T>;
14
+ declare function dedupe<T extends Record<string, unknown>>(val: T[], opts: DedupeOptionsWithKey<T>): T[];
15
+ declare function dedupe<T>(val: T[], opts?: DedupeOptionsNoKey<T>): T[];
14
16
  export { dedupe, dedupe as default };
package/array/is.d.ts CHANGED
@@ -3,5 +3,5 @@
3
3
  *
4
4
  * @param {unknown} val - Value to verify
5
5
  */
6
- declare function isArray(val: unknown): val is unknown[];
6
+ declare function isArray<T = unknown>(val: unknown): val is T[];
7
7
  export { isArray, isArray as default };
@@ -3,5 +3,5 @@
3
3
  *
4
4
  * @param {unknown} val - Value to verify
5
5
  */
6
- declare function isNotEmptyArray(val: unknown): val is unknown[];
6
+ declare function isNotEmptyArray<T = unknown>(val: unknown): val is T[];
7
7
  export { isNotEmptyArray, isNotEmptyArray as default };
@@ -2,7 +2,7 @@
2
2
  * Turn a function into a memoized function. An optional resolver function can be passed which allows custom cache key generation.
3
3
  *
4
4
  * Example:
5
- * const memoized_function = memoize((a) => fnv1A(a));
5
+ * const memoized_function = memoize((a) => djb2(a));
6
6
  *
7
7
  * @param fn - Function to memoize
8
8
  * @param resolver - Optional resolver function to generate cache key. If not passed the first argument is used as map key
@@ -2,53 +2,41 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.dedupe = dedupe;
4
4
  exports.default = dedupe;
5
- const REPL_NAN = 'nan';
6
- const REPL_TRUE = 'true';
7
- const REPL_FALSE = 'false';
8
- const REPL_UNDEF = 'undefined';
9
- const REPL_NULL = 'null';
10
- function getTypeString(el) {
11
- switch (typeof el) {
12
- case 'string':
13
- return el;
14
- case 'number':
15
- return Number.isNaN(el) || !Number.isFinite(el) ? REPL_NAN : String(el);
16
- case 'boolean':
17
- return el ? REPL_TRUE : REPL_FALSE;
18
- case 'undefined':
19
- return REPL_UNDEF;
20
- case 'object':
21
- if (el === null) {
22
- return REPL_NULL;
23
- }
24
- else if (Array.isArray(el) || el.toString() === '[object Object]') {
25
- return JSON.stringify(el);
26
- }
27
- else if (el instanceof RegExp) {
28
- return el.toString();
29
- }
30
- else if (el instanceof Date) {
31
- return String(el.getTime());
32
- }
33
- }
34
- return '';
35
- }
5
+ const utils_1 = require("../hash/utils");
36
6
  function dedupe(val, opts) {
37
7
  if (!Array.isArray(val))
38
8
  return [];
39
9
  const FILTER_FN = opts?.filter_fn;
10
+ const KEY = opts?.key;
40
11
  const set = new Set();
41
12
  const acc = [];
42
13
  let hash;
43
14
  const len = val.length;
44
- for (let i = 0; i < len; i++) {
45
- const el = val[i];
46
- if (FILTER_FN && !FILTER_FN(el))
47
- continue;
48
- hash = getTypeString(el);
49
- if (!set.has(hash)) {
50
- set.add(hash);
51
- acc.push(el);
15
+ if (KEY) {
16
+ const CUSTOM_FILTER_FN = typeof FILTER_FN === 'function'
17
+ ? (el) => el && Object.prototype.toString.call(el) === '[object Object]' && FILTER_FN(el)
18
+ : (el) => el && Object.prototype.toString.call(el) === '[object Object]';
19
+ for (let i = 0; i < len; i++) {
20
+ const el = val[i];
21
+ if (!CUSTOM_FILTER_FN(el))
22
+ continue;
23
+ hash = (0, utils_1.toString)(el[KEY]);
24
+ if (!set.has(hash)) {
25
+ set.add(hash);
26
+ acc.push(el);
27
+ }
28
+ }
29
+ }
30
+ else {
31
+ for (let i = 0; i < len; i++) {
32
+ const el = val[i];
33
+ if (FILTER_FN && !FILTER_FN(el))
34
+ continue;
35
+ hash = (0, utils_1.toString)(el);
36
+ if (!set.has(hash)) {
37
+ set.add(hash);
38
+ acc.push(el);
39
+ }
52
40
  }
53
41
  }
54
42
  return acc;
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.memoize = memoize;
7
7
  exports.default = memoize;
8
8
  const isAsync_1 = __importDefault(require("../function/isAsync"));
9
- const fnv1A_1 = __importDefault(require("../hash/fnv1A"));
9
+ const djb2_1 = __importDefault(require("../hash/djb2"));
10
10
  const isIntegerAbove_1 = __importDefault(require("../number/isIntegerAbove"));
11
11
  const LRU_1 = __importDefault(require("./LRU"));
12
12
  function memoize(fn, resolver, cache_duration_ms = false, cache_max_size = 100) {
@@ -16,7 +16,7 @@ function memoize(fn, resolver, cache_duration_ms = false, cache_max_size = 100)
16
16
  const memoized = (0, isAsync_1.default)(fn)
17
17
  ? async function (...args) {
18
18
  let key = isResolverFn ? resolver(...args) : args[0];
19
- key = typeof key === 'string' ? key : Number.isFinite(key) ? String(key) : String((0, fnv1A_1.default)(key));
19
+ key = typeof key === 'string' ? key : Number.isFinite(key) ? String(key) : (0, djb2_1.default)(key);
20
20
  const cached_val = cache.get(key);
21
21
  const now = Date.now();
22
22
  if (cached_val !== undefined && (cache_duration === false || (now - cached_val.ts) < cache_duration)) {
@@ -28,7 +28,7 @@ function memoize(fn, resolver, cache_duration_ms = false, cache_max_size = 100)
28
28
  }
29
29
  : function (...args) {
30
30
  let key = isResolverFn ? resolver(...args) : args[0];
31
- key = typeof key === 'string' ? key : Number.isFinite(key) ? String(key) : String((0, fnv1A_1.default)(key));
31
+ key = typeof key === 'string' ? key : Number.isFinite(key) ? String(key) : (0, djb2_1.default)(key);
32
32
  const cached_val = cache.get(key);
33
33
  const now = Date.now();
34
34
  if (cached_val !== undefined && (cache_duration === false || (now - cached_val.ts) < cache_duration)) {
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.djb2 = djb2;
4
+ exports.default = djb2;
5
+ const utils_1 = require("./utils");
6
+ function djb2(data) {
7
+ let hash = 5381;
8
+ const normalized = (0, utils_1.toString)(data);
9
+ const len = normalized.length;
10
+ for (let i = 0; i < len; i++) {
11
+ hash = ((hash << 5) + hash) ^ normalized.charCodeAt(i);
12
+ }
13
+ return String(hash >>> 0);
14
+ }
package/cjs/hash/fnv1A.js CHANGED
@@ -3,52 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FNV_64 = exports.FNV_32 = void 0;
4
4
  exports.fnv1A = fnv1A;
5
5
  exports.default = fnv1A;
6
+ const utils_1 = require("./utils");
6
7
  exports.FNV_32 = 2166136261;
7
- exports.FNV_64 = 1099511628211;
8
- const REPL_NAN = 'nan';
9
- const REPL_TRUE = 'true';
10
- const REPL_FALSE = 'false';
11
- const REPL_UNDEF = 'undefined';
12
- const REPL_NULL = 'null';
8
+ exports.FNV_64 = 1099511628211n;
13
9
  function fnv1A(data, offset = exports.FNV_32) {
14
10
  let hash = offset;
15
- let sanitized;
16
- switch (typeof data) {
17
- case 'string':
18
- sanitized = data;
19
- break;
20
- case 'number':
21
- sanitized = Number.isNaN(data) || !Number.isFinite(data) ? REPL_NAN : String(data);
22
- break;
23
- case 'boolean':
24
- sanitized = data ? REPL_TRUE : REPL_FALSE;
25
- break;
26
- case 'undefined':
27
- sanitized = REPL_UNDEF;
28
- break;
29
- case 'object':
30
- if (data === null) {
31
- sanitized = REPL_NULL;
32
- }
33
- else if (Array.isArray(data) || Object.prototype.toString.call(data) === '[object Object]') {
34
- sanitized = JSON.stringify(data);
35
- }
36
- else if (data instanceof RegExp) {
37
- sanitized = String(data);
38
- }
39
- else if (data instanceof Date) {
40
- sanitized = String(data.getTime());
41
- }
42
- else {
43
- throw new TypeError('An FNV1A Hash could not be calculated for this datatype');
44
- }
45
- break;
46
- default:
47
- throw new TypeError('An FNV1A Hash could not be calculated for this datatype');
48
- }
49
- const len = sanitized.length;
11
+ const normalized = (0, utils_1.toString)(data);
12
+ const len = normalized.length;
50
13
  for (let i = 0; i < len; i++) {
51
- hash ^= sanitized.charCodeAt(i);
14
+ hash ^= normalized.charCodeAt(i);
52
15
  hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
53
16
  }
54
17
  return hash >>> 0;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toString = toString;
4
+ function toString(raw) {
5
+ switch (typeof raw) {
6
+ case 'string':
7
+ return raw;
8
+ case 'number':
9
+ return Number.isFinite(raw) ? String(raw) : 'nan';
10
+ case 'bigint':
11
+ return raw.toString();
12
+ case 'boolean':
13
+ return raw ? 'true' : 'false';
14
+ case 'undefined':
15
+ return 'undefined';
16
+ case 'object':
17
+ if (raw === null) {
18
+ return 'null';
19
+ }
20
+ else if (Array.isArray(raw) || Object.prototype.toString.call(raw) === '[object Object]') {
21
+ return JSON.stringify(raw);
22
+ }
23
+ else if (raw instanceof RegExp) {
24
+ return String(raw);
25
+ }
26
+ else if (raw instanceof Date) {
27
+ return String(raw.getTime());
28
+ }
29
+ else if (raw instanceof Error) {
30
+ return raw.name + '|' + raw.message;
31
+ }
32
+ else {
33
+ throw new TypeError('A Hash could not be calculated for this datatype');
34
+ }
35
+ case 'symbol':
36
+ return String(raw);
37
+ default:
38
+ throw new TypeError('A Hash could not be calculated for this datatype');
39
+ }
40
+ }
@@ -1,50 +1,38 @@
1
- const REPL_NAN = 'nan';
2
- const REPL_TRUE = 'true';
3
- const REPL_FALSE = 'false';
4
- const REPL_UNDEF = 'undefined';
5
- const REPL_NULL = 'null';
6
- function getTypeString(el) {
7
- switch (typeof el) {
8
- case 'string':
9
- return el;
10
- case 'number':
11
- return Number.isNaN(el) || !Number.isFinite(el) ? REPL_NAN : String(el);
12
- case 'boolean':
13
- return el ? REPL_TRUE : REPL_FALSE;
14
- case 'undefined':
15
- return REPL_UNDEF;
16
- case 'object':
17
- if (el === null) {
18
- return REPL_NULL;
19
- }
20
- else if (Array.isArray(el) || el.toString() === '[object Object]') {
21
- return JSON.stringify(el);
22
- }
23
- else if (el instanceof RegExp) {
24
- return el.toString();
25
- }
26
- else if (el instanceof Date) {
27
- return String(el.getTime());
28
- }
29
- }
30
- return '';
31
- }
1
+ import { toString } from '../hash/utils';
32
2
  function dedupe(val, opts) {
33
3
  if (!Array.isArray(val))
34
4
  return [];
35
5
  const FILTER_FN = opts?.filter_fn;
6
+ const KEY = opts?.key;
36
7
  const set = new Set();
37
8
  const acc = [];
38
9
  let hash;
39
10
  const len = val.length;
40
- for (let i = 0; i < len; i++) {
41
- const el = val[i];
42
- if (FILTER_FN && !FILTER_FN(el))
43
- continue;
44
- hash = getTypeString(el);
45
- if (!set.has(hash)) {
46
- set.add(hash);
47
- acc.push(el);
11
+ if (KEY) {
12
+ const CUSTOM_FILTER_FN = typeof FILTER_FN === 'function'
13
+ ? (el) => el && Object.prototype.toString.call(el) === '[object Object]' && FILTER_FN(el)
14
+ : (el) => el && Object.prototype.toString.call(el) === '[object Object]';
15
+ for (let i = 0; i < len; i++) {
16
+ const el = val[i];
17
+ if (!CUSTOM_FILTER_FN(el))
18
+ continue;
19
+ hash = toString(el[KEY]);
20
+ if (!set.has(hash)) {
21
+ set.add(hash);
22
+ acc.push(el);
23
+ }
24
+ }
25
+ }
26
+ else {
27
+ for (let i = 0; i < len; i++) {
28
+ const el = val[i];
29
+ if (FILTER_FN && !FILTER_FN(el))
30
+ continue;
31
+ hash = toString(el);
32
+ if (!set.has(hash)) {
33
+ set.add(hash);
34
+ acc.push(el);
35
+ }
48
36
  }
49
37
  }
50
38
  return acc;
@@ -1,5 +1,5 @@
1
1
  import isAsyncFunction from '../function/isAsync';
2
- import fnv1A from '../hash/fnv1A';
2
+ import djb2 from '../hash/djb2';
3
3
  import isIntegerGt from '../number/isIntegerAbove';
4
4
  import LRU from './LRU';
5
5
  function memoize(fn, resolver, cache_duration_ms = false, cache_max_size = 100) {
@@ -9,7 +9,7 @@ function memoize(fn, resolver, cache_duration_ms = false, cache_max_size = 100)
9
9
  const memoized = isAsyncFunction(fn)
10
10
  ? async function (...args) {
11
11
  let key = isResolverFn ? resolver(...args) : args[0];
12
- key = typeof key === 'string' ? key : Number.isFinite(key) ? String(key) : String(fnv1A(key));
12
+ key = typeof key === 'string' ? key : Number.isFinite(key) ? String(key) : djb2(key);
13
13
  const cached_val = cache.get(key);
14
14
  const now = Date.now();
15
15
  if (cached_val !== undefined && (cache_duration === false || (now - cached_val.ts) < cache_duration)) {
@@ -21,7 +21,7 @@ function memoize(fn, resolver, cache_duration_ms = false, cache_max_size = 100)
21
21
  }
22
22
  : function (...args) {
23
23
  let key = isResolverFn ? resolver(...args) : args[0];
24
- key = typeof key === 'string' ? key : Number.isFinite(key) ? String(key) : String(fnv1A(key));
24
+ key = typeof key === 'string' ? key : Number.isFinite(key) ? String(key) : djb2(key);
25
25
  const cached_val = cache.get(key);
26
26
  const now = Date.now();
27
27
  if (cached_val !== undefined && (cache_duration === false || (now - cached_val.ts) < cache_duration)) {
@@ -0,0 +1,11 @@
1
+ import { toString } from './utils';
2
+ function djb2(data) {
3
+ let hash = 5381;
4
+ const normalized = toString(data);
5
+ const len = normalized.length;
6
+ for (let i = 0; i < len; i++) {
7
+ hash = ((hash << 5) + hash) ^ normalized.charCodeAt(i);
8
+ }
9
+ return String(hash >>> 0);
10
+ }
11
+ export { djb2, djb2 as default };
package/esm/hash/fnv1A.js CHANGED
@@ -1,49 +1,12 @@
1
+ import { toString } from './utils';
1
2
  export const FNV_32 = 2166136261;
2
- export const FNV_64 = 1099511628211;
3
- const REPL_NAN = 'nan';
4
- const REPL_TRUE = 'true';
5
- const REPL_FALSE = 'false';
6
- const REPL_UNDEF = 'undefined';
7
- const REPL_NULL = 'null';
3
+ export const FNV_64 = 1099511628211n;
8
4
  function fnv1A(data, offset = FNV_32) {
9
5
  let hash = offset;
10
- let sanitized;
11
- switch (typeof data) {
12
- case 'string':
13
- sanitized = data;
14
- break;
15
- case 'number':
16
- sanitized = Number.isNaN(data) || !Number.isFinite(data) ? REPL_NAN : String(data);
17
- break;
18
- case 'boolean':
19
- sanitized = data ? REPL_TRUE : REPL_FALSE;
20
- break;
21
- case 'undefined':
22
- sanitized = REPL_UNDEF;
23
- break;
24
- case 'object':
25
- if (data === null) {
26
- sanitized = REPL_NULL;
27
- }
28
- else if (Array.isArray(data) || Object.prototype.toString.call(data) === '[object Object]') {
29
- sanitized = JSON.stringify(data);
30
- }
31
- else if (data instanceof RegExp) {
32
- sanitized = String(data);
33
- }
34
- else if (data instanceof Date) {
35
- sanitized = String(data.getTime());
36
- }
37
- else {
38
- throw new TypeError('An FNV1A Hash could not be calculated for this datatype');
39
- }
40
- break;
41
- default:
42
- throw new TypeError('An FNV1A Hash could not be calculated for this datatype');
43
- }
44
- const len = sanitized.length;
6
+ const normalized = toString(data);
7
+ const len = normalized.length;
45
8
  for (let i = 0; i < len; i++) {
46
- hash ^= sanitized.charCodeAt(i);
9
+ hash ^= normalized.charCodeAt(i);
47
10
  hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
48
11
  }
49
12
  return hash >>> 0;
@@ -0,0 +1,37 @@
1
+ export function toString(raw) {
2
+ switch (typeof raw) {
3
+ case 'string':
4
+ return raw;
5
+ case 'number':
6
+ return Number.isFinite(raw) ? String(raw) : 'nan';
7
+ case 'bigint':
8
+ return raw.toString();
9
+ case 'boolean':
10
+ return raw ? 'true' : 'false';
11
+ case 'undefined':
12
+ return 'undefined';
13
+ case 'object':
14
+ if (raw === null) {
15
+ return 'null';
16
+ }
17
+ else if (Array.isArray(raw) || Object.prototype.toString.call(raw) === '[object Object]') {
18
+ return JSON.stringify(raw);
19
+ }
20
+ else if (raw instanceof RegExp) {
21
+ return String(raw);
22
+ }
23
+ else if (raw instanceof Date) {
24
+ return String(raw.getTime());
25
+ }
26
+ else if (raw instanceof Error) {
27
+ return raw.name + '|' + raw.message;
28
+ }
29
+ else {
30
+ throw new TypeError('A Hash could not be calculated for this datatype');
31
+ }
32
+ case 'symbol':
33
+ return String(raw);
34
+ default:
35
+ throw new TypeError('A Hash could not be calculated for this datatype');
36
+ }
37
+ }
package/hash/djb2.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * DJB2 Hash implementation
3
+ *
4
+ * @param {unknown} data - Value to hash
5
+ */
6
+ declare function djb2(data: unknown): string;
7
+ export { djb2, djb2 as default };
package/hash/fnv1A.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export declare const FNV_32 = 2166136261;
2
- export declare const FNV_64 = 1099511628211;
2
+ export declare const FNV_64 = 1099511628211n;
3
3
  /**
4
4
  * Convert a provided value into a Fowler-Noll-Vo 1A hash
5
5
  * For more info: https://tools.ietf.org/html/draft-eastlake-fnv-03
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Convert data to a format that is hashable
3
+ *
4
+ * @param {unknown} raw - Value to be converted
5
+ */
6
+ export declare function toString(raw: unknown): string;
package/index.d.ts CHANGED
@@ -2,11 +2,19 @@ declare module "equal" {
2
2
  function equal(a: any, b: any): boolean;
3
3
  export { equal, equal as default };
4
4
  }
5
+ declare module "hash/utils" {
6
+ export function toString(raw: unknown): string;
7
+ }
5
8
  declare module "array/dedupe" {
6
- type DedupeOptions<T> = {
9
+ type DedupeOptionsBase<T> = {
7
10
  filter_fn?: (el: T) => boolean;
8
11
  };
9
- function dedupe<T>(val: T[], opts?: DedupeOptions<T>): T[];
12
+ type DedupeOptionsWithKey<T extends Record<string, unknown>> = DedupeOptionsBase<T> & {
13
+ key: keyof T;
14
+ };
15
+ type DedupeOptionsNoKey<T> = DedupeOptionsBase<T>;
16
+ function dedupe<T extends Record<string, unknown>>(val: T[], opts: DedupeOptionsWithKey<T>): T[];
17
+ function dedupe<T>(val: T[], opts?: DedupeOptionsNoKey<T>): T[];
10
18
  export { dedupe, dedupe as default };
11
19
  }
12
20
  declare module "number/round" {
@@ -91,7 +99,7 @@ declare module "array/mapPrimitive" {
91
99
  export { mapPrimitive, mapPrimitive as default };
92
100
  }
93
101
  declare module "object/isNotEmpty" {
94
- function isNotEmptyObject<T extends Record<string, any>>(val: T | unknown): val is T;
102
+ function isNotEmptyObject<T extends Record<string, unknown> = Record<string, unknown>>(val: T | unknown): val is T;
95
103
  export { isNotEmptyObject, isNotEmptyObject as default };
96
104
  }
97
105
  declare module "array/groupBy" {
@@ -111,7 +119,7 @@ declare module "array/split" {
111
119
  export { split, split as default };
112
120
  }
113
121
  declare module "object/is" {
114
- function isObject<T extends Record<string, any>>(val: T | unknown): val is T;
122
+ function isObject<T extends Record<string, unknown> = Record<string, unknown>>(val: T | unknown): val is T;
115
123
  export { isObject, isObject as default };
116
124
  }
117
125
  declare module "array/sort" {
@@ -127,11 +135,11 @@ declare module "array/sort" {
127
135
  export { sort, sort as default };
128
136
  }
129
137
  declare module "array/is" {
130
- function isArray(val: unknown): val is unknown[];
138
+ function isArray<T = unknown>(val: unknown): val is T[];
131
139
  export { isArray, isArray as default };
132
140
  }
133
141
  declare module "array/isNotEmpty" {
134
- function isNotEmptyArray(val: unknown): val is unknown[];
142
+ function isNotEmptyArray<T = unknown>(val: unknown): val is T[];
135
143
  export { isNotEmptyArray, isNotEmptyArray as default };
136
144
  }
137
145
  declare module "array/index" {
@@ -635,11 +643,9 @@ declare module "is" {
635
643
  }>;
636
644
  export { Is, Is as default };
637
645
  }
638
- declare module "hash/fnv1A" {
639
- export const FNV_32 = 2166136261;
640
- export const FNV_64 = 1099511628211;
641
- function fnv1A(data: unknown, offset?: number): number;
642
- export { fnv1A, fnv1A as default };
646
+ declare module "hash/djb2" {
647
+ function djb2(data: unknown): string;
648
+ export { djb2, djb2 as default };
643
649
  }
644
650
  declare module "caching/memoize" {
645
651
  function memoize<T extends (...args: any[]) => unknown>(fn: T, resolver?: (...args: Parameters<T>) => any, cache_duration_ms?: number | false, cache_max_size?: number): T;
@@ -692,6 +698,12 @@ declare module "deep/index" {
692
698
  export { deepSet as set } from "deep/set";
693
699
  export { deepSet } from "deep/set";
694
700
  }
701
+ declare module "hash/fnv1A" {
702
+ export const FNV_32 = 2166136261;
703
+ export const FNV_64 = 1099511628211n;
704
+ function fnv1A(data: unknown, offset?: number): number;
705
+ export { fnv1A, fnv1A as default };
706
+ }
695
707
  declare module "hash/guid" {
696
708
  function guid(): string;
697
709
  export { guid, guid as default };
package/object/is.d.ts CHANGED
@@ -3,5 +3,5 @@
3
3
  *
4
4
  * @param {unknown} val - Value to verify
5
5
  */
6
- declare function isObject<T extends Record<string, any>>(val: T | unknown): val is T;
6
+ declare function isObject<T extends Record<string, unknown> = Record<string, unknown>>(val: T | unknown): val is T;
7
7
  export { isObject, isObject as default };
@@ -3,5 +3,5 @@
3
3
  *
4
4
  * @param {unknown} val - Value to verify
5
5
  */
6
- declare function isNotEmptyObject<T extends Record<string, any>>(val: T | unknown): val is T;
6
+ declare function isNotEmptyObject<T extends Record<string, unknown> = Record<string, unknown>>(val: T | unknown): val is T;
7
7
  export { isNotEmptyObject, isNotEmptyObject as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valkyriestudios/utils",
3
- "version": "12.42.0",
3
+ "version": "12.43.0",
4
4
  "description": "A collection of single-function utilities for common tasks",
5
5
  "author": {
6
6
  "name": "Peter Vermeulen",
@@ -514,12 +514,12 @@
514
514
  }
515
515
  },
516
516
  "devDependencies": {
517
- "@types/node": "^22.15.31",
518
- "@vitest/coverage-v8": "^3.2.3",
517
+ "@types/node": "^22.18.0",
518
+ "@vitest/coverage-v8": "^3.2.4",
519
519
  "esbuild-register": "^3.6.0",
520
- "eslint": "^9.29.0",
521
- "typescript": "^5.8.3",
522
- "typescript-eslint": "^8.34.0",
523
- "vitest": "^3.2.3"
520
+ "eslint": "^9.34.0",
521
+ "typescript": "^5.9.2",
522
+ "typescript-eslint": "^8.41.0",
523
+ "vitest": "^3.2.4"
524
524
  }
525
525
  }