web-tree-sitter
Version:
Tree-sitter bindings for the web
1,508 lines (1,499 loc) • 201 kB
JavaScript
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
// src/edit.ts
var Edit = class {
static {
__name(this, "Edit");
}
/** The start position of the change. */
startPosition;
/** The end position of the change before the edit. */
oldEndPosition;
/** The end position of the change after the edit. */
newEndPosition;
/** The start index of the change. */
startIndex;
/** The end index of the change before the edit. */
oldEndIndex;
/** The end index of the change after the edit. */
newEndIndex;
constructor({
startIndex,
oldEndIndex,
newEndIndex,
startPosition,
oldEndPosition,
newEndPosition
}) {
this.startIndex = startIndex >>> 0;
this.oldEndIndex = oldEndIndex >>> 0;
this.newEndIndex = newEndIndex >>> 0;
this.startPosition = startPosition;
this.oldEndPosition = oldEndPosition;
this.newEndPosition = newEndPosition;
}
/**
* Edit a point and index to keep it in-sync with source code that has been edited.
*
* This function updates a single point's byte offset and row/column position
* based on an edit operation. This is useful for editing points without
* requiring a tree or node instance.
*/
editPoint(point, index) {
let newIndex = index;
const newPoint = { ...point };
if (index >= this.oldEndIndex) {
newIndex = this.newEndIndex + (index - this.oldEndIndex);
const originalRow = point.row;
newPoint.row = this.newEndPosition.row + (point.row - this.oldEndPosition.row);
newPoint.column = originalRow === this.oldEndPosition.row ? this.newEndPosition.column + (point.column - this.oldEndPosition.column) : point.column;
} else if (index > this.startIndex) {
newIndex = this.newEndIndex;
newPoint.row = this.newEndPosition.row;
newPoint.column = this.newEndPosition.column;
}
return { point: newPoint, index: newIndex };
}
/**
* Edit a range to keep it in-sync with source code that has been edited.
*
* This function updates a range's start and end positions based on an edit
* operation. This is useful for editing ranges without requiring a tree
* or node instance.
*/
editRange(range) {
const newRange = {
startIndex: range.startIndex,
startPosition: { ...range.startPosition },
endIndex: range.endIndex,
endPosition: { ...range.endPosition }
};
if (range.endIndex >= this.oldEndIndex) {
if (range.endIndex !== Number.MAX_SAFE_INTEGER) {
newRange.endIndex = this.newEndIndex + (range.endIndex - this.oldEndIndex);
newRange.endPosition = {
row: this.newEndPosition.row + (range.endPosition.row - this.oldEndPosition.row),
column: range.endPosition.row === this.oldEndPosition.row ? this.newEndPosition.column + (range.endPosition.column - this.oldEndPosition.column) : range.endPosition.column
};
if (newRange.endIndex < this.newEndIndex) {
newRange.endIndex = Number.MAX_SAFE_INTEGER;
newRange.endPosition = { row: Number.MAX_SAFE_INTEGER, column: Number.MAX_SAFE_INTEGER };
}
}
} else if (range.endIndex > this.startIndex) {
newRange.endIndex = this.startIndex;
newRange.endPosition = { ...this.startPosition };
}
if (range.startIndex >= this.oldEndIndex) {
newRange.startIndex = this.newEndIndex + (range.startIndex - this.oldEndIndex);
newRange.startPosition = {
row: this.newEndPosition.row + (range.startPosition.row - this.oldEndPosition.row),
column: range.startPosition.row === this.oldEndPosition.row ? this.newEndPosition.column + (range.startPosition.column - this.oldEndPosition.column) : range.startPosition.column
};
if (newRange.startIndex < this.newEndIndex) {
newRange.startIndex = Number.MAX_SAFE_INTEGER;
newRange.startPosition = { row: Number.MAX_SAFE_INTEGER, column: Number.MAX_SAFE_INTEGER };
}
} else if (range.startIndex > this.startIndex) {
newRange.startIndex = this.startIndex;
newRange.startPosition = { ...this.startPosition };
}
return newRange;
}
};
// src/constants.ts
var SIZE_OF_SHORT = 2;
var SIZE_OF_INT = 4;
var SIZE_OF_CURSOR = 4 * SIZE_OF_INT;
var SIZE_OF_NODE = 5 * SIZE_OF_INT;
var SIZE_OF_POINT = 2 * SIZE_OF_INT;
var SIZE_OF_RANGE = 2 * SIZE_OF_INT + 2 * SIZE_OF_POINT;
var ZERO_POINT = { row: 0, column: 0 };
var INTERNAL = /* @__PURE__ */ Symbol("INTERNAL");
function assertInternal(x) {
if (x !== INTERNAL) throw new Error("Illegal constructor");
}
__name(assertInternal, "assertInternal");
function isPoint(point) {
return !!point && typeof point.row === "number" && typeof point.column === "number";
}
__name(isPoint, "isPoint");
function setModule(module2) {
C = module2;
}
__name(setModule, "setModule");
var C;
// src/lookahead_iterator.ts
var LookaheadIterator = class {
static {
__name(this, "LookaheadIterator");
}
/** @internal */
[0] = 0;
// Internal handle for Wasm
/** @internal */
language;
/** @internal */
constructor(internal, address, language) {
assertInternal(internal);
this[0] = address;
this.language = language;
}
/** Get the current symbol of the lookahead iterator. */
get currentTypeId() {
return C._ts_lookahead_iterator_current_symbol(this[0]);
}
/** Get the current symbol name of the lookahead iterator. */
get currentType() {
return this.language.types[this.currentTypeId] || "ERROR";
}
/** Delete the lookahead iterator, freeing its resources. */
delete() {
C._ts_lookahead_iterator_delete(this[0]);
this[0] = 0;
}
/**
* Reset the lookahead iterator.
*
* This returns `true` if the language was set successfully and `false`
* otherwise.
*/
reset(language, stateId) {
if (C._ts_lookahead_iterator_reset(this[0], language[0], stateId)) {
this.language = language;
return true;
}
return false;
}
/**
* Reset the lookahead iterator to another state.
*
* This returns `true` if the iterator was reset to the given state and
* `false` otherwise.
*/
resetState(stateId) {
return Boolean(C._ts_lookahead_iterator_reset_state(this[0], stateId));
}
/**
* Returns an iterator that iterates over the symbols of the lookahead iterator.
*
* The iterator will yield the current symbol name as a string for each step
* until there are no more symbols to iterate over.
*/
[Symbol.iterator]() {
return {
next: /* @__PURE__ */ __name(() => {
if (C._ts_lookahead_iterator_next(this[0])) {
return { done: false, value: this.currentType };
}
return { done: true, value: "" };
}, "next")
};
}
};
// src/tree.ts
function getText(tree, startIndex, endIndex, startPosition) {
const length = endIndex - startIndex;
let result = tree.textCallback(startIndex, startPosition);
if (result) {
startIndex += result.length;
while (startIndex < endIndex) {
const string = tree.textCallback(startIndex, startPosition);
if (string && string.length > 0) {
startIndex += string.length;
result += string;
} else {
break;
}
}
if (startIndex > endIndex) {
result = result.slice(0, length);
}
}
return result ?? "";
}
__name(getText, "getText");
var Tree = class _Tree {
static {
__name(this, "Tree");
}
/** @internal */
[0] = 0;
// Internal handle for Wasm
/** @internal */
textCallback;
/** The language that was used to parse the syntax tree. */
language;
/** @internal */
constructor(internal, address, language, textCallback) {
assertInternal(internal);
this[0] = address;
this.language = language;
this.textCallback = textCallback;
}
/** Create a shallow copy of the syntax tree. This is very fast. */
copy() {
const address = C._ts_tree_copy(this[0]);
return new _Tree(INTERNAL, address, this.language, this.textCallback);
}
/** Delete the syntax tree, freeing its resources. */
delete() {
C._ts_tree_delete(this[0]);
this[0] = 0;
}
/** Get the root node of the syntax tree. */
get rootNode() {
C._ts_tree_root_node_wasm(this[0]);
return unmarshalNode(this);
}
/**
* Get the root node of the syntax tree, but with its position shifted
* forward by the given offset.
*/
rootNodeWithOffset(offsetBytes, offsetExtent) {
const address = TRANSFER_BUFFER + SIZE_OF_NODE;
C.setValue(address, offsetBytes, "i32");
marshalPoint(address + SIZE_OF_INT, offsetExtent);
C._ts_tree_root_node_with_offset_wasm(this[0]);
return unmarshalNode(this);
}
/**
* Edit the syntax tree to keep it in sync with source code that has been
* edited.
*
* You must describe the edit both in terms of byte offsets and in terms of
* row/column coordinates.
*/
edit(edit) {
marshalEdit(edit);
C._ts_tree_edit_wasm(this[0]);
}
/** Create a new {@link TreeCursor} starting from the root of the tree. */
walk() {
return this.rootNode.walk();
}
/**
* Compare this old edited syntax tree to a new syntax tree representing
* the same document, returning a sequence of ranges whose syntactic
* structure has changed.
*
* For this to work correctly, this syntax tree must have been edited such
* that its ranges match up to the new tree. Generally, you'll want to
* call this method right after calling one of the [`Parser::parse`]
* functions. Call it on the old tree that was passed to parse, and
* pass the new tree that was returned from `parse`.
*/
getChangedRanges(other) {
if (!(other instanceof _Tree)) {
throw new TypeError("Argument must be a Tree");
}
C._ts_tree_get_changed_ranges_wasm(this[0], other[0]);
const count = C.getValue(TRANSFER_BUFFER, "i32");
const buffer = C.getValue(TRANSFER_BUFFER + SIZE_OF_INT, "i32");
const result = new Array(count);
if (count > 0) {
let address = buffer;
for (let i2 = 0; i2 < count; i2++) {
result[i2] = unmarshalRange(address);
address += SIZE_OF_RANGE;
}
C._free(buffer);
}
return result;
}
/** Get the included ranges that were used to parse the syntax tree. */
getIncludedRanges() {
C._ts_tree_included_ranges_wasm(this[0]);
const count = C.getValue(TRANSFER_BUFFER, "i32");
const buffer = C.getValue(TRANSFER_BUFFER + SIZE_OF_INT, "i32");
const result = new Array(count);
if (count > 0) {
let address = buffer;
for (let i2 = 0; i2 < count; i2++) {
result[i2] = unmarshalRange(address);
address += SIZE_OF_RANGE;
}
C._free(buffer);
}
return result;
}
};
// src/tree_cursor.ts
var TreeCursor = class _TreeCursor {
static {
__name(this, "TreeCursor");
}
/** @internal */
// @ts-expect-error: never read
[0] = 0;
// Internal handle for Wasm
/** @internal */
// @ts-expect-error: never read
[1] = 0;
// Internal handle for Wasm
/** @internal */
// @ts-expect-error: never read
[2] = 0;
// Internal handle for Wasm
/** @internal */
// @ts-expect-error: never read
[3] = 0;
// Internal handle for Wasm
/** @internal */
tree;
/** @internal */
constructor(internal, tree) {
assertInternal(internal);
this.tree = tree;
unmarshalTreeCursor(this);
}
/** Creates a deep copy of the tree cursor. This allocates new memory. */
copy() {
const copy = new _TreeCursor(INTERNAL, this.tree);
C._ts_tree_cursor_copy_wasm(this.tree[0]);
unmarshalTreeCursor(copy);
return copy;
}
/** Delete the tree cursor, freeing its resources. */
delete() {
marshalTreeCursor(this);
C._ts_tree_cursor_delete_wasm(this.tree[0]);
this[0] = this[1] = this[2] = 0;
}
/** Get the tree cursor's current {@link Node}. */
get currentNode() {
marshalTreeCursor(this);
C._ts_tree_cursor_current_node_wasm(this.tree[0]);
return unmarshalNode(this.tree);
}
/**
* Get the numerical field id of this tree cursor's current node.
*
* See also {@link TreeCursor#currentFieldName}.
*/
get currentFieldId() {
marshalTreeCursor(this);
return C._ts_tree_cursor_current_field_id_wasm(this.tree[0]);
}
/** Get the field name of this tree cursor's current node. */
get currentFieldName() {
return this.tree.language.fields[this.currentFieldId];
}
/**
* Get the depth of the cursor's current node relative to the original
* node that the cursor was constructed with.
*/
get currentDepth() {
marshalTreeCursor(this);
return C._ts_tree_cursor_current_depth_wasm(this.tree[0]);
}
/**
* Get the index of the cursor's current node out of all of the
* descendants of the original node that the cursor was constructed with.
*/
get currentDescendantIndex() {
marshalTreeCursor(this);
return C._ts_tree_cursor_current_descendant_index_wasm(this.tree[0]);
}
/** Get the type of the cursor's current node. */
get nodeType() {
return this.tree.language.types[this.nodeTypeId] || "ERROR";
}
/** Get the type id of the cursor's current node. */
get nodeTypeId() {
marshalTreeCursor(this);
return C._ts_tree_cursor_current_node_type_id_wasm(this.tree[0]);
}
/** Get the state id of the cursor's current node. */
get nodeStateId() {
marshalTreeCursor(this);
return C._ts_tree_cursor_current_node_state_id_wasm(this.tree[0]);
}
/** Get the id of the cursor's current node. */
get nodeId() {
marshalTreeCursor(this);
return C._ts_tree_cursor_current_node_id_wasm(this.tree[0]);
}
/**
* Check if the cursor's current node is *named*.
*
* Named nodes correspond to named rules in the grammar, whereas
* *anonymous* nodes correspond to string literals in the grammar.
*/
get nodeIsNamed() {
marshalTreeCursor(this);
return C._ts_tree_cursor_current_node_is_named_wasm(this.tree[0]) === 1;
}
/**
* Check if the cursor's current node is *missing*.
*
* Missing nodes are inserted by the parser in order to recover from
* certain kinds of syntax errors.
*/
get nodeIsMissing() {
marshalTreeCursor(this);
return C._ts_tree_cursor_current_node_is_missing_wasm(this.tree[0]) === 1;
}
/** Get the string content of the cursor's current node. */
get nodeText() {
marshalTreeCursor(this);
const startIndex = C._ts_tree_cursor_start_index_wasm(this.tree[0]);
const endIndex = C._ts_tree_cursor_end_index_wasm(this.tree[0]);
C._ts_tree_cursor_start_position_wasm(this.tree[0]);
const startPosition = unmarshalPoint(TRANSFER_BUFFER);
return getText(this.tree, startIndex, endIndex, startPosition);
}
/** Get the start position of the cursor's current node. */
get startPosition() {
marshalTreeCursor(this);
C._ts_tree_cursor_start_position_wasm(this.tree[0]);
return unmarshalPoint(TRANSFER_BUFFER);
}
/** Get the end position of the cursor's current node. */
get endPosition() {
marshalTreeCursor(this);
C._ts_tree_cursor_end_position_wasm(this.tree[0]);
return unmarshalPoint(TRANSFER_BUFFER);
}
/** Get the start index of the cursor's current node. */
get startIndex() {
marshalTreeCursor(this);
return C._ts_tree_cursor_start_index_wasm(this.tree[0]);
}
/** Get the end index of the cursor's current node. */
get endIndex() {
marshalTreeCursor(this);
return C._ts_tree_cursor_end_index_wasm(this.tree[0]);
}
/**
* Move this cursor to the first child of its current node.
*
* This returns `true` if the cursor successfully moved, and returns
* `false` if there were no children.
*/
gotoFirstChild() {
marshalTreeCursor(this);
const result = C._ts_tree_cursor_goto_first_child_wasm(this.tree[0]);
unmarshalTreeCursor(this);
return result === 1;
}
/**
* Move this cursor to the last child of its current node.
*
* This returns `true` if the cursor successfully moved, and returns
* `false` if there were no children.
*
* Note that this function may be slower than
* {@link TreeCursor#gotoFirstChild} because it needs to
* iterate through all the children to compute the child's position.
*/
gotoLastChild() {
marshalTreeCursor(this);
const result = C._ts_tree_cursor_goto_last_child_wasm(this.tree[0]);
unmarshalTreeCursor(this);
return result === 1;
}
/**
* Move this cursor to the parent of its current node.
*
* This returns `true` if the cursor successfully moved, and returns
* `false` if there was no parent node (the cursor was already on the
* root node).
*
* Note that the node the cursor was constructed with is considered the root
* of the cursor, and the cursor cannot walk outside this node.
*/
gotoParent() {
marshalTreeCursor(this);
const result = C._ts_tree_cursor_goto_parent_wasm(this.tree[0]);
unmarshalTreeCursor(this);
return result === 1;
}
/**
* Move this cursor to the next sibling of its current node.
*
* This returns `true` if the cursor successfully moved, and returns
* `false` if there was no next sibling node.
*
* Note that the node the cursor was constructed with is considered the root
* of the cursor, and the cursor cannot walk outside this node.
*/
gotoNextSibling() {
marshalTreeCursor(this);
const result = C._ts_tree_cursor_goto_next_sibling_wasm(this.tree[0]);
unmarshalTreeCursor(this);
return result === 1;
}
/**
* Move this cursor to the previous sibling of its current node.
*
* This returns `true` if the cursor successfully moved, and returns
* `false` if there was no previous sibling node.
*
* Note that this function may be slower than
* {@link TreeCursor#gotoNextSibling} due to how node
* positions are stored. In the worst case, this will need to iterate
* through all the children up to the previous sibling node to recalculate
* its position. Also note that the node the cursor was constructed with is
* considered the root of the cursor, and the cursor cannot walk outside this node.
*/
gotoPreviousSibling() {
marshalTreeCursor(this);
const result = C._ts_tree_cursor_goto_previous_sibling_wasm(this.tree[0]);
unmarshalTreeCursor(this);
return result === 1;
}
/**
* Move the cursor to the node that is the nth descendant of
* the original node that the cursor was constructed with, where
* zero represents the original node itself.
*/
gotoDescendant(goalDescendantIndex) {
marshalTreeCursor(this);
C._ts_tree_cursor_goto_descendant_wasm(this.tree[0], goalDescendantIndex);
unmarshalTreeCursor(this);
}
/**
* Move this cursor to the first child of its current node that contains or
* starts after the given byte offset.
*
* This returns `true` if the cursor successfully moved to a child node, and returns
* `false` if no such child was found.
*/
gotoFirstChildForIndex(goalIndex) {
marshalTreeCursor(this);
C.setValue(TRANSFER_BUFFER + SIZE_OF_CURSOR, goalIndex, "i32");
const result = C._ts_tree_cursor_goto_first_child_for_index_wasm(this.tree[0]);
unmarshalTreeCursor(this);
return result === 1;
}
/**
* Move this cursor to the first child of its current node that contains or
* starts after the given byte offset.
*
* This returns the index of the child node if one was found, and returns
* `null` if no such child was found.
*/
gotoFirstChildForPosition(goalPosition) {
marshalTreeCursor(this);
marshalPoint(TRANSFER_BUFFER + SIZE_OF_CURSOR, goalPosition);
const result = C._ts_tree_cursor_goto_first_child_for_position_wasm(this.tree[0]);
unmarshalTreeCursor(this);
return result === 1;
}
/**
* Re-initialize this tree cursor to start at the original node that the
* cursor was constructed with.
*/
reset(node) {
marshalNode(node);
marshalTreeCursor(this, TRANSFER_BUFFER + SIZE_OF_NODE);
C._ts_tree_cursor_reset_wasm(this.tree[0]);
unmarshalTreeCursor(this);
}
/**
* Re-initialize a tree cursor to the same position as another cursor.
*
* Unlike {@link TreeCursor#reset}, this will not lose parent
* information and allows reusing already created cursors.
*/
resetTo(cursor) {
marshalTreeCursor(this, TRANSFER_BUFFER);
marshalTreeCursor(cursor, TRANSFER_BUFFER + SIZE_OF_CURSOR);
C._ts_tree_cursor_reset_to_wasm(this.tree[0], cursor.tree[0]);
unmarshalTreeCursor(this);
}
};
// src/node.ts
var Node = class {
static {
__name(this, "Node");
}
/** @internal */
// @ts-expect-error: never read
[0] = 0;
// Internal handle for Wasm
/** @internal */
_children;
/** @internal */
_namedChildren;
/** @internal */
constructor(internal, {
id,
tree,
startIndex,
startPosition,
other
}) {
assertInternal(internal);
this[0] = other;
this.id = id;
this.tree = tree;
this.startIndex = startIndex;
this.startPosition = startPosition;
}
/**
* The numeric id for this node that is unique.
*
* Within a given syntax tree, no two nodes have the same id. However:
*
* * If a new tree is created based on an older tree, and a node from the old tree is reused in
* the process, then that node will have the same id in both trees.
*
* * A node not marked as having changes does not guarantee it was reused.
*
* * If a node is marked as having changed in the old tree, it will not be reused.
*/
id;
/** The byte index where this node starts. */
startIndex;
/** The position where this node starts. */
startPosition;
/** The tree that this node belongs to. */
tree;
/** Get this node's type as a numerical id. */
get typeId() {
marshalNode(this);
return C._ts_node_symbol_wasm(this.tree[0]);
}
/**
* Get the node's type as a numerical id as it appears in the grammar,
* ignoring aliases.
*/
get grammarId() {
marshalNode(this);
return C._ts_node_grammar_symbol_wasm(this.tree[0]);
}
/** Get this node's type as a string. */
get type() {
return this.tree.language.types[this.typeId] || "ERROR";
}
/**
* Get this node's symbol name as it appears in the grammar, ignoring
* aliases as a string.
*/
get grammarType() {
return this.tree.language.types[this.grammarId] || "ERROR";
}
/**
* Check if this node is *named*.
*
* Named nodes correspond to named rules in the grammar, whereas
* *anonymous* nodes correspond to string literals in the grammar.
*/
get isNamed() {
marshalNode(this);
return C._ts_node_is_named_wasm(this.tree[0]) === 1;
}
/**
* Check if this node is *extra*.
*
* Extra nodes represent things like comments, which are not required
* by the grammar, but can appear anywhere.
*/
get isExtra() {
marshalNode(this);
return C._ts_node_is_extra_wasm(this.tree[0]) === 1;
}
/**
* Check if this node represents a syntax error.
*
* Syntax errors represent parts of the code that could not be incorporated
* into a valid syntax tree.
*/
get isError() {
marshalNode(this);
return C._ts_node_is_error_wasm(this.tree[0]) === 1;
}
/**
* Check if this node is *missing*.
*
* Missing nodes are inserted by the parser in order to recover from
* certain kinds of syntax errors.
*/
get isMissing() {
marshalNode(this);
return C._ts_node_is_missing_wasm(this.tree[0]) === 1;
}
/** Check if this node has been edited. */
get hasChanges() {
marshalNode(this);
return C._ts_node_has_changes_wasm(this.tree[0]) === 1;
}
/**
* Check if this node represents a syntax error or contains any syntax
* errors anywhere within it.
*/
get hasError() {
marshalNode(this);
return C._ts_node_has_error_wasm(this.tree[0]) === 1;
}
/** Get the byte index where this node ends. */
get endIndex() {
marshalNode(this);
return C._ts_node_end_index_wasm(this.tree[0]);
}
/** Get the position where this node ends. */
get endPosition() {
marshalNode(this);
C._ts_node_end_point_wasm(this.tree[0]);
return unmarshalPoint(TRANSFER_BUFFER);
}
/** Get the string content of this node. */
get text() {
return getText(this.tree, this.startIndex, this.endIndex, this.startPosition);
}
/** Get this node's parse state. */
get parseState() {
marshalNode(this);
return C._ts_node_parse_state_wasm(this.tree[0]);
}
/** Get the parse state after this node. */
get nextParseState() {
marshalNode(this);
return C._ts_node_next_parse_state_wasm(this.tree[0]);
}
/** Check if this node is equal to another node. */
equals(other) {
return this.tree === other.tree && this.id === other.id;
}
/**
* Get the node's child at the given index, where zero represents the first child.
*
* This method is fairly fast, but its cost is technically log(n), so if
* you might be iterating over a long list of children, you should use
* {@link Node#children} instead.
*/
child(index) {
marshalNode(this);
C._ts_node_child_wasm(this.tree[0], index);
return unmarshalNode(this.tree);
}
/**
* Get this node's *named* child at the given index.
*
* See also {@link Node#isNamed}.
* This method is fairly fast, but its cost is technically log(n), so if
* you might be iterating over a long list of children, you should use
* {@link Node#namedChildren} instead.
*/
namedChild(index) {
marshalNode(this);
C._ts_node_named_child_wasm(this.tree[0], index);
return unmarshalNode(this.tree);
}
/**
* Get this node's child with the given numerical field id.
*
* See also {@link Node#childForFieldName}. You can
* convert a field name to an id using {@link Language#fieldIdForName}.
*/
childForFieldId(fieldId) {
marshalNode(this);
C._ts_node_child_by_field_id_wasm(this.tree[0], fieldId);
return unmarshalNode(this.tree);
}
/**
* Get the first child with the given field name.
*
* If multiple children may have the same field name, access them using
* {@link Node#childrenForFieldName}.
*/
childForFieldName(fieldName) {
const fieldId = this.tree.language.fields.indexOf(fieldName);
if (fieldId !== -1) return this.childForFieldId(fieldId);
return null;
}
/** Get the field name of this node's child at the given index. */
fieldNameForChild(index) {
marshalNode(this);
const address = C._ts_node_field_name_for_child_wasm(this.tree[0], index);
if (!address) return null;
return C.AsciiToString(address);
}
/** Get the field name of this node's named child at the given index. */
fieldNameForNamedChild(index) {
marshalNode(this);
const address = C._ts_node_field_name_for_named_child_wasm(this.tree[0], index);
if (!address) return null;
return C.AsciiToString(address);
}
/**
* Get an array of this node's children with a given field name.
*
* See also {@link Node#children}.
*/
childrenForFieldName(fieldName) {
const fieldId = this.tree.language.fields.indexOf(fieldName);
if (fieldId !== -1 && fieldId !== 0) return this.childrenForFieldId(fieldId);
return [];
}
/**
* Get an array of this node's children with a given field id.
*
* See also {@link Node#childrenForFieldName}.
*/
childrenForFieldId(fieldId) {
marshalNode(this);
C._ts_node_children_by_field_id_wasm(this.tree[0], fieldId);
const count = C.getValue(TRANSFER_BUFFER, "i32");
const buffer = C.getValue(TRANSFER_BUFFER + SIZE_OF_INT, "i32");
const result = new Array(count);
if (count > 0) {
let address = buffer;
for (let i2 = 0; i2 < count; i2++) {
result[i2] = unmarshalNode(this.tree, address);
address += SIZE_OF_NODE;
}
C._free(buffer);
}
return result;
}
/** Get the node's first child that contains or starts after the given byte offset. */
firstChildForIndex(index) {
marshalNode(this);
const address = TRANSFER_BUFFER + SIZE_OF_NODE;
C.setValue(address, index, "i32");
C._ts_node_first_child_for_byte_wasm(this.tree[0]);
return unmarshalNode(this.tree);
}
/** Get the node's first named child that contains or starts after the given byte offset. */
firstNamedChildForIndex(index) {
marshalNode(this);
const address = TRANSFER_BUFFER + SIZE_OF_NODE;
C.setValue(address, index, "i32");
C._ts_node_first_named_child_for_byte_wasm(this.tree[0]);
return unmarshalNode(this.tree);
}
/** Get this node's number of children. */
get childCount() {
marshalNode(this);
return C._ts_node_child_count_wasm(this.tree[0]);
}
/**
* Get this node's number of *named* children.
*
* See also {@link Node#isNamed}.
*/
get namedChildCount() {
marshalNode(this);
return C._ts_node_named_child_count_wasm(this.tree[0]);
}
/** Get this node's first child. */
get firstChild() {
return this.child(0);
}
/**
* Get this node's first named child.
*
* See also {@link Node#isNamed}.
*/
get firstNamedChild() {
return this.namedChild(0);
}
/** Get this node's last child. */
get lastChild() {
return this.child(this.childCount - 1);
}
/**
* Get this node's last named child.
*
* See also {@link Node#isNamed}.
*/
get lastNamedChild() {
return this.namedChild(this.namedChildCount - 1);
}
/**
* Iterate over this node's children.
*
* If you're walking the tree recursively, you may want to use the
* {@link TreeCursor} APIs directly instead.
*/
get children() {
if (!this._children) {
marshalNode(this);
C._ts_node_children_wasm(this.tree[0]);
const count = C.getValue(TRANSFER_BUFFER, "i32");
const buffer = C.getValue(TRANSFER_BUFFER + SIZE_OF_INT, "i32");
this._children = new Array(count);
if (count > 0) {
let address = buffer;
for (let i2 = 0; i2 < count; i2++) {
this._children[i2] = unmarshalNode(this.tree, address);
address += SIZE_OF_NODE;
}
C._free(buffer);
}
}
return this._children;
}
/**
* Iterate over this node's named children.
*
* See also {@link Node#children}.
*/
get namedChildren() {
if (!this._namedChildren) {
marshalNode(this);
C._ts_node_named_children_wasm(this.tree[0]);
const count = C.getValue(TRANSFER_BUFFER, "i32");
const buffer = C.getValue(TRANSFER_BUFFER + SIZE_OF_INT, "i32");
this._namedChildren = new Array(count);
if (count > 0) {
let address = buffer;
for (let i2 = 0; i2 < count; i2++) {
this._namedChildren[i2] = unmarshalNode(this.tree, address);
address += SIZE_OF_NODE;
}
C._free(buffer);
}
}
return this._namedChildren;
}
/**
* Get the descendants of this node that are the given type, or in the given types array.
*
* The types array should contain node type strings, which can be retrieved from {@link Language#types}.
*
* Additionally, a `startPosition` and `endPosition` can be passed in to restrict the search to a byte range.
*/
descendantsOfType(types, startPosition = ZERO_POINT, endPosition = ZERO_POINT) {
if (!Array.isArray(types)) types = [types];
const symbols = [];
const typesBySymbol = this.tree.language.types;
for (const node_type of types) {
if (node_type == "ERROR") {
symbols.push(65535);
}
}
for (let i2 = 0, n = typesBySymbol.length; i2 < n; i2++) {
if (types.includes(typesBySymbol[i2])) {
symbols.push(i2);
}
}
const symbolsAddress = C._malloc(SIZE_OF_INT * symbols.length);
for (let i2 = 0, n = symbols.length; i2 < n; i2++) {
C.setValue(symbolsAddress + i2 * SIZE_OF_INT, symbols[i2], "i32");
}
marshalNode(this);
C._ts_node_descendants_of_type_wasm(
this.tree[0],
symbolsAddress,
symbols.length,
startPosition.row,
startPosition.column,
endPosition.row,
endPosition.column
);
const descendantCount = C.getValue(TRANSFER_BUFFER, "i32");
const descendantAddress = C.getValue(TRANSFER_BUFFER + SIZE_OF_INT, "i32");
const result = new Array(descendantCount);
if (descendantCount > 0) {
let address = descendantAddress;
for (let i2 = 0; i2 < descendantCount; i2++) {
result[i2] = unmarshalNode(this.tree, address);
address += SIZE_OF_NODE;
}
}
C._free(descendantAddress);
C._free(symbolsAddress);
return result;
}
/** Get this node's next sibling. */
get nextSibling() {
marshalNode(this);
C._ts_node_next_sibling_wasm(this.tree[0]);
return unmarshalNode(this.tree);
}
/** Get this node's previous sibling. */
get previousSibling() {
marshalNode(this);
C._ts_node_prev_sibling_wasm(this.tree[0]);
return unmarshalNode(this.tree);
}
/**
* Get this node's next *named* sibling.
*
* See also {@link Node#isNamed}.
*/
get nextNamedSibling() {
marshalNode(this);
C._ts_node_next_named_sibling_wasm(this.tree[0]);
return unmarshalNode(this.tree);
}
/**
* Get this node's previous *named* sibling.
*
* See also {@link Node#isNamed}.
*/
get previousNamedSibling() {
marshalNode(this);
C._ts_node_prev_named_sibling_wasm(this.tree[0]);
return unmarshalNode(this.tree);
}
/** Get the node's number of descendants, including one for the node itself. */
get descendantCount() {
marshalNode(this);
return C._ts_node_descendant_count_wasm(this.tree[0]);
}
/**
* Get this node's immediate parent.
* Prefer {@link Node#childWithDescendant} for iterating over this node's ancestors.
*/
get parent() {
marshalNode(this);
C._ts_node_parent_wasm(this.tree[0]);
return unmarshalNode(this.tree);
}
/**
* Get the node that contains `descendant`.
*
* Note that this can return `descendant` itself.
*/
childWithDescendant(descendant) {
marshalNode(this);
marshalNode(descendant, 1);
C._ts_node_child_with_descendant_wasm(this.tree[0]);
return unmarshalNode(this.tree);
}
/** Get the smallest node within this node that spans the given byte range. */
descendantForIndex(start2, end = start2) {
if (typeof start2 !== "number" || typeof end !== "number") {
throw new Error("Arguments must be numbers");
}
marshalNode(this);
const address = TRANSFER_BUFFER + SIZE_OF_NODE;
C.setValue(address, start2, "i32");
C.setValue(address + SIZE_OF_INT, end, "i32");
C._ts_node_descendant_for_index_wasm(this.tree[0]);
return unmarshalNode(this.tree);
}
/** Get the smallest named node within this node that spans the given byte range. */
namedDescendantForIndex(start2, end = start2) {
if (typeof start2 !== "number" || typeof end !== "number") {
throw new Error("Arguments must be numbers");
}
marshalNode(this);
const address = TRANSFER_BUFFER + SIZE_OF_NODE;
C.setValue(address, start2, "i32");
C.setValue(address + SIZE_OF_INT, end, "i32");
C._ts_node_named_descendant_for_index_wasm(this.tree[0]);
return unmarshalNode(this.tree);
}
/** Get the smallest node within this node that spans the given point range. */
descendantForPosition(start2, end = start2) {
if (!isPoint(start2) || !isPoint(end)) {
throw new Error("Arguments must be {row, column} objects");
}
marshalNode(this);
const address = TRANSFER_BUFFER + SIZE_OF_NODE;
marshalPoint(address, start2);
marshalPoint(address + SIZE_OF_POINT, end);
C._ts_node_descendant_for_position_wasm(this.tree[0]);
return unmarshalNode(this.tree);
}
/** Get the smallest named node within this node that spans the given point range. */
namedDescendantForPosition(start2, end = start2) {
if (!isPoint(start2) || !isPoint(end)) {
throw new Error("Arguments must be {row, column} objects");
}
marshalNode(this);
const address = TRANSFER_BUFFER + SIZE_OF_NODE;
marshalPoint(address, start2);
marshalPoint(address + SIZE_OF_POINT, end);
C._ts_node_named_descendant_for_position_wasm(this.tree[0]);
return unmarshalNode(this.tree);
}
/**
* Create a new {@link TreeCursor} starting from this node.
*
* Note that the given node is considered the root of the cursor,
* and the cursor cannot walk outside this node.
*/
walk() {
marshalNode(this);
C._ts_tree_cursor_new_wasm(this.tree[0]);
return new TreeCursor(INTERNAL, this.tree);
}
/**
* Edit this node to keep it in-sync with source code that has been edited.
*
* This function is only rarely needed. When you edit a syntax tree with
* the {@link Tree#edit} method, all of the nodes that you retrieve from
* the tree afterward will already reflect the edit. You only need to
* use {@link Node#edit} when you have a specific {@link Node} instance that
* you want to keep and continue to use after an edit.
*/
edit(edit) {
if (this.startIndex >= edit.oldEndIndex) {
this.startIndex = edit.newEndIndex + (this.startIndex - edit.oldEndIndex);
let subbedPointRow;
let subbedPointColumn;
if (this.startPosition.row > edit.oldEndPosition.row) {
subbedPointRow = this.startPosition.row - edit.oldEndPosition.row;
subbedPointColumn = this.startPosition.column;
} else {
subbedPointRow = 0;
subbedPointColumn = this.startPosition.column;
if (this.startPosition.column >= edit.oldEndPosition.column) {
subbedPointColumn = this.startPosition.column - edit.oldEndPosition.column;
}
}
if (subbedPointRow > 0) {
this.startPosition.row += subbedPointRow;
this.startPosition.column = subbedPointColumn;
} else {
this.startPosition.column += subbedPointColumn;
}
} else if (this.startIndex > edit.startIndex) {
this.startIndex = edit.newEndIndex;
this.startPosition.row = edit.newEndPosition.row;
this.startPosition.column = edit.newEndPosition.column;
}
}
/** Get the S-expression representation of this node. */
toString() {
marshalNode(this);
const address = C._ts_node_to_string_wasm(this.tree[0]);
const result = C.AsciiToString(address);
C._free(address);
return result;
}
};
// src/marshal.ts
function unmarshalCaptures(query, tree, address, patternIndex, result) {
for (let i2 = 0, n = result.length; i2 < n; i2++) {
const captureIndex = C.getValue(address, "i32");
address += SIZE_OF_INT;
const node = unmarshalNode(tree, address);
address += SIZE_OF_NODE;
result[i2] = { patternIndex, name: query.captureNames[captureIndex], node };
}
return address;
}
__name(unmarshalCaptures, "unmarshalCaptures");
function marshalNode(node, index = 0) {
let address = TRANSFER_BUFFER + index * SIZE_OF_NODE;
C.setValue(address, node.id, "i32");
address += SIZE_OF_INT;
C.setValue(address, node.startIndex, "i32");
address += SIZE_OF_INT;
C.setValue(address, node.startPosition.row, "i32");
address += SIZE_OF_INT;
C.setValue(address, node.startPosition.column, "i32");
address += SIZE_OF_INT;
C.setValue(address, node[0], "i32");
}
__name(marshalNode, "marshalNode");
function unmarshalNode(tree, address = TRANSFER_BUFFER) {
const id = C.getValue(address, "i32");
address += SIZE_OF_INT;
if (id === 0) return null;
const index = C.getValue(address, "i32");
address += SIZE_OF_INT;
const row = C.getValue(address, "i32");
address += SIZE_OF_INT;
const column = C.getValue(address, "i32");
address += SIZE_OF_INT;
const other = C.getValue(address, "i32");
const result = new Node(INTERNAL, {
id,
tree,
startIndex: index,
startPosition: { row, column },
other
});
return result;
}
__name(unmarshalNode, "unmarshalNode");
function marshalTreeCursor(cursor, address = TRANSFER_BUFFER) {
C.setValue(address + 0 * SIZE_OF_INT, cursor[0], "i32");
C.setValue(address + 1 * SIZE_OF_INT, cursor[1], "i32");
C.setValue(address + 2 * SIZE_OF_INT, cursor[2], "i32");
C.setValue(address + 3 * SIZE_OF_INT, cursor[3], "i32");
}
__name(marshalTreeCursor, "marshalTreeCursor");
function unmarshalTreeCursor(cursor) {
cursor[0] = C.getValue(TRANSFER_BUFFER + 0 * SIZE_OF_INT, "i32");
cursor[1] = C.getValue(TRANSFER_BUFFER + 1 * SIZE_OF_INT, "i32");
cursor[2] = C.getValue(TRANSFER_BUFFER + 2 * SIZE_OF_INT, "i32");
cursor[3] = C.getValue(TRANSFER_BUFFER + 3 * SIZE_OF_INT, "i32");
}
__name(unmarshalTreeCursor, "unmarshalTreeCursor");
function marshalPoint(address, point) {
C.setValue(address, point.row, "i32");
C.setValue(address + SIZE_OF_INT, point.column, "i32");
}
__name(marshalPoint, "marshalPoint");
function unmarshalPoint(address) {
const result = {
row: C.getValue(address, "i32") >>> 0,
column: C.getValue(address + SIZE_OF_INT, "i32") >>> 0
};
return result;
}
__name(unmarshalPoint, "unmarshalPoint");
function marshalRange(address, range) {
marshalPoint(address, range.startPosition);
address += SIZE_OF_POINT;
marshalPoint(address, range.endPosition);
address += SIZE_OF_POINT;
C.setValue(address, range.startIndex, "i32");
address += SIZE_OF_INT;
C.setValue(address, range.endIndex, "i32");
address += SIZE_OF_INT;
}
__name(marshalRange, "marshalRange");
function unmarshalRange(address) {
const result = {};
result.startPosition = unmarshalPoint(address);
address += SIZE_OF_POINT;
result.endPosition = unmarshalPoint(address);
address += SIZE_OF_POINT;
result.startIndex = C.getValue(address, "i32") >>> 0;
address += SIZE_OF_INT;
result.endIndex = C.getValue(address, "i32") >>> 0;
return result;
}
__name(unmarshalRange, "unmarshalRange");
function marshalEdit(edit, address = TRANSFER_BUFFER) {
marshalPoint(address, edit.startPosition);
address += SIZE_OF_POINT;
marshalPoint(address, edit.oldEndPosition);
address += SIZE_OF_POINT;
marshalPoint(address, edit.newEndPosition);
address += SIZE_OF_POINT;
C.setValue(address, edit.startIndex, "i32");
address += SIZE_OF_INT;
C.setValue(address, edit.oldEndIndex, "i32");
address += SIZE_OF_INT;
C.setValue(address, edit.newEndIndex, "i32");
address += SIZE_OF_INT;
}
__name(marshalEdit, "marshalEdit");
function unmarshalLanguageMetadata(address) {
const major_version = C.getValue(address, "i32");
const minor_version = C.getValue(address += SIZE_OF_INT, "i32");
const patch_version = C.getValue(address += SIZE_OF_INT, "i32");
return { major_version, minor_version, patch_version };
}
__name(unmarshalLanguageMetadata, "unmarshalLanguageMetadata");
// src/language.ts
var LANGUAGE_FUNCTION_REGEX = /^tree_sitter_\w+$/;
var Language = class _Language {
static {
__name(this, "Language");
}
/** @internal */
[0] = 0;
// Internal handle for Wasm
/**
* A list of all node types in the language. The index of each type in this
* array is its node type id.
*/
types;
/**
* A list of all field names in the language. The index of each field name in
* this array is its field id.
*/
fields;
/** @internal */
constructor(internal, address) {
assertInternal(internal);
this[0] = address;
this.types = new Array(C._ts_language_symbol_count(this[0]));
for (let i2 = 0, n = this.types.length; i2 < n; i2++) {
if (C._ts_language_symbol_type(this[0], i2) < 2) {
this.types[i2] = C.UTF8ToString(C._ts_language_symbol_name(this[0], i2));
}
}
this.fields = new Array(C._ts_language_field_count(this[0]) + 1);
for (let i2 = 0, n = this.fields.length; i2 < n; i2++) {
const fieldName = C._ts_language_field_name_for_id(this[0], i2);
if (fieldName !== 0) {
this.fields[i2] = C.UTF8ToString(fieldName);
} else {
this.fields[i2] = null;
}
}
}
/**
* Gets the name of the language.
*/
get name() {
const ptr = C._ts_language_name(this[0]);
if (ptr === 0) return null;
return C.UTF8ToString(ptr);
}
/**
* Gets the ABI version of the language.
*/
get abiVersion() {
return C._ts_language_abi_version(this[0]);
}
/**
* Get the metadata for this language. This information is generated by the
* CLI, and relies on the language author providing the correct metadata in
* the language's `tree-sitter.json` file.
*/
get metadata() {
C._ts_language_metadata_wasm(this[0]);
const length = C.getValue(TRANSFER_BUFFER, "i32");
if (length === 0) return null;
return unmarshalLanguageMetadata(TRANSFER_BUFFER + SIZE_OF_INT);
}
/**
* Gets the number of fields in the language.
*/
get fieldCount() {
return this.fields.length - 1;
}
/**
* Gets the number of states in the language.
*/
get stateCount() {
return C._ts_language_state_count(this[0]);
}
/**
* Get the field id for a field name.
*/
fieldIdForName(fieldName) {
const result = this.fields.indexOf(fieldName);
return result !== -1 ? result : null;
}
/**
* Get the field name for a field id.
*/
fieldNameForId(fieldId) {
return this.fields[fieldId] ?? null;
}
/**
* Get the node type id for a node type name.
*/
idForNodeType(type, named) {
const typeLength = C.lengthBytesUTF8(type);
const typeAddress = C._malloc(typeLength + 1);
C.stringToUTF8(type, typeAddress, typeLength + 1);
const result = C._ts_language_symbol_for_name(this[0], typeAddress, typeLength, named ? 1 : 0);
C._free(typeAddress);
return result || null;
}
/**
* Gets the number of node types in the language.
*/
get nodeTypeCount() {
return C._ts_language_symbol_count(this[0]);
}
/**
* Get the node type name for a node type id.
*/
nodeTypeForId(typeId) {
const name2 = C._ts_language_symbol_name(this[0], typeId);
return name2 ? C.UTF8ToString(name2) : null;
}
/**
* Check if a node type is named.
*
* @see {@link https://tree-sitter.github.io/tree-sitter/using-parsers/2-basic-parsing.html#named-vs-anonymous-nodes}
*/
nodeTypeIsNamed(typeId) {
return C._ts_language_type_is_named_wasm(this[0], typeId) ? true : false;
}
/**
* Check if a node type is visible.
*/
nodeTypeIsVisible(typeId) {
return C._ts_language_type_is_visible_wasm(this[0], typeId) ? true : false;
}
/**
* Get the supertypes ids of this language.
*
* @see {@link https://tree-sitter.github.io/tree-sitter/using-parsers/6-static-node-types.html?highlight=supertype#supertype-nodes}
*/
get supertypes() {
C._ts_language_supertypes_wasm(this[0]);
const count = C.getValue(TRANSFER_BUFFER, "i32");
const buffer = C.getValue(TRANSFER_BUFFER + SIZE_OF_INT, "i32");
const result = new Array(count);
if (count > 0) {
let address = buffer;
for (let i2 = 0; i2 < count; i2++) {
result[i2] = C.getValue(address, "i16");
address += SIZE_OF_SHORT;
}
}
return result;
}
/**
* Get the subtype ids for a given supertype node id.
*/
subtypes(supertype) {
C._ts_language_subtypes_wasm(this[0], supertype);
const count = C.getValue(TRANSFER_BUFFER, "i32");
const buffer = C.getValue(TRANSFER_BUFFER + SIZE_OF_INT, "i32");
const result = new Array(count);
if (count > 0) {
let address = buffer;
for (let i2 = 0; i2 < count; i2++) {
result[i2] = C.getValue(address, "i16");
address += SIZE_OF_SHORT;
}
}
return result;
}
/**
* Get the next state id for a given state id and node type id.
*/
nextState(stateId, typeId) {
return C._ts_language_next_state(this[0], stateId, typeId);
}
/**
* Create a new lookahead iterator for this language and parse state.
*
* This returns `null` if state is invalid for this language.
*
* Iterating {@link LookaheadIterator} will yield valid symbols in the given
* parse state. Newly created lookahead iterators will return the `ERROR`
* symbol from {@link LookaheadIterator#currentType}.
*
* Lookahead iterators can be useful for generating suggestions and improving
* syntax error diagnostics. To get symbols valid in an `ERROR` node, use the
* lookahead iterator on its first leaf node state. For `MISSING` nodes, a
* lookahead iterator created on the previous non-extra leaf node may be
* appropriate.
*/
lookaheadIterator(stateId) {
const address = C._ts_lookahead_iterator_new(this[0], stateId);
if (address) return new LookaheadIterator(INTERNAL, address, this);
return null;
}
/**
* Load a language from a WebAssembly module.
* The module can be provided as a path to a file or as a buffer.
*/
static async load(input) {
let binary2;
if (input instanceof Uint8Array) {
binary2 = input;
} else if (globalThis.process?.versions.node) {
const fs2 = await import("fs/promises");
binary2 = await fs2.readFile(input);
} else {
const response = await fetch(input);
if (!response.ok) {
const body2 = await response.text();
throw new Error(`Language.load failed with status ${response.status}.
${body2}`);
}
const retryResp = response.clone();
try {
binary2 = await WebAssembly.compileStreaming(response);
} catch (reason) {
console.error("wasm streaming compile failed:", reason);
console.error("falling back to ArrayBuffer instantiation");
binary2 = new Uint8Array(await retryResp.arrayBuffer());
}
}
const mod = await C.loadWebAssemblyModule(binary2, { loadAsync: true });
const symbolNames = Object.keys(mod);
const functionName = symbolNames.find((key) => LANGUAGE_FUNCTION_REGEX.test(key) && !key.includes("external_scan