> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/nodejs/userland-migrations/llms.txt
> Use this file to discover all available pages before exploring further.

# How Codemods Work

> Learn how Node.js Userland codemods use AST transformations with ast-grep and the jssg API to automate code migrations

Codemods are automated code transformation tools that modify your source code by analyzing and manipulating its Abstract Syntax Tree (AST). This page explains the technical foundation of Node.js Userland codemods.

## Abstract Syntax Trees (AST)

An Abstract Syntax Tree is a structured representation of your code that the computer can understand and manipulate. When you run a codemod:

<Steps>
  <Step title="Parse">
    Your source code is parsed into an AST representation
  </Step>

  <Step title="Analyze">
    The codemod searches for specific patterns in the AST
  </Step>

  <Step title="Transform">
    Matching nodes are replaced with updated code
  </Step>

  <Step title="Generate">
    The modified AST is converted back to source code
  </Step>
</Steps>

### Example: From Code to AST

Consider this simple code:

```javascript theme={null}
const { isArray } = require('util');
isArray([]);
```

The AST represents this as a tree structure with nodes like `variable_declarator`, `object_pattern`, `call_expression`, etc. The codemod can identify these patterns and transform them.

## ast-grep: The Pattern Matching Engine

[ast-grep](https://ast-grep.github.io/) is a powerful tool for searching and manipulating ASTs using pattern matching. It provides:

* **Pattern-based search**: Find code using intuitive patterns like `util.isArray($ARG)`
* **Structural matching**: Match based on code structure, not just text
* **Language awareness**: Understands JavaScript and TypeScript syntax

<Note>
  ast-grep is the core engine powering Node.js Userland codemods. It handles the heavy lifting of AST parsing and traversal.
</Note>

## The jssg API

The `jssg` (JavaScript ast-grep) API is the interface codemods use to interact with ASTs. It's provided by the [Codemod.com platform](https://docs.codemod.com/jssg/reference).

### Core Concepts

Every codemod exports a transform function:

```typescript theme={null}
import type { SgRoot, Edit } from "@codemod.com/jssg-types/main";
import type JS from "@codemod.com/jssg-types/langs/javascript";

export default function transform(root: SgRoot<JS>): string | null {
  const rootNode = root.root();
  const edits: Edit[] = [];
  
  // Find nodes, build edits, commit changes
  
  return rootNode.commitEdits(edits);
}
```

**Key types:**

* `SgRoot<JS>`: The root object containing the parsed AST
* `SgNode<JS>`: Individual AST nodes you can query and manipulate
* `Edit`: Represents a single code modification
* `Range`: Represents a location in the source code

### Finding Nodes

Use pattern matching to locate code:

```typescript theme={null}
// Find all calls to util.isArray
const nodes = rootNode.findAll({
  rule: { pattern: 'util.isArray($ARG)' }
});

// Find specific node kinds
const imports = rootNode.findAll({
  rule: { kind: 'import_statement' }
});
```

### Creating Edits

Build transformation edits:

```typescript theme={null}
for (const node of nodes) {
  const arg = node.getMatch('ARG');
  if (arg) {
    // Replace util.isArray(x) with Array.isArray(x)
    edits.push(node.replace(`Array.isArray(${arg.text()})`));
  }
}
```

### Committing Changes

Apply all edits and return the transformed code:

```typescript theme={null}
if (!edits.length) return null;
return rootNode.commitEdits(edits);
```

<Warning>
  Always return `null` when no changes are made. This signals to the codemod runner that the file should not be modified.
</Warning>

## Real-World Example

Here's a simplified version of the `util.types.isNativeError` to `Error.isError` migration:

```typescript theme={null}
export default function transform(root: SgRoot<JS>): string | null {
  const rootNode = root.root();
  const edits: Edit[] = [];
  
  // Find all util imports/requires
  const statements = [
    ...getNodeRequireCalls(root, 'util'),
    ...getNodeImportStatements(root, 'util'),
  ];
  
  if (!statements.length) return null;
  
  for (const stmt of statements) {
    // Resolve how types.isNativeError is accessed locally
    const binding = resolveBindingPath(stmt, '$.types.isNativeError');
    if (!binding) continue;
    
    // Find all calls using this binding
    const calls = rootNode.findAll({
      rule: { pattern: binding }
    });
    
    // Replace with Error.isError
    for (const call of calls) {
      edits.push(call.replace('Error.isError'));
    }
  }
  
  if (!edits.length) return null;
  return rootNode.commitEdits(edits);
}
```

This example demonstrates:

1. **Import detection**: Finding where `util` is imported or required
2. **Binding resolution**: Determining how `types.isNativeError` is accessed (could be `util.types.isNativeError`, `types.isNativeError`, or `isNativeError` depending on the import style)
3. **Pattern matching**: Locating all usages of the resolved binding
4. **Replacement**: Transforming to the new API

## Codemod Utilities

The `@nodejs/codemod-utils` package provides battle-tested helpers for common operations:

### Import/Require Detection

```typescript theme={null}
import { getModuleDependencies } from '@nodejs/codemod-utils/ast-grep/module-dependencies';

// Finds all import/require statements for 'fs'
const fsImports = getModuleDependencies(root, 'fs');
```

### Binding Resolution

```typescript theme={null}
import { resolveBindingPath } from '@nodejs/codemod-utils/ast-grep/resolve-binding-path';

// Given: const { readFile } = require('fs')
// Returns: 'readFile'
const binding = resolveBindingPath(node, '$.readFile');

// Given: const fs = require('fs')
// Returns: 'fs.readFile'
const binding = resolveBindingPath(node, '$.readFile');
```

### Cleanup Operations

```typescript theme={null}
import { removeBinding } from '@nodejs/codemod-utils/ast-grep/remove-binding';
import { removeLines } from '@nodejs/codemod-utils/ast-grep/remove-lines';

// Remove unused import binding
const result = removeBinding(importNode, 'isArray');
if (result?.edit) edits.push(result.edit);

// Remove entire lines (like unused imports)
const cleanCode = removeLines(sourceCode, linesToRemove);
```

<Tip>
  Always use the utility functions from `@nodejs/codemod-utils` instead of writing your own. They handle edge cases like destructuring, aliasing, and dynamic imports.
</Tip>

## Workflow Structure

Each codemod follows a standard workflow:

```typescript theme={null}
// 1. Import utilities and types
import { getModuleDependencies } from '@nodejs/codemod-utils/ast-grep/module-dependencies';
import type { SgRoot, Edit } from "@codemod.com/jssg-types/main";
import type JS from "@codemod.com/jssg-types/langs/javascript";

// 2. Define the transform function
export default function transform(root: SgRoot<JS>): string | null {
  const rootNode = root.root();
  const edits: Edit[] = [];
  
  // 3. Find relevant imports/requires
  const imports = getModuleDependencies(root, 'module-name');
  if (!imports.length) return null;
  
  // 4. Locate and transform usage patterns
  for (const importNode of imports) {
    // ... find usages and build edits
  }
  
  // 5. Apply edits and return result
  if (!edits.length) return null;
  return rootNode.commitEdits(edits);
}
```

## Performance Considerations

* **Early exit**: Return `null` immediately if the file doesn't contain relevant code
* **Batch edits**: Collect all edits before calling `commitEdits()` once
* **Efficient patterns**: Use specific patterns to avoid searching the entire AST

```typescript theme={null}
// ❌ Inefficient: Commits after each edit
for (const node of nodes) {
  const newCode = rootNode.commitEdits([node.replace(newText)]);
}

// ✅ Efficient: Batch all edits
const edits: Edit[] = [];
for (const node of nodes) {
  edits.push(node.replace(newText));
}
return rootNode.commitEdits(edits);
```

## Next Steps

<CardGroup cols={2}>
  <Card title="When to Use Codemods" href="/concepts/when-to-use">
    Learn when codemods are the right choice for your migration
  </Card>

  <Card title="Safety Best Practices" href="/concepts/safety-best-practices">
    Ensure safe, reliable code transformations
  </Card>
</CardGroup>

## Additional Resources

* [JS ast-grep (jssg) API Reference](https://docs.codemod.com/jssg/reference)
* [ast-grep Pattern Syntax](https://ast-grep.github.io/guide/pattern-syntax.html)
* [Semantic Analysis with jssg](https://docs.codemod.com/jssg/semantic-analysis)
* [API Reference](/api/overview)
