UNPKG

web-tree-sitter

Version:
1,487 lines (1,480 loc) 185 kB
var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); // 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 = 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/query.ts var PREDICATE_STEP_TYPE_CAPTURE = 1; var PREDICATE_STEP_TYPE_STRING = 2; var QUERY_WORD_REGEX = /[\w-]+/g; var CaptureQuantifier = { Zero: 0, ZeroOrOne: 1, ZeroOrMore: 2, One: 3, OneOrMore: 4 }; var isCaptureStep = /* @__PURE__ */ __name((step) => step.type === "capture", "isCaptureStep"); var isStringStep = /* @__PURE__ */ __name((step) => step.type === "string", "isStringStep"); var QueryErrorKind = { Syntax: 1, NodeName: 2, FieldName: 3, CaptureName: 4, PatternStructure: 5 }; var QueryError = class _QueryError extends Error { constructor(kind, info2, index, length) { super(_QueryError.formatMessage(kind, info2)); this.kind = kind; this.info = info2; this.index = index; this.length = length; this.name = "QueryError"; } static { __name(this, "QueryError"); } /** Formats an error message based on the error kind and info */ static formatMessage(kind, info2) { switch (kind) { case QueryErrorKind.NodeName: return `Bad node name '${info2.word}'`; case QueryErrorKind.FieldName: return `Bad field name '${info2.word}'`; case QueryErrorKind.CaptureName: return `Bad capture name @${info2.word}`; case QueryErrorKind.PatternStructure: return `Bad pattern structure at offset ${info2.suffix}`; case QueryErrorKind.Syntax: return `Bad syntax at offset ${info2.suffix}`; } } }; function parseAnyPredicate(steps, index, operator, textPredicates) { if (steps.length !== 3) { throw new Error( `Wrong number of arguments to \`#${operator}\` predicate. Expected 2, got ${steps.length - 1}` ); } if (!isCaptureStep(steps[1])) { throw new Error( `First argument of \`#${operator}\` predicate must be a capture. Got "${steps[1].value}"` ); } const isPositive = operator === "eq?" || operator === "any-eq?"; const matchAll = !operator.startsWith("any-"); if (isCaptureStep(steps[2])) { const captureName1 = steps[1].name; const captureName2 = steps[2].name; textPredicates[index].push((captures) => { const nodes1 = []; const nodes2 = []; for (const c of captures) { if (c.name === captureName1) nodes1.push(c.node); if (c.name === captureName2) nodes2.push(c.node); } const compare = /* @__PURE__ */ __name((n1, n2, positive) => { return positive ? n1.text === n2.text : n1.text !== n2.text; }, "compare"); return matchAll ? nodes1.every((n1) => nodes2.some((n2) => compare(n1, n2, isPositive))) : nodes1.some((n1) => nodes2.some((n2) => compare(n1, n2, isPositive))); }); } else { const captureName = steps[1].name; const stringValue = steps[2].value; const matches = /* @__PURE__ */ __name((n) => n.text === stringValue, "matches"); const doesNotMatch = /* @__PURE__ */ __name((n) => n.text !== stringValue, "doesNotMatch"); textPredicates[index].push((captures) => { const nodes = []; for (const c of captures) { if (c.name === captureName) nodes.push(c.node); } const test = isPositive ? matches : doesNotMatch; return matchAll ? nodes.every(test) : nodes.some(test); }); } } __name(parseAnyPredicate, "parseAnyPredicate"); function parseMatchPredicate(steps, index, operator, textPredicates) { if (steps.length !== 3) { throw new Error( `Wrong number of arguments to \`#${operator}\` predicate. Expected 2, got ${steps.length - 1}.` ); } if (steps[1].type !== "capture") { throw new Error( `First argument of \`#${operator}\` predicate must be a capture. Got "${steps[1].value}".` ); } if (steps[2].type !== "string") { throw new Error( `Second argument of \`#${operator}\` predicate must be a string. Got @${steps[2].name}.` ); } const isPositive = operator === "match?" || operator === "any-match?"; const matchAll = !operator.startsWith("any-"); const captureName = steps[1].name; const regex = new RegExp(steps[2].value); textPredicates[index].push((captures) => { const nodes = []; for (const c of captures) { if (c.name === captureName) nodes.push(c.node.text); } const test = /* @__PURE__ */ __name((text, positive) => { return positive ? regex.test(text) : !regex.test(text); }, "test"); if (nodes.length === 0) return !isPositive; return matchAll ? nodes.every((text) => test(text, isPositive)) : nodes.some((text) => test(text, isPositive)); }); } __name(parseMatchPredicate, "parseMatchPredicate"); function parseAnyOfPredicate(steps, index, operator, textPredicates) { if (steps.length < 2) { throw new Error( `Wrong number of arguments to \`#${operator}\` predicate. Expected at least 1. Got ${steps.length - 1}.` ); } if (steps[1].type !== "capture") { throw new Error( `First argument of \`#${operator}\` predicate must be a capture. Got "${steps[1].value}".` ); } const isPositive = operator === "any-of?"; const captureName = steps[1].name; const stringSteps = steps.slice(2); if (!stringSteps.every(isStringStep)) { throw new Error( `Arguments to \`#${operator}\` predicate must be strings.".` ); } const values = stringSteps.map((s) => s.value); textPredicates[index].push((captures) => { const nodes = []; for (const c of captures) { if (c.name === captureName) nodes.push(c.node.text); } if (nodes.length === 0) return !isPositive; return nodes.every((text) => values.includes(text)) === isPositive; }); } __name(parseAnyOfPredicate, "parseAnyOfPredicate"); function parseIsPredicate(steps, index, operator, assertedProperties, refutedProperties) { if (steps.length < 2 || steps.length > 3) { throw new Error( `Wrong number of arguments to \`#${operator}\` predicate. Expected 1 or 2. Got ${steps.length - 1}.` ); } if (!steps.every(isStringStep)) { throw new Error( `Arguments to \`#${operator}\` predicate must be strings.".` ); } const properties = operator === "is?" ? assertedProperties : refutedProperties; if (!properties[index]) properties[index] = {}; properties[index][steps[1].value] = steps[2]?.value ?? null; } __name(parseIsPredicate, "parseIsPredicate"); function parseSetDirective(steps, index, setProperties) { if (steps.length < 2 || steps.length > 3) { throw new Error(`Wrong number of arguments to \`#set!\` predicate. Expected 1 or 2. Got ${steps.length - 1}.`); } if (!steps.every(isStringStep)) { throw new Error(`Arguments to \`#set!\` predicate must be strings.".`); } if (!setProperties[index]) setProperties[index] = {}; setProperties[index][steps[1].value] = steps[2]?.value ?? null; } __name(parseSetDirective, "parseSetDirective"); function parsePattern(index, stepType, stepValueId, captureNames, stringValues, steps, textPredicates, predicates, setProperties, assertedProperties, refutedProperties) { if (stepType === PREDICATE_STEP_TYPE_CAPTURE) { const name2 = captureNames[stepValueId]; steps.push({ type: "capture", name: name2 }); } else if (stepType === PREDICATE_STEP_TYPE_STRING) { steps.push({ type: "string", value: stringValues[stepValueId] }); } else if (steps.length > 0) { if (steps[0].type !== "string") { throw new Error("Predicates must begin with a literal value"); } const operator = steps[0].value; switch (operator) { case "any-not-eq?": case "not-eq?": case "any-eq?": case "eq?": parseAnyPredicate(steps, index, operator, textPredicates); break; case "any-not-match?": case "not-match?": case "any-match?": case "match?": parseMatchPredicate(steps, index, operator, textPredicates); break; case "not-any-of?": case "any-of?": parseAnyOfPredicate(steps, index, operator, textPredicates); break; case "is?": case "is-not?": parseIsPredicate(steps, index, operator, assertedProperties, refutedProperties); break; case "set!": parseSetDirective(steps, index, setProperties); break; default: predicates[index].push({ operator, operands: steps.slice(1) }); } steps.length = 0; } } __name(parsePattern, "parsePattern"); var Query = class { static { __name(this, "Query"); } /** @internal */ [0] = 0; // Internal handle for WASM /** @internal */ exceededMatchLimit; /** @internal */ textPredicates; /** The names of the captures used in the query. */ captureNames; /** The quantifiers of the captures used in the query. */ captureQuantifiers; /** * The other user-defined predicates associated with the given index. * * This includes predicates with operators other than: * - `match?` * - `eq?` and `not-eq?` * - `any-of?` and `not-any-of?` * - `is?` and `is-not?` * - `set!` */ predicates; /** The properties for predicates with the operator `set!`. */ setProperties; /** The properties for predicates with the operator `is?`. */ assertedProperties; /** The properties for predicates with the operator `is-not?`. */ refutedProperties; /** The maximum number of in-progress matches for this cursor. */ matchLimit; /** * Create a new query from a string containing one or more S-expression * patterns. * * The query is associated with a particular language, and can only be run * on syntax nodes parsed with that language. References to Queries can be * shared between multiple threads. * * @link {@see https://tree-sitter.github.io/tree-sitter/using-parsers/queries} */ constructor(language, source) { const sourceLength = C.lengthBytesUTF8(source); const sourceAddress = C._malloc(sourceLength + 1); C.stringToUTF8(source, sourceAddress, sourceLength + 1); const address = C._ts_query_new( language[0], sourceAddress, sourceLength, TRANSFER_BUFFER, TRANSFER_BUFFER + SIZE_OF_INT ); if (!address) { const errorId = C.getValue(TRANSFER_BUFFER + SIZE_OF_INT, "i32"); const errorByte = C.getValue(TRANSFER_BUFFER, "i32"); const errorIndex = C.UTF8ToString(sourceAddress, errorByte).length; const suffix = source.slice(errorIndex, errorIndex + 100).split("\n")[0]; const word = suffix.match(QUERY_WORD_REGEX)?.[0] ?? ""; C._free(sourceAddress); switch (errorId) { case QueryErrorKind.Syntax: throw new QueryError(QueryErrorKind.Syntax, { suffix: `${errorIndex}: '${suffix}'...` }, errorIndex, 0); case QueryErrorKind.NodeName: throw new QueryError(errorId, { word }, errorIndex, word.length); case QueryErrorKind.FieldName: throw new QueryError(errorId, { word }, errorIndex, word.length); case QueryErrorKind.CaptureName: throw new QueryError(errorId, { word }, errorIndex, word.length); case QueryErrorKind.PatternStructure: throw new QueryError(errorId, { suffix: `${errorIndex}: '${suffix}'...` }, errorIndex, 0); } } const stringCount = C._ts_query_string_count(address); const captureCount = C._ts_query_cap