Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
immutable-treeutils
Advanced tools
Functional tree traversal helpers for ImmutableJS data structures
1.2.0 |
This CommonJS module is a collection of helpers to access and traverse ImmutableJS tree data structure with a DOM-inspired interface.
It imposes some very basic conventions on your data structure, but I tried to make everything as low-level and configurable as possible. Still, a few conditions that need to be met remain:
Supports and tested against ImmutableJS versions ^4.0.0-rc.9 || >=3.8
.
Check the changelog for further information and migration instructions.
You probably should feel comfortable working with ImmutableJS data structures, so if you don't I strongly recommend you to get familiar with the concepts of ImmutableJS first.
As you already know, with ImmutableJS we retrieve nested values like this:
let map = Immutable.Map({a: { b: 'c' }});
map.getIn(['a', 'b']);
// 'c'
We could say that the key path to the value 'c'
is ['a', 'b']
.
Instead of an array you can also use Seq objects to describe key paths:
map.getIn(Immutable.Seq(['a', 'b']));
// 'c'
This might feel a little over the top at first but comes with a few advantages that are pivotal to TreeUtils. As a matter of fact, all the functions in this lib, that give you a node or a collection of nodes don't return the actual ImmutableJS values but the key paths to the substate where the resulting node(s) are located. A lot of operations become very trivial with key paths. Let's look at the parent function. Determining the parent of a given node represented by a key path is as simple as this:
let nodePath = Immutable.Seq(['data', 'childNodes', 0, 'childNodes', 1]);
let parentPath = nodePath.skipLast(2);
The actual retrieval of the ImmutableJS values is left to you, but you will notice that working with key paths can be quite fun. Imagine you want to get value at key content
of the next sibling of a given node. You could do this like so:
let keyPath = treeUtils.nextSibling(state, 'node-id');
let content = state.getIn(keyPath.concat('content'));
// or even shorter
let content = state.getIn(treeUtils.nextSibling(state, 'node-id').concat('name'));
Please note, that while ImmutableJS works well with Arrays as key paths, TreeUtils will only accept Seq objects as valid key paths.
TreeUtils works just fine with cursor libraries like immutable-cursor because cursors actually implement ImmutableJS interfaces.
TreeUtils doesn't provide mutation helpers, because IMHO the varietiy of use cases and implementations ist just too huge to spec a sensible API for that kind of thing. However, simple mutation functions can easily be implemented. An insert function could look something like this:
function insert(state, newNode, parentId, index) {
return state.updateIn(
tree.getById(state, parentId).concat('childNodes'),
childNodes => childNodes.splice(index, 0, newNode)
);
}
Install the package from npm:
npm install immutable-treeutils
Import the module and provide some state. Examples in the docs below refer to this data structure:
const Immutable = require('immutable');
// import Immutable from 'immutable';
const TreeUtils = require('immutable-treeutils');
// import TreeUtils from 'immutable-treeutils';
let treeUtils = new TreeUtils();
let data = Immutable.fromJS({
id: 'root',
name: 'My Documents',
type: 'folder',
childNodes: [
{
id: 'node-1',
name: 'Pictures',
type: 'folder',
childNodes: [
{
id: 'node-2',
name: 'Me in Paris',
type: 'image'
},
{
id: 'node-3',
name: 'Barbecue July 2015',
type: 'image'
}
]
},
{
id: 'node-4',
name: 'Music',
type: 'folder',
childNodes: [
{
id: 'node-5',
name: 'Pink Floyd - Wish You Were Here',
type: 'audio'
},
{
id: 'node-6',
name: 'The Doors - People Are Strange',
type: 'audio'
}
]
}
]
});
A collection of functional tree traversal helper functions for ImmutableJS data structures.
Example
var treeUtils = new TreeUtils(Immutable.Seq(['path', 'to', 'tree']));
With custom key accessors
var treeUtils = new TreeUtils(Immutable.Seq(['path', 'to', 'tree']), '__id', '__children');
With custom no result-default
var treeUtils = new TreeUtils(Immutable.Seq(['path', 'to', 'tree']), 'id', 'children', false);
Note
The first argument of every method of a TreeUtils
object is the state you want to analyse. I won't mention / explain it again in method descriptions bellow. The argument idOrKeyPath
also appears in most signatures, its purpose is thoroughly explained in the docs of byArbitrary.
new TreeUtils(
rootPath?: immutable.Seq,
idKey?: string,
childNodesKey?: string,
nonValue?: any
)
rootPath
- The path to the substate of your ImmutableJS state that represents the root node of your tree. Default: Immutable.Seq()
.idKey
- The name of the key that points at unique identifiers of all nodes in your tree . Default: 'id'
.childNodesKey
- The name of the key at which child nodes can be found. Default: 'childNodes'
.noneValue
- The value that will get returned if a query doesn't return any results. Default: undefined
.TreeUtils
objectMain traversal algorithm. Lets you walk over all nodes in the tree in no particular order.
walk(
state: Immutable.Iterable,
iterator: (
accumulator: any,
keyPath: Immutable.Seq<string|number>
stop: (
value: any
): any
): any,
path?: Immutable.Seq<string|number>
): any
iterator
- A function that gets passed an accumulator, the current key path and a stop function:
stop
call, the walk operation will return immediately, giving back any value you passed to the stop
function.path
- The key path that points at the root of the (sub)tree you want to walk over. Default: The TreeUtils
object's rootPath
.The result of the walk operation.
treeUtils.nodes(state).forEach(
keyPath =>
console.log(treeUtils.id(state, keyPath));
)
nodes(
state: Immutable.Iterable,
path?: Immutable.Seq<string|number>
): Immutable.List<Immutable.Seq<string|number>>
path
- The key path that points at the root of the (sub)tree whose descendants you want to iterate. Default: The TreeUtils
object's rootPath
.An unordered List of all key paths that point to nodes in the tree, including the root of the (sub)tree..
Returns the key path to the first node for which compatator
returns true
. Uses nodes internally and as nodes is an unordered List, you should probably use this to find unique occurences of data.
treeUtils.find(state, node => node.get('name') === 'Me in Paris');
// Seq ["childNodes", 0, "childNodes", 0]
find(
state: Immutable.Iterable,
comparator: (
node: Immutable.Iterable,
keyPath: Immutable.Seq<string|number>
): boolean,
path?: Immutable.Seq<string|number>
): Immutable.Seq<string|number>
comparator
- A function that gets passed a node
and its keyPath
and should return whether it fits the criteria or not.path?
- An optional key path to the (sub)state you want to analyse: Default: The TreeUtils
object's rootPath
.The key path to the first node for which comparator
returned true
.
Returns an List of key paths pointing at the nodes for which comparator
returned true
.
treeUtils.filter(state, node => node.get('type') === 'folder');
//List [ Seq[], Seq["childNodes", 0], Seq["childNodes", 1] ]
filter(
state: Immutable.Iterable,
comparator: (
node: Immutable.Iterable,
keyPath: Immutable.Seq<string|number>
): boolean,
path?: Immutable.Seq<string|number>
): List<Immutable.Seq<string|number>>
comparator
- A function that gets passed a node
and its keyPath
and should return whether it fits the criteria or not.path?
- An optional key path to the (sub)state you want to analyse: Default: The TreeUtils
object's rootPath
.A List of all the key paths that point at nodes for which comparator
returned true
.
Returns the key path to the node with id === id
.
id(
state: Immutable.Iterable,
id: string
): Immutable.Seq<string|number>
id
- A unique identifierThe key path to the node with id === id
.
Returns idOrKeyPath
if it is a Seq, else returns the result of byId for idOrKeyPath
. This is used in all other functions that work on a unique identifiers in order to reduce the number of lookup operations.
byArbitrary(
state: Immutable.Iterable,
idOrKeyPath: string|Immutable.Seq<string|number>
): Immutable.Seq<string|number>
The key path pointing at the node found for id === idOrKeyPath
or, if is a Seq, the idOrKeyPath
itself.
Returns the id for the node at keyPath
. Most useful when you want to get the id of the result of a previous tree query:
treeUtils.id(state, treeUtils.parent(state, 'node-3'));
// 'node-1'
id(
state: Immutable.Iterable,
keyPath: Immutable.Seq<string|number>
): string
keyPath
- The absolute key path to the substate / node whose id you want to retrieveThe unique identifier of the node at the given key path.
nextSibling(
state: Immutable.Iterable,
idOrKeyPath: string|Immutable.Seq<string|number>
): Immutable.Seq<string|number>
Returns the next sibling node of the node at idOrKeyPath
previousSibling(
state: Immutable.Iterable,
idOrKeyPath: string|Immutable.Seq<string|number>
): Immutable.Seq<string|number>
Returns the previous sibling node of the node at idOrKeyPath
firstChild(
state: Immutable.Iterable,
idOrKeyPath: string|Immutable.Seq<string|number>
): Immutable.Seq<string|number>
Returns the first child node of the node at idOrKeyPath
lastChild(
state: Immutable.Iterable,
idOrKeyPath: string|Immutable.Seq<string|number>
): Immutable.Seq<string|number>
Returns the last child node of the node at idOrKeyPath
siblings(
state: Immutable.Iterable,
idOrKeyPath: string|Immutable.Seq<string|number>
): Immutable.List<Immutable.Seq<string|number>>
Returns a List of key paths pointing at the sibling nodes of the node at idOrKeyPath
childNodes(
state: Immutable.Iterable,
idOrKeyPath: string|Immutable.Seq<string|number>
): Immutable.List<Immutable.Seq<string|number>>
Returns a List of all child nodes of the node at idOrKeyPath
childAt(
state: Immutable.Iterable,
idOrKeyPath: string|Immutable.Seq<string|number>,
index: number
): Immutable.Seq<string|number>
Returns the child node at position of index
of the node at idOrKeyPath
descendants(
state: Immutable.Iterable,
idOrKeyPath: string|Immutable.Seq<string|number>,
): Immutable.List<Immutable.Seq<string|number>>
Returns a list of key paths pointing at all descendants of the node at idOrKeyPath
childIndex(
state: Immutable.Iterable,
idOrKeyPath: string|Immutable.Seq<string|number>,
): number
Returns the index at which the node at idOrKeyPath
is positioned in its parent child nodes list.
hasChildNodes(
state: Immutable.Iterable,
idOrKeyPath: string|Immutable.Seq<string|number>,
): boolean
Returns whether the node at idOrKeyPath
has children.
numChildNodes(
state: Immutable.Iterable,
idOrKeyPath: string|Immutable.Seq<string|number>,
): number
Returns the number of child nodes the node at idOrKeyPath
has.
parent(
state: Immutable.Iterable,
idOrKeyPath: string|Immutable.Seq<string|number>,
): Immutable.Seq<string|number>
Returns the key path to the parent of the node at idOrKeyPath
.
ancestors(
state: Immutable.Iterable,
idOrKeyPath: string|Immutable.Seq<string|number>,
): Immutable.Seq<string|number>
An List of all key paths that point at direct ancestors of the node at idOrKeyPath
.
depth(
state: Immutable.Iterable,
idOrKeyPath: string|Immutable.Seq<string|number>,
): number
A numeric representation of the depth of the node at idOrKeyPath
This method is a very naive attempt to calculate a unqiue numeric position descriptor that can be used to compare two nodes for their absolute position in the tree.
treeUtils.position(state, 'node-4') > treeUtils.position(state, 'node-3');
// true
Please note that position
should not get used to do any comparison with the root node.
position(
state: Immutable.Iterable,
idOrKeyPath: string|Immutable.Seq<string|number>,
): number
Returns a unique numeric value that represents the absolute position of the node at idOrKeyPath
.
Returns the key path to the next node to the right. The next right node is either:
var nodePath = treeUtils.byId(state, 'root');
while (nodePath) {
console.log(nodePath);
nodePath = treeUtils.right(state, nodePath);
}
// 'root'
// 'node-1'
// 'node-2'
// 'node-3'
// 'node-4'
// 'node-5'
// 'node-6'
right(
state: Immutable.Iterable,
idOrKeyPath: string|Immutable.Seq<string|number>,
): Immutable.Seq<string|number>
Returns the key path to the node to the right of the one at idOrKeyPath
.
Returns the key path to the next node to the left. The next left node is either:
var nodePath = treeUtils.lastDescendant(state, 'root');
while (nodePath) {
console.log(nodePath);
nodePath = treeUtils.left(state, nodePath);
}
// 'node-6'
// 'node-5'
// 'node-4'
// 'node-3'
// 'node-2'
// 'node-1'
// 'root'
left(
state: Immutable.Iterable,
idOrKeyPath: string|Immutable.Seq<string|number>,
): Immutable.Seq<string|number>
Returns the key path to the node to the right of the one at idOrKeyPath
.
Alias of firstChild.
Returns the key path to the most right node in the given subtree (keypath). The last child of the most deep descendant, if that makes any sense. Look at the example:
treeUtils.lastDescendant(state, 'root');
// 'node-6'
lastDescendant(
state: Immutable.Iterable,
idOrKeyPath: string|Immutable.Seq<string|number>,
): Immutable.Seq<string|number>
Returns the key path to the last descendant of the node at idOrKeyPath
.
Setup:
git clone https://github.com/lukasbuenger/immutable-treeutils
npm install
Run the tests:
npm test
Build the docs / README:
npm run docs
Update all local dependencies:
npx ncu -a
There's a pre-commit hook in place that keeps things in line with the Prettier guidelines. Please note that Node >= 4.2 is required for the pre-commit hooks (lint-staged, husky)
See CHANGELOG
See LICENSE.
FAQs
Functional tree traversal helpers for ImmutableJS data structures
The npm package immutable-treeutils receives a total of 396 weekly downloads. As such, immutable-treeutils popularity was classified as not popular.
We found that immutable-treeutils demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.