@valkyriestudios/utils 12.17.2 → 12.19.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
@@ -633,6 +633,9 @@ equal(new RegExp(/ab+c/, 'i'), /ab+c/i); // TRUE
633
633
  ```
634
634
 
635
635
  ### function
636
+ - **debounce(val:Fn, wait:number)**
637
+ Wrap a function in a debounce proxy that waits for X uninterrupted milliseconds before running callback function
638
+
636
639
  - **isFunction(val:unknown)**
637
640
  Check if a variable is a Function
638
641
 
@@ -848,12 +851,17 @@ Copies the keys passed in the 'keys' array from the passed object to a new objec
848
851
  pick({a: 1, b: 2, c: 3}, ['a','b']); // {a: 1, b: 2}
849
852
  ```
850
853
 
851
- - **merge(target:Object={},obj:Object={})**
854
+ - **merge(target:Object={},obj:Object|Object[]={}, opts?:{union?:boolean})**
852
855
  Merges two objects together, with the preference over the second object.
853
856
  ```typescript
854
- merge({a: 1, b: false}, {a: 900, c: 50}); // {a: 900, b: false, c: 50}
857
+ merge({a: 1, b: false}, {a: 900, c: 50}, {union: true}); // {a: 900, b: false, c: 50}
858
+ merge({a: 1, b: false}, {a: 900, c: 50}, {union: false}); // {a: 900, b: false}
859
+ merge({a: 1, c: {bar: 'foo'}}, [{b: 2}, {c: {foo: 'bar'}}], {union: true}); // {a: 1, b: 2, c: {bar: 'foo', foo: 'bar'}}
855
860
  ```
856
861
 
862
+ Take Note: The default behavior is to not have union, this means that ONLY the keys in the target object
863
+ are going to be available in the response of this function.
864
+
857
865
  - **define(props:Object, obj:Object={})**
858
866
  Creates an object with the passed accessors set on it
859
867
  ```typescript
@@ -923,13 +931,16 @@ isNotEmptyString(' ', false); // TRUE
923
931
  isNotEmptyString('Hi'); // TRUE
924
932
  ```
925
933
 
926
- - **shorten(val:any, length:integer, postfix:string=...)**
934
+ - **shorten(val:any, length:integer, postfix:string=..., truncate_words=true)**
927
935
  Shorten a string and add a postfix if string went over length
928
936
  ```typescript
929
937
  shorten('To the moon and beyond', 11, '..'); // 'To the moon..'
930
938
  shorten('Hi', 250); // 'Hi'
931
939
  shorten('To the moon and beyond'); // 'To the moon...'
932
940
  shorten('To the moon and beyond', 11, ' '); // 'To the moon '
941
+
942
+ /* For when you don't want words to be truncated mid-word */
943
+ shorten('To the moon and beyond', 11, '...', false);
933
944
  ```
934
945
 
935
946
  - **humanizeBytes(val:number|string)**
package/array/dedupe.d.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  type DedupeOptions<T> = {
2
+ /**
3
+ * Pass a custom filter function which will be run in O(n) while deduping is going on
4
+ */
2
5
  filter_fn?: (el: T) => boolean;
3
6
  };
4
7
  /**
package/array/dedupe.js CHANGED
@@ -2,35 +2,53 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.dedupe = dedupe;
4
4
  exports.default = dedupe;
5
- const fnv1A_1 = require("../hash/fnv1A");
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
+ }
6
36
  function dedupe(val, opts) {
7
37
  if (!Array.isArray(val))
8
38
  return [];
9
- const FILTER_FN = typeof opts?.filter_fn === 'function' ? opts?.filter_fn : false;
39
+ const FILTER_FN = opts?.filter_fn;
10
40
  const set = new Set();
11
41
  const acc = [];
12
42
  let hash;
13
43
  const len = val.length;
14
- if (FILTER_FN) {
15
- for (let i = 0; i < len; i++) {
16
- const el = val[i];
17
- if (FILTER_FN && !FILTER_FN(el))
18
- continue;
19
- hash = (0, fnv1A_1.fnv1A)(el);
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
- hash = (0, fnv1A_1.fnv1A)(el);
30
- if (!set.has(hash)) {
31
- set.add(hash);
32
- acc.push(el);
33
- }
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);
34
52
  }
35
53
  }
36
54
  return acc;
package/array/groupBy.js CHANGED
@@ -23,11 +23,12 @@ function groupBy(arr, handler) {
23
23
  key = n_handler(el);
24
24
  if (key === undefined || (typeof key === 'string' && !key.length))
25
25
  key = FALLBACK;
26
- if (Array.isArray(acc[key])) {
26
+ if (!acc[key]) {
27
+ acc[key] = [el];
28
+ }
29
+ else {
27
30
  acc[key].push(el);
28
- continue;
29
31
  }
30
- acc[key] = [el];
31
32
  }
32
33
  return acc;
33
34
  }
package/array/mapKey.js CHANGED
@@ -3,19 +3,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.mapKey = mapKey;
4
4
  exports.default = mapKey;
5
5
  function mapKey(arr, key, opts) {
6
- if ((!Array.isArray(arr) || !arr.length) ||
7
- typeof key !== 'string')
6
+ if (!Array.isArray(arr) || typeof key !== 'string')
8
7
  return {};
9
8
  const key_s = key.trim();
10
9
  if (!key_s.length)
11
10
  return {};
11
+ const len = arr.length;
12
+ if (!len)
13
+ return {};
12
14
  const MERGE = opts?.merge === true;
13
15
  const map = {};
14
- for (let i = 0; i < arr.length; i++) {
16
+ for (let i = 0; i < len; i++) {
15
17
  const el = arr[i];
16
- if (el?.[key_s] === undefined)
18
+ const el_key = el?.[key_s];
19
+ if (el_key === undefined)
17
20
  continue;
18
- map[el[key_s]] = MERGE && map.hasOwnProperty(el[key_s]) ? { ...map[el[key_s]], ...el } : el;
21
+ map[el_key] = MERGE && el_key in map ? { ...map[el_key], ...el } : el;
19
22
  }
20
23
  return map;
21
24
  }
package/array/sort.js CHANGED
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.sort = sort;
4
4
  exports.default = sort;
5
- const isNotEmpty_1 = require("../object/isNotEmpty");
5
+ const is_1 = require("../object/is");
6
6
  const INSERTION_SORT_THRESHOLD = 10;
7
7
  function partition(arr, low, high) {
8
8
  const pivot = arr[(low + high) >> 1][0];
@@ -24,9 +24,9 @@ function partition(arr, low, high) {
24
24
  return i;
25
25
  }
26
26
  function quickSort(arr) {
27
- const stack = [{ low: 0, high: arr.length - 1 }];
27
+ const stack = [[0, arr.length - 1]];
28
28
  while (stack.length) {
29
- const { low, high } = stack.pop();
29
+ const [low, high] = stack.pop();
30
30
  if (high - low <= INSERTION_SORT_THRESHOLD) {
31
31
  for (let i = low + 1; i <= high; i++) {
32
32
  const key = arr[i];
@@ -41,22 +41,24 @@ function quickSort(arr) {
41
41
  else {
42
42
  const p = partition(arr, low, high);
43
43
  if (p - 1 > low)
44
- stack.push({ low, high: p - 1 });
44
+ stack.push([low, p - 1]);
45
45
  if (p < high)
46
- stack.push({ low: p, high });
46
+ stack.push([p, high]);
47
47
  }
48
48
  }
49
- return arr;
50
49
  }
51
50
  function sort(arr, by, dir = 'asc', opts) {
52
- if (!Array.isArray(arr) || !arr.length)
51
+ if (!Array.isArray(arr))
52
+ return [];
53
+ const len = arr.length;
54
+ if (!len)
53
55
  return [];
54
56
  const NOKEY_HIDE = opts?.nokey_hide === true;
55
57
  const NOKEY_AT_END = opts?.nokey_atend !== false;
56
- let FILTER_FN = isNotEmpty_1.isNotEmptyObject;
58
+ let FILTER_FN = is_1.isObject;
57
59
  if (typeof opts?.filter_fn === 'function') {
58
60
  const fn = opts.filter_fn;
59
- FILTER_FN = (el => (0, isNotEmpty_1.isNotEmptyObject)(el) && fn(el));
61
+ FILTER_FN = (el => (0, is_1.isObject)(el) && fn(el));
60
62
  }
61
63
  const prepared_arr = [];
62
64
  const nokey_arr = [];
@@ -64,19 +66,22 @@ function sort(arr, by, dir = 'asc', opts) {
64
66
  const by_s = by.trim();
65
67
  if (!by_s.length)
66
68
  throw new Error('Sort by as string should contain content');
67
- for (const el of arr) {
69
+ for (let i = 0; i < len; i++) {
70
+ const el = arr[i];
68
71
  if (!FILTER_FN(el))
69
72
  continue;
70
- if (el?.[by_s] === undefined) {
73
+ const key = el?.[by_s];
74
+ if (key === undefined) {
71
75
  nokey_arr.push(el);
72
76
  }
73
77
  else {
74
- prepared_arr.push([el[by_s], el]);
78
+ prepared_arr.push([key, el]);
75
79
  }
76
80
  }
77
81
  }
78
82
  else if (typeof by === 'function') {
79
- for (const el of arr) {
83
+ for (let i = 0; i < len; i++) {
84
+ const el = arr[i];
80
85
  if (!FILTER_FN(el))
81
86
  continue;
82
87
  const key = by(el);
package/deep/freeze.js CHANGED
@@ -4,8 +4,8 @@ exports.deepFreeze = deepFreeze;
4
4
  exports.default = deepFreeze;
5
5
  function deep(obj) {
6
6
  if (Array.isArray(obj)) {
7
- for (const el of obj)
8
- deep(el);
7
+ for (let i = 0; i < obj.length; i++)
8
+ deep(obj[i]);
9
9
  }
10
10
  else {
11
11
  for (const key in obj) {
package/deep/get.d.ts CHANGED
@@ -2,16 +2,16 @@
2
2
  * Get a property's value deep inside the structure of an array/object
3
3
  *
4
4
  * Example:
5
- * const myObj = {
6
- * a: 2,
7
- * b: [
8
- * {price : 2},
9
- * {price : 4},
10
- * ],
11
- * };
12
- * deepGet(myObj, 'b[0].price');
5
+ * const myObj = {
6
+ * a: 2,
7
+ * b: [
8
+ * {price : 2},
9
+ * {price : 4},
10
+ * ],
11
+ * };
12
+ * deepGet(myObj, 'b[0].price');
13
13
  * Output:
14
- * 2
14
+ * 2
15
15
  *
16
16
  * @param val - Object/Array to get the value from
17
17
  * @param path - Path string to deeply get the value at
@@ -20,9 +20,10 @@
20
20
  * @returns Value stored at property or undefined
21
21
  * @throws {TypeError}
22
22
  */
23
- declare function deepGet(obj: {
23
+ type ObjectType = {
24
24
  [key: string]: any;
25
- } | {
26
- [key: string]: any;
27
- }[] | any[], path: string, get_parent?: boolean): any | undefined;
25
+ };
26
+ type ArrayType = any[];
27
+ type DeepGetResult<T extends ObjectType | ArrayType, P extends string> = P extends `${infer Key}.${infer Rest}` ? Key extends keyof T ? T[Key] extends ObjectType | ArrayType ? DeepGetResult<T[Key], Rest> : undefined : T extends ArrayType ? number extends keyof T ? DeepGetResult<T[number], Rest> : undefined : undefined : P extends `${infer Key}[${infer Index}]` ? Key extends keyof T ? T[Key] extends ArrayType ? Index extends `${number}` ? DeepGetResult<T[Key][number], ''> : undefined : undefined : T extends ArrayType ? number extends keyof T ? DeepGetResult<T[number], `[${Index}]`> : undefined : undefined : P extends keyof T ? T[P] : T extends ArrayType ? number extends keyof T ? T[number] : undefined : undefined;
28
+ declare function deepGet<T extends ObjectType | ArrayType, P extends string>(obj: T, path: P, get_parent?: boolean): DeepGetResult<T, P> | undefined;
28
29
  export { deepGet, deepGet as default };
package/deep/get.js CHANGED
@@ -9,34 +9,56 @@ function deepGet(obj, path, get_parent = false) {
9
9
  if (typeof path !== 'string')
10
10
  throw new TypeError('No path was given');
11
11
  const path_s = path.trim();
12
- if (!path_s.length)
12
+ const path_len = path_s.length;
13
+ if (!path_len)
13
14
  throw new TypeError('No path was given');
14
- const parts = path_s
15
- .replace(/\[/g, '.')
16
- .replace(/(\.){2,}/g, '.')
17
- .replace(/(^\.|\.$|\])/g, '')
18
- .split('.');
19
- if (!parts.length || (parts.length === 1 && get_parent))
15
+ const parts = [];
16
+ let cursor_part = '';
17
+ let in_bracket = false;
18
+ for (let i = 0; i < path_len; i++) {
19
+ const char = path_s[i];
20
+ if (char === '[' || char === ']') {
21
+ in_bracket = !in_bracket;
22
+ if (cursor_part) {
23
+ parts.push(cursor_part);
24
+ cursor_part = '';
25
+ }
26
+ }
27
+ else if (char === '.' && !in_bracket) {
28
+ if (cursor_part) {
29
+ parts.push(cursor_part);
30
+ cursor_part = '';
31
+ }
32
+ }
33
+ else {
34
+ cursor_part += char;
35
+ }
36
+ }
37
+ if (cursor_part)
38
+ parts.push(cursor_part);
39
+ let len = parts.length;
40
+ if (!len || (len === 1 && get_parent))
20
41
  return obj;
21
- if (get_parent)
42
+ if (get_parent) {
22
43
  parts.pop();
44
+ len -= 1;
45
+ }
23
46
  let cursor = obj;
24
- while (parts.length) {
47
+ for (let i = 0; i < len; i++) {
25
48
  if (Array.isArray(cursor)) {
26
- const ix = parseInt(parts.shift());
27
- if (!Number.isInteger(ix) || ix < 0 || ix > (cursor.length - 1))
49
+ const ix = parseInt(parts[i], 10);
50
+ if (ix < 0 || ix > cursor.length - 1)
28
51
  return undefined;
29
52
  cursor = cursor[ix];
30
53
  }
31
54
  else if (Object.prototype.toString.call(cursor) === '[object Object]') {
32
- const key = parts.shift();
33
- if (cursor[key] === undefined)
55
+ cursor = cursor[parts[i]];
56
+ if (cursor === undefined)
34
57
  return undefined;
35
- cursor = cursor[key];
36
58
  }
37
- if ((!Array.isArray(cursor) && Object.prototype.toString.call(cursor) !== '[object Object]') &&
38
- parts.length)
59
+ else {
39
60
  return undefined;
61
+ }
40
62
  }
41
63
  return cursor;
42
64
  }
package/deep/seal.js CHANGED
@@ -4,8 +4,8 @@ exports.deepSeal = deepSeal;
4
4
  exports.default = deepSeal;
5
5
  function deep(obj) {
6
6
  if (Array.isArray(obj)) {
7
- for (const el of obj)
8
- deep(el);
7
+ for (let i = 0; i < obj.length; i++)
8
+ deep(obj[i]);
9
9
  }
10
10
  else {
11
11
  for (const key in obj) {
package/equal.js CHANGED
@@ -4,9 +4,10 @@ exports.equal = equal;
4
4
  exports.default = equal;
5
5
  const isNumericalNaN_1 = require("./number/isNumericalNaN");
6
6
  function isArrayEqual(a, b) {
7
- if (a.length !== b.length)
7
+ const a_len = a.length;
8
+ if (a_len !== b.length)
8
9
  return false;
9
- for (let i = a.length - 1; i >= 0; i--) {
10
+ for (let i = a_len - 1; i >= 0; i--) {
10
11
  if (equal(a[i], b[i]))
11
12
  continue;
12
13
  return false;
@@ -15,9 +16,10 @@ function isArrayEqual(a, b) {
15
16
  }
16
17
  function isObjectEqual(a, b) {
17
18
  const keys_a = Object.keys(a);
18
- if (keys_a.length !== Object.keys(b).length)
19
+ const keys_a_len = keys_a.length;
20
+ if (keys_a_len !== Object.keys(b).length)
19
21
  return false;
20
- for (let i = keys_a.length - 1; i >= 0; i--) {
22
+ for (let i = keys_a_len - 1; i >= 0; i--) {
21
23
  if (equal(a[keys_a[i]], b[keys_a[i]]))
22
24
  continue;
23
25
  return false;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Debounce a function
3
+ *
4
+ * Take Note, the debounced function also contains a "cancel" and "flush" method
5
+ * "cancel": Allows clearing the timeout
6
+ * "flush": Allows immediately executing the debounced function if pending
7
+ *
8
+ * Example Usage:
9
+ *
10
+ * const log = (message: string) => console.log(message);
11
+ *
12
+ * const debouncedLog = debounce(log, 2000);
13
+ *
14
+ * debouncedLog("Hello, World!");
15
+ * debouncedLog.cancel();
16
+ * debouncedLog.flush();
17
+ *
18
+ * @param {Function} fn - Function to debounce
19
+ * @param {number} wait - Amount of time to debounce the function for
20
+ */
21
+ declare function debounce<T extends (...args: any[]) => any>(fn: T, wait: number): T & {
22
+ cancel: () => void;
23
+ flush: () => void;
24
+ };
25
+ export { debounce, debounce as default };
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.debounce = debounce;
4
+ exports.default = debounce;
5
+ const is_1 = require("./is");
6
+ const isIntegerAbove_1 = require("../number/isIntegerAbove");
7
+ function debounce(fn, wait) {
8
+ if (!(0, is_1.isFunction)(fn))
9
+ throw new Error('functions/debounce: Expected a function');
10
+ if (!(0, isIntegerAbove_1.isIntegerAbove)(wait, 0))
11
+ throw new Error('functions/debounce: Wait should be an integer above 0');
12
+ let timeout;
13
+ let self;
14
+ let current_args;
15
+ let current_rslt;
16
+ const clear = () => {
17
+ if (!timeout)
18
+ return;
19
+ clearTimeout(timeout);
20
+ timeout = null;
21
+ };
22
+ const flush = () => {
23
+ if (!timeout)
24
+ return;
25
+ current_rslt = fn.apply(self, current_args);
26
+ clearTimeout(timeout);
27
+ timeout = null;
28
+ };
29
+ const debouncedFn = function (...args) {
30
+ self = this;
31
+ current_args = args;
32
+ clear();
33
+ timeout = setTimeout(() => {
34
+ timeout = null;
35
+ current_rslt = fn.apply(self, current_args);
36
+ }, wait);
37
+ return current_rslt;
38
+ };
39
+ debouncedFn.cancel = clear;
40
+ debouncedFn.flush = flush;
41
+ return debouncedFn;
42
+ }
@@ -1,7 +1,8 @@
1
+ import { debounce } from './debounce';
1
2
  import { isFunction } from './is';
2
3
  import { isAsyncFunction } from './isAsync';
3
4
  import { noop } from './noop';
4
5
  import { noopresolve } from './noopresolve';
5
6
  import { noopreturn } from './noopreturn';
6
7
  import { sleep } from './sleep';
7
- export { isFunction, isFunction as is, isFunction as isFn, isAsyncFunction, isAsyncFunction as isAsync, isAsyncFunction as isAsyncFn, noop, noopresolve, noopreturn, sleep };
8
+ export { debounce, isFunction, isFunction as is, isFunction as isFn, isAsyncFunction, isAsyncFunction as isAsync, isAsyncFunction as isAsyncFn, noop, noopresolve, noopreturn, sleep };
package/function/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.sleep = exports.noopreturn = exports.noopresolve = exports.noop = exports.isAsyncFn = exports.isAsync = exports.isAsyncFunction = exports.isFn = exports.is = exports.isFunction = void 0;
3
+ exports.sleep = exports.noopreturn = exports.noopresolve = exports.noop = exports.isAsyncFn = exports.isAsync = exports.isAsyncFunction = exports.isFn = exports.is = exports.isFunction = exports.debounce = void 0;
4
+ const debounce_1 = require("./debounce");
5
+ Object.defineProperty(exports, "debounce", { enumerable: true, get: function () { return debounce_1.debounce; } });
4
6
  const is_1 = require("./is");
5
7
  Object.defineProperty(exports, "isFunction", { enumerable: true, get: function () { return is_1.isFunction; } });
6
8
  Object.defineProperty(exports, "is", { enumerable: true, get: function () { return is_1.isFunction; } });
package/index.d.ts CHANGED
@@ -6,10 +6,6 @@ declare module "equal" {
6
6
  function equal(a: any, b: any): boolean;
7
7
  export { equal, equal as default };
8
8
  }
9
- declare module "hash/fnv1A" {
10
- function fnv1A(data: unknown, offset?: number): number;
11
- export { fnv1A, fnv1A as default };
12
- }
13
9
  declare module "array/dedupe" {
14
10
  type DedupeOptions<T> = {
15
11
  filter_fn?: (el: T) => boolean;
@@ -91,6 +87,12 @@ declare module "array/split" {
91
87
  function split<T>(arr: T[], size: number, opts?: SplitOptions<T>): T[][];
92
88
  export { split, split as default };
93
89
  }
90
+ declare module "object/is" {
91
+ function isObject(val: unknown): val is {
92
+ [key: string]: any;
93
+ };
94
+ export { isObject, isObject as default };
95
+ }
94
96
  declare module "array/sort" {
95
97
  type sortOptions<T> = {
96
98
  filter_fn?: (el: T) => boolean;
@@ -205,6 +207,17 @@ declare module "function/is" {
205
207
  function isFunction(val: unknown): val is (...args: unknown[]) => unknown;
206
208
  export { isFunction, isFunction as default };
207
209
  }
210
+ declare module "number/isIntegerAbove" {
211
+ function isIntegerAbove(val: unknown, ref: number): val is number;
212
+ export { isIntegerAbove, isIntegerAbove as default };
213
+ }
214
+ declare module "function/debounce" {
215
+ function debounce<T extends (...args: any[]) => any>(fn: T, wait: number): T & {
216
+ cancel: () => void;
217
+ flush: () => void;
218
+ };
219
+ export { debounce, debounce as default };
220
+ }
208
221
  declare module "function/isAsync" {
209
222
  function isAsyncFunction(val: unknown): val is (...args: unknown[]) => Promise<unknown>;
210
223
  export { isAsyncFunction, isAsyncFunction as default };
@@ -226,13 +239,14 @@ declare module "function/sleep" {
226
239
  export { sleep, sleep as default };
227
240
  }
228
241
  declare module "function/index" {
242
+ import { debounce } from "function/debounce";
229
243
  import { isFunction } from "function/is";
230
244
  import { isAsyncFunction } from "function/isAsync";
231
245
  import { noop } from "function/noop";
232
246
  import { noopresolve } from "function/noopresolve";
233
247
  import { noopreturn } from "function/noopreturn";
234
248
  import { sleep } from "function/sleep";
235
- export { isFunction, isFunction as is, isFunction as isFn, isAsyncFunction, isAsyncFunction as isAsync, isAsyncFunction as isAsyncFn, noop, noopresolve, noopreturn, sleep };
249
+ export { debounce, isFunction, isFunction as is, isFunction as isFn, isAsyncFunction, isAsyncFunction as isAsync, isAsyncFunction as isAsyncFn, noop, noopresolve, noopreturn, sleep };
236
250
  }
237
251
  declare module "regexp/is" {
238
252
  function isRegExp(val: unknown): val is RegExp;
@@ -257,42 +271,30 @@ declare module "object/define" {
257
271
  };
258
272
  export { define, define as default };
259
273
  }
260
- declare module "object/is" {
261
- function isObject(val: unknown): val is {
262
- [key: string]: any;
263
- };
264
- export { isObject, isObject as default };
265
- }
266
274
  declare module "object/merge" {
267
- function merge(target: {
268
- [key: string]: any;
269
- }, source?: {
270
- [key: string]: any;
271
- }): {
272
- [key: string]: any;
275
+ type MergeOptions = {
276
+ union?: boolean;
273
277
  };
278
+ function merge(target: Record<string, any>, source?: Record<string, any> | Record<string, any>[], opts?: MergeOptions): Record<string, any>;
274
279
  export { merge, merge as default };
275
280
  }
276
281
  declare module "deep/get" {
277
- function deepGet(obj: {
278
- [key: string]: any;
279
- } | {
282
+ type ObjectType = {
280
283
  [key: string]: any;
281
- }[] | any[], path: string, get_parent?: boolean): any | undefined;
284
+ };
285
+ type ArrayType = any[];
286
+ type DeepGetResult<T extends ObjectType | ArrayType, P extends string> = P extends `${infer Key}.${infer Rest}` ? Key extends keyof T ? T[Key] extends ObjectType | ArrayType ? DeepGetResult<T[Key], Rest> : undefined : T extends ArrayType ? number extends keyof T ? DeepGetResult<T[number], Rest> : undefined : undefined : P extends `${infer Key}[${infer Index}]` ? Key extends keyof T ? T[Key] extends ArrayType ? Index extends `${number}` ? DeepGetResult<T[Key][number], ''> : undefined : undefined : T extends ArrayType ? number extends keyof T ? DeepGetResult<T[number], `[${Index}]`> : undefined : undefined : P extends keyof T ? T[P] : T extends ArrayType ? number extends keyof T ? T[number] : undefined : undefined;
287
+ function deepGet<T extends ObjectType | ArrayType, P extends string>(obj: T, path: P, get_parent?: boolean): DeepGetResult<T, P> | undefined;
282
288
  export { deepGet, deepGet as default };
283
289
  }
284
- declare module "deep/set" {
285
- function deepSet(obj: {
286
- [key: string]: any;
287
- } | {
288
- [key: string]: any;
289
- }[] | any[], path: string, value: any, define?: boolean): boolean;
290
- export { deepSet, deepSet as default };
291
- }
292
290
  declare module "object/pick" {
293
- function pick(obj: {
291
+ type ObjectType = {
294
292
  [key: string]: any;
295
- }, keys: string[]): {
293
+ };
294
+ type DottedKeys<T> = (T extends ObjectType ? {
295
+ [K in keyof T & string]: T[K] extends ObjectType ? K | `${K}.${DottedKeys<T[K]>}` : K;
296
+ }[keyof T & string] : string) & string;
297
+ function pick<T extends Record<string, any>, K extends DottedKeys<T>>(obj: T, keys: K[]): {
296
298
  [key: string]: any;
297
299
  };
298
300
  export { pick, pick as default };
@@ -333,10 +335,6 @@ declare module "number/isInteger" {
333
335
  function isInteger(val: unknown): val is number;
334
336
  export { isInteger, isInteger as default };
335
337
  }
336
- declare module "number/isIntegerAbove" {
337
- function isIntegerAbove(val: unknown, ref: number): val is number;
338
- export { isIntegerAbove, isIntegerAbove as default };
339
- }
340
338
  declare module "number/isIntegerBelow" {
341
339
  function isIntegerBelow(val: unknown, ref: number): val is number;
342
340
  export { isIntegerBelow, isIntegerBelow as default };
@@ -412,7 +410,7 @@ declare module "string/isBetween" {
412
410
  export { isStringBetween, isStringBetween as default };
413
411
  }
414
412
  declare module "string/shorten" {
415
- function shorten(val: string, length: number, postfix?: string): string;
413
+ function shorten(val: string, length: number, postfix?: string, truncate_words?: boolean): string;
416
414
  export { shorten, shorten as default };
417
415
  }
418
416
  declare module "string/index" {
@@ -521,6 +519,14 @@ declare module "deep/seal" {
521
519
  function deepSeal<T extends deepInput>(obj: T): Sealed<T>;
522
520
  export { deepSeal, deepSeal as default };
523
521
  }
522
+ declare module "deep/set" {
523
+ function deepSet(obj: {
524
+ [key: string]: any;
525
+ } | {
526
+ [key: string]: any;
527
+ }[] | any[], path: string, value: any, define?: boolean): boolean;
528
+ export { deepSet, deepSet as default };
529
+ }
524
530
  declare module "deep/index" {
525
531
  import { deepFreeze } from "deep/freeze";
526
532
  import { deepGet } from "deep/get";
@@ -528,6 +534,10 @@ declare module "deep/index" {
528
534
  import { deepSet } from "deep/set";
529
535
  export { deepFreeze as freeze, deepFreeze, deepGet as get, deepGet, deepSeal as seal, deepSeal, deepSet as set, deepSet };
530
536
  }
537
+ declare module "hash/fnv1A" {
538
+ function fnv1A(data: unknown, offset?: number): number;
539
+ export { fnv1A, fnv1A as default };
540
+ }
531
541
  declare module "hash/guid" {
532
542
  function guid(): string;
533
543
  export { guid, guid as default };
package/object/merge.d.ts CHANGED
@@ -1,3 +1,10 @@
1
+ type MergeOptions = {
2
+ /**
3
+ * Defaults to false, when passed as true it ensures all keys from both objects
4
+ * are available in the merged object
5
+ */
6
+ union?: boolean;
7
+ };
1
8
  /**
2
9
  * Deep merge two objects together while ensuring nested objects also get merged,
3
10
  * take note: this does not merge onto passed objects by reference but instead
@@ -8,11 +15,5 @@
8
15
  *
9
16
  * @returns Combined target and source objects
10
17
  */
11
- declare function merge(target: {
12
- [key: string]: any;
13
- }, source?: {
14
- [key: string]: any;
15
- }): {
16
- [key: string]: any;
17
- };
18
+ declare function merge(target: Record<string, any>, source?: Record<string, any> | Record<string, any>[], opts?: MergeOptions): Record<string, any>;
18
19
  export { merge, merge as default };
package/object/merge.js CHANGED
@@ -3,19 +3,33 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.merge = merge;
4
4
  exports.default = merge;
5
5
  const PROTO_OBJ = '[object Object]';
6
- function merge(target, source = {}) {
7
- if (Object.prototype.toString.call(target) !== PROTO_OBJ ||
8
- Object.prototype.toString.call(source) !== PROTO_OBJ)
9
- throw new TypeError('Please pass a target and object to merge');
10
- const acc = {};
11
- for (const key in target) {
12
- if (Object.prototype.toString.call(target[key]) === PROTO_OBJ &&
13
- Object.prototype.toString.call(source[key]) === PROTO_OBJ) {
14
- acc[key] = merge(target[key], source[key]);
6
+ function innerMerge(target, source, UNION) {
7
+ const origin = UNION ? source : target;
8
+ for (const key in origin) {
9
+ const t_key = target[key];
10
+ const s_key = source[key];
11
+ if (Object.prototype.toString.call(t_key) === PROTO_OBJ &&
12
+ Object.prototype.toString.call(s_key) === PROTO_OBJ) {
13
+ target[key] = innerMerge({ ...t_key }, s_key, UNION);
15
14
  }
16
15
  else {
17
- acc[key] = source[key] !== undefined ? source[key] : target[key];
16
+ target[key] = s_key !== undefined ? s_key : t_key;
18
17
  }
19
18
  }
19
+ return target;
20
+ }
21
+ function merge(target, source = {}, opts = {}) {
22
+ if (Object.prototype.toString.call(target) !== PROTO_OBJ)
23
+ throw new Error('object/merge: Please ensure valid target/source is passed');
24
+ const union = opts?.union === true;
25
+ const sources = Array.isArray(source) ? source : [source];
26
+ let acc = { ...target };
27
+ for (let i = 0; i < sources.length; i++) {
28
+ const el = sources[i];
29
+ if (Object.prototype.toString.call(el) !== PROTO_OBJ) {
30
+ throw new Error('object/merge: Please ensure valid target/source is passed');
31
+ }
32
+ acc = innerMerge(acc, el, union);
33
+ }
20
34
  return acc;
21
35
  }
package/object/pick.d.ts CHANGED
@@ -1,3 +1,9 @@
1
+ type ObjectType = {
2
+ [key: string]: any;
3
+ };
4
+ type DottedKeys<T> = (T extends ObjectType ? {
5
+ [K in keyof T & string]: T[K] extends ObjectType ? K | `${K}.${DottedKeys<T[K]>}` : K;
6
+ }[keyof T & string] : string) & string;
1
7
  /**
2
8
  * Returns a new object with the keys picked from the passed object
3
9
  *
@@ -6,9 +12,7 @@
6
12
  *
7
13
  * @returns Object containing the picked keys from source object
8
14
  */
9
- declare function pick(obj: {
10
- [key: string]: any;
11
- }, keys: string[]): {
15
+ declare function pick<T extends Record<string, any>, K extends DottedKeys<T>>(obj: T, keys: K[]): {
12
16
  [key: string]: any;
13
17
  };
14
18
  export { pick, pick as default };
package/object/pick.js CHANGED
@@ -3,8 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.pick = pick;
4
4
  exports.default = pick;
5
5
  const get_1 = require("../deep/get");
6
- const set_1 = require("../deep/set");
7
- const RGX_DEEP = /(\.|\[)/;
8
6
  function pick(obj, keys) {
9
7
  if (Object.prototype.toString.call(obj) !== '[object Object]' ||
10
8
  !Array.isArray(keys) ||
@@ -20,11 +18,21 @@ function pick(obj, keys) {
20
18
  sanitized = key.trim();
21
19
  if (!sanitized.length)
22
20
  continue;
23
- if (RGX_DEEP.test(sanitized)) {
21
+ if (sanitized.includes('.')) {
24
22
  val = (0, get_1.deepGet)(obj, sanitized);
25
23
  if (val === undefined)
26
24
  continue;
27
- (0, set_1.deepSet)(map, sanitized, val);
25
+ const parts = key.split('.');
26
+ const parts_len = parts.length;
27
+ let cursor = map;
28
+ for (let y = 0; y < parts_len - 1; y++) {
29
+ const part = parts[y].trim();
30
+ if (!cursor[part]) {
31
+ cursor[part] = {};
32
+ }
33
+ cursor = cursor[part];
34
+ }
35
+ cursor[parts[parts_len - 1].trim()] = val;
28
36
  }
29
37
  else if (obj[sanitized] !== undefined) {
30
38
  map[sanitized] = obj[sanitized];
package/package.json CHANGED
@@ -1 +1 @@
1
- { "name": "@valkyriestudios/utils", "version": "12.17.2", "description": "A collection of single-function utilities for common tasks", "author": { "name": "Peter Vermeulen", "url": "https://www.linkedin.com/in/petervermeulen1/" }, "keywords": [ "utility", "library", "javascript", "js", "node", "bun" ], "license": "MIT", "repository": { "type": "git", "url": "git+https://github.com/ValkyrieStudios/utils.git" }, "bugs": { "url": "https://github.com/ValkyrieStudios/utils/issues" }, "homepage": "https://github.com/ValkyrieStudios/utils#readme", "types": "index.d.ts" }
1
+ { "name": "@valkyriestudios/utils", "version": "12.19.0", "description": "A collection of single-function utilities for common tasks", "author": { "name": "Peter Vermeulen", "url": "https://www.linkedin.com/in/petervermeulen1/" }, "keywords": [ "utility", "library", "javascript", "js", "node", "bun" ], "license": "MIT", "repository": { "type": "git", "url": "git+https://github.com/ValkyrieStudios/utils.git" }, "bugs": { "url": "https://github.com/ValkyrieStudios/utils/issues" }, "homepage": "https://github.com/ValkyrieStudios/utils#readme", "types": "index.d.ts" }
@@ -1,11 +1,12 @@
1
1
  /**
2
2
  * Shorten a string and add a postfix if it goes over a specific length, will autotrim value.
3
3
  *
4
- * @param val - String value to shorten
5
- * @param length - Length to shorten it to
6
- * @param postfix - (default='...') Postfix to use in case the string got shortened
4
+ * @param {string} val - String value to shorten
5
+ * @param {number} length - Length to shorten it to
6
+ * @param {string} postfix - (default:'...') Postfix to use in case the string got shortened
7
+ * @param {boolean?} truncate_words - (default:true) Truncate words or not
7
8
  *
8
9
  * @returns Shortened string
9
10
  */
10
- declare function shorten(val: string, length: number, postfix?: string): string;
11
+ declare function shorten(val: string, length: number, postfix?: string, truncate_words?: boolean): string;
11
12
  export { shorten, shorten as default };
package/string/shorten.js CHANGED
@@ -2,11 +2,23 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.shorten = shorten;
4
4
  exports.default = shorten;
5
- function shorten(val, length, postfix = '...') {
5
+ function shorten(val, length, postfix = '...', truncate_words = true) {
6
6
  if (typeof val !== 'string')
7
7
  return '';
8
8
  if (typeof postfix !== 'string' || !Number.isInteger(length) || length <= 0)
9
9
  return val;
10
10
  const sanitized = val.trim();
11
- return sanitized.length <= length ? sanitized : `${sanitized.substring(0, length)}${postfix}`;
11
+ if (sanitized.length <= length)
12
+ return sanitized;
13
+ const truncated = sanitized.substring(0, length);
14
+ if (truncate_words)
15
+ return truncated + postfix;
16
+ let end = length;
17
+ while (end > 0 && sanitized[end] !== ' ' && sanitized[end - 1] !== ' ') {
18
+ end--;
19
+ }
20
+ if (end === 0) {
21
+ return sanitized.substring(0, length) + postfix;
22
+ }
23
+ return sanitized.substring(0, end).trim() + postfix;
12
24
  }