ESQuery is a library for querying ECMAScript Abstract Syntax Trees (ASTs) using CSS-style selectors. It enables developers to search through JavaScript code structures using familiar CSS selector syntax, making it an essential tool for static code analysis, linting, and code transformation utilities.
npm install esqueryESQuery exports a default function with attached methods. The package provides both UMD and ES module builds.
// ES6 module import (uses dist/esquery.esm.min.js)
import esquery from "esquery";
// Individual method access
const results = esquery(ast, 'selector');
const parsed = esquery.parse('selector');
const matches = esquery.matches(node, parsed, ancestry);For CommonJS:
// CommonJS require (uses dist/esquery.min.js - UMD build)
const esquery = require("esquery");
// Access methods as properties
const results = esquery(ast, 'selector');
const parsed = esquery.parse('selector');import esquery from "esquery";
import * as esprima from "esprima";
// Parse JavaScript code into an AST
const ast = esprima.parse('for (let i = 0; i < arr.length; i++) { console.log(arr[i]); }');
// Query for all ForStatement nodes
const forLoops = esquery(ast, 'ForStatement');
// Query for all function calls
const functionCalls = esquery(ast, 'CallExpression');
// Query for console.log calls specifically
const consoleLogs = esquery(ast, 'CallExpression[callee.object.name="console"][callee.property.name="log"]');
// Check if a specific node matches a selector
const selector = esquery.parse('IfStatement');
const matches = esquery.matches(someNode, selector, ancestry || []);ESQuery is built around several key components:
Execute CSS-style selectors against JavaScript ASTs to find matching nodes.
/**
* Query the code AST using the selector string.
* @param ast - The AST to query
* @param selector - CSS-style selector string
* @param options - Optional query configuration
* @returns Array of matching AST nodes
*/
function query(ast: AST, selector: string, options?: ESQueryOptions): AST[];Parse selector strings into internal selector AST format for reuse and analysis.
/**
* Parse a selector string and return its AST.
* @param selector - CSS-style selector string
* @returns Parsed selector AST
*/
function parse(selector: string): SelectorAST;Test parsed selectors against AST nodes with ancestry context for complex queries.
/**
* Determine if a node matches a selector.
* @param node - The AST node to test
* @param selector - Parsed selector AST
* @param ancestry - Node ancestry chain for context (defaults to [] if not provided)
* @param options - Optional query configuration
* @returns True if node matches selector
*/
function matches(node: AST, selector: SelectorAST, ancestry: AST[], options?: ESQueryOptions): boolean;Match parsed selectors against ASTs without string parsing overhead.
/**
* Match AST nodes against a parsed selector AST.
* @param ast - The AST to search
* @param selector - Parsed selector AST
* @param options - Optional query configuration
* @returns Array of matching AST nodes
*/
function match(ast: AST, selector: SelectorAST, options?: ESQueryOptions): AST[];Traverse ASTs with custom visitor functions for complex analysis workflows.
/**
* Traverse AST and call visitor for matching nodes.
* @param ast - The AST to traverse
* @param selector - Parsed selector AST
* @param visitor - Callback function for matches
* @param options - Optional query configuration
*/
function traverse(ast: AST, selector: SelectorAST, visitor: TraverseVisitor, options?: ESQueryOptions): void;
/**
* Visitor callback for traverse function
* @param node - Current matching node
* @param parent - Parent node in AST
* @param ancestry - Full ancestry chain from root
*/
type TraverseVisitor = (node: AST, parent: AST, ancestry: AST[]) => void;/**
* Configuration options for ESQuery operations
*/
interface ESQueryOptions {
/** Key for node type identification (default: "type") */
nodeTypeKey?: string;
/** Custom visitor keys mapping for extended AST node types */
visitorKeys?: { [nodeType: string]: string[] };
/** Fallback function for unknown node types during traversal */
fallback?: (node: AST) => string[];
/** Custom class matcher function for :class() selectors */
matchClass?: (className: string, node: AST, ancestry: AST[]) => boolean;
}
/**
* AST representation of parsed selector
* Generated from grammar.pegjs parsing rules
*/
interface SelectorAST {
type: string;
[key: string]: any;
}
/**
* ECMAScript AST node
* Follows ESTree specification format
*/
interface AST {
type: string;
[key: string]: any;
}ESQuery supports comprehensive CSS selector syntax adapted for AST queries:
ForStatement, IfStatement, FunctionDeclaration* (matches any node)[attr] (node has property)[attr="value"], [attr=123] (exact match)[attr=/pattern/], [attr=/pattern/flags] (regex match)[attr!="value"], [attr>2], [attr<=3] (comparison operators)[obj.prop="value"] (deep property access)FunctionDeclaration > Identifier.id (specific child property)parent > child (direct child relationship)ancestor descendant (any descendant)node + adjacent (immediately following sibling)node ~ sibling (any following sibling):first-child, :last-child, :nth-child(2), :nth-last-child(1):not(selector) (negation):has(selector), :has(> selector) (contains matching descendant):matches(sel1, sel2) (matches any of multiple selectors)!selector (subject indicator for complex queries):statement: Any statement node type:expression: Any expression node type:declaration: Any declaration node type:function: Function declarations and expressions:pattern: Any pattern node typeUsage Examples:
// Find all variable declarations
esquery(ast, 'VariableDeclaration');
// Find function calls to specific methods
esquery(ast, 'CallExpression[callee.property.name="forEach"]');
// Find nested if statements
esquery(ast, 'IfStatement IfStatement');
// Find functions with specific parameter counts
esquery(ast, 'FunctionDeclaration[params.length=2]');
// Find return statements that are not in functions
esquery(ast, ':not(FunctionDeclaration) ReturnStatement');
// Find identifiers that are function names
esquery(ast, 'FunctionDeclaration > Identifier.id');ESQuery functions throw Error objects for:
:statement, etc.)Common error handling:
try {
const results = esquery(ast, 'InvalidSelector[badOperator~="value"]');
} catch (error) {
console.error('Query failed:', error.message);
// Handle invalid selector syntax
}