or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.mdparsing.mdtransformation.mdtraversal.mdutilities.md
tile.json

transformation.mddocs/

AST Transformation

Utilities for modifying and transforming AST nodes with immutable patterns and parent pointer management.

Capabilities

SimpleTransform Class

Main class for transforming AST nodes with callback-based mutation and automatic parent pointer management.

/**
 * A simple class for recursively transforming AST trees
 */
class SimpleTransform {
  /**
   * Transform AST tree with callback (static method)
   * @param node - Root AST node to transform
   * @param options - Transformation configuration
   * @returns Transformed node or null if removed
   */
  static transform(node: ESNode, options: TransformOptions): ESNode | null;
  
  /**
   * Transform Program node specifically
   * @param program - Program AST node to transform
   * @param options - Transformation configuration  
   * @returns Transformed Program node
   */
  static transformProgram(program: Program, options: TransformOptions): Program;
  
  /**
   * Create new node with property overrides
   * @param node - Base AST node to modify
   * @param overrideProps - Properties to override
   * @param visitorKeys - Optional visitor keys for parent pointer management
   * @returns New node with overrides or original if unchanged
   */
  static nodeWith<T extends ESNode>(
    node: T, 
    overrideProps: Partial<T>,
    visitorKeys?: VisitorKeysType
  ): T;
  
  /**
   * Transform AST tree with callback (instance method)
   * @param rootNode - Root AST node to transform
   * @param options - Transformation configuration
   * @returns Transformed node or null if removed  
   */
  transform(rootNode: ESNode, options: TransformOptions): ESNode | null;
}

interface TransformOptions {
  /** Callback invoked for each node to perform transformation */
  transform: TransformCallback;
  
  /** Custom visitor keys for traversal (optional) */
  visitorKeys?: VisitorKeysType;
}

/**
 * Transform callback function
 * @param node - Current AST node being visited
 * @returns Modified node, original node, or null to remove
 */
type TransformCallback = (node: ESNode) => ESNode | null;

Usage Examples:

import { SimpleTransform } from "hermes-parser";

const ast = parse("const x = 1; const y = 2;");

// Remove all const declarations
const transformed = SimpleTransform.transform(ast, {
  transform(node) {
    if (node.type === "VariableDeclaration" && node.kind === "const") {
      return null; // Remove this node
    }
    return node; // Keep unchanged
  }
});

// Transform literals to double their value
const doubled = SimpleTransform.transform(ast, {
  transform(node) {
    if (node.type === "Literal" && typeof node.value === "number") {
      return {
        ...node,
        value: node.value * 2,
        raw: String(node.value * 2)
      };
    }
    return node;
  }
});

// Use transformProgram for program-specific transforms
const program = SimpleTransform.transformProgram(ast, {
  transform(node) {
    // Add "use strict" directive at the beginning
    if (node.type === "Program") {
      return {
        ...node,
        body: [
          {
            type: "ExpressionStatement",
            expression: {
              type: "Literal",
              value: "use strict",
              raw: '"use strict"'
            }
          },
          ...node.body
        ]
      };
    }
    return node;
  }
});

Node Creation and Modification

Helper functions for creating and modifying AST nodes with proper parent pointer management.

/**
 * Create new node with property overrides, maintaining referential equality when possible
 * @param node - Base AST node
 * @param overrideProps - Properties to override
 * @param visitorKeys - Optional visitor keys for parent management
 * @returns New node with overrides or original if unchanged
 */
function nodeWith<T extends ESNode>(
  node: T,
  overrideProps: Partial<T>, 
  visitorKeys?: VisitorKeysType
): T;

/**
 * Shallow clone an AST node with correct parent pointers
 * @param node - AST node to clone
 * @param visitorKeys - Optional visitor keys for parent management
 * @returns Shallow clone of the node
 */
function shallowCloneNode<T extends ESNode>(
  node: T,
  visitorKeys?: VisitorKeysType  
): T;

/**
 * Deep clone an AST node and entire subtree
 * @param node - AST node to clone
 * @param visitorKeys - Optional visitor keys for parent management
 * @returns Deep clone of node and all children
 */
function deepCloneNode<T extends ESNode>(
  node: T,
  visitorKeys?: VisitorKeysType
): T;

Node Modification Examples:

import { SimpleTransform } from "hermes-parser";

// Efficient node modification with nodeWith
const updatedNode = SimpleTransform.nodeWith(identifierNode, {
  name: "newName"
});

// Only creates new object if properties actually changed
const sameNode = SimpleTransform.nodeWith(identifierNode, {
  name: identifierNode.name // No change, returns same reference
});

// Manual node modification in transform
SimpleTransform.transform(ast, {
  transform(node) {
    if (node.type === "Identifier" && node.name === "oldName") {
      return SimpleTransform.nodeWith(node, { name: "newName" });
    }
    return node;
  }
});

AST Node Mutation Helpers

Low-level utilities for directly manipulating AST nodes and their relationships.

/**
 * Replace a node with new node in its parent
 * @param originalNode - Node to replace
 * @param originalNodeParent - Parent containing the node
 * @param nodeToReplaceWith - New node to insert
 * @param visitorKeys - Optional visitor keys
 */
function replaceNodeOnParent(
  originalNode: ESNode,
  originalNodeParent: ESNode, 
  nodeToReplaceWith: ESNode,
  visitorKeys?: VisitorKeysType
): void;

/**
 * Remove a node from its parent
 * @param originalNode - Node to remove
 * @param originalNodeParent - Parent containing the node
 * @param visitorKeys - Optional visitor keys
 */
function removeNodeOnParent(
  originalNode: ESNode,
  originalNodeParent: ESNode,
  visitorKeys?: VisitorKeysType
): void;

/**
 * Set parent pointers on direct children of a node
 * @param node - Parent node
 * @param visitorKeys - Optional visitor keys
 */
function setParentPointersInDirectChildren(
  node: ESNode,
  visitorKeys?: VisitorKeysType
): void;

/**
 * Update all parent pointers in an entire subtree
 * @param node - Root node of subtree
 * @param visitorKeys - Optional visitor keys
 */
function updateAllParentPointers(
  node: ESNode,
  visitorKeys?: VisitorKeysType
): void;

AST Array Mutation Helpers

Utilities for manipulating arrays within AST nodes during transformations.

/**
 * Check if two arrays are equal by reference and content
 * @param a1 - First array
 * @param a2 - Second array  
 * @returns True if arrays are equal
 */
function arrayIsEqual(a1: ReadonlyArray<unknown>, a2: ReadonlyArray<unknown>): boolean;

/**
 * Insert elements at a specific index in array
 * @param array - Source array
 * @param index - Index to insert at
 * @param elements - Elements to insert
 * @returns New array with elements inserted
 */
function insertInArray<T>(
  array: ReadonlyArray<T>,
  index: number,
  elements: ReadonlyArray<T>
): T[];

/**
 * Remove element at specific index from array
 * @param array - Source array
 * @param index - Index to remove
 * @returns New array with element removed
 */
function removeFromArray<T>(array: ReadonlyArray<T>, index: number): T[];

/**
 * Replace element at index with new elements
 * @param array - Source array
 * @param index - Index to replace
 * @param elements - New elements to insert
 * @returns New array with replacement
 */
function replaceInArray<T>(
  array: ReadonlyArray<T>,
  index: number, 
  elements: ReadonlyArray<T>
): T[];

Array Manipulation Examples:

import { insertInArray, removeFromArray, replaceInArray } from "hermes-parser";

const statements = [stmt1, stmt2, stmt3];

// Insert new statements
const withInserted = insertInArray(statements, 1, [newStmt1, newStmt2]);
// Result: [stmt1, newStmt1, newStmt2, stmt2, stmt3]

// Remove statement
const withRemoved = removeFromArray(statements, 1);
// Result: [stmt1, stmt3]

// Replace statement
const withReplaced = replaceInArray(statements, 1, [replacementStmt]);
// Result: [stmt1, replacementStmt, stmt3]

Pre-built Transforms

Ready-to-use transformation functions for common AST modifications.

/**
 * Collection of pre-built AST transformation functions
 */
const Transforms: {
  /** Transform experimental match syntax */
  transformMatchSyntax: (program: Program, options: ParserOptions) => Program;
  
  /** Strip experimental component syntax */
  stripComponentSyntax: (program: Program, options: ParserOptions) => Program;
  
  /** Strip Flow types for Babel compatibility */
  stripFlowTypesForBabel: (program: Program, options: ParserOptions) => Program;
  
  /** Strip Flow types for ESTree output */
  stripFlowTypes: (program: Program, options: ParserOptions) => Program;
};

Pre-built Transform Examples:

import { Transforms, parse } from "hermes-parser";

const flowCode = "function add(x: number, y: number): number { return x + y; }";
const ast = parse(flowCode, { flow: "all" });

// Strip Flow types for plain JavaScript
const cleanAst = Transforms.stripFlowTypes(ast, { flow: "all" });

// Chain multiple transforms
const processedAst = [
  Transforms.transformMatchSyntax,
  Transforms.stripComponentSyntax,
  Transforms.stripFlowTypesForBabel
].reduce((ast, transform) => transform(ast, { flow: "all", babel: true }), ast);

Transform Patterns

Common patterns for AST transformation workflows.

Conditional Node Replacement:

SimpleTransform.transform(ast, {
  transform(node) {
    // Replace console.log with custom logger
    if (node.type === "CallExpression" && 
        node.callee.type === "MemberExpression" &&
        node.callee.object.name === "console" &&
        node.callee.property.name === "log") {
      return {
        ...node,
        callee: {
          type: "Identifier",
          name: "customLogger"
        }
      };
    }
    return node;
  }
});

Node Removal with Conditions:

SimpleTransform.transform(ast, {
  transform(node) {
    // Remove all debugger statements
    if (node.type === "DebuggerStatement") {
      return null;
    }
    
    // Remove empty statements
    if (node.type === "EmptyStatement") {
      return null;
    }
    
    return node;
  }
});

Complex Node Restructuring:

SimpleTransform.transform(ast, {
  transform(node) {
    // Convert arrow functions to regular functions
    if (node.type === "ArrowFunctionExpression") {
      return {
        type: "FunctionExpression",
        id: null,
        params: node.params,
        body: node.body.type === "BlockStatement" 
          ? node.body 
          : {
              type: "BlockStatement",
              body: [{
                type: "ReturnStatement", 
                argument: node.body
              }]
            },
        generator: false,
        async: node.async
      };
    }
    return node;
  }
});