or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

acorn-loose.mdacorn-walk.mdacorn.mdindex.md
tile.json

acorn-walk.mddocs/

Acorn Walk

Acorn Walk is an ECMAScript (ESTree) AST walker library that provides multiple traversal strategies for JavaScript syntax trees. It offers a comprehensive set of algorithms for visiting, finding, and processing AST nodes with flexible state management and custom visitor functions.

Package Information

  • Package Name: acorn-walk
  • Package Type: npm
  • Language: JavaScript (with TypeScript definitions)
  • Installation: npm install acorn-walk

Core Imports

import { simple, ancestor, recursive, full, findNodeAt, base } from "acorn-walk";

For CommonJS:

const { simple, ancestor, recursive, full, findNodeAt, base } = require("acorn-walk");

Basic Usage

import { parse } from "acorn";
import { simple, findNodeAt } from "acorn-walk";

// Parse JavaScript code into AST
const ast = parse("let x = 10; function foo() { return x + 1; }");

// Simple walk to find all literals
simple(ast, {
  Literal(node) {
    console.log(`Found literal: ${node.value}`);
  }
});

// Find specific node at position
const node = findNodeAt(ast, 4, 10, "Literal");
if (node) {
  console.log(`Found node: ${node.node.value}`);
}

Architecture

Acorn Walk is built around several key components:

  • Walking Algorithms: Multiple traversal strategies (simple, ancestor, recursive, full) for different use cases
  • Node Visitors: Callback-based system allowing custom processing for specific node types
  • State Threading: Optional state parameter threaded through all walk operations
  • Base Walker: Default visitor implementations for all ESTree node types
  • Finding Utilities: Position-based node lookup functions for editor-like functionality

Capabilities

Simple Walking

Performs a basic walk over an AST, calling visitor functions for specific node types.

/**
 * Performs a simple walk over a tree with visitor callbacks
 * @param node - The AST node to walk
 * @param visitors - Object mapping node types to visitor functions
 * @param baseVisitor - Optional custom walker algorithm
 * @param state - Optional initial state
 * @param override - Optional node type override
 */
function simple(
  node: Node,
  visitors: SimpleVisitors,
  baseVisitor?: RecursiveVisitors,
  state?: any,
  override?: string
): void;

interface SimpleVisitors {
  [nodeType: string]: (node: Node, state: any) => void;
}

Usage Example:

import { parse } from "acorn";
import { simple } from "acorn-walk";

const ast = parse("let x = 42; console.log(x);");

simple(ast, {
  VariableDeclaration(node, state) {
    console.log("Found variable declaration");
  },
  CallExpression(node, state) {
    console.log("Found function call");
  }
});

Ancestor Walking

Walks an AST while building up an array of ancestor nodes, useful for context-aware processing.

/**
 * Walks a tree building up an array of ancestor nodes
 * @param node - The AST node to walk
 * @param visitors - Object mapping node types to visitor functions
 * @param baseVisitor - Optional custom walker algorithm
 * @param state - Optional initial state
 * @param override - Optional node type override
 */
function ancestor(
  node: Node,
  visitors: AncestorVisitors,
  baseVisitor?: RecursiveVisitors,
  state?: any,
  override?: string
): void;

interface AncestorVisitors {
  [nodeType: string]: (node: Node, state: any, ancestors: Node[]) => void;
}

Usage Example:

import { parse } from "acorn";
import { ancestor } from "acorn-walk";

const ast = parse("function outer() { function inner() { return 42; } }");

ancestor(ast, {
  FunctionDeclaration(node, state, ancestors) {
    console.log(`Function ${node.id.name} has ${ancestors.length - 1} ancestors`);
  }
});

Recursive Walking

Provides full control over the walking process, where visitor functions are responsible for continuing traversal.

/**
 * Performs a recursive walk where visitors control child traversal
 * @param node - The AST node to walk
 * @param state - Initial state value
 * @param functions - Object mapping node types to walker functions
 * @param baseVisitor - Optional fallback walker functions
 * @param override - Optional node type override
 */
function recursive(
  node: Node,
  state: any,
  functions: RecursiveVisitors,
  baseVisitor?: RecursiveVisitors,
  override?: string
): void;

interface RecursiveVisitors {
  [nodeType: string]: (node: Node, state: any, callback: WalkerCallback) => void;
}

interface WalkerCallback {
  (node: Node, state: any): void;
}

Usage Example:

import { parse } from "acorn";
import { recursive } from "acorn-walk";

const ast = parse("let x = { a: 1, b: 2 };");

recursive(ast, { depth: 0 }, {
  VariableDeclaration(node, state, c) {
    console.log(`Variable declaration at depth ${state.depth}`);
    for (const decl of node.declarations) {
      c(decl, { ...state, depth: state.depth + 1 });
    }
  }
});

Full Walking

Triggers a callback on every node in the AST.

/**
 * Performs a full walk calling callback on each node
 * @param node - The AST node to walk
 * @param callback - Function called for each node
 * @param baseVisitor - Optional custom walker algorithm
 * @param state - Optional initial state
 * @param override - Optional node type override
 */
function full(
  node: Node,
  callback: FullWalkerCallback,
  baseVisitor?: RecursiveVisitors,
  state?: any,
  override?: string
): void;

interface FullWalkerCallback {
  (node: Node, state: any, type: string): void;
}

Usage Example:

import { parse } from "acorn";
import { full } from "acorn-walk";

const ast = parse("let x = 10;");
let nodeCount = 0;

full(ast, (node, state, type) => {
  nodeCount++;
  console.log(`Node ${nodeCount}: ${type}`);
});

Full Ancestor Walking

Combines full walking with ancestor tracking.

/**
 * Performs a full walk with ancestor array on each node
 * @param node - The AST node to walk
 * @param callback - Function called for each node with ancestors
 * @param baseVisitor - Optional custom walker algorithm
 * @param state - Optional initial state
 */
function fullAncestor(
  node: Node,
  callback: FullAncestorWalkerCallback,
  baseVisitor?: RecursiveVisitors,
  state?: any
): void;

interface FullAncestorWalkerCallback {
  (node: Node, state: any, ancestors: Node[], type: string): void;
}

Node Finding

Find Node At Position

Locates a node at specific start/end positions.

/**
 * Finds a node at given start and/or end offsets
 * @param node - The AST node to search
 * @param start - Start position (null as wildcard)
 * @param end - End position (null as wildcard)
 * @param test - Node type string or predicate function
 * @param baseVisitor - Optional custom walker algorithm
 * @param state - Optional initial state
 * @returns Found node and state, or undefined
 */
function findNodeAt(
  node: Node,
  start: number | null,
  end?: number | null,
  test?: string | FindPredicate,
  baseVisitor?: RecursiveVisitors,
  state?: any
): Found | undefined;

interface Found {
  node: Node;
  state: any;
}

interface FindPredicate {
  (type: string, node: Node): boolean;
}

Usage Example:

import { parse } from "acorn";
import { findNodeAt } from "acorn-walk";

const code = "let x = 42;";
const ast = parse(code);

// Find literal at specific position
const result = findNodeAt(ast, 8, 10, "Literal");
if (result) {
  console.log(`Found literal: ${result.node.value}`);
}

Find Node Around Position

Finds the innermost node that contains a given position.

/**
 * Finds the innermost node containing the given position
 * @param node - The AST node to search
 * @param pos - Position to search around
 * @param test - Node type string or predicate function
 * @param baseVisitor - Optional custom walker algorithm
 * @param state - Optional initial state
 * @returns Found node and state, or undefined
 */
function findNodeAround(
  node: Node,
  pos: number,
  test?: string | FindPredicate,
  baseVisitor?: RecursiveVisitors,
  state?: any
): Found | undefined;

Find Node After Position

Finds the outermost matching node after a given position.

/**
 * Finds the outermost matching node after a given position
 * @param node - The AST node to search
 * @param pos - Position to search after
 * @param test - Node type string or predicate function
 * @param baseVisitor - Optional custom walker algorithm
 * @param state - Optional initial state
 * @returns Found node and state, or undefined
 */
function findNodeAfter<TState>(
  node: Node,
  pos: number,
  test?: string | FindPredicate,
  baseVisitor?: RecursiveVisitors<TState>,
  state?: TState
): Found<TState> | undefined;

Find Node Before Position

Finds the outermost matching node before a given position.

/**
 * Finds the outermost matching node before a given position
 * @param node - The AST node to search
 * @param pos - Position to search before
 * @param test - Node type string or predicate function
 * @param baseVisitor - Optional custom walker algorithm
 * @param state - Optional initial state
 * @returns Found node and state, or undefined
 */
function findNodeBefore<TState>(
  node: Node,
  pos: number,
  test?: string | FindPredicate,
  baseVisitor?: RecursiveVisitors<TState>,
  state?: TState
): Found<TState> | undefined;

Walker Creation

Creates custom walker objects by combining visitor functions with defaults.

/**
 * Creates a custom walker by combining functions with base defaults
 * @param functions - Object mapping node types to walker functions
 * @param baseVisitor - Optional base walker to inherit from
 * @returns New walker object with combined functions
 */
function make<TState>(
  functions: RecursiveVisitors<TState>,
  baseVisitor?: RecursiveVisitors<TState>
): RecursiveVisitors<TState>;

Usage Example:

import { make, base } from "acorn-walk";

const customWalker = make({
  FunctionDeclaration(node, state, c) {
    console.log(`Custom function handler for ${node.id.name}`);
    // Call default behavior
    base.FunctionDeclaration(node, state, c);
  }
}, base);

Base Walker Object

Default walker implementation containing visitor functions for all ESTree node types.

/**
 * Default walker object with visitors for all ESTree node types
 */
const base: RecursiveVisitors<any>;

The base object contains walker functions for all standard ESTree node types including:

  • Statements: Program, BlockStatement, ExpressionStatement, IfStatement, etc.
  • Expressions: BinaryExpression, CallExpression, MemberExpression, etc.
  • Declarations: FunctionDeclaration, VariableDeclaration, ClassDeclaration, etc.
  • Patterns: ArrayPattern, ObjectPattern, RestElement, etc.
  • ES6+ Features: ArrowFunctionExpression, TemplateLiteral, etc.
  • ES2022 Features: StaticBlock, PrivateIdentifier, etc.
  • Import/Export: ImportDeclaration, ExportDeclaration, etc.

Core Types

interface Node {
  type: string;
  start?: number;
  end?: number;
  [key: string]: any;
}

// Aggregate node types for convenience
type AggregateType = {
  Expression: Expression;
  Statement: Statement;
  Function: Function;
  Class: Class;
  Pattern: Pattern;
  ForInit: VariableDeclaration | Expression;
};

interface SimpleVisitors<TState> {
  [nodeType: string]: (node: Node, state: TState) => void;
  // Also supports aggregate types:
  Expression?: (node: Expression, state: TState) => void;
  Statement?: (node: Statement, state: TState) => void;
  Function?: (node: Function, state: TState) => void;
  Class?: (node: Class, state: TState) => void;
  Pattern?: (node: Pattern, state: TState) => void;
}

interface AncestorVisitors<TState> {
  [nodeType: string]: (node: Node, state: TState, ancestors: Node[]) => void;
}

interface RecursiveVisitors<TState> {
  [nodeType: string]: (node: Node, state: TState, callback: WalkerCallback<TState>) => void;
}

interface WalkerCallback<TState> {
  (node: Node, state: TState): void;
}

interface FullWalkerCallback<TState> {
  (node: Node, state: TState, type: string): void;
}

interface FullAncestorWalkerCallback<TState> {
  (node: Node, state: TState, ancestors: Node[], type: string): void;
}

interface FindPredicate {
  (type: string, node: Node): boolean;
}

interface Found<TState> {
  node: Node;
  state: TState;
}

Common Usage Patterns

Collecting Information

import { parse } from "acorn";
import { simple } from "acorn-walk";

const ast = parse("function foo() { let x = 1; return x + 1; }");
const info = { functions: [], variables: [] };

simple(ast, {
  FunctionDeclaration(node, state) {
    state.functions.push(node.id.name);
  },
  VariableDeclaration(node, state) {
    node.declarations.forEach(decl => {
      state.variables.push(decl.id.name);
    });
  }
}, null, info);

console.log(info); // { functions: ['foo'], variables: ['x'] }

Code Transformation Analysis

import { parse } from "acorn";
import { ancestor } from "acorn-walk";

const ast = parse("function outer() { function inner() { console.log('nested'); } }");

ancestor(ast, {
  CallExpression(node, state, ancestors) {
    const depth = ancestors.filter(n => n.type === 'FunctionDeclaration').length;
    console.log(`Function call at nesting depth: ${depth}`);
  }
});

Position-Based Node Lookup

import { parse } from "acorn";
import { findNodeAround } from "acorn-walk";

const code = "let x = function() { return 42; };";
const ast = parse(code, { locations: true });

// Find what's at position 20 (inside the function)
const result = findNodeAround(ast, 20);
if (result) {
  console.log(`Node at position 20: ${result.node.type}`);
}