Skip to content

Commit

Permalink
new function walktree(); 1.9.0
Browse files Browse the repository at this point in the history
  • Loading branch information
andrasq committed Jan 9, 2021
1 parent a4ebb14 commit 196afaf
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 3 deletions.
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ Objects

### qibl.isHash( object )

Test whether the object is a generic hash `{}` ie `new Object()`, or is an instance of some
class. Tests the object constructor.
Test whether the object is a generic hash `{}` ie `new Object()` and return `true`, else `false`
if is an instance of some class. Tests the object constructor.

### qibl.isMethodContext( _this )

Expand Down Expand Up @@ -560,11 +560,19 @@ Errors accessing the visited files are reported out of band via 'error' events o
emitter, and the visitor is not called on them. The emitter does not throw, un-listened for
errors are ignored. Errors accessing the top-level `dirname` are returned to the callback.

### walktree( tree, visitor(value, name, node, depth) )

Recursively examine the properties of tree and call `visitor(node)` on each. `tree` may be any
value, but only `isHash` hashes are traversed. Like Array.forEach, the visitor is called with
the property value, the property name (index), the object whose property it is, plus `depth`,
the current level of property traversal, 1 for the direct properties of `tree`. If the visitor
returns `'skip'` the property is not recursed into, and if `'stop'` the traversal is halted.


Changelog
---------

- 1.9.0 - new `startsWith` / `endsWith`, document `str_locate`
- 1.9.0 - new `startsWith` / `endsWith`, document `str_locate`, new `walktree`
- 1.8.2 - optimize populate() separately for arrays and buffers,
omit empty strings from generated compileVinterpolate code, calibrate microtime longer
- 1.8.1 - tune microtime accuracy, fix setProperty readonly mode (undocumented)
Expand Down
18 changes: 18 additions & 0 deletions qibl.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ var qibl = module.exports = {
repeatUntil: repeatUntil,
repeatFor: repeatFor,
walkdir: walkdir,
walktree: walktree,
keys: keys,
values: values,
entries: entries,
Expand Down Expand Up @@ -789,6 +790,23 @@ function walkdir( dirname, visitor, callback ) {
function pathJoin(dirname, filename) { return filename === null ? dirname : dirname + '/' + filename }
}

/*
* Recursively visit all nodes in the tree and parade them in front of visitor().
* Behaves like an Array.forEach for recursive objects: visitor is passed value, index and object.
* Does not traverse arrays, functions, or class instances, just {} hash Objects.
*/
function walktree( tree, visitor ) {
_visitnodes(tree, visitor, { depth: 1, stop: false });
}
function _visitnodes( node, visitor, state ) {
if (qibl.isHash(node)) for (var k in node) {
var next = visitor(node[k], k, node, state.depth);
if (next === 'stop') state.stop = true;
else if (next !== 'skip') { state.depth += 1; _visitnodes(node[k], visitor, state); state.depth -= 1 }
if (state.stop) break;
}
}

// backslash-escape the chars that have special meaning in regex strings
// See also microrest, restiq.
function escapeRegex( str ) {
Expand Down
41 changes: 41 additions & 0 deletions test-qibl.js
Original file line number Diff line number Diff line change
Expand Up @@ -1712,6 +1712,47 @@ module.exports = {
},
},

'walktree': {
'recursively traverses object': function(t) {
var keys = [];
var tree = { a: 1, b: { ba: 2 }, c: 3};
qibl.walktree(tree, function(value, key, node) {
keys.push(key);
});
t.deepEqual(keys, ['a', 'b', 'ba', 'c']);
t.done();
},

'calls visitor with value, key, object, depth': function(t) {
var calls = [];
var tree = { a: 1, b: { ba: 2 }, c: 3 };
qibl.walktree(tree, function(v, k, o, depth) { calls.push({ v: v, k: k, o: o, depth: depth }) });
t.deepEqual(calls, [
{ v: 1, k: 'a', o: tree, depth: 1 },
{ v: { ba: 2 }, k: 'b', o: tree, depth: 1 },
{ v: 2, k: 'ba', o: { ba: 2 }, depth: 2 },
{ v: 3, k: 'c', o: tree, depth: 1 },
]);
t.done();
},

'stops early on stop': function(t) {
var keys = [];
var tree = { a: 1, b: { ba: 2 }, c: 3};
qibl.walktree(tree, function(v, k) { keys.push(k); return k === 'ba' ? 'stop' : null });
t.deepEqual(keys, ['a', 'b', 'ba']);
t.done();
},

'does not recurse on skip': function(t) {
var keys = [];
var tree = { a: 1, b: { ba: 2 }, c: 3};
qibl.walktree(tree, function(v, k) { keys.push(k); return 'skip' });
t.deepEqual(keys, ['a', 'b', 'c']);
t.done();
},
},

'escapeRegex': {
'should escape all metachars': function(t) {
var chars = [];
Expand Down

0 comments on commit 196afaf

Please sign in to comment.