# Query

Pattern-based querying for complex syntax tree analysis and extraction. Queries use S-expression patterns to match specific structures in syntax trees and extract relevant nodes with named captures.

## Capabilities

### Query Creation

Create queries from S-expression pattern strings.

```typescript { .api }
/**
 * Create a new query from S-expression patterns
 * @param language - Language the query is associated with
 * @param source - Query source containing one or more S-expression patterns
 */
constructor(language: Language, source: string);

/**
 * Delete the query and free its resources
 */
delete(): void;
```

**Usage Example:**

```typescript
import { Query, Language } from "web-tree-sitter";

const language = await Language.load("/tree-sitter-javascript.wasm");

// Create query to find function declarations with their names
const query = new Query(language, `
  (function_declaration
    name: (identifier) @function-name
    parameters: (formal_parameters) @params)
  
  (variable_declarator
    name: (identifier) @var-name
    value: (arrow_function) @arrow-func)
`);
```

### Pattern Matching

Execute queries to find matching patterns in syntax trees.

```typescript { .api }
/**
 * Get all matches in the order they were found
 * @param node - Root node to execute the query on
 * @param options - Query execution options
 * @returns Array of matches with pattern indices and captures
 */
matches(node: Node, options?: QueryOptions): QueryMatch[];

/**
 * Get all individual captures in the order they appear
 * @param node - Root node to execute the query on  
 * @param options - Query execution options
 * @returns Array of captures without grouping by match
 */
captures(node: Node, options?: QueryOptions): QueryCapture[];
```

**Usage Examples:**

```typescript
const tree = parser.parse(`
  function add(a, b) { return a + b; }
  const multiply = (x, y) => x * y;
`);

// Get all matches
const matches = query.matches(tree.rootNode);
console.log(`Found ${matches.length} matches`);

matches.forEach((match, i) => {
  console.log(`Match ${i} (pattern ${match.patternIndex}):`);
  match.captures.forEach(capture => {
    console.log(`  ${capture.name}: ${capture.node.text}`);
  });
});

// Get just the captures
const captures = query.captures(tree.rootNode);
captures.forEach(capture => {
  console.log(`${capture.name}: ${capture.node.text}`);
});
```

### Query Metadata

Access information about query patterns and captures.

```typescript { .api }
/** The names of the captures used in the query */
readonly captureNames: string[];

/** The quantifiers of the captures used in the query */
readonly captureQuantifiers: CaptureQuantifier[][];

/** The predicates associated with each pattern index */
readonly predicates: QueryPredicate[][];

/** Properties for predicates with the operator 'set!' */
readonly setProperties: QueryProperties[];

/** Properties for predicates with the operator 'is?' */
readonly assertedProperties: QueryProperties[];

/** Properties for predicates with the operator 'is-not?' */
readonly refutedProperties: QueryProperties[];
```

**Usage Example:**

```typescript
console.log("Capture names:", query.captureNames);
console.log("Pattern count:", query.patternCount());

// Check predicates for first pattern
const predicates = query.predicatesForPattern(0);
console.log("Predicates for pattern 0:", predicates);
```

### Pattern Information

Get detailed information about individual patterns.

```typescript { .api }
/**
 * Get the predicates for a given pattern
 * @param patternIndex - Index of the pattern
 * @returns Array of predicates for the pattern
 */
predicatesForPattern(patternIndex: number): QueryPredicate[];

/**
 * Get the byte offset where the given pattern starts in the query's source
 * @param patternIndex - Index of the pattern
 * @returns Start byte offset in query source
 */
startIndexForPattern(patternIndex: number): number;

/**
 * Get the byte offset where the given pattern ends in the query's source
 * @param patternIndex - Index of the pattern
 * @returns End byte offset in query source
 */
endIndexForPattern(patternIndex: number): number;

/**
 * Get the number of patterns in the query
 * @returns Total number of patterns
 */
patternCount(): number;
```

### Capture Management

Work with named captures in the query.

```typescript { .api }
/**
 * Get the index for a given capture name
 * @param captureName - Name of the capture to look up
 * @returns Index of the capture or -1 if not found
 */
captureIndexForName(captureName: string): number;

/**
 * Disable a certain capture within a query
 * @param captureName - Name of the capture to disable
 */
disableCapture(captureName: string): void;
```

**Usage Example:**

```typescript
// Disable a specific capture to improve performance
query.disableCapture("params");

// Get capture index
const nameIndex = query.captureIndexForName("function-name");
console.log("Function name capture index:", nameIndex);
```

### Pattern Control

Control pattern execution and analysis.

```typescript { .api }
/**
 * Disable a certain pattern within a query
 * @param patternIndex - Index of the pattern to disable
 */
disablePattern(patternIndex: number): void;

/**
 * Check if a given pattern within a query has a single root node
 * @param patternIndex - Index of the pattern to check
 * @returns True if pattern has single root node
 */
isPatternRooted(patternIndex: number): boolean;

/**
 * Check if a given pattern within a query is non-local
 * @param patternIndex - Index of the pattern to check
 * @returns True if pattern is non-local
 */
isPatternNonLocal(patternIndex: number): boolean;

/**
 * Check if a given step in a query is 'definite'
 * @param byteIndex - Byte index in the query source
 * @returns True if step is guaranteed to match
 */
isPatternGuaranteedAtStep(byteIndex: number): boolean;
```

### Match Limits and Performance

Control query execution limits and check performance metrics.

```typescript { .api }
/** The maximum number of in-progress matches for this query */
matchLimit?: number;

/**
 * Check if, on its last execution, this cursor exceeded its maximum number of in-progress matches
 * @returns True if match limit was exceeded
 */
didExceedMatchLimit(): boolean;
```

**Usage Example:**

```typescript
// Set match limit for performance
query.matchLimit = 1000;

const matches = query.matches(tree.rootNode);

if (query.didExceedMatchLimit()) {
  console.warn("Query exceeded match limit, results may be incomplete");
}
```

## Types

```typescript { .api }
interface QueryOptions {
  /** The start position of the range to query */
  startPosition?: Point;
  /** The end position of the range to query */
  endPosition?: Point;
  /** The start index of the range to query */
  startIndex?: number;
  /** The end index of the range to query */
  endIndex?: number;
  /** The maximum number of in-progress matches (1-65536) */
  matchLimit?: number;
  /** The maximum start depth for query cursor */
  maxStartDepth?: number;
  /** Maximum execution time in microseconds */
  timeoutMicros?: number;
  /** Progress callback for monitoring/cancelling execution */
  progressCallback?: (state: QueryState) => void;
}

interface QueryState {
  /** The byte offset in the document that the query is at */
  currentOffset: number;
}

/** Key-value pairs associated with a pattern */
type QueryProperties = Record<string, string | null>;

interface QueryPredicate {
  /** The operator of the predicate (match?, eq?, set!, etc.) */
  operator: string;
  /** The operands of the predicate (captures or strings) */
  operands: PredicateStep[];
}

interface QueryCapture {
  /** The index of the pattern that matched */
  patternIndex: number;
  /** The name of the capture */
  name: string;
  /** The captured node */
  node: Node;
  /** Properties for predicates declared with 'set!' */
  setProperties?: QueryProperties;
  /** Properties for predicates declared with 'is?' */
  assertedProperties?: QueryProperties;
  /** Properties for predicates declared with 'is-not?' */
  refutedProperties?: QueryProperties;
}

interface QueryMatch {
  /** @deprecated Use patternIndex instead */
  pattern: number;
  /** The index of the pattern that matched */
  patternIndex: number;
  /** The captures associated with the match */
  captures: QueryCapture[];
  /** Properties for predicates declared with 'set!' */
  setProperties?: QueryProperties;
  /** Properties for predicates declared with 'is?' */
  assertedProperties?: QueryProperties;
  /** Properties for predicates declared with 'is-not?' */
  refutedProperties?: QueryProperties;
}

/** Quantifiers for captures */
const CaptureQuantifier: {
  readonly Zero: 0;
  readonly ZeroOrOne: 1;
  readonly ZeroOrMore: 2;
  readonly One: 3;
  readonly OneOrMore: 4;
};

type CaptureQuantifier = typeof CaptureQuantifier[keyof typeof CaptureQuantifier];

/** Steps in predicates - either captures or strings */
type PredicateStep = CapturePredicateStep | StringPredicateStep;

interface CapturePredicateStep {
  type: 'capture';
  name: string;
}

interface StringPredicateStep {
  type: 'string';
  value: string;
}
```

## Query Examples

### Basic Pattern Matching

```typescript
// Find all function calls
const callQuery = new Query(language, `
  (call_expression
    function: (identifier) @function-name
    arguments: (arguments) @args)
`);

// Find all string literals
const stringQuery = new Query(language, `
  (string) @string-literal
`);
```

### Advanced Patterns with Predicates

```typescript
// Find functions with specific names
const specificFuncQuery = new Query(language, `
  (function_declaration
    name: (identifier) @name
    (#match? @name "^(test|spec)"))
`);

// Find variable declarations with initialization
const varQuery = new Query(language, `
  (variable_declarator
    name: (identifier) @var-name
    value: (_) @initial-value)
`);
```

### Complex Structural Patterns

```typescript
// Find nested function calls
const nestedQuery = new Query(language, `
  (call_expression
    function: (member_expression
      object: (identifier) @object
      property: (property_identifier) @method)
    arguments: (arguments
      (call_expression) @nested-call))
`);
```