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.

Query operators extend the basic pattern syntax with powerful features for capturing specific nodes, repeating patterns, creating alternatives, and controlling match behavior.

Capturing Nodes

When matching patterns, you often want to process specific nodes within the pattern. Captures allow you to associate names with specific nodes so you can refer to them later. Capture names are written after the nodes they refer to and start with an @ character.

Basic Capture

This pattern matches any assignment of a function to an identifier, capturing the identifier as the-function-name:
(assignment_expression
  left: (identifier) @the-function-name
  right: (function))

Multiple Captures

You can capture multiple nodes in a single pattern. This matches all method definitions, capturing both the method name and class name:
(class_declaration
  name: (identifier) @the-class-name
  body: (class_body
    (method_definition
      name: (property_identifier) @the-method-name)))
Capture names can use hyphens, underscores, dots, and alphanumeric characters. Common conventions include @function.name, @variable.builtin, or @keyword.

Quantification Operators

Quantification operators match repeating sequences of sibling nodes, similar to regular expression quantifiers.

One or More: +

The + operator matches one or more repetitions of a pattern. Match a sequence of one or more comments:
(comment)+

Zero or More: *

The * operator matches zero or more repetitions of a pattern. Match a class declaration, capturing all decorators if any are present:
(class_declaration
  (decorator)* @the-decorator
  name: (identifier) @the-name)

Optional: ?

The ? operator marks a node as optional. Match all function calls, capturing a string argument if one is present:
(call_expression
  function: (identifier) @the-function
  arguments: (arguments (string)? @the-string-arg))
Use + when the pattern must appear at least once:
(import_statement (identifier)+ @imported_names)

Grouping Sibling Nodes

Use parentheses to group a sequence of sibling nodes. Groups can have quantification operators applied to them.

Basic Grouping

Match a comment followed by a function declaration:
(
  (comment)
  (function_declaration)
)

Quantified Groups

Match a comma-separated series of numbers:
(
  (number)
  ("," (number))*
)
This pattern:
  1. Matches the first number
  2. Matches zero or more groups of comma + number
Grouping is essential for matching common patterns like comma-separated lists, decorator chains, or documentation followed by declarations.

Alternations

An alternation is written as square brackets [] containing a list of alternative patterns, similar to character classes in regular expressions.

Alternations with Captures

Match a call to either a variable or an object property:
(call_expression
  function: [
    (identifier) @function
    (member_expression
      property: (property_identifier) @method)
  ])
In this pattern:
  • If the function is an identifier, capture it as @function
  • If the function is a member expression, capture the property as @method

Matching Multiple Tokens

Match a set of keyword tokens:
[
  "break"
  "delete"
  "else"
  "for"
  "function"
  "if"
  "return"
  "try"
  "while"
] @keyword
All alternatives in an alternation must be valid in the same structural position. They represent different ways to match the same syntactic role.

Anchors

The anchor operator . constrains how child patterns are matched based on their position among siblings.

First Child Anchor

When . is placed before the first child, that child only matches when it’s the first named node in the parent. Match only the first identifier in an array:
(array . (identifier) @the-element)
Without the anchor, this would match every identifier in the array. With the anchor, it matches only the first one.

Last Child Anchor

When . is placed after the last child, that child only matches when it’s the last named node in the parent. Match only the last expression in a block:
(block (_) @last-expression .)

Immediate Sibling Anchor

When . is placed between two child patterns, they only match immediate siblings. Given a dotted name like a.b.c.d, match only consecutive identifier pairs:
(dotted_name
  (identifier) @prev-id
  .
  (identifier) @next-id)
This matches: (a, b), (b, c), (c, d) Without the anchor, it would also match: (a, c), (b, d), (a, d) - all combinations.
Anchors ignore anonymous nodes when determining position. This ensures anchors work based on semantic structure, not just syntax tokens.

Combining Operators

Operators can be combined to create sophisticated patterns.

Quantified Captures with Alternations

Match multiple imports of specific types:
(import_statement
  ([
    (identifier)
    (aliased_import)
  ] @import)+)

Anchored Groups

Match a JSDoc comment immediately before a function:
(
  (comment)+ @doc
  .
  (function_declaration) @function
)

Nested Captures with Quantifiers

Match all parameters in a function:
(function_declaration
  name: (identifier) @function.name
  parameters: (formal_parameters
    (identifier)* @parameter.name))

Practical Examples

((comment) @todo
  (#match? @todo "TODO|FIXME|XXX"))
Captures comments containing TODO, FIXME, or XXX.
(call_expression
  function: (identifier) @func
  arguments: (arguments
    . (string) @first-arg))
Captures functions where the first argument is a string.
[
  (export_statement)
  (export_declaration)
] @export
Captures any form of export statement.
(call_expression
  function: (member_expression
    object: (call_expression) @chained))
Captures the inner call in chained calls like obj.method1().method2().

Best Practices

Name Captures Semantically

Use descriptive names like @function.name or @variable.builtin that indicate the role or meaning of captured nodes.

Use Anchors Judiciously

Anchors make patterns more specific but also more brittle. Use them when position truly matters.

Combine Quantifiers with Predicates

Use quantifiers to capture multiple nodes, then predicates to filter them based on content.

Test Alternations Thoroughly

Each alternative branch should be tested to ensure it matches the intended nodes.

Next Steps

Predicates

Add conditions and filters to your captured nodes

Query API

Execute queries programmatically using the C API