New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

tree-climber

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tree-climber - npm Package Compare versions

Comparing version

to
1.2.0

98

lib/climber.js

@@ -5,2 +5,3 @@ 'use strict';

var Promise = require('promise');
var format = require('util').format;

@@ -17,6 +18,9 @@ module.exports = {

* @param {Function} visitor
* @param {String} [sep]
*/
function climb (tree, visitor) {
function climb (tree, visitor, sep) {
var visited = [];
sep = sep || '.';
(function climber (value, key, path) {

@@ -31,3 +35,3 @@ if (isNode(value)) {

edgeTraverser(value, function handleEdge (childValue, key) {
climber(childValue, key, calculatePath(path, key));
climber(childValue, key, calculatePath(path, key, sep));
});

@@ -47,54 +51,60 @@ }

* @param {Function} visitor
* @param {String} [sep]
* @returns {Promise} A promise fulfilled when all nodes have been resolved.
*/
function climbAsync (tree, visitor) {
function climbAsync (tree, visitor, sep) {
var allPromises = [];
var paths = {};
sep = sep || '.';
climb(tree, function (key, value, path) {
var boundVisitor = visitor.bind(null, key, value, path);
var pathParts = path.split('.').slice(0, -1);
pathParts.unshift('_ROOT');
var pathToNode = pathParts.join('.');
var newPromise;
try {
climb(tree, function (key, value, path) {
var boundVisitor = visitor.bind(null, key, value, path);
var pathParts = path.split(sep).slice(0, -1);
pathParts.unshift('_ROOT');
var pathToNode = pathParts.join(sep);
var newPromise;
Object.keys(paths).sort(sorter).some(function chainOffSlot (storedPath) {
var containsPath = pathToNode.indexOf(storedPath) === 0;
Object.keys(paths).sort(sorter).some(function chainOffSlot (storedPath) {
var containsPath = pathToNode.indexOf(storedPath) === 0;
if (containsPath)
newPromise = paths[storedPath].then(boundVisitor);
if (containsPath)
newPromise = paths[storedPath].then(boundVisitor);
return containsPath;
});
return containsPath;
});
pathParts.reduce(function fillEmptySlots (currentPath, part) {
currentPath = (!currentPath ? part : [currentPath, part].join('.'));
pathParts.reduce(function fillEmptySlots (currentPath, part) {
currentPath = (!currentPath ? part : [currentPath, part].join(sep));
if (!paths[currentPath])
paths[currentPath] = newPromise || (newPromise = boundVisitor());
if (!paths[currentPath])
paths[currentPath] = newPromise || (newPromise = boundVisitor());
return currentPath;
}, null);
return currentPath;
}, null);
/**
* Sorts the paths from longest to shortest.
* @param {String} a
* @param {String} b
* @returns {Number}
*/
function sorter (a, b) {
return getPathLength(b) - getPathLength(a);
}
/**
* Sorts the paths from longest to shortest.
* @param {String} a
* @param {String} b
* @returns {Number}
*/
function sorter (a, b) {
return getPathLength(b) - getPathLength(a);
}
/**
* Returns the number of path separators (.) in a string
* @param {String} path
* @returns {Number}
*/
function getPathLength (path) {
return path.split('.').length;
}
/**
* Returns the number of path separators (.) in a string
* @param {String} path
* @returns {Number}
*/
function getPathLength (path) {
return path.split(sep).length;
}
allPromises.push(newPromise);
});
allPromises.push(newPromise);
}, sep);
} catch (error) {
return Promise.reject(error);
}

@@ -108,9 +118,13 @@ return Promise.all(allPromises);

* @param {String} key
* @param {String} sep
* @returns {String}
*/
function calculatePath (path, key) {
function calculatePath (path, key, sep) {
if (key.indexOf(sep) !== -1)
throw new Error(format('Key cannot contain a %s character.', sep));
if (!path)
return key;
else
return path + '.' + key;
return path + sep + key;
}

@@ -117,0 +131,0 @@

{
"name": "tree-climber",
"version": "1.1.0",
"version": "1.2.0",
"description": "Traverses a JavaScript tree like structure. Calls a callback when visiting each node with the key, value, and current tree path.",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -65,7 +65,7 @@ Tree Climber

. `obj` {Array|Object} The "tree" to visit each node on.
. `visitor` {Function} Called when visiting a node.
. `key` {String} The key of this node.
. `value` {Mixed} The value of this node.
. `path` {String} The full path of the tree to this node.
* `obj` {Array|Object} The "tree" to visit each node on.
* `visitor` {Function} Called when visiting a node.
* `key` {String} The key of this node.
* `value` {Mixed} The value of this node.
* `path` {String} The full path of the tree to this node.

@@ -75,8 +75,8 @@ tree.climbAsync(obj, visitor)

. `obj` {Array|Object} The "tree" to visit each node on.
. `visitor` {Function} Called when visiting a node.
. `key` {String} The key of this node.
. `value` {Mixed} The value of this node.
. `path` {String} The full path of the tree to this node.
. return: {Promise} A promise to pend resolving other nodes in the tree on.
* `obj` {Array|Object} The "tree" to visit each node on.
* `visitor` {Function} Called when visiting a node.
* `key` {String} The key of this node.
* `value` {Mixed} The value of this node.
* `path` {String} The full path of the tree to this node.
* return: {Promise} A promise to pend resolving other nodes in the tree on.

@@ -83,0 +83,0 @@ Allows the user to perform asynchronous work on each node of the tree. Chains promises

@@ -107,2 +107,14 @@ 'use strict';

it('should let the sep be overridden', function () {
climb([
{
a: {
b: 'c'
}
}
], visitor, '/');
expect(visitor).toHaveBeenCalledWith('b', 'c', '0/a/b');
});
it('should throw if a cycle is detected', function () {

@@ -123,2 +135,16 @@ var obj = {

});
it('should throw if a separator is used in the key', function () {
var obj = {
'a.b': {
c: 'd'
}
};
expect(shouldThrow).toThrow(new Error('Key cannot contain a . character.'));
function shouldThrow () {
climb(obj, visitor);
}
});
});

@@ -185,2 +211,18 @@ });

it('should reject if a separator character is used in a key', function (done) {
var obj = {
'a.b': {
c: 'd'
}
};
climbAsync(obj, function visitor () {
return Promise.resolve('whatever');
})
.catch(function checkVisited (error) {
expect(error).toEqual(new Error('Key cannot contain a . character.'));
})
.done(done);
});
it('should visit all the nodes of a complex object in dependency order', function (done) {

@@ -233,2 +275,19 @@ climbAsync(complexObj, function visitor (key) {

});
it('should not visit any other nodes if f is rejected', function (done) {
climbAsync(complexObj, function visitor (key) {
visited.push(key);
if (key === 'f')
return new Promise(function (resolve, reject) {
reject();
});
else
return Promise.resolve('foo');
})
.catch(function () {
expect(visited).toEqual(['f']);
})
.done(done);
});
});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet