CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-web-tree-sitter

Tree-sitter bindings for the web providing WebAssembly-based incremental parsing of source code

Pending
Overview
Eval results
Files

tree-cursor.mddocs/

Tree Cursor

Efficient tree traversal using stateful cursors for performance-critical applications. TreeCursor provides a low-level, memory-efficient way to walk syntax trees without creating intermediate Node objects.

Capabilities

Cursor Creation and Management

Create and manage tree cursor instances.

/**
 * Create a deep copy of the tree cursor (allocates new memory)
 * @returns New TreeCursor instance
 */
copy(): TreeCursor;

/**
 * Delete the tree cursor and free its resources
 */
delete(): void;

Usage Example:

const tree = parser.parse("let x = 1 + 2;");
const cursor = tree.walk();

// Create a copy for parallel traversal
const cursorCopy = cursor.copy();

// Clean up when done
cursor.delete();
cursorCopy.delete();

Current Node Access

Access information about the current node without creating Node objects.

/**
 * Get the tree cursor's current Node
 * @returns Current node (creates Node object)
 */
get currentNode(): Node;

/**
 * Get the numerical field id of this tree cursor's current node
 * @returns Field ID or 0 if no field
 */
get currentFieldId(): number;

/**
 * Get the field name of this tree cursor's current node
 * @returns Field name or null if no field
 */
get currentFieldName(): string | null;

Position Information

Get cursor position and depth information.

/**
 * Get the depth of the cursor's current node relative to the original node
 * @returns Depth from root node
 */
get currentDepth(): number;

/**
 * Get the index of the cursor's current node out of all descendants
 * @returns Descendant index
 */
get currentDescendantIndex(): number;

Node Type Information

Access type information for the current node efficiently.

/**
 * Get the type of the cursor's current node
 * @returns Node type as string
 */
get nodeType(): string;

/**
 * Get the type id of the cursor's current node
 * @returns Node type ID
 */
get nodeTypeId(): number;

/**
 * Get the state id of the cursor's current node
 * @returns Parse state ID
 */
get nodeStateId(): number;

/**
 * Get the id of the cursor's current node
 * @returns Unique node ID
 */
get nodeId(): number;

Node Classification

Check node properties without creating Node objects.

/**
 * Check if the cursor's current node is named
 * @returns True if node corresponds to named rule in grammar
 */
get nodeIsNamed(): boolean;

/**
 * Check if the cursor's current node is missing
 * @returns True if node was inserted for error recovery
 */
get nodeIsMissing(): boolean;

Content and Position Access

Get node content and position information.

/**
 * Get the string content of the cursor's current node
 * @returns Text content of current node
 */
get nodeText(): string;

/**
 * Get the start position of the cursor's current node
 * @returns Start position
 */
get startPosition(): Point;

/**
 * Get the end position of the cursor's current node
 * @returns End position
 */
get endPosition(): Point;

/**
 * Get the start index of the cursor's current node
 * @returns Start byte index
 */
get startIndex(): number;

/**
 * Get the end index of the cursor's current node
 * @returns End byte index
 */
get endIndex(): number;

Usage Example:

const cursor = tree.walk();

console.log("Current node type:", cursor.nodeType);
console.log("Text:", cursor.nodeText);
console.log("Position:", cursor.startPosition, "to", cursor.endPosition);
console.log("Depth:", cursor.currentDepth);
console.log("Is named:", cursor.nodeIsNamed);

Tree Navigation

Navigate through the tree structure efficiently.

/**
 * Move cursor to the first child of current node
 * @returns True if successfully moved, false if no children
 */
gotoFirstChild(): boolean;

/**
 * Move cursor to the last child of current node
 * @returns True if successfully moved, false if no children
 */
gotoLastChild(): boolean;

/**
 * Move cursor to the parent of current node
 * @returns True if successfully moved, false if already at root
 */
gotoParent(): boolean;

/**
 * Move cursor to the next sibling of current node
 * @returns True if successfully moved, false if no next sibling
 */
gotoNextSibling(): boolean;

/**
 * Move cursor to the previous sibling of current node
 * @returns True if successfully moved, false if no previous sibling
 */
gotoPreviousSibling(): boolean;

Usage Example:

const cursor = tree.walk();

// Walk through all children of root
if (cursor.gotoFirstChild()) {
  do {
    console.log("Child:", cursor.nodeType, cursor.nodeText);
    
    // Visit grandchildren
    if (cursor.gotoFirstChild()) {
      do {
        console.log("  Grandchild:", cursor.nodeType);
      } while (cursor.gotoNextSibling());
      cursor.gotoParent(); // Back to child level
    }
  } while (cursor.gotoNextSibling());
}

Advanced Navigation

Navigate to specific positions and descendants.

/**
 * Move cursor to the nth descendant of the original node
 * @param goalDescendantIndex - Index of target descendant (0 = original node)
 */
gotoDescendant(goalDescendantIndex: number): void;

/**
 * Move cursor to first child containing or starting after given byte offset
 * @param goalIndex - Target byte offset
 * @returns True if found and moved, false if no such child
 */
gotoFirstChildForIndex(goalIndex: number): boolean;

/**
 * Move cursor to first child containing or starting after given position
 * @param goalPosition - Target position
 * @returns True if found and moved, false if no such child
 */
gotoFirstChildForPosition(goalPosition: Point): boolean;

Usage Example:

// Find node at specific byte offset
const cursor = tree.walk();
if (cursor.gotoFirstChildForIndex(15)) {
  console.log("Found node at offset 15:", cursor.nodeType);
}

// Navigate to specific descendant
cursor.gotoDescendant(5); // Go to 5th descendant
console.log("5th descendant:", cursor.nodeType);

Cursor Reset Operations

Reset cursor position and state.

/**
 * Re-initialize cursor to start at the given node
 * @param node - Node to reset cursor to
 */
reset(node: Node): void;

/**
 * Re-initialize cursor to the same position as another cursor
 * @param cursor - Cursor to copy position from
 */
resetTo(cursor: TreeCursor): void;

Usage Example:

const cursor1 = tree.walk();
const cursor2 = tree.walk();

// Move cursor1 to some position
cursor1.gotoFirstChild();
cursor1.gotoFirstChild();

// Copy position to cursor2
cursor2.resetTo(cursor1);

console.log("Both cursors at same position:");
console.log("Cursor1:", cursor1.nodeType);
console.log("Cursor2:", cursor2.nodeType);

// Reset cursor1 to root
cursor1.reset(tree.rootNode);

Performance Benefits

TreeCursor provides significant performance advantages for tree traversal:

  • Memory Efficient: No intermediate Node object creation during navigation
  • Cache Friendly: Maintains position state without repeated tree walks
  • Fast Iteration: Direct access to node properties without object allocation
  • Stateful Navigation: Remembers position for complex traversal patterns

Usage Patterns

Full Tree Traversal

function traverseTree(cursor: TreeCursor, depth: number = 0) {
  const indent = "  ".repeat(depth);
  console.log(`${indent}${cursor.nodeType}: ${cursor.nodeText}`);
  
  if (cursor.gotoFirstChild()) {
    do {
      traverseTree(cursor, depth + 1);
    } while (cursor.gotoNextSibling());
    cursor.gotoParent();
  }
}

const cursor = tree.walk();
traverseTree(cursor);
cursor.delete();

Find All Nodes of Type

function findNodesOfType(tree: Tree, targetType: string): string[] {
  const results: string[] = [];
  const cursor = tree.walk();
  
  function visit() {
    if (cursor.nodeType === targetType) {
      results.push(cursor.nodeText);
    }
    
    if (cursor.gotoFirstChild()) {
      do {
        visit();
      } while (cursor.gotoNextSibling());
      cursor.gotoParent();
    }
  }
  
  visit();
  cursor.delete();
  return results;
}

const identifiers = findNodesOfType(tree, "identifier");
console.log("Found identifiers:", identifiers);

Range-Based Processing

function processRange(tree: Tree, startIndex: number, endIndex: number) {
  const cursor = tree.walk();
  
  // Find first node in range
  if (cursor.gotoFirstChildForIndex(startIndex)) {
    while (cursor.startIndex <= endIndex) {
      if (cursor.endIndex >= startIndex) {
        console.log("Processing:", cursor.nodeType, cursor.nodeText);
      }
      
      if (!cursor.gotoNextSibling()) {
        break;
      }
    }
  }
  
  cursor.delete();
}

Install with Tessl CLI

npx tessl i tessl/npm-web-tree-sitter

docs

index.md

language.md

parser.md

query.md

tree-cursor.md

tree-node.md

tile.json