Core Concepts
Understanding AST
An Abstract Syntax Tree (AST) is a tree representation of the syntactic structure of source code. Understanding ASTs is crucial for effectively using Mutates to transform TypeScript code.
What is an AST?
An AST represents code as a hierarchical structure where each node represents a construct in the source code. For example:
// Source Code
const greeting = "Hello, World!";
// AST Structure (simplified)
{
type: "VariableDeclaration",
declarations: [{
type: "VariableDeclarator",
id: {
type: "Identifier",
name: "greeting"
},
init: {
type: "StringLiteral",
value: "Hello, World!"
}
}],
kind: "const"
}
Common AST Node Types
Declarations
// Class Declaration
class MyClass {}
// Function Declaration
function myFunction() {}
// Variable Declaration
const myVar = 42;
Expressions
// Object Literal
const obj = { key: 'value' };
// Array Literal
const arr = [1, 2, 3];
// Function Call
console.log('Hello');
Statements
// If Statement
if (condition) {
// ...
}
// For Loop
for (let i = 0; i < 10; i++) {
// ...
}
How Mutates Uses ASTs
Mutates provides a high-level API to manipulate TypeScript ASTs without dealing with the raw tree structure directly.
Example: Adding a Class
import { addClasses } from '@mutates/core';
// High-level API
addClasses('file.ts', {
name: 'MyClass',
properties: [{
name: 'prop',
type: 'string'
}]
});
// Equivalent AST manipulation (internal)
{
type: "ClassDeclaration",
id: {
type: "Identifier",
name: "MyClass"
},
body: {
type: "ClassBody",
body: [{
type: "PropertyDefinition",
key: {
type: "Identifier",
name: "prop"
},
typeAnnotation: {
type: "TSTypeAnnotation",
typeAnnotation: {
type: "TSStringKeyword"
}
}
}]
}
}
Common AST Operations
Finding Nodes
import { getClasses } from '@mutates/core';
// Find all classes in TypeScript files
const classes = getClasses({ pattern: '**/*.ts' });
Modifying Nodes
import { editClasses } from '@mutates/core';
// Modify class properties
editClasses(classes, (structure) => ({
...structure,
isExported: true,
}));
Adding Nodes
import { addMethods } from '@mutates/core';
// Add methods to a class
addMethods(targetClass, {
name: 'newMethod',
statements: 'return true;',
});
Best Practices for AST Manipulation
Preserve Semantics: Ensure your transformations maintain the original code's meaning.
Handle Edge Cases: Consider different code structures that might exist:
// Different ways to declare a class
class A {}
const B = class {};
export class C {}
Maintain Code Style: Mutates preserves formatting and comments by default.
Validate Changes: Always test your transformations with various code patterns.
Common Pitfalls
Forgetting Node References: AST nodes might become invalid after certain operations.
Incorrect Node Types: Make sure to use the correct node type for transformations.
Missing Parent Context: Some operations require understanding the node's context.
Tools for AST Exploration
- AST Explorer - Visualize ASTs online
- TypeScript AST Viewer - Specifically for TypeScript
Further Reading
- TypeScript Compiler API Documentation
- ts-morph Documentation (used internally by Mutates)
- Advanced Usage Guide
Next Steps
- Learn about Framework Integrations
- Explore Advanced Usage
- Check out Frequently Asked Questions