@valkyriestudios/utils 12.18.0 → 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
@@ -851,12 +851,17 @@ Copies the keys passed in the 'keys' array from the passed object to a new objec
851
851
  pick({a: 1, b: 2, c: 3}, ['a','b']); // {a: 1, b: 2}
852
852
  ```
853
853
 
854
- - **merge(target:Object={},obj:Object={})**
854
+ - **merge(target:Object={},obj:Object|Object[]={}, opts?:{union?:boolean})**
855
855
  Merges two objects together, with the preference over the second object.
856
856
  ```typescript
857
- 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'}}
858
860
  ```
859
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
+
860
865
  - **define(props:Object, obj:Object={})**
861
866
  Creates an object with the passed accessors set on it
862
867
  ```typescript
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/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;
package/index.d.ts CHANGED
@@ -272,35 +272,29 @@ declare module "object/define" {
272
272
  export { define, define as default };
273
273
  }
274
274
  declare module "object/merge" {
275
- function merge(target: {
276
- [key: string]: any;
277
- }, source?: {
278
- [key: string]: any;
279
- }): {
280
- [key: string]: any;
275
+ type MergeOptions = {
276
+ union?: boolean;
281
277
  };
278
+ function merge(target: Record<string, any>, source?: Record<string, any> | Record<string, any>[], opts?: MergeOptions): Record<string, any>;
282
279
  export { merge, merge as default };
283
280
  }
284
281
  declare module "deep/get" {
285
- function deepGet(obj: {
286
- [key: string]: any;
287
- } | {
282
+ type ObjectType = {
288
283
  [key: string]: any;
289
- }[] | 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;
290
288
  export { deepGet, deepGet as default };
291
289
  }
292
- declare module "deep/set" {
293
- function deepSet(obj: {
294
- [key: string]: any;
295
- } | {
296
- [key: string]: any;
297
- }[] | any[], path: string, value: any, define?: boolean): boolean;
298
- export { deepSet, deepSet as default };
299
- }
300
290
  declare module "object/pick" {
301
- function pick(obj: {
291
+ type ObjectType = {
302
292
  [key: string]: any;
303
- }, 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[]): {
304
298
  [key: string]: any;
305
299
  };
306
300
  export { pick, pick as default };
@@ -525,6 +519,14 @@ declare module "deep/seal" {
525
519
  function deepSeal<T extends deepInput>(obj: T): Sealed<T>;
526
520
  export { deepSeal, deepSeal as default };
527
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
+ }
528
530
  declare module "deep/index" {
529
531
  import { deepFreeze } from "deep/freeze";
530
532
  import { deepGet } from "deep/get";
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.18.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
+ { "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" }