Some rules and APIs allow the use of selectors to query an AST. This page is intended to:
A selector is a string that can be used to match nodes in an Abstract Syntax Tree (AST). This is useful for describing a particular syntax pattern in your code.
The syntax for AST selectors is similar to the syntax for CSS selectors. If you've used CSS selectors before, the syntax for AST selectors should be easy to understand.
The simplest selector is just a node type. A node type selector will match all nodes with the given type. For example, consider the following program:
var foo = 1;
bar.baz();
The selector "Identifier
" will match all Identifier
nodes in the program. In this case, the selector will match the nodes for foo
, bar
, and baz
.
Selectors are not limited to matching against single node types. For example, the selector VariableDeclarator > Identifier
will match all Identifier
nodes that have a VariableDeclarator
as a direct parent. In the program above, this will match the node for foo
, but not the nodes for bar
and baz
.
The following selectors are supported:
ForStatement
*
[attr]
[attr="foo"]
or [attr=123]
[attr=/foo.*/]
[attr!="foo"]
, [attr>2]
, [attr<3]
, [attr>=2]
, or [attr<=3]
[attr.level2="foo"]
FunctionDeclaration > Identifier.id
:first-child
or :last-child
:nth-child(2)
:nth-last-child(1)
FunctionExpression ReturnStatement
UnaryExpression > Literal
ArrayExpression > Literal + SpreadElement
VariableDeclaration ~ VariableDeclaration
:not(ForStatement)
:matches([attr] > :first-child, :last-child)
:statement
, :expression
, :declaration
, :function
, or :pattern
This syntax is very powerful, and can be used to precisely select many syntactic patterns in your code.
The examples in this section were adapted from the esquery documentation.
If you're writing custom ESLint rules, you might be interested in using selectors to examine specific parts of the AST. If you're configuring ESLint for your codebase, you might be interested in restricting particular syntax patterns with selectors.
When writing a custom ESLint rule, you can listen for nodes that match a particular selector as the AST is traversed.
module.exports = {
create(context) {
// ...
return {
// This listener will be called for all IfStatement nodes with blocks.
"IfStatement > BlockStatement": function(blockStatementNode) {
// ...your logic here
},
// This listener will be called for all function declarations with more than 3 parameters.
"FunctionDeclaration[params.length>3]": function(functionDeclarationNode) {
// ...your logic here
}
};
}
};
Adding :exit
to the end of a selector will cause the listener to be called when the matching nodes are exited during traversal, rather than when they are entered.
If two or more selectors match the same node, their listeners will be called in order of increasing specificity. The specificity of an AST selector is similar to the specificity of a CSS selector:
:not()
) has higher specificity.If multiple selectors have equal specificity, their listeners will be called in alphabetical order for that node.
With the no-restricted-syntax rule, you can restrict the usage of particular syntax in your code. For example, you can use the following configuration to disallow using if
statements that do not have block statements as their body:
{
"rules": {
"no-restricted-syntax": ["error", "IfStatement > :not(BlockStatement).consequent"]
}
}
...or equivalently, you can use this configuration:
{
"rules": {
"no-restricted-syntax": ["error", "IfStatement[consequent.type!='BlockStatement']"]
}
}
As another example, you can disallow calls to require()
:
{
"rules": {
"no-restricted-syntax": ["error", "CallExpression[callee.name='require']"]
}
}
Or you can enforce that calls to setTimeout
always have two arguments:
{
"rules": {
"no-restricted-syntax": ["error", "CallExpression[callee.name='setTimeout'][arguments.length!=2]"]
}
}
Using selectors in the no-restricted-syntax
rule can give you a lot of control over problematic patterns in your codebase, without needing to write custom rules to detect each pattern.
© JS Foundation and other contributors
Licensed under the MIT License.
https://eslint.org/docs/developer-guide/selectors