Skip to main content
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:
1

Parse

Your source code is parsed into an AST representation
2

Analyze

The codemod searches for specific patterns in the AST
3

Transform

Matching nodes are replaced with updated code
4

Generate

The modified AST is converted back to source code

Example: From Code to AST

Consider this simple code:
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 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
ast-grep is the core engine powering Node.js Userland codemods. It handles the heavy lifting of AST parsing and traversal.

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.

Core Concepts

Every codemod exports a transform function:
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:

Creating Edits

Build transformation edits:

Committing Changes

Apply all edits and return the transformed code:
Always return null when no changes are made. This signals to the codemod runner that the file should not be modified.

Real-World Example

Here’s a simplified version of the util.types.isNativeError to Error.isError migration:
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

Binding Resolution

Cleanup Operations

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

Workflow Structure

Each codemod follows a standard workflow:

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

Next Steps

When to Use Codemods

Learn when codemods are the right choice for your migration

Safety Best Practices

Ensure safe, reliable code transformations

Additional Resources