Skip to content

Commit aab373f

Browse files
MartyJREljharb
andcommitted
[New] [Fix] add includeSymbols option; partial revert of "[New] support enumerable Symbol properties"
This partially reverts commit 7d659e7. Co-authored-by: Martin Pražák <[email protected]> Co-authored-by: Jordan Harband <[email protected]>
1 parent 7539473 commit aab373f

File tree

3 files changed

+56
-20
lines changed

3 files changed

+56
-20
lines changed

.eslintrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"no-invalid-this": 0,
2020
"object-curly-newline": 0,
2121
"sort-keys": 0,
22+
"max-lines": "warn",
2223
},
2324

2425
"overrides": [

index.js

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ function isWritable(object, key) {
6666
return !gopd(object, key).writable;
6767
}
6868

69-
function copy(src) {
69+
function copy(src, options) {
7070
if (typeof src === 'object' && src !== null) {
7171
var dst;
7272

@@ -98,25 +98,28 @@ function copy(src) {
9898
}
9999
}
100100

101-
forEach(ownEnumerableKeys(src), function (key) {
101+
var iteratorFunction = options.includeSymbols ? ownEnumerableKeys : objectKeys;
102+
forEach(iteratorFunction(src), function (key) {
102103
dst[key] = src[key];
103104
});
104105
return dst;
105106
}
106107
return src;
107108
}
108109

110+
/** @type {TraverseOptions} */
109111
var emptyNull = { __proto__: null };
110112

111113
function walk(root, cb) {
112114
var path = [];
113115
var parents = [];
114116
var alive = true;
115117
var options = arguments.length > 2 ? arguments[2] : emptyNull;
118+
var iteratorFunction = options.includeSymbols ? ownEnumerableKeys : objectKeys;
116119
var immutable = !!options.immutable;
117120

118121
return (function walker(node_) {
119-
var node = immutable ? copy(node_) : node_;
122+
var node = immutable ? copy(node_, options) : node_;
120123
var modifiers = {};
121124

122125
var keepGoing = true;
@@ -164,7 +167,7 @@ function walk(root, cb) {
164167
function updateState() {
165168
if (typeof state.node === 'object' && state.node !== null) {
166169
if (!state.keys || state.node_ !== state.node) {
167-
state.keys = ownEnumerableKeys(state.node);
170+
state.keys = iteratorFunction(state.node);
168171
}
169172

170173
state.isLeaf = state.keys.length === 0;
@@ -233,27 +236,42 @@ function walk(root, cb) {
233236
}(root)).node;
234237
}
235238

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+
*/
236247
function Traverse(obj) {
248+
/** @type {TraverseOptions} */
249+
this.options = arguments.length > 1 ? arguments[1] : emptyNull;
237250
this.value = obj;
238251
}
239252

253+
/** @type {(ps: PropertyKey[]) => Traverse['value']} */
240254
Traverse.prototype.get = function (ps) {
241255
var node = this.value;
242-
for (var i = 0; i < ps.length; i++) {
256+
for (var i = 0; node && i < ps.length; i++) {
243257
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+
) {
245262
return void undefined;
246263
}
247264
node = node[key];
248265
}
249266
return node;
250267
};
251268

269+
/** @type {(ps: PropertyKey[]) => boolean} */
252270
Traverse.prototype.has = function (ps) {
253271
var node = this.value;
254-
for (var i = 0; i < ps.length; i++) {
272+
for (var i = 0; node && i < ps.length; i++) {
255273
var key = ps[i];
256-
if (!node || !hasOwnProperty.call(node, key)) {
274+
if (!hasOwnProperty.call(node, key) || (!this.options.includeSymbols && typeof key === 'symbol')) {
257275
return false;
258276
}
259277
node = node[key];
@@ -272,14 +290,12 @@ Traverse.prototype.set = function (ps, value) {
272290
return value;
273291
};
274292

275-
var immutableOpts = { __proto__: null, immutable: true };
276-
277293
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 });
279295
};
280296

281297
Traverse.prototype.forEach = function (cb) {
282-
this.value = walk(this.value, cb);
298+
this.value = walk(this.value, cb, this.options);
283299
return this.value;
284300
};
285301

@@ -313,6 +329,7 @@ Traverse.prototype.nodes = function () {
313329
Traverse.prototype.clone = function () {
314330
var parents = [];
315331
var nodes = [];
332+
var options = this.options;
316333

317334
if (whichTypedArray(this.value)) {
318335
return taSlice(this.value);
@@ -326,12 +343,13 @@ Traverse.prototype.clone = function () {
326343
}
327344

328345
if (typeof src === 'object' && src !== null) {
329-
var dst = copy(src);
346+
var dst = copy(src, options);
330347

331348
parents.push(src);
332349
nodes.push(dst);
333350

334-
forEach(ownEnumerableKeys(src), function (key) {
351+
var iteratorFunction = options.includeSymbols ? ownEnumerableKeys : objectKeys;
352+
forEach(iteratorFunction(src), function (key) {
335353
dst[key] = clone(src[key]);
336354
});
337355

@@ -345,8 +363,10 @@ Traverse.prototype.clone = function () {
345363
}(this.value));
346364
};
347365

366+
/** @type {(obj: object, options?: TraverseOptions) => Traverse} */
348367
function traverse(obj) {
349-
return new Traverse(obj);
368+
var options = arguments.length > 1 ? arguments[1] : emptyNull;
369+
return new Traverse(obj, options);
350370
}
351371

352372
// TODO: replace with object.assign?

test/has.js

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,29 @@ test('has', function (t) {
2323
obj[globalSymbol][localSymbol] = 7;
2424
obj[localSymbol] = 8;
2525

26-
st.equal(traverse(obj).has([globalSymbol]), true);
26+
st.equal(traverse(obj).has([globalSymbol]), false);
27+
st.equal(traverse(obj, { includeSymbols: true }).has([globalSymbol]), true);
28+
2729
st.equal(traverse(obj).has([globalSymbol, globalSymbol]), false);
28-
st.equal(traverse(obj).has([globalSymbol, localSymbol]), true);
29-
st.equal(traverse(obj).has([localSymbol]), true);
30-
st.equal(traverse(obj).has([localSymbol]), true);
30+
st.equal(traverse(obj, { includeSymbols: true }).has([globalSymbol, globalSymbol]), false);
31+
32+
st.equal(traverse(obj).has([globalSymbol, localSymbol]), false);
33+
st.equal(traverse(obj, { includeSymbols: true }).has([globalSymbol, localSymbol]), true);
34+
35+
st.equal(traverse(obj).has([localSymbol]), false);
36+
st.equal(traverse(obj, { includeSymbols: true }).has([localSymbol]), true);
37+
38+
st.equal(traverse(obj).has([Symbol('d')]), false);
39+
st.equal(traverse(obj, { includeSymbols: true }).has([Symbol('d')]), false);
40+
3141
st.equal(traverse(obj).has([Symbol('e')]), false);
32-
st.equal(traverse(obj).has([Symbol.for('d')]), true);
42+
st.equal(traverse(obj, { includeSymbols: true }).has([Symbol('e')]), false);
43+
44+
st.equal(traverse(obj).has([Symbol.for('d')]), false);
45+
st.equal(traverse(obj, { includeSymbols: true }).has([Symbol.for('d')]), true);
46+
3347
st.equal(traverse(obj).has([Symbol.for('e')]), false);
48+
st.equal(traverse(obj, { includeSymbols: true }).has([Symbol.for('e')]), false);
3449

3550
st.end();
3651
});

0 commit comments

Comments
 (0)