UNPKG

tree-sitter

Version:

Node.js bindings to the Tree-sitter parsing library

1,043 lines (894 loc) 35 kB
/** @module */ declare module "tree-sitter" { class Parser { /** * Parse UTF8 text into a syntax tree. * * @param input - The text to parse, either as a string or a custom input function * that provides text chunks. If providing a function, it should return text chunks * based on byte index and position. * * @param oldTree - An optional previous syntax tree from the same document. * If provided and the document has changed, you must first edit this tree using * {@link Parser.Tree.edit} to match the new text. * * @param options - Optional parsing settings: * - bufferSize: Size of internal parsing buffer * - includedRanges: Array of ranges to parse within the input * * @returns A syntax tree representing the parsed text * * @throws May return null or fail if: * - No language has been set via {@link Parser.setLanguage} * - The parsing timeout (set via {@link Parser.setTimeoutMicros}) was reached * - Parsing was cancelled via cancellation flag */ parse(input: string | Parser.Input, oldTree?: Parser.Tree | null, options?: Parser.Options): Parser.Tree; /** * Get the ranges of text that the parser will include when parsing. * * @returns An array of ranges that will be included in parsing */ getIncludedRanges(): Parser.Range[]; /** * Get the duration in microseconds that parsing is allowed to take. * * This timeout can be set via {@link Parser.setTimeoutMicros}. * * @returns The parsing timeout in microseconds */ getTimeoutMicros(): number; /** * Set the maximum duration that parsing is allowed to take before halting. * * If parsing takes longer than this, it will halt early, returning null. * * @param timeout - The maximum parsing duration in microseconds */ setTimeoutMicros(timeout: number): void; /** * Instruct the parser to start the next parse from the beginning. * * If the parser previously failed because of a timeout or cancellation, * it will resume where it left off on the next parse by default. * Call this method if you want to parse a different document instead * of resuming. */ reset(): void; /** * Get the parser's current language */ getLanguage(): Parser.Language; /** * Set the language that the parser should use for parsing. * * The language must be compatible with the version of tree-sitter * being used. A version mismatch will prevent the language from * being assigned successfully. * * @param language - The language to use for parsing */ setLanguage(language?: Parser.Language): void; /** * Get the parser's current logger * * @returns The current logging callback */ getLogger(): Parser.Logger; /** * Set the logging callback that the parser should use during parsing. * * @param logFunc - The logging callback to use, or null/false to disable logging */ setLogger(logFunc?: Parser.Logger | string | false | null): void; /** * Set the destination to which the parser should write debugging graphs during parsing. * * The graphs are formatted in the DOT language. You may want to pipe these graphs * directly to a 'dot' process to generate SVG output. * * @param enabled - Whether to enable or disable graph output * @param fd - Optional file descriptor for the output */ printDotGraphs(enabled?: boolean, fd?: number): void; } namespace Parser { /** Configuration options for parsing */ export type Options = { /** Size of the internal parsing buffer */ bufferSize?: number; /** Array of ranges to include when parsing the input */ includedRanges?: Range[]; }; /** * A position in a multi-line text document, in terms of rows and columns. * Both values are zero-based. */ export type Point = { /** Zero-based row number */ row: number; /** Zero-based column number */ column: number; }; /** * A range of positions in a multi-line text document, specified both in * terms of byte offsets and row/column positions. */ export type Range = { /** The byte offset of the start of the range */ startIndex: number; /** The byte offset of the end of the range */ endIndex: number; /** The row and column where the range starts */ startPosition: Point; /** The row and column where the range ends */ endPosition: Point; }; /** * A summary of a change to a text document */ export type Edit = { /** The byte offset where the edit starts */ startIndex: number; /** The byte offset where the edit ends in the old document */ oldEndIndex: number; /** The byte offset where the edit ends in the new document */ newEndIndex: number; /** The row and column where the edit starts */ startPosition: Point; /** The row and column where the edit ends in the old document */ oldEndPosition: Point; /** The row and column where the edit ends in the new document */ newEndPosition: Point; }; /** * A callback that receives log messages during parser. * * @param message - The log message * @param params - Parameters associated with the log message * @param type - The type of log message */ export type Logger = ( message: string, params: { [param: string]: string }, type: "parse" | "lex" ) => void; /** A function that provides text content for parsing based on byte index and position */ export interface Input { /** * Get a chunk of text at the given byte offset. * * @param index - The byte index into the text * @param position - Optional position in the text as {row, column} * @returns A string chunk, or null/undefined if no text at this index */ (index: number, position?: Point): string | null | undefined | {}; } /** The syntax tree that contains this node */ export interface SyntaxNode { /** The syntax tree that contains this node */ tree: Tree; /** * A unique numeric identifier for this node. * Within a given syntax tree, no two nodes have the same id. * If a new tree is created based on an older tree and reuses * a node, that node will have the same id in both trees. */ id: number; /** * This node's type as a numeric id */ typeId: number; /** * This node's type as a numeric id as it appears in the grammar, * ignoring aliases */ grammarId: number; /** * This node's type as a string */ type: string; /** * This node's symbol name as it appears in the grammar, * ignoring aliases */ grammarType: string; /** * Whether this node is named. * Named nodes correspond to named rules in the grammar, * whereas anonymous nodes correspond to string literals in the grammar. */ isNamed: boolean; /** * Whether this node is missing. * Missing nodes are inserted by the parser in order to * recover from certain kinds of syntax errors. */ isMissing: boolean; /** * Whether this node is extra. * Extra nodes represent things like comments, which are not * required by the grammar but can appear anywhere. */ isExtra: boolean; /** * Whether this node has been edited */ hasChanges: boolean; /** * Whether this node represents a syntax error or contains * any syntax errors within it */ hasError: boolean; /** * Whether this node represents a syntax error. * Syntax errors represent parts of the code that could not * be incorporated into a valid syntax tree. */ isError: boolean; /** The text content for this node from the source code */ text: string; /** The parse state of this node */ parseState: number; /** The parse state that follows this node */ nextParseState: number; /** The position where this node starts in terms of rows and columns */ startPosition: Point; /** The position where this node ends in terms of rows and columns */ endPosition: Point; /** The byte offset where this node starts */ startIndex: number; /** The byte offset where this node ends */ endIndex: number; /** * This node's immediate parent. * For iterating over ancestors, prefer using {@link childWithDescendant} */ parent: SyntaxNode | null; /** Array of all child nodes */ children: Array<SyntaxNode>; /** Array of all named child nodes */ namedChildren: Array<SyntaxNode>; /** The number of children this node has */ childCount: number; /** * The number of named children this node has. * @see {@link isNamed} */ namedChildCount: number; /** The first child of this node */ firstChild: SyntaxNode | null; /** The first named child of this node */ firstNamedChild: SyntaxNode | null; /** The last child of this node */ lastChild: SyntaxNode | null; /** The last child of this node */ lastNamedChild: SyntaxNode | null; /** This node's next sibling */ nextSibling: SyntaxNode | null; /** This node's next named sibling */ nextNamedSibling: SyntaxNode | null; /** This node's previous sibling */ previousSibling: SyntaxNode | null; /** This node's previous named sibling */ previousNamedSibling: SyntaxNode | null; /** * The number of descendants this node has, including itself */ descendantCount: number; /** * Convert this node to its string representation */ toString(): string; /** * Get the node's child at the given index, where zero represents the first child. * * Note: While fairly fast, this method's cost is technically log(i). * For iterating over many children, prefer using the children array. * * @param index - Zero-based index of the child to retrieve * @returns The child node, or null if none exists at the given index */ child(index: number): SyntaxNode | null; /** * Get this node's named child at the given index. * * Note: While fairly fast, this method's cost is technically log(i). * For iterating over many children, prefer using the namedChildren array. * * @param index - Zero-based index of the named child to retrieve * @returns The named child node, or null if none exists at the given index */ namedChild(index: number): SyntaxNode | null; /** * Get the first child with the given field name. * * For fields that may have multiple children, use childrenForFieldName instead. * * @param fieldName - The field name to search for * @returns The child node, or null if no child has the given field name */ childForFieldName(fieldName: string): SyntaxNode | null; /** * Get this node's child with the given numerical field id. * * Field IDs can be obtained from field names using the parser's language object. * * @param fieldId - The field ID to search for * @returns The child node, or null if no child has the given field ID */ childForFieldId(fieldId: number): SyntaxNode | null; /** * Get the field name of the child at the given index * * @param childIndex - Zero-based index of the child * @returns The field name, or null if the child has no field name */ fieldNameForChild(childIndex: number): string | null; /** * Get the field name of the named child at the given index * * @param namedChildIndex - Zero-based index of the named child * @returns The field name, or null if the named child has no field name */ fieldNameForNamedChild(namedChildIndex: number): string | null; /** * Get all children that have the given field name * * @param fieldName - The field name to search for * @returns Array of child nodes with the given field name */ childrenForFieldName(fieldName: string): Array<SyntaxNode>; /** * Get all children that have the given field ID * * @param fieldId - The field ID to search for * @returns Array of child nodes with the given field ID */ childrenForFieldId(fieldId: number): Array<SyntaxNode>; /** * Get the node's first child that extends beyond the given byte offset * * @param index - The byte offset to search from * @returns The first child extending beyond the offset, or null if none found */ firstChildForIndex(index: number): SyntaxNode | null; /** * Get the node's first named child that extends beyond the given byte offset * * @param index - The byte offset to search from * @returns The first named child extending beyond the offset, or null if none found */ firstNamedChildForIndex(index: number): SyntaxNode | null; /** * Get the immediate child that contains the given descendant node. * Note that this can return the descendant itself if it is an immediate child. * * @param descendant - The descendant node to find the parent of * @returns The child containing the descendant, or null if not found */ childWithDescendant(descendant: SyntaxNode): SyntaxNode | null; /** * Get the smallest node within this node that spans the given byte offset. * * @param index - The byte offset to search for * @returns The smallest node spanning the offset */ descendantForIndex(index: number): SyntaxNode; /** * Get the smallest node within this node that spans the given byte range. * * @param startIndex - The starting byte offset * @param endIndex - The ending byte offset * @returns The smallest node spanning the range */ descendantForIndex(startIndex: number, endIndex: number): SyntaxNode; /** * Get the smallest named node within this node that spans the given byte offset. * * @param index - The byte offset to search for * @returns The smallest named node spanning the offset */ namedDescendantForIndex(index: number): SyntaxNode; /** * Get the smallest named node within this node that spans the given byte range. * * @param startIndex - The starting byte offset * @param endIndex - The ending byte offset * @returns The smallest named node spanning the range */ namedDescendantForIndex(startIndex: number, endIndex: number): SyntaxNode; /** * Get the smallest node within this node that spans the given position. * When only one position is provided, it's used as both start and end. * * @param position - The point to search for * @returns The smallest node spanning the position */ descendantForPosition(position: Point): SyntaxNode; /** * Get the smallest node within this node that spans the given position range. * * @param startPosition - The starting position * @param endPosition - The ending position * @returns The smallest node spanning the range */ descendantForPosition(startPosition: Point, endPosition: Point): SyntaxNode; /** * Get the smallest named node within this node that spans the given position. * When only one position is provided, it's used as both start and end. * * @param position - The point to search for * @returns The smallest named node spanning the position */ namedDescendantForPosition(position: Point): SyntaxNode; /** * Get the smallest named node within this node that spans the given position range. * * @param startPosition - The starting position * @param endPosition - The ending position * @returns The smallest named node spanning the range */ namedDescendantForPosition(startPosition: Point, endPosition: Point): SyntaxNode; /** * Get all descendants of this node that have the given type(s) * * @param types - A string or array of strings of node types to find * @param startPosition - Optional starting position to search from * @param endPosition - Optional ending position to search to * @returns Array of descendant nodes matching the given types */ descendantsOfType(types: String | Array<String>, startPosition?: Point, endPosition?: Point): Array<SyntaxNode>; /** * Find the closest ancestor of the current node that matches the given type(s). * * Starting from the node's parent, walks up the tree until it finds a node * whose type matches any of the given types. * * @example * const property = tree.rootNode.descendantForIndex(5); * // Find closest unary expression ancestor * const unary = property.closest('unary_expression'); * // Find closest binary or call expression ancestor * const expr = property.closest(['binary_expression', 'call_expression']); * * @param types - A string or array of strings representing the node types to search for * @returns The closest matching ancestor node, or null if none found * @throws If the argument is not a string or array of strings */ closest(types: String | Array<String>): SyntaxNode | null; /** * Create a new TreeCursor starting from this node. * * @returns A new cursor positioned at this node */ walk(): TreeCursor; } /** A stateful object for walking a syntax {@link Tree} efficiently */ export interface TreeCursor { /** The type of the current node as a string */ nodeType: string; /** The type of the current node as a numeric ID */ nodeTypeId: number; /** The parse state of the current node */ nodeStateId: number; /** The text of the current node */ nodeText: string; /** Whether the current node is named */ nodeIsNamed: boolean; /** Whether the current node is missing from the source code */ nodeIsMissing: boolean; /** The start position of the current node */ startPosition: Point; /** The end position of the current node */ endPosition: Point; /** The start byte index of the current node */ startIndex: number; /** The end byte index of the current node */ endIndex: number; /** The current node that the cursor is pointing to */ readonly currentNode: SyntaxNode; /** The field name of the current node */ readonly currentFieldName: string; /** The numerical field ID of the current node */ readonly currentFieldId: number; /** The depth of the current node relative to the node where the cursor was created */ readonly currentDepth: number; /** The index of the current node among all descendants of the original node */ readonly currentDescendantIndex: number; /** * Re-initialize this cursor to start at a new node * * @param node - The node to start from */ reset(node: SyntaxNode): void; /** * Re-initialize this cursor to the same position as another cursor. * Unlike reset(), this will not lose parent information and allows * reusing already created cursors. * * @param cursor - The cursor to copy the position from */ resetTo(cursor: TreeCursor): void; /** * Move this cursor to the parent of its current node. * * @returns true if cursor successfully moved, false if there was no parent * (cursor was already at the root node) */ gotoParent(): boolean; /** * Move this cursor to the first child of its current node. * * @returns true if cursor successfully moved, false if there were no children */ gotoFirstChild(): boolean; /** * Move this cursor to the last child of its current node. * Note: This may be slower than gotoFirstChild() as it needs to iterate * through all children to compute the position. * * @returns true if cursor successfully moved, false if there were no children */ gotoLastChild(): boolean; /** * Move this cursor to the first child that extends beyond the given byte offset * * @param goalIndex - The byte offset to search for * @returns true if a child was found and cursor moved, false otherwise */ gotoFirstChildForIndex(goalIndex: number): boolean; /** * Move this cursor to the first child that extends beyond the given position * * @param goalPosition - The position to search for * @returns true if a child was found and cursor moved, false otherwise */ gotoFirstChildForPosition(goalPosition: Point): boolean; /** * Move this cursor to the next sibling of its current node * * @returns true if cursor successfully moved, false if there was no next sibling */ gotoNextSibling(): boolean; /** * Move this cursor to the previous sibling of its current node. * Note: This may be slower than gotoNextSibling() due to how node positions * are stored. In the worst case, it will need to iterate through all previous * siblings to recalculate positions. * * @returns true if cursor successfully moved, false if there was no previous sibling */ gotoPreviousSibling(): boolean; /** * Move the cursor to the descendant node at the given index, where zero * represents the original node the cursor was created with. * * @param goalDescendantIndex - The index of the descendant to move to */ gotoDescendant(goalDescendantIndex: number): void; } /** * A tree that represents the syntactic structure of a source code file. */ export interface Tree { /** * The root node of the syntax tree */ readonly rootNode: SyntaxNode; /** * Get the root node of the syntax tree, but with its position shifted * forward by the given offset. * * @param offsetBytes - The number of bytes to shift by * @param offsetExtent - The number of rows/columns to shift by * @returns The root node with its position offset */ rootNodeWithOffset(offsetBytes: number, offsetExtent: Point): SyntaxNode; /** * Edit the syntax tree to keep it in sync with source code that has been edited. * The edit must be described both in terms of byte offsets and in terms of * row/column coordinates. * * @param edit - The edit to apply to the tree * @returns The edited tree */ edit(edit: Edit): Tree; /** * Create a new TreeCursor starting from the root of the tree. * * @returns A new cursor positioned at the root node */ walk(): TreeCursor; /** * Get the text for a node within this tree * * @param node - The syntax node to get text for * @returns The source text for the node */ getText(node: SyntaxNode): string; /** * Compare this edited syntax tree to a new syntax tree representing the * same document, returning ranges whose syntactic structure has changed. * * For this to work correctly, this tree must have been edited to match * the new tree's ranges. Generally, you'll want to call this right after * parsing, using the old tree that was passed to parse and the new tree * that was returned. * * @param other - The new tree to compare against * @returns Array of ranges that have changed */ getChangedRanges(other: Tree): Range[]; /** * Get the ranges that were included when parsing this syntax tree * * @returns Array of included ranges */ getIncludedRanges(): Range[]; /** * Get the range that was edited in this tree * * @returns The edited range */ getEditedRange(): Range; /** * Print a graph of the tree in the DOT language. * You may want to pipe this to a 'dot' process to generate SVG output. * * @param fd - Optional file descriptor for the output */ printDotGraph(fd?: number): void; } /** * A particular syntax node that was captured by a named pattern in a query. */ export interface QueryCapture { /** The name that was used to capture the node in the query */ name: string; /** The captured syntax node */ node: SyntaxNode; } /** * A match of a {@link Query} to a particular set of {@link SyntaxNode}s. */ export interface QueryMatch { /** * The index of the pattern that was matched. * Each pattern in a query is assigned a numeric index in sequence. */ pattern: number; /** Array of nodes that were captured in the pattern match */ captures: QueryCapture[]; } export type QueryOptions = { /** The starting row/column position in which the query will be executed. */ startPosition?: Point; /** The ending row/column position in which the query will be executed. */ endPosition?: Point; /** The starting byte offset in which the query will be executed. */ startIndex?: number; /** The ending byte offset in which the query will be executed. */ endIndex?: number; /** The maximum number of in-progress matches for this cursor. The limit must be > 0 and <= 65536. */ matchLimit?: number; /** * The maximum start depth for a query cursor. * * This prevents cursors from exploring children nodes at a certain depth. * Note if a pattern includes many children, then they will still be * checked. * * The zero max start depth value can be used as a special behavior and * it helps to destructure a subtree by staying on a node and using * captures for interested parts. Note that the zero max start depth * only limit a search depth for a pattern's root node but other nodes * that are parts of the pattern may be searched at any depth what * defined by the pattern structure. */ maxStartDepth?: number; /** * The maximum duration in microseconds that query execution should be allowed to * take before halting. * * If query execution takes longer than this, it will halt early, returning None. */ timeoutMicros?: number; }; export class Query { /** The maximum number of in-progress matches for this cursor. */ readonly matchLimit: number; /** * 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. */ constructor(language: Language, source: string | Buffer); /** * Iterate over all of the individual captures in the order that they * appear. * * This is useful if you don't care about which pattern matched, and just * want a single, ordered sequence of captures. * * @param node - The syntax node to query * @param options - Optional query options * * @returns An array of captures */ captures(node: SyntaxNode, options?: QueryOptions): QueryCapture[]; /** * Iterate over all of the matches in the order that they were found. * * Each match contains the index of the pattern that matched, and a list of * captures. Because multiple patterns can match the same set of nodes, * one match may contain captures that appear *before* some of the * captures from a previous match. * * @param node - The syntax node to query * @param options - Optional query options * * @returns An array of matches */ matches(node: SyntaxNode, options?: QueryOptions): QueryMatch[]; /** * Disable a certain capture within a query. * * This prevents the capture from being returned in matches, and also * avoids any resource usage associated with recording the capture. * * @param captureName - The name of the capture to disable */ disableCapture(captureName: string): void; /** * Disable a certain pattern within a query. * * This prevents the pattern from matching, and also avoids any resource * usage associated with the pattern. * * @param patternIndex - The index of the pattern to disable */ disablePattern(patternIndex: number): void; /** * Check if a given step in a query is 'definite'. * * A query step is 'definite' if its parent pattern will be guaranteed to * match successfully once it reaches the step. * * @param byteOffset - The byte offset of the step to check */ isPatternGuaranteedAtStep(byteOffset: number): boolean; /** * Check if a given pattern within a query has a single root node. * * @param patternIndex - The index of the pattern to check */ isPatternRooted(patternIndex: number): boolean; /** * Check if a given pattern within a query has a single root node. * * @param patternIndex - The index of the pattern to check */ isPatternNonLocal(patternIndex: number): boolean; /** * Get the byte offset where the given pattern starts in the query's * source. * * @param patternIndex - The index of the pattern to check * * @returns The byte offset where the pattern starts */ startIndexForPattern(patternIndex: number): number; /** * Get the byte offset where the given pattern ends in the query's * source. * * @param patternIndex - The index of the pattern to check * * @returns The byte offset where the pattern ends */ endIndexForPattern(patternIndex: number): number; /** * Check if, on its last execution, this cursor exceeded its maximum number * of in-progress matches. * * @returns true if the cursor exceeded its match limit */ didExceedMatchLimit(): boolean; } export class LookaheadIterator { /** The current symbol of the lookahead iterator. */ readonly currentTypeId: number; /** The current symbol name of the lookahead iterator. */ readonly currentType: string; /** * Create a new lookahead iterator for this language and parse state. * * This returns `null` if the state is invalid for this language. * * Iterating {@link LookaheadIterator} will yield valid symbols in the given * parse state. Newly created lookahead iterators will have {@link currentType} * populated with the `ERROR` symbol. * * Lookahead iterators can be useful to generate suggestions and improve * 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. * * @param language - The language to use for the lookahead iterator * @param state - The parse state to use for the lookahead iterator */ constructor(language: Language, state: number); /** * Reset the lookahead iterator. * * This returns `true` if the language was set successfully and `false` * otherwise. * * @param language - The language to use for the lookahead iterator * @param stateId - The parse state to use for the lookahead iterator */ reset(language: Language, stateId: number): boolean; /** * Reset the lookahead iterator to another state. * * This returns `true` if the iterator was reset to the given state and * `false` otherwise. * * @param stateId - The parse state to reset the lookahead iterator to */ resetState(stateId: number): boolean; /** * Get an iterator for the lookahead iterator. * * This allows the lookahead iterator to be used in a for-of loop, * iterating over the valid symbols in the current parse state. * * @returns An iterator over the symbol names */ [Symbol.iterator](): Iterator<string>; } /** The base node type */ type BaseNode = { /** The node's type */ type: string; /** Whether the node is named */ named: boolean; }; /** A child within a node */ type ChildNode = { /** Whether the child is repeated */ multiple: boolean; /** Whether the child is required */ required: boolean; /** The child's type */ types: BaseNode[]; }; /** Information about a language's node types */ type NodeInfo = | (BaseNode & { /** The subtypes of this node if it's a supertype */ subtypes: BaseNode[]; }) | (BaseNode & { /** The fields within this node */ fields: { [name: string]: ChildNode }; /** The child nodes of this node */ children: ChildNode[]; }); /** Information about a language */ interface Language { /** The name of the language */ name: string; /** The inner language object */ language: Language; /** The node type information of the language */ nodeTypeInfo: NodeInfo[]; } } export = Parser }