Skip to content

neotraverse

Traverse and transform objects by visiting every node on a recursive walk. A TypeScript rewrite of traverse with 0 dependencies, prototype-pollution hardening, and ~5× the throughput with the functional API (up to ~10× on core walks) and ~6× less allocation per op.

Utility-first, tree-shakeable API

Import only what you use from neotraverse (sideEffects: false). Named imports like import { forEach } from 'neotraverse' pull in one walk; importing every function is the upper bound. See Bundle size (brotli) below.

Coming from traverse? See Differences from traverse (drop-in vs functional) or the Legacy / Classic API for the this-bound reference.

  • 🤌 ~2 to 6 KB brotli (tree-shaken functional API; see bundle range)
  • 🚥 Zero dependencies, no polyfills
  • 🎹 Types included: drop @types/traverse
  • 🛡️ Safe on untrusted input (see Security)
  • ⚡ ~5× faster and ~6× leaner than traverse with the functional API, up to ~10× / ~11× (see benchmarks)
  • 🧰 Query helpers, lazy iteration, async traversal, Map/Set clone

Install

sh
npm install neotraverse
# or: pnpm add neotraverse / bun add neotraverse / yarn add neotraverse

Quick start

ts
import * as t from 'neotraverse';

const obj = { a: 1, b: 2, c: [3, 4] };

t.forEach(obj, (ctx, x) => {
  if (typeof x === 'number') ctx.update(x * 10);
});
// → { a: 10, b: 20, c: [30, 40] }

Named imports work too (import { forEach, clone } from 'neotraverse') when you only need a few ops.

Functional API

Each t method call is a terminal operation: one walk per invocation. There is no pipe() helper; tree-to-tree ops such as t.map and t.clone compose as plain nested calls (t.clone(t.map(obj, cb))).

t.reduce(obj, cb) is seedless: the accumulator starts at the root and the root node is skipped. Pass an explicit initial value as the third argument for a seeded fold: t.reduce(obj, cb, 0). Seedless calls cannot also pass options positionally; pass an explicit seed (for example undefined) if you need options.

Bundle size (brotli)

Sizes are brotli after your bundler minifies and tree-shakes neotraverse (measured with esbuild; see bench/bundle-sizes.json). Reproduce with pnpm bundle-size in packages/neotraverse.

What you importBrotli (approx.)Notes
One walk terminal (forEach, map, find, size, …)~2 KBSame ballpark for any single DFS callback op
Path helpers only (get / has / set, or getPath)~0.3 to 0.5 KBNo full-tree walk, keyed access / parse only
clone only~0.9 KBDeep copy without installing the walk callback surface
All functions~5.8 KBUpper bound when you use the full toolkit

Range: ~2 to 6 KB brotli, floor is one traversal (forEach-class import), ceiling is the full function surface.

Always use named imports

Pulling in every function without tree-shaking is ~5.8 KB brotli, same as “all functions”. Use named imports so dead code drops out.

Documentation map

Getting started

Concepts

API reference (reference + examples on each page)

  • Core: map, forEach, reduce, paths, nodes, clone, get / set / has
  • Paths & metrics: string paths, findPaths, select, count, getType
  • Structural: deleteWhere, prune, deepEqual, toJSON, freeze, diff, patch
  • Walk variants: walk, BFS, skipWhere, groupBy, merge, dereference
  • Query: find, filter, some, every
  • Iteration: entries, values, Map/Set leaves
  • Async: forEachAsync, mapAsync, concurrency, AbortSignal

More

Example index

Runnable snippets live next to each API on the pages above:

RecipePage
In-place forEach (negatives → offset)Core → forEach
Immutable mapCore → map
Scrub circular refsCore → map
Dot / JSON Pointer pathsPaths → getPath
Find / filter pathsPaths → findPaths
Redact secretsStructural → deleteWhere
Freeze snapshotStructural → freeze
Cycle-safe JSONStructural → toJSON
Diff / patchStructural → diff
Leaf filter / reduce sumQuery
block / skip subtreeContext
getType branchingWalk
Async translateAsync

Builds & browser support

The default neotraverse (functional) build is ES2022 (Chrome/Edge 94+, Firefox 93+, Safari 15+, Node 18+, Deno, Bun). For the classic this-bound API and an ES2015 build for older targets, see the Legacy / Classic API.

Migrating from traverse

Start with Differences from traverse, then the Migration guide for install steps, side-by-side diffs, and the class→function table.

License

MIT, Puru Vijay.

Released under the MIT License.

157.47Mtotal npm downloadssince Dec 2024