@@ -66,7 +66,7 @@ function isWritable(object, key) {
66
66
return ! gopd ( object , key ) . writable ;
67
67
}
68
68
69
- function copy ( src ) {
69
+ function copy ( src , options ) {
70
70
if ( typeof src === 'object' && src !== null ) {
71
71
var dst ;
72
72
@@ -98,25 +98,28 @@ function copy(src) {
98
98
}
99
99
}
100
100
101
- forEach ( ownEnumerableKeys ( src ) , function ( key ) {
101
+ var iteratorFunction = options . includeSymbols ? ownEnumerableKeys : objectKeys ;
102
+ forEach ( iteratorFunction ( src ) , function ( key ) {
102
103
dst [ key ] = src [ key ] ;
103
104
} ) ;
104
105
return dst ;
105
106
}
106
107
return src ;
107
108
}
108
109
110
+ /** @type {TraverseOptions } */
109
111
var emptyNull = { __proto__ : null } ;
110
112
111
113
function walk ( root , cb ) {
112
114
var path = [ ] ;
113
115
var parents = [ ] ;
114
116
var alive = true ;
115
117
var options = arguments . length > 2 ? arguments [ 2 ] : emptyNull ;
118
+ var iteratorFunction = options . includeSymbols ? ownEnumerableKeys : objectKeys ;
116
119
var immutable = ! ! options . immutable ;
117
120
118
121
return ( function walker ( node_ ) {
119
- var node = immutable ? copy ( node_ ) : node_ ;
122
+ var node = immutable ? copy ( node_ , options ) : node_ ;
120
123
var modifiers = { } ;
121
124
122
125
var keepGoing = true ;
@@ -164,7 +167,7 @@ function walk(root, cb) {
164
167
function updateState ( ) {
165
168
if ( typeof state . node === 'object' && state . node !== null ) {
166
169
if ( ! state . keys || state . node_ !== state . node ) {
167
- state . keys = ownEnumerableKeys ( state . node ) ;
170
+ state . keys = iteratorFunction ( state . node ) ;
168
171
}
169
172
170
173
state . isLeaf = state . keys . length === 0 ;
@@ -233,27 +236,42 @@ function walk(root, cb) {
233
236
} ( root ) ) . node ;
234
237
}
235
238
239
+ /** @typedef {{ immutable?: boolean, includeSymbols?: boolean } } TraverseOptions */
240
+
241
+ /**
242
+ * A traverse constructor
243
+ * @param {object } obj - the object to traverse
244
+ * @param {TraverseOptions | undefined } [options] - options for the traverse
245
+ * @constructor
246
+ */
236
247
function Traverse ( obj ) {
248
+ /** @type {TraverseOptions } */
249
+ this . options = arguments . length > 1 ? arguments [ 1 ] : emptyNull ;
237
250
this . value = obj ;
238
251
}
239
252
253
+ /** @type {(ps: PropertyKey[]) => Traverse['value'] } */
240
254
Traverse . prototype . get = function ( ps ) {
241
255
var node = this . value ;
242
- for ( var i = 0 ; i < ps . length ; i ++ ) {
256
+ for ( var i = 0 ; node && i < ps . length ; i ++ ) {
243
257
var key = ps [ i ] ;
244
- if ( ! node || ! hasOwnProperty . call ( node , key ) ) {
258
+ if (
259
+ ! hasOwnProperty . call ( node , key )
260
+ || ( ! this . options . includeSymbols && typeof key === 'symbol' )
261
+ ) {
245
262
return void undefined ;
246
263
}
247
264
node = node [ key ] ;
248
265
}
249
266
return node ;
250
267
} ;
251
268
269
+ /** @type {(ps: PropertyKey[]) => boolean } */
252
270
Traverse . prototype . has = function ( ps ) {
253
271
var node = this . value ;
254
- for ( var i = 0 ; i < ps . length ; i ++ ) {
272
+ for ( var i = 0 ; node && i < ps . length ; i ++ ) {
255
273
var key = ps [ i ] ;
256
- if ( ! node || ! hasOwnProperty . call ( node , key ) ) {
274
+ if ( ! hasOwnProperty . call ( node , key ) || ( ! this . options . includeSymbols && typeof key === 'symbol' ) ) {
257
275
return false ;
258
276
}
259
277
node = node [ key ] ;
@@ -272,14 +290,12 @@ Traverse.prototype.set = function (ps, value) {
272
290
return value ;
273
291
} ;
274
292
275
- var immutableOpts = { __proto__ : null , immutable : true } ;
276
-
277
293
Traverse . prototype . map = function ( cb ) {
278
- return walk ( this . value , cb , immutableOpts ) ;
294
+ return walk ( this . value , cb , { __proto__ : null , immutable : true , includeSymbols : ! ! this . options . includeSymbols } ) ;
279
295
} ;
280
296
281
297
Traverse . prototype . forEach = function ( cb ) {
282
- this . value = walk ( this . value , cb ) ;
298
+ this . value = walk ( this . value , cb , this . options ) ;
283
299
return this . value ;
284
300
} ;
285
301
@@ -313,6 +329,7 @@ Traverse.prototype.nodes = function () {
313
329
Traverse . prototype . clone = function ( ) {
314
330
var parents = [ ] ;
315
331
var nodes = [ ] ;
332
+ var options = this . options ;
316
333
317
334
if ( whichTypedArray ( this . value ) ) {
318
335
return taSlice ( this . value ) ;
@@ -326,12 +343,13 @@ Traverse.prototype.clone = function () {
326
343
}
327
344
328
345
if ( typeof src === 'object' && src !== null ) {
329
- var dst = copy ( src ) ;
346
+ var dst = copy ( src , options ) ;
330
347
331
348
parents . push ( src ) ;
332
349
nodes . push ( dst ) ;
333
350
334
- forEach ( ownEnumerableKeys ( src ) , function ( key ) {
351
+ var iteratorFunction = options . includeSymbols ? ownEnumerableKeys : objectKeys ;
352
+ forEach ( iteratorFunction ( src ) , function ( key ) {
335
353
dst [ key ] = clone ( src [ key ] ) ;
336
354
} ) ;
337
355
@@ -345,8 +363,10 @@ Traverse.prototype.clone = function () {
345
363
} ( this . value ) ) ;
346
364
} ;
347
365
366
+ /** @type {(obj: object, options?: TraverseOptions) => Traverse } */
348
367
function traverse ( obj ) {
349
- return new Traverse ( obj ) ;
368
+ var options = arguments . length > 1 ? arguments [ 1 ] : emptyNull ;
369
+ return new Traverse ( obj , options ) ;
350
370
}
351
371
352
372
// TODO: replace with object.assign?
0 commit comments