or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.mdsearch-functions.mdwalker-utilities.mdwalking-functions.md
tile.json

walker-utilities.mddocs/

Walker Utilities

Utility functions for creating custom walkers and accessing the default base walker containing handlers for all ESTree node types. These utilities enable advanced customization of AST traversal behavior.

Capabilities

Make Custom Walker

Creates a custom walker by combining user-defined functions with a base walker. Missing node type handlers are filled in from the base walker.

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

Usage Examples:

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

// Create custom walker for counting nodes
const counter = make({
  FunctionDeclaration(node, state, c) {
    state.functions++;
    // Continue with default traversal
    base.FunctionDeclaration(node, state, c);
  },
  VariableDeclaration(node, state, c) {
    state.variables++;
    // Continue with default traversal
    base.VariableDeclaration(node, state, c);
  }
}, base);

const ast = acorn.parse("function test() { let x = 1; let y = 2; }");
const counts = { functions: 0, variables: 0 };

recursive(ast, counts, counter);
console.log(counts); // { functions: 1, variables: 2 }

Advanced Custom Walker Example:

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

// Custom walker that tracks scope depth
const scopeTracker = make({
  Program(node, state, c) {
    console.log("Entering program scope");
    state.depth = 0;
    base.Program(node, state, c);
  },
  
  FunctionDeclaration(node, state, c) {
    console.log(`Entering function '${node.id.name}' at depth ${state.depth}`);
    state.depth++;
    base.FunctionDeclaration(node, { ...state }, c);
    state.depth--;
    console.log(`Exiting function '${node.id.name}'`);
  },
  
  BlockStatement(node, state, c) {
    if (state.depth > 0) {
      console.log(`Block at depth ${state.depth}`);
    }
    base.BlockStatement(node, state, c);
  }
});

Base Walker Object

The default walker object containing functions for all ESTree node types. Each function defines how to traverse that specific node type.

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

Note: The base constant is exported from the source code but is missing from the official TypeScript definitions.

The base walker contains handlers for all standard ESTree node types:

Statement Handlers:

  • Program, BlockStatement - Walk statement bodies
  • ExpressionStatement - Walk the expression
  • IfStatement - Walk test, consequent, alternate
  • WhileStatement, DoWhileStatement - Walk test and body
  • ForStatement - Walk init, test, update, body
  • ForInStatement, ForOfStatement - Walk left, right, body
  • SwitchStatement - Walk discriminant and cases
  • TryStatement - Walk block, handler, finalizer
  • FunctionDeclaration - Walk as function
  • VariableDeclaration - Walk declarators
  • ReturnStatement, ThrowStatement - Walk argument
  • BreakStatement, ContinueStatement - No-op walkers

Expression Handlers:

  • ArrayExpression - Walk elements
  • ObjectExpression - Walk properties
  • FunctionExpression, ArrowFunctionExpression - Walk as function
  • CallExpression, NewExpression - Walk callee and arguments
  • MemberExpression - Walk object and computed property
  • BinaryExpression, LogicalExpression - Walk left and right
  • UnaryExpression, UpdateExpression - Walk argument
  • ConditionalExpression - Walk test, consequent, alternate
  • SequenceExpression - Walk expressions
  • TemplateLiteral - Walk quasis and expressions

Pattern and Declaration Handlers:

  • ArrayPattern - Walk elements
  • ObjectPattern - Walk properties
  • RestElement - Walk argument
  • AssignmentPattern - Walk left and right

Module Handlers:

  • ImportDeclaration - Walk specifiers and source
  • ExportNamedDeclaration, ExportDefaultDeclaration - Walk declaration and source
  • ExportAllDeclaration - Walk exported and source

Usage Examples:

import { base } from "acorn-walk";

// Access specific node handler
console.log(typeof base.FunctionDeclaration); // "function"

// Use base walker directly in custom function
const customWalker = {
  FunctionDeclaration(node, state, c) {
    console.log(`Custom handling for function: ${node.id.name}`);
    // Delegate to base implementation
    base.FunctionDeclaration(node, state, c);
  }
};

Extending Base Walker:

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

// Create walker that logs all identifier access
const identifierLogger = make({
  Identifier(node, state, c) {
    if (state.inExpression) {
      console.log(`Accessing identifier: ${node.name}`);
    }
    // base.Identifier is a no-op, but call it for consistency
    base.Identifier(node, state, c);
  },
  
  Expression(node, state, c) {
    // Mark that we're in an expression context
    base.Expression(node, { ...state, inExpression: true }, c);
  }
}, base);

Walker Function Patterns

Traversal Control:

// Custom walker that skips function bodies
const skipFunctions = make({
  FunctionDeclaration(node, state, c) {
    // Process function declaration but don't traverse body
    console.log(`Function declared: ${node.id.name}`);
    // Don't call base.FunctionDeclaration to skip traversal
  },
  
  FunctionExpression(node, state, c) {
    console.log("Anonymous function expression");
    // Skip body traversal
  }
}, base);

State Transformation:

// Walker that transforms state for nested scopes
const scopeWalker = make({
  FunctionDeclaration(node, state, c) {
    const newState = {
      ...state,
      scope: state.scope + 1,
      functionName: node.id.name
    };
    base.FunctionDeclaration(node, newState, c);
  }
}, base);

Types

type RecursiveWalkerFn<TState> = (
  node: Node,
  state: TState,
  callback: WalkerCallback<TState>
) => void;

type RecursiveVisitors<TState> = {
  [type: string]: RecursiveWalkerFn<TState>;
};

type WalkerCallback<TState> = (node: Node, state: TState) => void;