ESLint InterlaceESLint Interlace

AST Fundamentals

How ESLint reads and analyzes your code

The Tree Inside Your Code

ESLint doesn't read code like humans. It parses your JavaScript into an Abstract Syntax Tree (AST)—a structured representation of your code's grammar.

Understanding the AST unlocks:

  • Custom rule creation for your specific patterns
  • Better debugging of false positives
  • Advanced selectors for precise rule targeting

What is an AST?

When you write:

const query = 'SELECT * FROM users WHERE id = ' + userId;

ESLint parses it into a tree structure:

Program
└── VariableDeclaration (kind: "const")
    └── VariableDeclarator
        ├── Identifier (name: "query")
        └── BinaryExpression (operator: "+")
            ├── Literal (value: "SELECT * FROM users WHERE id = ")
            └── Identifier (name: "userId")

Each node in the tree represents a syntactic element:

  • Program — The root of every JavaScript file
  • VariableDeclaration — A const, let, or var statement
  • BinaryExpression — An operation like +, -, *, etc.
  • Identifier — A variable name
  • Literal — A raw value like a string or number

How Security Rules Use the AST

Security rules match patterns in the AST. For example, the no-sql-concatenation rule triggers when it finds:

BinaryExpression (operator: "+")
├── Literal (value contains SQL keywords)
└── Identifier (untrusted input)

This pattern-matching approach is:

  • Precise — Only matches actual vulnerable patterns
  • Fast — Tree traversal is O(n) complexity
  • Flexible — Can target any syntactic structure

ESLint Selectors

ESLint uses CSS-like selectors to target AST nodes. Here are common patterns:

SelectorMatches
CallExpressionAny function call
CallExpression[callee.name="eval"]Calls to eval()
BinaryExpression[operator="+"]Any + operation
VariableDeclaration[kind="var"]var declarations
Identifier[name="password"]Variables named "password"

Advanced Selector Example

To match dangerous SQL concatenation:

// This selector:
'BinaryExpression[operator="+"] > Literal[value=/SELECT|INSERT|UPDATE|DELETE/i]';

// Matches patterns like:
const query = 'SELECT * FROM users' + userInput;

Common AST Node Types

Declarations

Node TypeExample
VariableDeclarationconst x = 1
FunctionDeclarationfunction foo() {}
ClassDeclarationclass Foo {}

Expressions

Node TypeExample
CallExpressionfoo()
MemberExpressionobj.prop
BinaryExpressiona + b
TemplateLiteral`Hello ${name}`

Statements

Node TypeExample
IfStatementif (x) {}
ReturnStatementreturn value
ThrowStatementthrow error

Try It Yourself

Explore AST Interactively

The best way to understand AST is to experiment with real code. Use the tools below to visualize how ESLint parses your JavaScript.

Recommended tools:

  • AST Explorer — The gold standard for AST visualization. Select @babel/eslint-parser to see exactly what ESLint sees.
  • ESLint Playground — Test rules against code in real-time

Writing Custom Rules

Understanding the AST enables you to write custom rules. Here's a minimal example:

no-console-log.js
module.exports = {
  meta: {
    type: 'suggestion',
    docs: { description: 'Disallow console.log' },
  },
  create(context) {
    return {
      // Selector: CallExpression where callee is console.log
      'CallExpression[callee.object.name="console"][callee.property.name="log"]'(
        node,
      ) {
        context.report({
          node,
          message: 'Unexpected console.log statement',
        });
      },
    };
  },
};

Next Steps

On this page