@magic/deep 0.1.15 → 0.1.17

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
@@ -23,11 +23,13 @@ Work with deeply nested objects and arrays.
23
23
  [snyk-url]: https://snyk.io/test/github/magic/deep
24
24
 
25
25
  ##### install
26
+
26
27
  ```bash
27
28
  npm i --save --save-exact @magic/deep
28
29
  ```
29
30
 
30
31
  ##### import
32
+
31
33
  ```javascript
32
34
  // single function
33
35
  import { equal, flatten, loop, merge } from '@magic/deep'
@@ -39,27 +41,29 @@ import deep from '@magic/deep'
39
41
  Currently implemented:
40
42
 
41
43
  ##### deep.equal
44
+
42
45
  ```javascript
43
46
  // test equality
44
47
  deep.equal(['shallow', ['deep']], ['shallow', ['deep']])
45
48
  // true
46
49
 
47
50
  // alias
48
- deep.equals, deep.eq
51
+ // deep.equals, deep.eq
49
52
  ```
50
53
 
51
54
  ##### deep.different
55
+
52
56
  ```javascript
53
57
  // test difference
54
58
  deep.different(['shallow', ['deep']], ['shallow', ['deep']])
55
59
  // false
56
60
 
57
61
  // alias
58
- deep.diff
62
+ // deep.diff
59
63
  ```
60
64
 
61
-
62
65
  ##### deep.flatten
66
+
63
67
  ```javascript
64
68
  // flatten a deeply nested array
65
69
  deep.flatten(['shallow', ['deep']])
@@ -67,6 +71,7 @@ deep.flatten(['shallow', ['deep']])
67
71
  ```
68
72
 
69
73
  ##### deep.loop
74
+
70
75
  ```javascript
71
76
  // apply function add
72
77
  const add = e => e + 1
@@ -82,11 +87,12 @@ deep.loop(items, add)
82
87
  ```
83
88
 
84
89
  ##### deep.merge
90
+
85
91
  ```javascript
86
92
  // merge objects and arrays, with infinite recursion if needed.
87
93
  // this can be slow...
88
94
 
89
- deep.merge({ obj1Key: { val: 1 } }, { obj2Key: { val: 2 } } )
95
+ deep.merge({ obj1Key: { val: 1 } }, { obj2Key: { val: 2 } })
90
96
 
91
97
  // { obj1Key: { val: 1}, obj2Key: { val: 2 } }
92
98
 
@@ -98,56 +104,82 @@ deep.merge({ key: { val: 1, str: 'test' } }, { key: { val: 2, str: 'overwritten'
98
104
  ### Changelog
99
105
 
100
106
  #### 0.1.0
107
+
101
108
  use ecmascript modules instead of commonjs.
102
109
 
103
110
  #### 0.1.1
104
- * update readme
105
- * also export deep.eq alias for deep.equal
111
+
112
+ - update readme
113
+ - also export deep.eq alias for deep.equal
106
114
 
107
115
  #### 0.1.2
108
- * require node 13.5.0
109
- * use deep.equal and deep.different from @magic/types
116
+
117
+ - require node 13.5.0
118
+ - use deep.equal and deep.different from @magic/types
110
119
 
111
120
  #### 0.1.3
121
+
112
122
  bump required node version to 14.2.0
113
123
 
114
- #### 0.1.4
124
+ #### 0.1.4
125
+
115
126
  update dependencies
116
127
 
117
128
  #### 0.1.5
118
- * bump required node version to 14.15.4
119
- * update dependencies
129
+
130
+ - bump required node version to 14.15.4
131
+ - update dependencies
120
132
 
121
133
  ##### 0.1.6
122
- * merge now checks if o2.hasOwnProperty is a function before using it to check if we should overwrite keys of o1 or not.
123
134
 
124
- ##### 0.1.7
135
+ - merge now checks if o2.hasOwnProperty is a function before using it to check if we should overwrite keys of o1 or not.
136
+
137
+ ##### 0.1.7
138
+
125
139
  update @magic/types to avoid circular dependency
126
140
 
127
141
  ##### 0.1.8
128
- * update dependencies
129
- * use @magic/types for all type comparisons
142
+
143
+ - update dependencies
144
+ - use @magic/types for all type comparisons
130
145
 
131
146
  ##### 0.1.9
147
+
132
148
  update dependencies
133
149
 
134
150
  ##### 0.1.10
151
+
135
152
  update dependencies
136
153
 
137
154
  ##### 0.1.11
155
+
138
156
  update dependencies
139
157
 
140
158
  ##### 0.1.12
159
+
141
160
  update dependencies
142
161
 
143
- ##### 0.0.13
162
+ ##### 0.1.13
163
+
144
164
  update dependencies
145
165
 
146
- ##### 0.0.14
166
+ ##### 0.1.14
167
+
147
168
  update dependencies
148
169
 
149
- ##### 0.0.15
170
+ ##### 0.1.15
171
+
172
+ update dependencies
173
+
174
+ ##### 0.1.16
175
+
150
176
  update dependencies
151
177
 
152
- ##### 0.0.16 - unreleased
178
+ ##### 0.1.17
179
+
180
+ - add typescript types
181
+ - update dependencies
182
+
183
+ ##### 0.1.18 - unreleased
184
+
153
185
  ...
package/package.json CHANGED
@@ -1,15 +1,18 @@
1
1
  {
2
2
  "name": "@magic/deep",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "author": "Wizards & Witches",
5
5
  "description": "manipulate nested objects and arrays",
6
6
  "homepage": "https://github.com/magic/deep",
7
7
  "license": "AGPL-3.0",
8
- "main": "src/index.mjs",
9
- "module": "src/index.mjs",
8
+ "main": "src/index.js",
9
+ "types": "types/index.d.ts",
10
+ "module": "src/index.js",
10
11
  "type": "module",
11
12
  "scripts": {
12
13
  "start": "t",
14
+ "build": "tsc && npm run format",
15
+ "prepublishOnly": "npm run build",
13
16
  "test": "t",
14
17
  "format": "f -w",
15
18
  "format:check": "f",
@@ -30,11 +33,13 @@
30
33
  "src"
31
34
  ],
32
35
  "dependencies": {
33
- "@magic/types": "0.1.22"
36
+ "@magic/types": "0.1.26"
34
37
  },
35
38
  "devDependencies": {
36
- "@magic/format": "0.0.41",
37
- "@magic/test": "0.2.12"
39
+ "@magic/format": "0.0.68",
40
+ "@magic/test": "0.2.20",
41
+ "@types/node": "24.5.2",
42
+ "typescript": "5.9.2"
38
43
  },
39
44
  "contributors": [
40
45
  {
package/src/flatten.js ADDED
@@ -0,0 +1,33 @@
1
+ import is from '@magic/types'
2
+
3
+ /**
4
+ * Flattens one level of an array if input is an array, otherwise returns the input as-is.
5
+ *
6
+ * @template T
7
+ * @param {T | T[]} flat - An array or value to flatten.
8
+ * @returns {T[]} The flattened value or array.
9
+ */
10
+ export const shallow = flat => (is.array(flat) ? flatten(...flat) : [flat])
11
+
12
+ /**
13
+ * Concatenates a flat array with another deep value or array.
14
+ *
15
+ * @template T
16
+ * @param {T[]} flat - The flat array to concatenate into.
17
+ * @param {T | T[]} deep - A value or array to be flattened and concatenated.
18
+ * @returns {T[]} The concatenated array.
19
+ */
20
+ export const concat = (flat, deep) => flat.concat(shallow(deep))
21
+
22
+ /**
23
+ * Recursively flattens one or more arrays into a single-level array.
24
+ *
25
+ * @template T
26
+ * @param {...(T | T[])} arr - The arrays or values to flatten.
27
+ * @returns {T[]} The flattened array.
28
+ */
29
+ export const flatten = (...arr) =>
30
+ /** @type {T[]} */ (arr.reduce(/** @type {any} */ (concat), /** @type {T[]} */ ([])))
31
+
32
+ /** @type {(arr: any[]) => any[]} */
33
+ export default flatten
@@ -1,8 +1,8 @@
1
1
  import is from '@magic/types'
2
2
 
3
- import { loop as lo } from './loop.mjs'
4
- import { merge as me } from './merge.mjs'
5
- import { flatten as fl } from './flatten.mjs'
3
+ import { loop as lo } from './loop.js'
4
+ import { merge as me } from './merge.js'
5
+ import { flatten as fl } from './flatten.js'
6
6
 
7
7
  export const equal = is.deep.equal
8
8
  export const equals = is.deep.equal
package/src/loop.js ADDED
@@ -0,0 +1,94 @@
1
+ import is from '@magic/types'
2
+
3
+ /**
4
+ * Recursively applies a function to items or transforms items based on conditions.
5
+ *
6
+ * @template T, R
7
+ * @param {((item: T) => R) | T} fn - Function to apply or the first item.
8
+ * @param {...any} items - Items to loop over (can be nested arrays).
9
+ * @returns {any} The transformed result, array of results, or undefined.
10
+ */
11
+ export const loop = (fn, ...items) => {
12
+ // If no arguments, return undefined
13
+ if (!fn && items.length === 0) {
14
+ return undefined
15
+ }
16
+
17
+ // If only function provided, return undefined
18
+ if (is.function(fn) && items.length === 0) {
19
+ return undefined
20
+ }
21
+
22
+ let targets = items
23
+
24
+ // Check for argument swapping: if fn is not a function but we have items and one of them is a function
25
+ if (!is.function(fn) && items.length > 0) {
26
+ const functionIndex = items.findIndex(item => is.function(item))
27
+ if (functionIndex !== -1) {
28
+ // Swap: fn becomes the target, and the function becomes fn
29
+ const actualFn = items[functionIndex]
30
+ targets = [fn, ...items.slice(0, functionIndex), ...items.slice(functionIndex + 1)]
31
+ fn = actualFn
32
+ }
33
+ }
34
+
35
+ // Handle the case where we have multiple items but one of them is an object (options)
36
+ if (is.array(targets) && targets.length > 1) {
37
+ // Check if any item is an object (options pattern)
38
+ const hasOptions = targets.some(item => is.object(item) && !is.array(item))
39
+
40
+ if (hasOptions && is.function(fn)) {
41
+ // Apply function to each item
42
+ return targets.map(item => {
43
+ if (is.array(item)) {
44
+ return item.map(subItem => loop(fn, subItem))
45
+ }
46
+ return is.object(item) && !is.array(item)
47
+ ? item
48
+ : /** @type {(item: any) => any} */ (fn)(item)
49
+ })
50
+ }
51
+
52
+ if (!is.function(fn)) {
53
+ return [fn, ...targets]
54
+ }
55
+
56
+ // Apply function to multiple items
57
+ return targets.map(item => {
58
+ if (is.array(item)) {
59
+ return item.map(subItem => loop(fn, subItem))
60
+ }
61
+ return /** @type {(item: any) => any} */ (fn)(item)
62
+ })
63
+ }
64
+
65
+ // Single item case - if targets is an array with one element, unwrap it
66
+ if (is.array(targets) && targets.length === 1) {
67
+ targets = /** @type {any} */ (targets[0])
68
+ }
69
+
70
+ // If fn is not a function, return tuple
71
+ if (!is.function(fn)) {
72
+ return [fn, targets]
73
+ }
74
+
75
+ // If targets is null/undefined, apply function directly
76
+ if (!targets) {
77
+ return fn(targets)
78
+ }
79
+
80
+ // If targets has map method (is array-like), map over it
81
+ if (is.array(targets)) {
82
+ return targets.map(item => {
83
+ if (is.array(item)) {
84
+ return loop(fn, item)
85
+ }
86
+ return /** @type {(item: any) => any} */ (fn)(item)
87
+ })
88
+ }
89
+
90
+ // For non-array targets, apply function directly
91
+ return /** @type {(item: any) => any} */ (fn)(targets)
92
+ }
93
+
94
+ export default loop
@@ -1,5 +1,14 @@
1
1
  import is from '@magic/types'
2
2
 
3
+ /**
4
+ * Recursively merges two values or objects.
5
+ *
6
+ * @template T
7
+ * @template U
8
+ * @param {T} o1 - First value or object.
9
+ * @param {U} o2 - Second value or object.
10
+ * @returns {any} Merged result.
11
+ */
3
12
  export const merge = (o1, o2) => {
4
13
  if (is.undefined(o1)) {
5
14
  return o2
@@ -8,15 +17,16 @@ export const merge = (o1, o2) => {
8
17
  }
9
18
 
10
19
  if (is.array(o1)) {
11
- return o1.concat(o2)
20
+ return is.array(o2)
21
+ ? /** @type {any[]} */ (o1).concat(/** @type {any[]} */ (o2))
22
+ : /** @type {any[]} */ (o1).concat([o2])
12
23
  } else if (is.array(o2)) {
13
- return [].concat(o1, ...o2)
24
+ return [o1].concat(/** @type {any[]} */ (o2))
14
25
  }
15
26
 
16
27
  if (is.mergeable(o1) && is.mergeable(o2)) {
17
28
  const keys = Object.keys({ ...o1, ...o2 })
18
- const final = {}
19
-
29
+ const final = /** @type {Record<string, any>} */ ({})
20
30
  keys.forEach(key => {
21
31
  if (!is.function(o2.hasOwnProperty) || !o2.hasOwnProperty(key)) {
22
32
  final[key] = o1[key]
@@ -24,7 +34,6 @@ export const merge = (o1, o2) => {
24
34
  final[key] = merge(o1[key], o2[key])
25
35
  }
26
36
  })
27
-
28
37
  return final
29
38
  }
30
39
 
package/src/flatten.mjs DELETED
@@ -1,9 +0,0 @@
1
- import is from '@magic/types'
2
-
3
- export const shallow = flat => (is.array(flat) ? flatten(...flat) : flat)
4
-
5
- export const concat = (flat, deep) => flat.concat(shallow(deep))
6
-
7
- export const flatten = (...arr) => arr.reduce(concat, [])
8
-
9
- export default flatten
package/src/loop.mjs DELETED
@@ -1,35 +0,0 @@
1
- import is from '@magic/types'
2
-
3
- export const loop = (fn, ...items) => {
4
- if (is.empty(items)) {
5
- if (is.fn(fn)) {
6
- return fn(...items)
7
- }
8
-
9
- return
10
- } else if (items.length === 1) {
11
- items = items[0]
12
- }
13
-
14
- if (!is.function(fn) && is.function(items)) {
15
- const oldFn = fn
16
- fn = items
17
- items = oldFn
18
- }
19
-
20
- if (!is.function(fn)) {
21
- return [fn, items]
22
- }
23
-
24
- if (!items) {
25
- return fn(items)
26
- }
27
-
28
- if (!is.function(items.map)) {
29
- return fn(items)
30
- }
31
-
32
- return items.map(item => loop(fn, item))
33
- }
34
-
35
- export default loop