Socket
Socket
Sign inDemoInstall

object-traversal

Package Overview
Dependencies
0
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    object-traversal

Flexible and performant utility for traversing javascript objects


Version published
Weekly downloads
11K
decreased by-3.84%
Maintainers
1
Install size
69.1 kB
Created
Weekly downloads
 

Readme

Source

object-traversal

License License npm downloads License License

Flexible and performant utility for traversing javascript objects.

Installation

npm i object-traversal

✔ Features

  1. Performance
    • Traverses over 20 million nodes per second. (2020 MacBook Air)
    • Around 10 times faster than popular alternatives. (npm run benchmark)
  2. Configurable
    • Tweak traversalOpts for even more speed, traversal order, maxDepth and more.
  3. Zero dependencies
    • Works on both NodeJS and the browser.
  4. Big test coverage
  5. 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:

// Callback function signature
export type TraversalCallback = (context: TraversalCallbackContext) => any;

// Callback context
export type TraversalCallbackContext = {
  parent: ArbitraryObject | null; // parent is null when callback is being called on the root `object`
  key: string | null; // key is null when callback is being called on the root `object`
  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 = {
  /**
   * Default: 'depth-first'
   */
  traversalType?: 'depth-first' | 'breadth-first';

  /**
   * Traversal stops when the traversed node count reaches this value.
   *
   * Default: Number.Infinity
   */
  maxNodes?: number;

  /**
   * If set to `true`, prevents infinite loops by not re-visiting repeated nodes.
   *
   * Default: true
   */
  cycleHandling?: boolean;

  /**
   * The maximum depth that must be traversed.
   *
   * Root object has depth 0.
   *
   * Default: Number.Infinity
   */
  maxDepth?: number;

  /**
   * If true, traversal will stop as soon as the callback returns a truthy value.
   *
   * This is useful for search use cases, where you typically want to skip traversing the remaining nodes once the target is found.
   *
   * Default: false
   */
  haltOnTruthy?: boolean;

  /**
   * The string to be used as separator for the `meta.nodePath` segments.
   *
   * Set to null if you wish to turn off `meta.nodePath` to increase traversal speed.
   *
   * Default: '.'
   */
  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);
// {
//   name: 'Hello World!',
//   age: 2,
//   accounts: { checking: 4, savings: 6 },
//   friends: 8
// }

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);
// [ 52, 42, 33 ]

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);
// [ 'friends.0', 'friends.1.friends.0' ]

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);
// { name: 'John Doe', age: 25, friends: [] }

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);
// [ 'Person 1', 'Person 2', 'Person 3', 'Person 4' ]

Roadmap

  • Configurable BFS/DFS
  • Max depth
  • Configurable path separator
  • Utility for consuming paths
  • Toggleable cycle handler
  • Iterator support
  • Sequential promise support
  • Multi threading & further speed enhancements
  • Streaming research
  • More granular cycleHandling: 'revisit', 'norevisit', and 'off'

Built with

TSDX
np
yarn 1.22.10

Keywords

FAQs

Last updated on 25 Mar 2022

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.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc