Documentation Index
Fetch the complete documentation index at: https://mintlify.com/tree-sitter/tree-sitter/llms.txt
Use this file to discover all available pages before exploring further.
The Query class allows you to search for patterns in syntax trees using a powerful pattern matching language. Queries are written in a Scheme-like S-expression syntax.
Constructor
new Query(language, source)
Create a new query from a string containing one or more S-expression patterns.
constructor(language: Language, source: string)
Parameters:
language - The Language object associated with the query
source - A string containing one or more query patterns
Throws: QueryError if the query string is invalid
Example:
import { Query } from 'web-tree-sitter';
const query = new Query(JavaScript, `
(function_declaration
name: (identifier) @function.name)
(call_expression
function: (identifier) @function.call)
`);
Properties
captureNames
The names of the captures used in the query.
readonly captureNames: string[]
Example:
const query = new Query(JavaScript, '(identifier) @var');
console.log(query.captureNames); // ['var']
captureQuantifiers
The quantifiers of the captures used in the query.
readonly captureQuantifiers: CaptureQuantifier[][]
Quantifier values:
CaptureQuantifier.Zero (0) - Zero occurrences
CaptureQuantifier.ZeroOrOne (1) - Zero or one occurrence
CaptureQuantifier.ZeroOrMore (2) - Zero or more occurrences
CaptureQuantifier.One (3) - Exactly one occurrence
CaptureQuantifier.OneOrMore (4) - One or more occurrences
predicates
User-defined predicates associated with each pattern.
readonly predicates: QueryPredicate[][]
This includes predicates other than the built-in ones (match?, eq?, any-of?, is?, is-not?, set!).
setProperties
Properties set via the #set! directive for each pattern.
readonly setProperties: QueryProperties[]
assertedProperties
Properties asserted via the #is? directive for each pattern.
readonly assertedProperties: QueryProperties[]
refutedProperties
Properties refuted via the #is-not? directive for each pattern.
readonly refutedProperties: QueryProperties[]
Methods
matches(node, options?)
Execute the query and return all matches in the order they were found.
matches(node: Node, options?: QueryOptions): QueryMatch[]
Parameters:
node - The node to execute the query on (typically the root node)
options (optional) - Options for query execution
Returns: An array of QueryMatch objects
Example:
const tree = parser.parse('function one() { two(); function three() {} }');
const query = new Query(JavaScript, `
(function_declaration name: (identifier) @fn-def)
(call_expression function: (identifier) @fn-ref)
`);
const matches = query.matches(tree.rootNode);
for (const match of matches) {
console.log('Pattern:', match.patternIndex);
for (const capture of match.captures) {
console.log(' Capture:', capture.name, '=', capture.node.text);
}
}
// Pattern: 0
// Capture: fn-def = one
// Pattern: 1
// Capture: fn-ref = two
// Pattern: 0
// Capture: fn-def = three
captures(node, options?)
Execute the query and return all individual captures in the order they appear.
captures(node: Node, options?: QueryOptions): QueryCapture[]
Parameters:
node - The node to execute the query on
options (optional) - Options for query execution
Returns: An array of QueryCapture objects
Example:
const tree = parser.parse('const a = 1, b = 2, c = 3;');
const query = new Query(JavaScript, '(identifier) @var');
const captures = query.captures(tree.rootNode);
for (const capture of captures) {
console.log(capture.name, ':', capture.node.text);
}
// var : a
// var : b
// var : c
Use captures() when you want a single ordered sequence of all captures, regardless of which pattern matched. Use matches() when you care about which pattern matched and need to see all captures grouped by match.
Query Options
Both matches() and captures() accept an optional options parameter:
interface QueryOptions {
// Byte range
startIndex?: number;
endIndex?: number;
// Position range
startPosition?: Point;
endPosition?: Point;
// Containing byte range (matches must be fully contained)
startContainingIndex?: number;
endContainingIndex?: number;
// Containing position range (matches must be fully contained)
startContainingPosition?: Point;
endContainingPosition?: Point;
// Performance tuning
matchLimit?: number; // Max in-progress matches (default: 0xFFFFFFFF)
maxStartDepth?: number; // Max depth to search (default: 0xFFFFFFFF)
// Progress callback
progressCallback?: (state: QueryState) => void;
}
Example with range:
const captures = query.captures(tree.rootNode, {
startPosition: { row: 10, column: 0 },
endPosition: { row: 20, column: 0 },
});
Example with timeout:
const startTime = Date.now();
const captures = query.captures(tree.rootNode, {
progressCallback: (state) => {
if (Date.now() - startTime > 1000) {
return true; // Cancel query
}
},
});
patternCount()
Get the number of patterns in the query.
startIndexForPattern(patternIndex)
Get the byte offset where the given pattern starts in the query’s source.
startIndexForPattern(patternIndex: number): number
endIndexForPattern(patternIndex)
Get the byte offset where the given pattern ends in the query’s source.
endIndexForPattern(patternIndex: number): number
predicatesForPattern(patternIndex)
Get the predicates for a given pattern.
predicatesForPattern(patternIndex: number): QueryPredicate[]
isPatternRooted(patternIndex)
Check if a given pattern has a single root node.
isPatternRooted(patternIndex: number): boolean
isPatternNonLocal(patternIndex)
Check if a given pattern is non-local (can match at any depth).
isPatternNonLocal(patternIndex: number): boolean
isPatternGuaranteedAtStep(byteIndex)
Check if a given step in a query is ‘definite’ (guaranteed to match once reached).
isPatternGuaranteedAtStep(byteIndex: number): boolean
captureIndexForName(captureName)
Get the index for a given capture name.
captureIndexForName(captureName: string): number
Returns: The index, or -1 if not found
Example:
const query = new Query(JavaScript, '(identifier) @var');
const index = query.captureIndexForName('var');
console.log(index); // 0
Disabling Patterns and Captures
disablePattern(patternIndex)
Disable a pattern, preventing it from matching.
disablePattern(patternIndex: number): void
Example:
const query = new Query(JavaScript, `
(function_declaration) @func
(class_declaration) @class
`);
// Disable the class pattern
query.disablePattern(1);
const captures = query.captures(tree.rootNode);
// Will only find functions, not classes
disableCapture(captureName)
Disable a capture, preventing it from being returned in results.
disableCapture(captureName: string): void
Example:
const query = new Query(JavaScript, `
(function_declaration name: (identifier) @name body: (statement_block) @body)
`);
query.disableCapture('body');
const captures = query.captures(tree.rootNode);
// Will only return @name captures
Match Limit
didExceedMatchLimit()
Check if the query exceeded its maximum number of in-progress matches on the last execution.
didExceedMatchLimit(): boolean
Example:
const matches = query.matches(tree.rootNode, { matchLimit: 100 });
if (query.didExceedMatchLimit()) {
console.warn('Query hit match limit - results may be incomplete');
}
delete()
Delete the query and free its resources.
Types
QueryMatch
A match of a query to a set of nodes.
interface QueryMatch {
patternIndex: number; // Index of the pattern that matched
captures: QueryCapture[]; // All captures in this match
setProperties?: QueryProperties; // Properties from #set!
assertedProperties?: QueryProperties; // Properties from #is?
refutedProperties?: QueryProperties; // Properties from #is-not?
}
QueryCapture
A particular node that has been captured with a name.
interface QueryCapture {
patternIndex: number; // Index of the pattern
name: string; // Name of the capture
node: Node; // The captured node
setProperties?: QueryProperties; // Properties from #set!
assertedProperties?: QueryProperties; // Properties from #is?
refutedProperties?: QueryProperties; // Properties from #is-not?
}
QueryPredicate
A predicate that contains an operator and operands.
interface QueryPredicate {
operator: string; // e.g., 'match?', 'eq?', 'set!'
operands: PredicateStep[]; // Captures or strings
}
PredicateStep
A step in a predicate (either a capture or a string).
type PredicateStep = CapturePredicateStep | StringPredicateStep;
interface CapturePredicateStep {
type: 'capture';
name: string;
}
interface StringPredicateStep {
type: 'string';
value: string;
}
QueryError
Error thrown when parsing a query fails.
class QueryError extends Error {
kind: QueryErrorKind;
info: QueryErrorInfo[typeof kind];
index: number; // Byte offset where error occurred
length: number; // Length of the error region
}
Error kinds:
QueryErrorKind.Syntax (1) - Syntax error
QueryErrorKind.NodeName (2) - Invalid node type name
QueryErrorKind.FieldName (3) - Invalid field name
QueryErrorKind.CaptureName (4) - Invalid capture name
QueryErrorKind.PatternStructure (5) - Invalid pattern structure
Query Language
Basic Patterns
Match nodes by type:
(function_declaration) @function
Match with fields:
(function_declaration
name: (identifier) @name
body: (statement_block) @body)
Match nested structures:
(call_expression
function: (member_expression
object: (identifier) @object
property: (property_identifier) @method))
Wildcards
Match any node:
(function_declaration
name: (_) @name) ; Any node type
Anonymous Nodes
Match literal tokens:
(binary_expression
left: (_) @left
operator: "+" ; Match literal '+' token
right: (_) @right)
Alternation
Match multiple patterns:
[
(function_declaration) @function
(class_declaration) @class
]
Negation
Match nodes that are NOT a certain type:
(call_expression
function: (identifier) @func
(#not-eq? @func "console"))
Predicates
Text Predicates
Match against regex:
((identifier) @constant
(#match? @constant "^[A-Z_]+$"))
String equality:
((identifier) @console
(#eq? @console "console"))
Compare two captures:
((assignment_expression
left: (identifier) @left
right: (identifier) @right)
(#eq? @left @right)) ; Same variable on both sides
Check against multiple values:
((identifier) @keyword
(#any-of? @keyword "if" "else" "while" "for"))
Property Predicates
Assert a property:
((identifier) @local
(#is? local))
Refute a property:
((identifier) @global
(#is-not? local))
Set a property:
((function_declaration) @func
(#set! kind "function"))
Quantifiers
Match multiple children:
; Zero or more
(call_expression
arguments: (arguments (_)* @arg))
; One or more
(array (_)+ @element)
; Optional
(function_declaration
name: (identifier)? @name)
Examples
Find All Function Calls
const query = new Query(JavaScript, `
(call_expression
function: (identifier) @function)
`);
const captures = query.captures(tree.rootNode);
for (const { node } of captures) {
console.log('Function call:', node.text);
}
Find Unused Variables
const query = new Query(JavaScript, `
(lexical_declaration
(variable_declarator
name: (identifier) @var.def))
(identifier) @var.use
`);
const captures = query.captures(tree.rootNode);
const defined = new Set();
const used = new Set();
for (const capture of captures) {
if (capture.name === 'var.def') {
defined.add(capture.node.text);
} else {
used.add(capture.node.text);
}
}
const unused = [...defined].filter(v => !used.has(v));
console.log('Unused variables:', unused);
Extract Function Names and Bodies
const query = new Query(JavaScript, `
(function_declaration
name: (identifier) @name
body: (statement_block) @body)
`);
const matches = query.matches(tree.rootNode);
for (const match of matches) {
const name = match.captures.find(c => c.name === 'name');
const body = match.captures.find(c => c.name === 'body');
console.log('Function:', name.node.text);
console.log('Body:', body.node.text);
}
Find JSX Components
const query = new Query(JSX, `
(jsx_element
open_tag: (jsx_opening_element
name: (identifier) @component))
`);
const components = query.captures(tree.rootNode)
.map(c => c.node.text)
.filter((name, i, arr) => arr.indexOf(name) === i); // unique
console.log('Components used:', components);
See Also