Position-based search utilities for locating specific nodes within an AST based on source code positions and type predicates. These functions are essential for building code editors, linters, and analysis tools that need to find nodes at specific locations in source code.
Finds a node with specific start and end positions that matches an optional test predicate. Useful for finding the exact node at a given location in source code.
/**
* Find node at specific start/end positions matching test predicate
* @param node - AST node to search in
* @param start - Start position (number or null as wildcard)
* @param end - End position (number or null as wildcard)
* @param test - String (node type) or function predicate
* @param baseVisitor - Optional custom walker (defaults to base)
* @param state - Optional initial state
* @returns {node, state} object or undefined
*/
function findNodeAt<TState>(
node: Node,
start: number | null,
end?: number | null,
test?: string | FindPredicate,
baseVisitor?: RecursiveVisitors<TState>,
state?: TState
): Found<TState> | undefined;Usage Examples:
import * as acorn from "acorn";
import { findNodeAt } from "acorn-walk";
const code = "let x = 10;";
const ast = acorn.parse(code);
// Find any node at exact position
const found = findNodeAt(ast, 8, 10);
if (found) {
console.log(`Found ${found.node.type}: ${found.node.value}`);
}
// Find literal node at position
const literal = findNodeAt(ast, 8, 10, "Literal");
if (literal) {
console.log(`Found literal: ${literal.node.value}`);
}
// Find node using custom predicate
const identifier = findNodeAt(ast, 4, 5, (type, node) => {
return type === "Identifier" && node.name === "x";
});Finds the innermost node that contains (spans) the given position. Perfect for finding the node under a cursor in an editor.
/**
* Find innermost node containing the given position
* @param node - AST node to search in
* @param pos - Position to search around
* @param test - String (node type) or function predicate
* @param baseVisitor - Optional custom walker (defaults to base)
* @param state - Optional initial state
* @returns {node, state} object or undefined
*/
function findNodeAround<TState>(
node: Node,
pos: number,
test?: string | FindPredicate,
baseVisitor?: RecursiveVisitors<TState>,
state?: TState
): Found<TState> | undefined;Usage Examples:
import * as acorn from "acorn";
import { findNodeAround } from "acorn-walk";
const code = "function test() { let x = 10; }";
const ast = acorn.parse(code);
// Find any node containing position 20
const found = findNodeAround(ast, 20);
if (found) {
console.log(`Node at cursor: ${found.node.type}`);
}
// Find identifier at cursor position
const identifier = findNodeAround(ast, 20, "Identifier");
if (identifier) {
console.log(`Identifier: ${identifier.node.name}`);
}
// Find using custom predicate
const variable = findNodeAround(ast, 20, (type, node) => {
return type === "VariableDeclaration";
});Finds the outermost matching node that starts after the given position. Useful for finding the next node of interest after a cursor position.
/**
* Find outermost matching node after given position
* @param node - AST node to search in
* @param pos - Position to search after
* @param test - String (node type) or function predicate
* @param baseVisitor - Optional custom walker (defaults to base)
* @param state - Optional initial state
* @returns {node, state} object or undefined
*/
function findNodeAfter<TState>(
node: Node,
pos: number,
test?: string | FindPredicate,
baseVisitor?: RecursiveVisitors<TState>,
state?: TState
): Found<TState> | undefined;Usage Examples:
import * as acorn from "acorn";
import { findNodeAfter } from "acorn-walk";
const code = "let a = 1; let b = 2; let c = 3;";
const ast = acorn.parse(code);
// Find any node after position 10
const found = findNodeAfter(ast, 10);
if (found) {
console.log(`Next node: ${found.node.type}`);
}
// Find next variable declaration
const nextVar = findNodeAfter(ast, 10, "VariableDeclaration");
if (nextVar) {
console.log(`Next variable: ${nextVar.node.declarations[0].id.name}`);
}Finds the outermost matching node that ends before the given position. Useful for finding the previous node of interest before a cursor position.
/**
* Find outermost matching node before given position
* @param node - AST node to search in
* @param pos - Position to search before
* @param test - String (node type) or function predicate
* @param baseVisitor - Optional custom walker (defaults to base)
* @param state - Optional initial state
* @returns {node, state} object or undefined
*/
function findNodeBefore<TState>(
node: Node,
pos: number,
test?: string | FindPredicate,
baseVisitor?: RecursiveVisitors<TState>,
state?: TState
): Found<TState> | undefined;Usage Examples:
import * as acorn from "acorn";
import { findNodeBefore } from "acorn-walk";
const code = "let a = 1; let b = 2; let c = 3;";
const ast = acorn.parse(code);
// Find any node before position 20
const found = findNodeBefore(ast, 20);
if (found) {
console.log(`Previous node: ${found.node.type}`);
}
// Find previous literal
const prevLiteral = findNodeBefore(ast, 20, "Literal");
if (prevLiteral) {
console.log(`Previous literal: ${prevLiteral.node.value}`);
}
// Find using custom predicate
const prevIdentifier = findNodeBefore(ast, 20, (type, node) => {
return type === "Identifier" && node.name.startsWith("a");
});Combining Search Functions:
import * as acorn from "acorn";
import { findNodeAround, findNodeAfter, findNodeBefore } from "acorn-walk";
const code = "function test() { let x = 10; let y = 20; }";
const ast = acorn.parse(code);
const cursorPos = 25; // Position in middle of function
// Find current context
const current = findNodeAround(ast, cursorPos, "VariableDeclaration");
// Find next variable declaration
const next = findNodeAfter(ast, cursorPos, "VariableDeclaration");
// Find previous variable declaration
const prev = findNodeBefore(ast, cursorPos, "VariableDeclaration");
console.log({
current: current?.node.declarations[0].id.name,
next: next?.node.declarations[0].id.name,
prev: prev?.node.declarations[0].id.name
});type FindPredicate = (type: string, node: Node) => boolean;
interface Found<TState> {
node: Node;
state: TState;
}All search functions work with character positions in the source code:
// Example with position mapping
const code = "let x = 10;";
// 0123456789...
// ^ ^ ^
// 0 4 8-10
// Position 0: start of "let"
// Position 4: start of "x"
// Position 8-10: "10" literalNote: Positions are 0-based character offsets from the start of the source code. The start and end properties on AST nodes correspond to these positions.
TypeScript Definition Note: The provided TypeScript definitions are incomplete compared to the actual source code implementation. Specifically, findNodeBefore is completely missing from the TypeScript definitions, and findNodeAfter is incorrectly defined as typeof findNodeAround. This documentation follows the source code implementation for accuracy.