Tree-sitter bindings for the web providing WebAssembly-based incremental parsing of source code
—
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.
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();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;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;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;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;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);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());
}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);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);TreeCursor provides significant performance advantages for 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();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);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