Skip to content

Commit

Permalink
[New] [Fix] add includeSymbols option; partial revert of "[New] sup…
Browse files Browse the repository at this point in the history
…port enumerable Symbol properties"

This partially reverts commit 7d659e7.

Co-authored-by: Martin Pražák <[email protected]>
Co-authored-by: Jordan Harband <[email protected]>
  • Loading branch information
MartyJRE and ljharb committed Mar 11, 2024
1 parent 7539473 commit aab373f
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 20 deletions.
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"no-invalid-this": 0,
"object-curly-newline": 0,
"sort-keys": 0,
"max-lines": "warn",
},

"overrides": [
Expand Down
50 changes: 35 additions & 15 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ function isWritable(object, key) {
return !gopd(object, key).writable;
}

function copy(src) {
function copy(src, options) {
if (typeof src === 'object' && src !== null) {
var dst;

Expand Down Expand Up @@ -98,25 +98,28 @@ function copy(src) {
}
}

forEach(ownEnumerableKeys(src), function (key) {
var iteratorFunction = options.includeSymbols ? ownEnumerableKeys : objectKeys;
forEach(iteratorFunction(src), function (key) {
dst[key] = src[key];
});
return dst;
}
return src;
}

/** @type {TraverseOptions} */
var emptyNull = { __proto__: null };

function walk(root, cb) {
var path = [];
var parents = [];
var alive = true;
var options = arguments.length > 2 ? arguments[2] : emptyNull;
var iteratorFunction = options.includeSymbols ? ownEnumerableKeys : objectKeys;
var immutable = !!options.immutable;

return (function walker(node_) {
var node = immutable ? copy(node_) : node_;
var node = immutable ? copy(node_, options) : node_;
var modifiers = {};

var keepGoing = true;
Expand Down Expand Up @@ -164,7 +167,7 @@ function walk(root, cb) {
function updateState() {
if (typeof state.node === 'object' && state.node !== null) {
if (!state.keys || state.node_ !== state.node) {
state.keys = ownEnumerableKeys(state.node);
state.keys = iteratorFunction(state.node);
}

state.isLeaf = state.keys.length === 0;
Expand Down Expand Up @@ -233,27 +236,42 @@ function walk(root, cb) {
}(root)).node;
}

/** @typedef {{ immutable?: boolean, includeSymbols?: boolean }} TraverseOptions */

/**
* A traverse constructor
* @param {object} obj - the object to traverse
* @param {TraverseOptions | undefined} [options] - options for the traverse
* @constructor
*/
function Traverse(obj) {
/** @type {TraverseOptions} */
this.options = arguments.length > 1 ? arguments[1] : emptyNull;
this.value = obj;
}

/** @type {(ps: PropertyKey[]) => Traverse['value']} */
Traverse.prototype.get = function (ps) {
var node = this.value;
for (var i = 0; i < ps.length; i++) {
for (var i = 0; node && i < ps.length; i++) {
var key = ps[i];
if (!node || !hasOwnProperty.call(node, key)) {
if (
!hasOwnProperty.call(node, key)
|| (!this.options.includeSymbols && typeof key === 'symbol')
) {
return void undefined;
}
node = node[key];
}
return node;
};

/** @type {(ps: PropertyKey[]) => boolean} */
Traverse.prototype.has = function (ps) {
var node = this.value;
for (var i = 0; i < ps.length; i++) {
for (var i = 0; node && i < ps.length; i++) {
var key = ps[i];
if (!node || !hasOwnProperty.call(node, key)) {
if (!hasOwnProperty.call(node, key) || (!this.options.includeSymbols && typeof key === 'symbol')) {
return false;
}
node = node[key];
Expand All @@ -272,14 +290,12 @@ Traverse.prototype.set = function (ps, value) {
return value;
};

var immutableOpts = { __proto__: null, immutable: true };

Traverse.prototype.map = function (cb) {
return walk(this.value, cb, immutableOpts);
return walk(this.value, cb, { __proto__: null, immutable: true, includeSymbols: !!this.options.includeSymbols });
};

Traverse.prototype.forEach = function (cb) {
this.value = walk(this.value, cb);
this.value = walk(this.value, cb, this.options);
return this.value;
};

Expand Down Expand Up @@ -313,6 +329,7 @@ Traverse.prototype.nodes = function () {
Traverse.prototype.clone = function () {
var parents = [];
var nodes = [];
var options = this.options;

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

if (typeof src === 'object' && src !== null) {
var dst = copy(src);
var dst = copy(src, options);

parents.push(src);
nodes.push(dst);

forEach(ownEnumerableKeys(src), function (key) {
var iteratorFunction = options.includeSymbols ? ownEnumerableKeys : objectKeys;
forEach(iteratorFunction(src), function (key) {
dst[key] = clone(src[key]);
});

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

/** @type {(obj: object, options?: TraverseOptions) => Traverse} */
function traverse(obj) {
return new Traverse(obj);
var options = arguments.length > 1 ? arguments[1] : emptyNull;
return new Traverse(obj, options);
}

// TODO: replace with object.assign?
Expand Down
25 changes: 20 additions & 5 deletions test/has.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,29 @@ test('has', function (t) {
obj[globalSymbol][localSymbol] = 7;
obj[localSymbol] = 8;

st.equal(traverse(obj).has([globalSymbol]), true);
st.equal(traverse(obj).has([globalSymbol]), false);
st.equal(traverse(obj, { includeSymbols: true }).has([globalSymbol]), true);

st.equal(traverse(obj).has([globalSymbol, globalSymbol]), false);
st.equal(traverse(obj).has([globalSymbol, localSymbol]), true);
st.equal(traverse(obj).has([localSymbol]), true);
st.equal(traverse(obj).has([localSymbol]), true);
st.equal(traverse(obj, { includeSymbols: true }).has([globalSymbol, globalSymbol]), false);

st.equal(traverse(obj).has([globalSymbol, localSymbol]), false);
st.equal(traverse(obj, { includeSymbols: true }).has([globalSymbol, localSymbol]), true);

st.equal(traverse(obj).has([localSymbol]), false);
st.equal(traverse(obj, { includeSymbols: true }).has([localSymbol]), true);

st.equal(traverse(obj).has([Symbol('d')]), false);
st.equal(traverse(obj, { includeSymbols: true }).has([Symbol('d')]), false);

st.equal(traverse(obj).has([Symbol('e')]), false);
st.equal(traverse(obj).has([Symbol.for('d')]), true);
st.equal(traverse(obj, { includeSymbols: true }).has([Symbol('e')]), false);

st.equal(traverse(obj).has([Symbol.for('d')]), false);
st.equal(traverse(obj, { includeSymbols: true }).has([Symbol.for('d')]), true);

st.equal(traverse(obj).has([Symbol.for('e')]), false);
st.equal(traverse(obj, { includeSymbols: true }).has([Symbol.for('e')]), false);

st.end();
});
Expand Down

0 comments on commit aab373f

Please sign in to comment.