@cleverbrush/deep 1.1.0 → 1.1.1

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
@@ -8,9 +8,11 @@ This is yet another library which provides operations over JavaScript objects, l
8
8
 
9
9
  ## Usage
10
10
 
11
- import deep from '@cleverbrush/deep';
12
- // or import functions individually
13
- import { deepEqual, deepExtend } from '@cleverbrush/deep';
11
+ ```typescript
12
+ import deep from '@cleverbrush/deep';
13
+ // or import functions individually
14
+ import { deepEqual, deepExtend } from '@cleverbrush/deep';
15
+ ```
14
16
 
15
17
  ## Functions
16
18
 
@@ -18,36 +20,45 @@ This is yet another library which provides operations over JavaScript objects, l
18
20
 
19
21
  Takes two objects as parameters, compares it recursively and returns `true` if they are equal or `false` in other case.
20
22
 
21
- import { deepEqual } from '@cleverbrush/deep';
23
+ ```typescript
24
+ import { deepEqual } from '@cleverbrush/deep';
22
25
 
23
- const equal1 = deepEqual({ a: {b : 1} }, { a: {b: 1} });
24
- // equal1 === true
26
+ const equal1 = deepEqual({ a: { b: 1 } }, { a: { b: 1 } });
27
+ // equal1 === true
25
28
 
26
- const equal2 = deepEqual({ a: {b : 1} }, { a: {b: 20} });
27
- // equal2 === false
29
+ const equal2 = deepEqual({ a: { b: 1 } }, { a: { b: 20 } });
30
+ // equal2 === false
28
31
 
29
- const equal3 = deepEqual({ a: {b : 1, c: 2} }, { a: {b: 20} });
30
- // equal3 === false
32
+ const equal3 = deepEqual({ a: { b: 1, c: 2 } }, { a: { b: 20 } });
33
+ // equal3 === false
34
+ ```
31
35
 
32
36
  ### deepExtend
33
37
 
34
38
  Works similary to `Object.extend`, but respects the deep structure of objects.
35
39
 
36
- import { deepExtend } from '@cleverbrush/deep';
40
+ ```typescript
41
+ import { deepExtend } from '@cleverbrush/deep';
37
42
 
38
- deepExtend({}, {
39
- a: 'something,
40
- name: {
41
- first: 'Ivan'
42
- }
43
- }, {
44
- name: {
45
- last: 'Ivanov'
46
- }
47
- });
43
+ deepExtend(
44
+ {},
45
+ {
46
+ a: 'something',
47
+ name: {
48
+ first: 'Ivan'
49
+ }
50
+ },
51
+ {
52
+ name: {
53
+ last: 'Ivanov'
54
+ }
55
+ }
56
+ );
57
+ ```
48
58
 
49
59
  will return the following object:
50
60
 
61
+ ```typescript
51
62
  {
52
63
  a: 'something',
53
64
  name: {
@@ -55,3 +66,42 @@ will return the following object:
55
66
  last: 'Ivanov'
56
67
  }
57
68
  }
69
+ ```
70
+
71
+ ### deepFlatten
72
+
73
+ Flattens an object to a single level. Accepts an optional separator as a second parameter.
74
+ If no separator is provided, the default separator is `.`.
75
+ Supports only objects with string keys. Supports nested objects of any depth.
76
+ Throws an error if the object contains circular references.
77
+
78
+ ```typescript
79
+ import { deepFlatten } from '@cleverbrush/deep';
80
+
81
+ deepFlatten({
82
+ a: {
83
+ b: 1,
84
+ c: 2
85
+ },
86
+ d: 3
87
+ });
88
+
89
+ // => { 'a.b': 1, 'a.c': 2, d: 3 }
90
+
91
+ deepFlatten(
92
+ {
93
+ a: {
94
+ b: 1,
95
+ c: 2
96
+ },
97
+ d: {
98
+ e: {
99
+ f: 3
100
+ }
101
+ }
102
+ },
103
+ '-'
104
+ );
105
+
106
+ // => { 'a-b': 1, 'a-c': 2, 'd-e-f': 3 }
107
+ ```
@@ -8,11 +8,10 @@
8
8
  * @param options additional options
9
9
  * @returns {boolean} `true` if the objects are equal, `false` otherwise
10
10
  */
11
- declare const deepEqual: (p1: any, p2: any, options?: {
11
+ export declare const deepEqual: (p1: any, p2: any, options?: {
12
12
  /**
13
13
  * if true, the order of the elements in the array will be disregarded
14
14
  * e.g. [1, 2] and [2, 1] will be considered equal
15
15
  */
16
16
  disregardArrayOrder?: boolean;
17
17
  }) => boolean;
18
- export default deepEqual;
package/dist/deepEqual.js CHANGED
@@ -1,7 +1,5 @@
1
1
  import { HashObject } from './hashObject.js';
2
- const isBothNaN = function (v1, v2) {
3
- return Number.isNaN(v1) && Number.isNaN(v2);
4
- };
2
+ const isBothNaN = (v1, v2) => Number.isNaN(v1) && Number.isNaN(v2);
5
3
  /**
6
4
  * Compares two objects and returns true if they
7
5
  * have the same structure and values. Can work
@@ -12,7 +10,7 @@ const isBothNaN = function (v1, v2) {
12
10
  * @param options additional options
13
11
  * @returns {boolean} `true` if the objects are equal, `false` otherwise
14
12
  */
15
- const deepEqual = function (p1, p2, options) {
13
+ export const deepEqual = function (p1, p2, options) {
16
14
  const cache = new Map();
17
15
  const compare = function (o1, o2) {
18
16
  const arraysAreIdentical = function (a1, a2) {
@@ -90,4 +88,3 @@ const deepEqual = function (p1, p2, options) {
90
88
  };
91
89
  return compare(p1, p2);
92
90
  };
93
- export default deepEqual;
@@ -6,5 +6,4 @@ export type MergeTwo<T1, T2> = PropsInFirstOnly<T1, T2> & PropsInFirstOnly<T2, T
6
6
  [k in keyof CommonProps<T1, T2>]: T1[k] extends Record<string, unknown> ? T2[k] extends Record<string, unknown> ? MergeTwo<T1[k], T2[k]> : T2[k] : T2[k];
7
7
  };
8
8
  export type Merge<T extends unknown[]> = T['length'] extends 3 ? MergeTwo<T[0], MergeTwo<T[1], T[2]>> : T['length'] extends 2 ? MergeTwo<T[0], T[1]> : T['length'] extends 1 ? T[0] : T extends [...infer K, infer PL, infer L] ? Merge<[Merge<[...K]>, MergeTwo<PL, L>]> : never;
9
- declare const deepExtend: <T extends unknown[]>(...args: T) => Merge<T>;
10
- export default deepExtend;
9
+ export declare const deepExtend: <T extends unknown[]>(...args: T) => Merge<T>;
@@ -1,38 +1,37 @@
1
- const deepExtend = function () {
2
- if (arguments.length === 0)
3
- return false;
4
- if (arguments.length === 1)
5
- return arguments[0];
6
- if (typeof arguments[0] !== 'object')
7
- return false;
1
+ export const deepExtend = ((...rest) => {
2
+ if (rest.length === 0)
3
+ throw new Error('no arguments');
4
+ if (typeof rest[0] !== 'object' || rest[0] === null)
5
+ throw new Error('not a non-null object');
6
+ if (rest.length === 1)
7
+ return rest[0];
8
8
  const result = {};
9
9
  const extendObject = function (o1, o2) {
10
- if (o2 == null)
11
- return;
12
10
  const keys = Object.keys(o2);
13
11
  for (let i = 0; i < keys.length; i++) {
14
- if (o2.hasOwnProperty(keys[i])) {
15
- if (!o1.hasOwnProperty(keys[i]) ||
16
- !(typeof o1[keys[i]] === 'object' &&
17
- typeof o2[keys[i]] === 'object')) {
12
+ if (!Reflect.has(o1, keys[i]) ||
13
+ !(typeof o1[keys[i]] === 'object' &&
14
+ o1[keys[i]] !== null &&
15
+ typeof o2[keys[i]] === 'object')) {
16
+ o1[keys[i]] = o2[keys[i]];
17
+ }
18
+ else {
19
+ if (o1[keys[i]] == null || o2[keys[i]] == null) {
18
20
  o1[keys[i]] = o2[keys[i]];
19
21
  }
20
22
  else {
21
- if (o1[keys[i]] == null) {
22
- o1[keys[i]] = o2[keys[i]];
23
- }
24
- else {
25
- extendObject(o1[keys[i]], o2[keys[i]]);
26
- }
23
+ extendObject(o1[keys[i]], o2[keys[i]]);
27
24
  }
28
25
  }
29
26
  }
30
27
  };
31
- for (let i = 0; i < arguments.length; i++) {
32
- if (typeof arguments[i] === 'object' && arguments[i]) {
33
- extendObject(result, arguments[i]);
28
+ for (let i = 0; i < rest.length; i++) {
29
+ if (typeof rest[i] === 'object' && rest[i] !== null && rest[i]) {
30
+ extendObject(result, rest[i]);
31
+ }
32
+ else {
33
+ throw new Error('not a non-null object');
34
34
  }
35
35
  }
36
36
  return result;
37
- };
38
- export default deepExtend;
37
+ });
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Flattens an object to a single level, with the nested keys separated by a `delimiter`.
3
+ * @example
4
+ * ```ts
5
+ * deepFlatten({ a: { b: 1, c: 2 } });
6
+ * // => { 'a.b': 1, 'a.c': 2 }
7
+ *
8
+ * deepFlatten({ a: { b: 1, c: 2 } }, '/');
9
+ * // => { 'a/b': 1, 'a/c': 2 }
10
+ *
11
+ * deepFlatten({ a: { b: 1, c: { d: 'some val' } }, d: 3 });
12
+ * // => { 'a.b': 1, 'a.c.d': 'some val', d: 3 }
13
+ *
14
+ * ```
15
+ * @param {string} [delimiter]
16
+ */
17
+ export declare function deepFlatten(obj: Record<string, any>, delimiter?: string): Record<string, any>;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Flattens an object to a single level, with the nested keys separated by a `delimiter`.
3
+ * @example
4
+ * ```ts
5
+ * deepFlatten({ a: { b: 1, c: 2 } });
6
+ * // => { 'a.b': 1, 'a.c': 2 }
7
+ *
8
+ * deepFlatten({ a: { b: 1, c: 2 } }, '/');
9
+ * // => { 'a/b': 1, 'a/c': 2 }
10
+ *
11
+ * deepFlatten({ a: { b: 1, c: { d: 'some val' } }, d: 3 });
12
+ * // => { 'a.b': 1, 'a.c.d': 'some val', d: 3 }
13
+ *
14
+ * ```
15
+ * @param {string} [delimiter]
16
+ */
17
+ export function deepFlatten(obj, delimiter = '.') {
18
+ const shouldFlatten = (obj) => typeof obj === 'object' &&
19
+ obj !== null &&
20
+ !Array.isArray(obj) &&
21
+ Object.getPrototypeOf(obj) === Object.prototype;
22
+ if (!shouldFlatten(obj))
23
+ throw new Error('cannot flatten this object');
24
+ const stack = [];
25
+ const result = {};
26
+ const deepFlattenHelper = (obj, prefix = '') => {
27
+ if (stack.find((o) => o === obj))
28
+ throw new Error('circular reference detected');
29
+ stack.push(obj);
30
+ Object.keys(obj).forEach((key) => {
31
+ if (!shouldFlatten(obj[key])) {
32
+ result[prefix ? `${prefix}${delimiter}${key}` : key] = obj[key];
33
+ return;
34
+ }
35
+ deepFlattenHelper(obj[key], prefix ? `${prefix}${delimiter}${key}` : key);
36
+ });
37
+ stack.pop();
38
+ };
39
+ deepFlattenHelper(obj);
40
+ return result;
41
+ }
package/dist/index.d.ts CHANGED
@@ -1,10 +1,12 @@
1
- import deepEqual from './deepEqual';
2
- import deepExtend, { Merge } from './deepExtend';
3
- export { deepEqual, deepExtend, Merge };
1
+ import { deepEqual } from './deepEqual.js';
2
+ import { deepExtend, type Merge } from './deepExtend.js';
3
+ import { deepFlatten } from './deepFlatten.js';
4
+ export { deepEqual, deepExtend, deepFlatten, type Merge };
4
5
  declare const _default: {
5
6
  deepEqual: (p1: any, p2: any, options?: {
6
7
  disregardArrayOrder?: boolean;
7
8
  }) => boolean;
8
9
  deepExtend: <T extends unknown[]>(...args: T) => Merge<T>;
10
+ deepFlatten: typeof deepFlatten;
9
11
  };
10
12
  export default _default;
package/dist/index.js CHANGED
@@ -1,7 +1,9 @@
1
- import deepEqual from './deepEqual';
2
- import deepExtend from './deepExtend';
3
- export { deepEqual, deepExtend };
1
+ import { deepEqual } from './deepEqual.js';
2
+ import { deepExtend } from './deepExtend.js';
3
+ import { deepFlatten } from './deepFlatten.js';
4
+ export { deepEqual, deepExtend, deepFlatten };
4
5
  export default {
5
6
  deepEqual,
6
- deepExtend
7
+ deepExtend,
8
+ deepFlatten
7
9
  };
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "files": [
9
9
  "dist"
10
10
  ],
11
- "homepage": "https://docs.cleverbrush.com/v1.0.0/modules/Deep_operations_on_objects.html",
11
+ "homepage": "https://docs.cleverbrush.com/v1.1.1/modules/Deep_operations_on_objects.html",
12
12
  "keywords": [
13
13
  "deep operations on objects",
14
14
  "deep equal",
@@ -35,5 +35,5 @@
35
35
  },
36
36
  "type": "module",
37
37
  "types": "./dist/index.d.ts",
38
- "version": "1.1.0"
38
+ "version": "1.1.1"
39
39
  }