or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

ast.mdcli.mdindex.mdtransform.md
tile.json

transform.mddocs/

Code Transformation

Advanced AST transformation capabilities for custom JavaScript code modifications and optimizations using UglifyJS's transformation infrastructure.

Capabilities

TreeTransformer

Primary utility for transforming Abstract Syntax Trees with before/after processing hooks.

/**
 * Creates a TreeTransformer for modifying AST nodes
 * @param before - Function called before processing child nodes
 * @param after - Function called after processing child nodes
 * @constructor
 */
function TreeTransformer(before, after);

interface TreeTransformer extends TreeWalker {
  /** Transformation applied before processing child nodes */
  before?: (node: AST_Node, descend: Function) => AST_Node;
  /** Transformation applied after processing child nodes */  
  after?: (node: AST_Node) => AST_Node;
}

Usage Examples:

const UglifyJS = require("uglify-js");

// Remove all console.log statements
const removeConsole = new UglifyJS.TreeTransformer(function(node) {
    if (node instanceof UglifyJS.AST_SimpleStatement &&
        node.body instanceof UglifyJS.AST_Call &&
        node.body.expression instanceof UglifyJS.AST_Dot &&
        node.body.expression.expression instanceof UglifyJS.AST_Symbol &&
        node.body.expression.expression.name === "console" &&
        node.body.expression.property === "log") {
        // Return empty statement to remove console.log
        return new UglifyJS.AST_EmptyStatement();
    }
});

const ast = UglifyJS.parse('console.log("test"); var x = 1;');
const transformed = ast.transform(removeConsole);

List Processing

Array transformation utility with special operation support for AST manipulation.

/**
 * Transform arrays with support for special operations
 * @param array - Input array to transform
 * @param fn - Transformation function that can return special operations
 * @returns Transformed array with operations applied
 */
function List(array, fn);

interface ListStatic {
  /** Check if value is a special List operation */
  is_op(value: any): boolean;
}

/** Special operation to skip an element during List transformation */
const skip: unique symbol;

/** Special operation to splice multiple elements into a List */
class Splice {
  constructor(elements: any[]);
  v: any[];
}

Usage Examples:

const UglifyJS = require("uglify-js");

// Transform statement list, removing empty statements
const statements = [
    new UglifyJS.AST_SimpleStatement({ body: new UglifyJS.AST_Number({ value: 1 }) }),
    new UglifyJS.AST_EmptyStatement(),
    new UglifyJS.AST_SimpleStatement({ body: new UglifyJS.AST_Number({ value: 2 }) })
];

const filtered = UglifyJS.List(statements, function(stmt) {
    if (stmt instanceof UglifyJS.AST_EmptyStatement) {
        return UglifyJS.List.skip; // Remove empty statements
    }
    return stmt;
});

// Using Splice to insert multiple elements
const withLogging = UglifyJS.List(statements, function(stmt, index) {
    if (stmt instanceof UglifyJS.AST_Function) {
        // Insert logging before function
        const logStmt = new UglifyJS.AST_SimpleStatement({
            body: new UglifyJS.AST_Call({
                expression: new UglifyJS.AST_Dot({
                    expression: new UglifyJS.AST_Symbol({ name: "console" }),
                    property: "log"
                }),
                args: [new UglifyJS.AST_String({ value: "Entering function" })]
            })
        });
        return new UglifyJS.List.Splice([logStmt, stmt]);
    }
    return stmt;
});

Node Transformation Patterns

Before and After Hooks

const transformer = new UglifyJS.TreeTransformer(
    // Before hook: modify node before processing children
    function(node, descend) {
        if (node instanceof UglifyJS.AST_Function) {
            console.log("Entering function:", node.name);
        }
        return node;
    },
    // After hook: modify node after processing children  
    function(node) {
        if (node instanceof UglifyJS.AST_Function) {
            console.log("Exiting function:", node.name);
        }
        return node;
    }
);

Conditional Transformation

const conditionalTransform = new UglifyJS.TreeTransformer(function(node) {
    // Transform specific patterns
    if (node instanceof UglifyJS.AST_Binary && 
        node.operator === "+" &&
        node.left instanceof UglifyJS.AST_String &&
        node.right instanceof UglifyJS.AST_String) {
        // Concatenate string literals at compile time
        return new UglifyJS.AST_String({
            value: node.left.value + node.right.value,
            quote: node.left.quote
        });
    }
    return node;
});

Utility Functions

push_uniq Function

Add unique elements to arrays during transformation.

/**
 * Add element to array if not already present
 * @param array - Target array to modify
 * @param element - Element to add if unique
 * @returns true if element was added, false if already present
 */
function push_uniq(array, element);

Usage Examples:

const UglifyJS = require("uglify-js");

const dependencies = [];
const transformer = new UglifyJS.TreeTransformer(function(node) {
    if (node instanceof UglifyJS.AST_Call &&
        node.expression instanceof UglifyJS.AST_Symbol &&
        node.expression.name === "require" &&
        node.args.length === 1 &&
        node.args[0] instanceof UglifyJS.AST_String) {
        // Collect unique require() calls
        UglifyJS.push_uniq(dependencies, node.args[0].value);
    }
    return node;
});

const ast = UglifyJS.parse('require("fs"); require("path"); require("fs");');
ast.transform(transformer);
console.log(dependencies); // ["fs", "path"]

Advanced Transformation Examples

Variable Renaming

const renameVariables = new UglifyJS.TreeTransformer(function(node) {
    if (node instanceof UglifyJS.AST_Symbol && node.name === "oldName") {
        return new UglifyJS.AST_Symbol({
            name: "newName",
            start: node.start,
            end: node.end
        });
    }
    return node;
});

Function Inlining

const inlineFunctions = new UglifyJS.TreeTransformer(function(node) {
    if (node instanceof UglifyJS.AST_Call &&
        node.expression instanceof UglifyJS.AST_Symbol &&
        knownFunctions[node.expression.name]) {
        // Replace function call with inlined body
        const fnBody = knownFunctions[node.expression.name];
        return fnBody.clone();
    }
    return node;
});

Dead Code Elimination

const removeDeadCode = new UglifyJS.TreeTransformer(function(node) {
    if (node instanceof UglifyJS.AST_If &&
        node.condition instanceof UglifyJS.AST_Boolean) {
        if (node.condition.value) {
            // Condition is always true, replace with then branch
            return node.body;
        } else {
            // Condition is always false, replace with else branch or remove
            return node.alternative || new UglifyJS.AST_EmptyStatement();
        }
    }
    return node;
});

AST Node Creation

Creating New Nodes

// Create a new variable declaration
const varDecl = new UglifyJS.AST_Var({
    definitions: [
        new UglifyJS.AST_VarDef({
            name: new UglifyJS.AST_Symbol({
                name: "newVar"
            }),
            value: new UglifyJS.AST_Number({
                value: 42
            })
        })
    ]
});

// Create a new function call
const funcCall = new UglifyJS.AST_Call({
    expression: new UglifyJS.AST_Symbol({
        name: "console.log"
    }),
    args: [
        new UglifyJS.AST_String({
            value: "Hello World",
            quote: '"'
        })
    ]
});

Node Cloning

// Deep clone a node
const clonedNode = originalNode.clone(true);

// Shallow clone a node
const shallowClone = originalNode.clone(false);

Transformation Pipeline

// Chain multiple transformations
const pipeline = [
    removeDeadCode,
    inlineFunctions,
    renameVariables
];

let ast = UglifyJS.parse(sourceCode);
for (const transformer of pipeline) {
    ast = ast.transform(transformer);
}

// Generate final output
const result = UglifyJS.minify(ast);

Integration with Minification

Transformations can be applied before minification for custom optimizations:

const UglifyJS = require("uglify-js");

// Custom transformation
const customTransform = new UglifyJS.TreeTransformer(function(node) {
    // Your transformation logic here
    return node;
});

// Parse, transform, then minify
const ast = UglifyJS.parse(sourceCode);
const transformed = ast.transform(customTransform);
const result = UglifyJS.minify(transformed, {
    compress: {},
    mangle: {}
});

Error Handling in Transformations

const safeTransform = new UglifyJS.TreeTransformer(function(node) {
    try {
        // Risky transformation
        if (canTransform(node)) {
            return transformNode(node);
        }
    } catch (error) {
        console.warn("Transformation failed:", error.message);
        // Return original node if transformation fails
    }
    return node;
});