@peter.naydenov/walk-async 3.0.6 → 3.0.7

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/Changelog.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
 
4
4
 
5
+ ### 3.0.7 (2026-07-07)
6
+ - [x] Fix: 'objectCallback' resolving the root object with a primitive value was crashing on null/undefined or producing broken results;
7
+ - [x] Fix: Own '__proto__' property was replacing the prototype of the copy instead of being copied as a regular property;
8
+
9
+
10
+
5
11
  ### 3.0.6 (2026-07-07)
6
12
  - [x] Fix: Top-level property named 'root' was flattened into the result or dropped;
7
13
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peter.naydenov/walk-async",
3
- "version": "3.0.6",
3
+ "version": "3.0.7",
4
4
  "description": "Deep copy with fine control during the process. Can be used also as a deep forEach function",
5
5
  "main": ".dist/walk-async.umd.js",
6
6
  "type": "module",
package/src/main.js CHANGED
@@ -43,31 +43,50 @@ function walk ({
43
43
  , objectCallback = null
44
44
  , keyCallback = null
45
45
  }, ...args ) {
46
- let
46
+ let
47
47
  type = findType ( origin )
48
48
  , result
49
49
  , extend = []
50
50
  , breadcrumbs = 'root'
51
51
  , cb = [ keyCallback, objectCallback ]
52
52
  , end = askForPromise ()
53
+ , rootTask = askForPromise ()
54
+ , IGNORE = Symbol ( 'ignore___' )
53
55
  ;
54
56
 
55
- switch ( type ) {
56
- case 'array' :
57
- result = []
58
- copyObject ( {root:origin}, result, extend, cb, breadcrumbs, true, ...args )
59
- .then ( () => goNext ( extend, result, end ))
60
- break
61
- case 'object' :
62
- result = {}
63
- copyObject ( {root:origin}, result, extend, cb, breadcrumbs, true, ...args )
64
- .then ( () => {
65
- goNext ( extend, result, end )
66
- })
67
- break
68
- case 'simple' :
69
- end.done ( origin )
70
- } // switch type
57
+ if ( type !== 'simple' && objectCallback ) { // Root object callback. Executed before the result is allocated, so it can replace the root with anything.
58
+ objectCallback ({
59
+ resolve : rootTask.done
60
+ , reject : () => rootTask.done ( IGNORE )
61
+ , value : origin
62
+ , key : 'root'
63
+ , breadcrumbs
64
+ }, ...args )
65
+ }
66
+ else rootTask.done ( origin )
67
+
68
+ rootTask.onComplete ( item => {
69
+ if ( item === IGNORE ) {
70
+ end.done ( ( type === 'array' ) ? [] : {} )
71
+ return
72
+ }
73
+ switch ( findType ( item ) ) {
74
+ case 'array' :
75
+ result = []
76
+ copyObject ( item, result, extend, cb, breadcrumbs, ...args )
77
+ .then ( () => goNext ( extend, result, end ))
78
+ break
79
+ case 'object' :
80
+ result = {}
81
+ copyObject ( item, result, extend, cb, breadcrumbs, ...args )
82
+ .then ( () => {
83
+ goNext ( extend, result, end )
84
+ })
85
+ break
86
+ case 'simple' :
87
+ end.done ( item )
88
+ } // switch type
89
+ })
71
90
  return end.promise
72
91
  } // walk func.
73
92
 
@@ -93,7 +112,7 @@ function findType ( x ) {
93
112
 
94
113
 
95
114
  async function* generateList ( data, location, ex, cb, breadcrumbs, args ) {
96
- yield await copyObject ( data , location, ex, cb, breadcrumbs, false, ...args )
115
+ yield await copyObject ( data , location, ex, cb, breadcrumbs, ...args )
97
116
  } // generateList func.
98
117
 
99
118
 
@@ -107,10 +126,16 @@ function validateForInsertion ( k, result ) {
107
126
 
108
127
 
109
128
 
110
- // 'isWrapper' is true only for the call from 'walk' where 'origin' is the
111
- // synthetic {root:origin} wrapper. Detecting the wrapper by its position in the
112
- // call chain (instead of by key name) keeps data keys named 'root' safe.
113
- function copyObject ( origin, result, extend, cb, breadcrumbs, isWrapper, ...args ) {
129
+ // Plain assignment of a '__proto__' key triggers the inherited setter and
130
+ // replaces the prototype of 'target' instead of creating an own property.
131
+ function setKey ( target, k, value ) {
132
+ if ( k === '__proto__' ) Object.defineProperty ( target, k, { value, enumerable:true, writable:true, configurable:true })
133
+ else target[k] = value
134
+ } // setKey func.
135
+
136
+
137
+
138
+ function copyObject ( origin, result, extend, cb, breadcrumbs, ...args ) {
114
139
  let
115
140
  [ keyCallback, objectCallback ] = cb
116
141
  , keys = Object.keys ( origin )
@@ -129,8 +154,7 @@ function copyObject ( origin, result, extend, cb, breadcrumbs, isWrapper, ...arg
129
154
  , resultIsArray = (findType (result) === 'array')
130
155
  , keyNumber = !isNaN ( k )
131
156
  , IGNORE = Symbol ( 'ignore___' )
132
- , isRoot = isWrapper // The wrapper has exactly one key: 'root'
133
- , br = isRoot ? 'root' : `${breadcrumbs}/${k}`
157
+ , br = `${breadcrumbs}/${k}`
134
158
  ;
135
159
 
136
160
  if ( hasObjectCallback ) {
@@ -178,12 +202,7 @@ function copyObject ( origin, result, extend, cb, breadcrumbs, isWrapper, ...arg
178
202
  }) // objectCallbackTask complete
179
203
 
180
204
  keyCallbackTask.onComplete ( value => {
181
- if ( isRoot ) {
182
- extend.push ( generateList ( item, result, extend, cb, 'root', args ) )
183
- executeCallback.promises[i].done ( 'root' )
184
- return
185
- }
186
- if ( value == IGNORE ) {
205
+ if ( value == IGNORE ) {
187
206
  executeCallback.promises[i].done ( 'ignore key' )
188
207
  return
189
208
  }
@@ -198,7 +217,7 @@ function copyObject ( origin, result, extend, cb, breadcrumbs, isWrapper, ...arg
198
217
  if ( type === 'simple' ) {
199
218
  const canInsert = validateForInsertion ( k, result )
200
219
  if ( canInsert ) result.push ( item )
201
- else result [k] = item
220
+ else setKey ( result, k, item )
202
221
  executeCallback.promises[i].done ('key')
203
222
  return
204
223
  }
@@ -210,14 +229,14 @@ function copyObject ( origin, result, extend, cb, breadcrumbs, isWrapper, ...arg
210
229
  if ( type === 'object' ) {
211
230
  const newObject = {};
212
231
  if ( resultIsArray && keyNumber ) result.push ( newObject )
213
- else result[k] = newObject
232
+ else setKey ( result, k, newObject )
214
233
  extend.push ( generateList( item, newObject, extend, cb, br, args ) )
215
234
  executeCallback.promises[i].done ('object')
216
235
  }
217
236
  if ( type === 'array' ) {
218
237
  const newArray = [];
219
238
  if ( resultIsArray && keyNumber ) result.push ( newArray )
220
- else result[k] = newArray
239
+ else setKey ( result, k, newArray )
221
240
  extend.push ( generateList( item, newArray, extend, cb, br, args ) )
222
241
  executeCallback.promises[i].done ('array')
223
242
  }