Skip to main content

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
    }
  },
});

Pattern Information

patternCount()

Get the number of patterns in the query.
patternCount(): number

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

Capture Information

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.
delete(): void

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

Build docs developers (and LLMs) love