object-traversal
Flexible and performant utility for traversing javascript objects.
Installation
npm i object-traversal
✔ Features
- Performance
- Traverses over 20 million nodes per second. (2020 MacBook Air)
- Around 10 times faster than popular alternatives. (
npm run benchmark
)
- Configurable
- Tweak
traversalOpts
for even more speed, traversal order, maxDepth and more.
- Zero dependencies
- Works on both NodeJS and the browser.
- Big test coverage
- Typescript
Docs
Usage
import { traverse } from 'object-traversal';
traverse(object, callback, opts?);
object
Any instance of javascript object, cyclic or otherwise.
callback
A function that will be called once for each node in the provided root object
, including the root object
itself.
The callback
function has the following signature:
export type TraversalCallback = (context: TraversalCallbackContext) => any;
export type TraversalCallbackContext = {
parent: ArbitraryObject | null;
key: string | null;
value: any;
meta: {
nodePath?: string | null;
visitedNodes: WeakSet<ArbitraryObject>;
depth: number;
};
};
opts
An optional configuration object. See below for the available options and their default values.
export type TraversalOpts = {
traversalType?: 'depth-first' | 'breadth-first';
maxNodes?: number;
cycleHandling?: boolean;
maxDepth?: number;
haltOnTruthy?: boolean;
pathSeparator?: string | null;
};
Examples
Double all numbers in-place
Click to expand
exampleObject = {
name: 'Hello World!',
age: 1,
accounts: 2,
friends: 3,
};
function double({ parent, key, value, meta }) {
if (typeof value === 'number') {
parent[key] = value * 2;
}
}
traverse(exampleObject, double);
console.log(exampleObject);
Find deep nested values by criteria
Click to expand
network = {
name: 'Person1',
age: 52,
friends: [
{
name: 'Person2',
age: 25,
friends: [],
},
{
name: 'Person3',
age: 42,
friends: [
{
name: 'Person4',
age: 18,
friends: [
{
name: 'Person5',
age: 33,
friends: [],
},
],
},
],
},
],
};
const numbersOver25 = [];
function collectOver25({ parent, key, value, meta }) {
if (key === 'age' && value > 25) {
numbersOver25.push(value);
}
}
traverse(network, collectOver25);
console.log(numbersOver25);
Find paths by criteria
Click to expand
network = {
name: 'Alice Doe',
age: 52,
friends: [
{
name: 'John Doe',
age: 25,
friends: [],
},
{
name: 'Bob Doe',
age: 42,
friends: [
{
name: 'John Smith',
age: 18,
friends: [
{
name: 'Charlie Doe',
age: 33,
friends: [],
},
],
},
],
},
],
};
const pathsToPeopleNamedJohn = [];
function callback({ parent, key, value, meta }) {
if (value.name && value.name.startsWith('John')) {
pathsToPeopleNamedJohn.push(meta.nodePath);
}
}
traverse(network, callback);
console.log(pathsToPeopleNamedJohn);
Get node by path
Click to expand
network = {
name: 'Alice Doe',
age: 52,
friends: [
{
name: 'John Doe',
age: 25,
friends: [],
},
{
name: 'Bob Doe',
age: 42,
friends: [
{
name: 'John Smith',
age: 18,
friends: [
{
name: 'Charlie Doe',
age: 33,
friends: [],
},
],
},
],
},
],
};
import { getNodeByPath } from 'object-traversal';
const firstFriend = getNodeByPath(network, 'friends.0');
console.log(firstFriend);
Breadth-first traversal
Click to expand
network = {
name: 'Person 1',
age: 52,
friends: [
{
name: 'Person 2',
age: 42,
friends: [
{
name: 'Person 4',
age: 18,
friends: [],
},
],
},
{
name: 'Person 3',
age: 25,
friends: [],
},
],
};
let names = [];
function getName({ parent, key, value, meta }) {
if (value.name) {
names.push(value.name);
}
}
traverse(network, getName, { traversalType: 'breadth-first' });
console.log(names);
Roadmap
Built with
TSDX
np
yarn 1.22.10