or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-estraverse

ECMAScript JS AST traversal functions

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/estraverse@5.3.x

To install, run

npx @tessl/cli install tessl/npm-estraverse@5.3.0

index.mddocs/

Estraverse

Estraverse is a JavaScript library that provides ECMAScript Abstract Syntax Tree (AST) traversal functionality. It offers a comprehensive API for walking through JavaScript code structures with visitor patterns, supporting tree modification, node replacement, and custom traversal rules. This library is essential for building JavaScript tools like linters, code transformers, and static analysis tools.

Package Information

  • Package Name: estraverse
  • Package Type: npm
  • Language: JavaScript
  • Installation: npm install estraverse

Core Imports

const estraverse = require('estraverse');

ES Modules:

import * as estraverse from 'estraverse';

Individual imports:

const { traverse, replace, Syntax, VisitorOption, VisitorKeys, Controller, attachComments, cloneEnvironment } = require('estraverse');

Basic Usage

const estraverse = require('estraverse');

// Basic traversal - visit all nodes in an AST
estraverse.traverse(ast, {
    enter: function (node, parent) {
        console.log('Entering:', node.type);
    },
    leave: function (node, parent) {
        console.log('Leaving:', node.type);
    }
});

// Skip traversing function bodies
estraverse.traverse(ast, {
    enter: function (node, parent) {
        if (node.type === 'FunctionExpression' || node.type === 'FunctionDeclaration') {
            return estraverse.VisitorOption.Skip;
        }
    }
});

// Replace nodes during traversal
const result = estraverse.replace(ast, {
    enter: function (node, parent) {
        if (node.type === 'Literal' && typeof node.value === 'string') {
            return {
                type: 'Literal',
                value: node.value.toUpperCase(),
                raw: '"' + node.value.toUpperCase() + '"'
            };
        }
    }
});

Architecture

Estraverse is built around several key components that work together to provide flexible AST traversal:

  • Visitor Pattern: The core traversal mechanism uses visitor objects with enter and leave callbacks that are invoked for each node during traversal
  • Controller System: The Controller class provides fine-grained control over traversal with methods for path tracking, parent access, and flow control
  • Syntax Constants: Comprehensive enumeration of all ECMAScript AST node types for consistent node type checking
  • Visitor Keys: Default mapping that defines which properties of each node type should be traversed as child nodes
  • Fallback Strategies: Configurable behavior for handling unknown or custom node types through iteration or custom functions

Capabilities

Tree Traversal

Core AST traversal functionality using the visitor pattern.

/**
 * Traverse an AST with a visitor object
 * @param {Object} root - The root AST node to traverse
 * @param {Object} visitor - Visitor object with enter/leave callbacks
 * @returns {void}
 */
function traverse(root, visitor);

/**
 * Traverse an AST and replace nodes based on visitor returns
 * @param {Object} root - The root AST node to traverse
 * @param {Object} visitor - Visitor object with enter/leave callbacks that can return replacement nodes
 * @returns {Object} - The modified AST
 */
function replace(root, visitor);

Visitor Object Structure:

interface Visitor {
    /** Called when entering a node during traversal */
    enter?: (node: Object, parent: Object) => any;
    /** Called when leaving a node during traversal */
    leave?: (node: Object, parent: Object) => any;
    /** Custom visitor keys for unknown node types */
    keys?: Object;
    /** Fallback strategy for unknown nodes ('iteration' or function) */
    fallback?: string | function;
}

Visitor Return Values:

  • estraverse.VisitorOption.Break - Stop traversal entirely
  • estraverse.VisitorOption.Skip - Skip child nodes of current node
  • estraverse.VisitorOption.Remove - Remove current node (replace() only)
  • Node object - Replace current node with returned node (replace() only)
  • undefined - Continue normal traversal

Advanced Controller

Manual traversal control with fine-grained operation management.

/**
 * Controller class for manual AST traversal
 * @constructor
 */
function Controller();

Controller Instance Methods:

interface ControllerInstance {
    /** Get the property path array from root to current node (returns null for root) */
    path(): string[] | null;
    /** Get the type of the current node */
    type(): string;
    /** Get array of parent elements */
    parents(): Object[];
    /** Get the current node */
    current(): Object;
    /** Skip child nodes of current node */
    skip(): void;
    /** Break traversal entirely */
    break(): void;
    /** Remove current node */
    remove(): void;
    /** Notify control flow (internal method used by skip/break/remove) */
    notify(flag: Object): void;
    /** Traverse using this controller instance */
    traverse(root: Object, visitor: Object): void;
    /** Replace traverse using this controller instance */
    replace(root: Object, visitor: Object): Object;
}

When using Controller, visitor functions can access controller methods via this:

const controller = new estraverse.Controller();
controller.traverse(ast, {
    enter: function (node, parent) {
        if (node.type === 'FunctionDeclaration') {
            this.skip(); // Skip function body
        }
        console.log('Path:', this.path());
        console.log('Parents:', this.parents().length);
    }
});

Node Type Constants

Enumeration of all supported ECMAScript AST node types.

/**
 * Object containing constants for all ECMAScript AST node types
 */
const Syntax: {
    AssignmentExpression: 'AssignmentExpression';
    AssignmentPattern: 'AssignmentPattern';
    ArrayExpression: 'ArrayExpression';
    ArrayPattern: 'ArrayPattern';
    ArrowFunctionExpression: 'ArrowFunctionExpression';
    AwaitExpression: 'AwaitExpression';
    BlockStatement: 'BlockStatement';
    BinaryExpression: 'BinaryExpression';
    BreakStatement: 'BreakStatement';
    CallExpression: 'CallExpression';
    CatchClause: 'CatchClause';
    ChainExpression: 'ChainExpression';
    ClassBody: 'ClassBody';
    ClassDeclaration: 'ClassDeclaration';
    ClassExpression: 'ClassExpression';
    ComprehensionBlock: 'ComprehensionBlock';
    ComprehensionExpression: 'ComprehensionExpression';
    ConditionalExpression: 'ConditionalExpression';
    ContinueStatement: 'ContinueStatement';
    DebuggerStatement: 'DebuggerStatement';
    DirectiveStatement: 'DirectiveStatement';
    DoWhileStatement: 'DoWhileStatement';
    EmptyStatement: 'EmptyStatement';
    ExportAllDeclaration: 'ExportAllDeclaration';
    ExportDefaultDeclaration: 'ExportDefaultDeclaration';
    ExportNamedDeclaration: 'ExportNamedDeclaration';
    ExportSpecifier: 'ExportSpecifier';
    ExpressionStatement: 'ExpressionStatement';
    ForStatement: 'ForStatement';
    ForInStatement: 'ForInStatement';
    ForOfStatement: 'ForOfStatement';
    FunctionDeclaration: 'FunctionDeclaration';
    FunctionExpression: 'FunctionExpression';
    GeneratorExpression: 'GeneratorExpression';
    Identifier: 'Identifier';
    IfStatement: 'IfStatement';
    ImportExpression: 'ImportExpression';
    ImportDeclaration: 'ImportDeclaration';
    ImportDefaultSpecifier: 'ImportDefaultSpecifier';
    ImportNamespaceSpecifier: 'ImportNamespaceSpecifier';
    ImportSpecifier: 'ImportSpecifier';
    Literal: 'Literal';
    LabeledStatement: 'LabeledStatement';
    LogicalExpression: 'LogicalExpression';
    MemberExpression: 'MemberExpression';
    MetaProperty: 'MetaProperty';
    MethodDefinition: 'MethodDefinition';
    ModuleSpecifier: 'ModuleSpecifier';
    NewExpression: 'NewExpression';
    ObjectExpression: 'ObjectExpression';
    ObjectPattern: 'ObjectPattern';
    PrivateIdentifier: 'PrivateIdentifier';
    Program: 'Program';
    Property: 'Property';
    PropertyDefinition: 'PropertyDefinition';
    RestElement: 'RestElement';
    ReturnStatement: 'ReturnStatement';
    SequenceExpression: 'SequenceExpression';
    SpreadElement: 'SpreadElement';
    Super: 'Super';
    SwitchStatement: 'SwitchStatement';
    SwitchCase: 'SwitchCase';
    TaggedTemplateExpression: 'TaggedTemplateExpression';
    TemplateElement: 'TemplateElement';
    TemplateLiteral: 'TemplateLiteral';
    ThisExpression: 'ThisExpression';
    ThrowStatement: 'ThrowStatement';
    TryStatement: 'TryStatement';
    UnaryExpression: 'UnaryExpression';
    UpdateExpression: 'UpdateExpression';
    VariableDeclaration: 'VariableDeclaration';
    VariableDeclarator: 'VariableDeclarator';
    WhileStatement: 'WhileStatement';
    WithStatement: 'WithStatement';
    YieldExpression: 'YieldExpression';
};

Traversal Control Options

Constants for controlling traversal flow from visitor functions.

/**
 * Control flow constants for visitor functions
 */
const VisitorOption: {
    /** Break traversal entirely */
    Break: Object;
    /** Skip child nodes of current node */
    Skip: Object;
    /** Remove current node (replace() only) */
    Remove: Object;
};

Default Visitor Keys

Default mapping of AST node types to their traversable child property names.

/**
 * Default visitor keys mapping node types to child property names
 */
const VisitorKeys: {
    AssignmentExpression: ['left', 'right'];
    AssignmentPattern: ['left', 'right'];
    ArrayExpression: ['elements'];
    ArrayPattern: ['elements'];
    ArrowFunctionExpression: ['params', 'body'];
    AwaitExpression: ['argument'];
    BlockStatement: ['body'];
    BinaryExpression: ['left', 'right'];
    BreakStatement: ['label'];
    CallExpression: ['callee', 'arguments'];
    CatchClause: ['param', 'body'];
    ChainExpression: ['expression'];
    ClassBody: ['body'];
    ClassDeclaration: ['id', 'superClass', 'body'];
    ClassExpression: ['id', 'superClass', 'body'];
    ComprehensionBlock: ['left', 'right'];
    ComprehensionExpression: ['blocks', 'filter', 'body'];
    ConditionalExpression: ['test', 'consequent', 'alternate'];
    ContinueStatement: ['label'];
    DebuggerStatement: [];
    DirectiveStatement: [];
    DoWhileStatement: ['body', 'test'];
    EmptyStatement: [];
    ExportAllDeclaration: ['source'];
    ExportDefaultDeclaration: ['declaration'];
    ExportNamedDeclaration: ['declaration', 'specifiers', 'source'];
    ExportSpecifier: ['exported', 'local'];
    ExpressionStatement: ['expression'];
    ForStatement: ['init', 'test', 'update', 'body'];
    ForInStatement: ['left', 'right', 'body'];
    ForOfStatement: ['left', 'right', 'body'];
    FunctionDeclaration: ['id', 'params', 'body'];
    FunctionExpression: ['id', 'params', 'body'];
    GeneratorExpression: ['blocks', 'filter', 'body'];
    Identifier: [];
    IfStatement: ['test', 'consequent', 'alternate'];
    ImportExpression: ['source'];
    ImportDeclaration: ['specifiers', 'source'];
    ImportDefaultSpecifier: ['local'];
    ImportNamespaceSpecifier: ['local'];
    ImportSpecifier: ['imported', 'local'];
    Literal: [];
    LabeledStatement: ['label', 'body'];
    LogicalExpression: ['left', 'right'];
    MemberExpression: ['object', 'property'];
    MetaProperty: ['meta', 'property'];
    MethodDefinition: ['key', 'value'];
    ModuleSpecifier: [];
    NewExpression: ['callee', 'arguments'];
    ObjectExpression: ['properties'];
    ObjectPattern: ['properties'];
    PrivateIdentifier: [];
    Program: ['body'];
    Property: ['key', 'value'];
    PropertyDefinition: ['key', 'value'];
    RestElement: ['argument'];
    ReturnStatement: ['argument'];
    SequenceExpression: ['expressions'];
    SpreadElement: ['argument'];
    Super: [];
    SwitchStatement: ['discriminant', 'cases'];
    SwitchCase: ['test', 'consequent'];
    TaggedTemplateExpression: ['tag', 'quasi'];
    TemplateElement: [];
    TemplateLiteral: ['quasis', 'expressions'];
    ThisExpression: [];
    ThrowStatement: ['argument'];
    TryStatement: ['block', 'handler', 'finalizer'];
    UnaryExpression: ['argument'];
    UpdateExpression: ['argument'];
    VariableDeclaration: ['declarations'];
    VariableDeclarator: ['id', 'init'];
    WhileStatement: ['test', 'body'];
    WithStatement: ['object', 'body'];
    YieldExpression: ['argument'];
};

Comment Attachment

Utility for attaching comments to AST nodes based on their position.

/**
 * Attach comments to AST nodes based on position relative to tokens
 * @param {Object} tree - The AST tree to attach comments to
 * @param {Array} providedComments - Array of comment objects with range information
 * @param {Array} tokens - Array of token objects with range information
 * @returns {Object} - The tree with attached comments
 */
function attachComments(tree, providedComments, tokens);

Comments are attached as leadingComments and trailingComments properties on AST nodes.

Environment Cloning

Create isolated estraverse environments for custom configurations.

/**
 * Create a new isolated estraverse environment
 * @returns {Object} - New estraverse instance with independent configuration
 */
function cloneEnvironment();

Extended Traversal Patterns

Custom Node Types

Extend estraverse to handle custom AST node types:

// Define custom visitor keys for unknown node types
estraverse.traverse(customAst, {
    enter: function (node) {
        console.log('Visiting:', node.type);
    },
    keys: {
        // CustomNodeType: ['child1', 'child2']
        TestExpression: ['argument']
    }
});

Fallback Strategies

Control behavior when encountering unknown node types:

// Use iteration fallback to explore all properties
estraverse.traverse(ast, {
    enter: function (node) { /* ... */ },
    fallback: 'iteration'
});

// Use custom function fallback for fine-grained control
estraverse.traverse(ast, {
    enter: function (node) { /* ... */ },
    fallback: function(node) {
        return Object.keys(node).filter(key => key !== 'parent');
    }
});

Path Tracking

Track the path to current node during traversal:

const controller = new estraverse.Controller();
controller.traverse(ast, {
    enter: function (node, parent) {
        const path = this.path();
        const depth = this.parents().length;
        console.log(`Node ${node.type} at path: ${path.join('.')} (depth: ${depth})`);
    }
});