Skip to Content
  • Website
Codsen
  • Home
  • Open Source
  • Articles
  • About

prevOpen Source→ast-monkey-traversenext

ast-monkey-traverse4.2.1

Utility library to traverse AST

Downloads per monthChangelogMIT Licenselibera manifesto
  • the top
  • Installation
  • Quick Take
  • Examples
  • PURPOSE
  • API — TRAVERSE()
  • API — VERSION
  • API — TYPES
  • INNEROBJ IN TH…
  • STOPPING
  • COMPARED TO…
  • Changelog

Installation

Quick Take

Examples

  • Collect the path of every visited node
  • Compatible With object-path
  • Delete nodes by returning NaN
  • Traverse without mutating the input
  • Inspect each node's parent metadata
  • Stop
  • Transform values while traversing

Purpose

Traverse, read and edit a parsed JSON-like data structure.

API — traverse()

The main function traverse() is imported like this:

It’s a function which takes two input arguments, 1. a data structure and 2. a callback function:

where the callback has the following API:

The callback API is similar to Array.forEach():

import { traverse } from "ast-monkey-traverse";
let ast = [{ a: "b", c: "d" }];
ast = traverse(ast, (key, val, innerObj, stop) => {
  let current = val !== undefined ? val : key;
  // if you are traversing and "stumbled" upon an object, it will have both "key" and "val"
  // if you are traversing and "stumbled" upon an array, it will have only "key"
  // you can detect either using the principle above.
  // you can also now change "current" - what you return will be overwritten.
  // return `NaN` to give instruction to delete currently traversed piece of AST.
  //
  return current; // #1 <------ it's obligatory to return it, unless you want to assign it to "undefined"
});

It’s very important to return the value of the callback function (point marked #1 above) because otherwise whatever you return will be written over the current AST piece being iterated.

If you want to delete, return NaNopens in a new tab.

API — version

You can import version:

API — types

This package is written in TypeScript and exports the following types:

TypeDescription
Callback
Type: Callback
CallbackThe signature of the callback — it receives the key, the value, an InnerObj and a Stop.
InnerObj
Type: InnerObj
InnerObjThe third callback argument, carrying depth, path, parent, parentType, parentKey and topmostKey.
Stop
Type: Stop
StopThe fourth callback argument — set its now key to true to end the traversal.
import type { Callback, InnerObj, Stop } from "ast-monkey-traverse";

innerObj in the callback

When you call traverse() like this:

input = traverse(input, (key, val, innerObj, stop) => {
  ...
})

you get four variables:

  • key
  • val
  • innerObj
  • stop — set stop.now = true; to stop the traversal

If traverse() is currently traversing a plain object, going each key/value pair, key will be the object’s current key and val will be the value. If traverse() is currently traversing an array, going through all elements, a key will be the current element and val will be null.

innerObj object’s keyTypeDescription
depth
Type: Integer number
depthInteger numberZero is root, topmost level. Every level deeper increments depth by 1.
path
Type: String
pathStringThe path to the current value. The path uses object-path notation.
topmostKey
Type: String
topmostKeyStringWhen you are very deep, this is the topmost parent’s key.
parent
Type: Type of the parent of current element being traversed
parentType of the parent of current element being traversedA whole parent (array or a plain object) which contains the current element. Its purpose is to allow you to query the siblings of the current element.
parentType
Type: String
parentTypeStringEither array if parent is array or object if parent is a plain object (not the “object” type, which includes functions, arrays etc.).

Stopping

Here’s how to stop the traversal. Let’s gather all the traversed paths first. By the way, paths are marked in object-path notation (arrays use dots too, a.1.b instead of a[1].b).

import { traverse } from "ast-monkey-traverse";
const input = { a: "1", b: { c: "2" } };
const gathered = [];
traverse(input, (key1, val1, innerObj) => {
  const current = val1 !== undefined ? val1 : key1;
  gathered.push(innerObj.path);
  return current;
});
console.log(gathered);
// => ["a", "b", "b.c"]

All paths were gathered: ["a", "b", "b.c"].

Let’s force the program to stop at the path “b”:

import { traverse } from "ast-monkey-traverse";
const input = { a: "1", b: { c: "2" } };
const gathered = [];
traverse(input, (key1, val1, innerObj, stop) => {
  const current = val1 !== undefined ? val1 : key1;
  gathered.push(innerObj.path);
  if (innerObj.path === "b") {
    stop.now = true; // <---------------- !!!!!!!!!!
  }
  return current;
});
console.log(gathered);
// => ["a", "b"]

Notice how there were no more gathered paths after “b”, only ["a", "b"].

Compared to ast-monkey-traverse-with-lookahead

ast-monkey-traverse can amend AST (it matters what you return within a callback) ast-monkey-traverse-with-lookahead is read-only, it can’t amend AST it reads

ast-monkey-traverse does not “see” future nodes, it just reports what it has just traversed ast-monkey-traverse-with-lookahead can report as many nodes “from the future”, upon request

Personally, in the context of linting, parsing and other tooling, we’re going to use ast-monkey-traverse-with-lookahead because we don’t need to mutate the AST, yet we need to “see” what’s next in order to patch AST tree errors.

Changelog

Open Changelog
↑ back to top
prev next

Copyright

All rights reserved © Roy Revelt 2026
All our open source packages are under MIT licenceopens in a new tab

Activities

🐛 See a bug? Raise an issueopens in a new tab
💘 Check out the Indiewebopens in a new tab and Libera manifestoopens in a new tab