Install (via npm for Node.js)
npm i esquery --save
Quick start
const esquery = require('esquery');
const conditional = "if (x === 1) { foo(); } else { x = 2; }"
var matches = esquery(conditional, "[name='x']")
console.log(matches);The following examples are taken from the test cases in /tests folder.
for loop
for (i = 0; i < foo.length; i++) { foo[i](); }
[operator="="]- matchesi = 0[object.name="foo"]- object namedfooie.foo.length[name=/i|foo/]- where name of node matchesiorfoo
simple function
function foo(x, y) {
var z = x + y;
z++;
return z;
}[kind="var"]- avar[id.name="foo"]-foodeclaration, fx a function or variable[left]- left expression, such asvar zFunctionDeclaration[params.0.name=x]- where first argument of function is namedx
simple program
var x = 1;
var y = 'y';
x = x * 2;
if (y) { y += 'z'; }[body]- full body, such as function/scope body[body.length<2]- body has less than 2 nodes[body.length>1]- body has more than 1 node[body.length<=2]- body has 2 or less nodes[body.length>=1]- body has 1 or more nodes[name=/[asdfy]/]- name matches the charactersasdfy
conditional
if (x === 1) { foo(); } else { x = 2; }
if (x == 'test' && true || x) { y = -1; } else if (false) { y = 1; }[name="x"]- node namedx[name!="x"]- node not namedx[name=/x|foo/]- node matchesxorfoo[name!=/x|y/]- node does not matchxory[callee.name="foo"]- Wherecalleeis namedfoo(ie. function call)[operator]- That is any type of operator (such as==,||etc)[prefix=true]- node that hasprefixset to true, such as++c[test=type(object)]- where subject of condition is an object, such asxin|| x[value=type(boolean)]- where value is a boolean, such as&& true
Example: prefix
AST node representing unary operators such as ++, ~, typeof and delete"
++c has prefix: true and c++ has prefix: false
interface UnaryExpression <: Expression {
type: "UnaryExpression";
operator: UnaryOperator;
prefix: boolean;
argument: Expression;
}:statement - a statement
:expression - an expression
:function - a function
:declaration - a declaration
:pattern - a pattern
Examples:
[name="x"]:function - function named x
[name="foo"]:declaration - declaration named foo
- descendant selector (
space) - child selector (
>) - adjacent sibling selector (
+) - general sibling selector (
~)
Please see javascript: expressions-vs-statements
IfStatement > BinaryExpression - if statement followed by a binary expression fx 3+4 or x*y
Valid: if (2 === 2)
IfStatement > BinaryExpression > Identifier
Valid: if (x === 2)
IfStatement BinaryExpression
An if statement with any binary expression below it.
VariableDeclaration ~ IfStatement
var declaration with sibling if statement
Valid: siblings of same body
var x = 1;
if (x === 2)VariableDeclaration + ExpressionStatement
Valid: variable declaration followed by next sibling which is an expression statement (see javascript statements and declarations)
var y = 'y';
x = x * 2;Shorthands
There are also shorthands such as:
@If > @Binary equivalent to IfStatement > BinaryExpression
See translateInput function in parser.js for the full list of supported shorthands and translations.
@Array:ArrayExpression@Arrow:ArrowExpression@AssignOp:AssignmentOperator@Assign:AssignmentExpression@BinaryOp:BinaryOperator@BinExp:BinaryExpression@BinOp:BinaryOperator@Bin:BinaryExpression@Block:BlockStatement@Break:BreakStatement@Call:CallExpression@Cond:ConditionalExpression@Cont:ContinueStatement@DoWhile:DoWhileStatement@Empty:EmptyStatement@Expr:ExpressionStatement@ForIn:ForInStatement@ForOf:ForOfStatement@For:ForStatement@FunctionDecl:FunctionDeclaration@FunDecl:FunctionDeclaration@Fun:FunctionExpression@Gen:GeneratorExpression@Id:Identifier@If:IfStatement@Labeled:LabeledStatement@Let:LetStatement@LogicalOp:LogicalOperator@Logical:LogicalExpression@Member:MemberExpression@New:NewExpression@Object:ObjectExpression@Return:ReturnStatement@Seq:SequenceExpression@Switch:SwitchStatement@This:ThisExpression@Throw:ThrowStatement@Try:TryStatement@UnaryOp:UnaryOperator@Unary:UnaryExpression@Var:VariableDeclaration@While:WhileStatement@With:WithStatement@Yield:YieldExpression
[left.name="x"][right.value=1] - where the left side is a node name x and the right has the value 1
Valid: x = 1
[left.name="x"]:matches(*) any type of node where the left side is named x
Program IfStatement - Any program with an if statement
Identifier[name=x] - identified named x such as const x. Identifiers are used to name variables and functions and to provide labels for certain loops...
Identifier [name=x] - any identifier with named x, such as const x
BinaryExpression [name=x] a binary expression where one side is named x, such as x !== 3
AssignmentExpression [name=x] an assignment where one side is named x, such as x = 2 or y = x
You can also query on the Mozilla Parser API fields directly
Example:
interface IfStatement <: Statement {
type: "IfStatement";
test: Expression;
consequent: Statement;
alternate: Statement | null;
}.test - node (object) that has a test field set
.declarations.init - node that has .declarations.init set
init means initialised, such as var x = 1, where x is initialised to value 1
interface VariableDeclaration <: Declaration {
type: "VariableDeclaration";
declarations: [ VariableDeclarator ];
kind: "var" | "let" | "const";
}
interface VariableDeclarator <: Node {
type: "VariableDeclarator";
id: Pattern;
init: Expression | null;
}ExpressionStatement:has([name="foo"][type="Identifier"])
Valid: const foo = 2
, means OR (ie. any of)
:matches(IfStatement):matches(BinaryExpression, MemberExpression):matches([name="foo"], ReturnStatement):matches(AssignmentExpression, BinaryExpression)AssignmentExpression, BinaryExpression, NonExistant
:not(Literal)not a literal:not([name="x"])not a node namedx:not(*)- not anything!:not(Identifier, IfStatement):not([value=1])not a node set to value of1
:first-child - first child node
:last-child - last child node
:nth-child(2) - 2nd child
:nth-last-child(2) - 2nd last child
!IfStatement Identifier - any not an If statement with an Identifier under, such as const x = 3 but not if (x == 2)
!* > [name="foo"] all nodes but those where the immediate child is a node named foo
More examples:
![test] [name="y"]![generator=type(boolean)] > BlockStatement![operator=/=+/] > [name="x"]!:matches(*) > [name="foo"]!:not(BlockStatement) > [name="foo"]![left.name="x"][right.value=1]* !AssignmentExpression!VariableDeclaration ~ IfStatement!VariableDeclaration + !ExpressionStatement
LogicalExpressionForStatementFunctionDeclarationReturnStatementAssignmentExpression