Skip to main content
The @nodejs/codemod-utils package provides a comprehensive set of utilities for building Node.js codemods with ast-grep. These utilities handle complex patterns for import/require analysis, binding resolution, code transformation, and package.json processing.

Why Use These Utilities?

Building Node.js codemods requires handling complex patterns for:
  • Import/Require Analysis: Finding and analyzing import statements and require() calls for specific modules
  • Binding Resolution: Determining how imported functions are accessed locally (destructured, aliased, etc.)
  • Code Transformation: Safely removing unused imports and modifying code while preserving formatting
  • Package.json Processing: Analyzing and transforming package.json scripts that use Node.js
These utilities provide battle-tested solutions for common codemod operations, reducing boilerplate and ensuring consistent behavior across all migration recipes.

API Categories

Import and Require Detection

Utilities for finding and analyzing module dependencies:

Binding Resolution and Transformation

Utilities for resolving and manipulating import bindings:

AST-grep Helper Functions

Core utilities for working with AST nodes:

Package.json Utilities

Utilities for processing package.json files:

Type Definitions

All utilities use types from @codemod.com/jssg-types:
  • SgRoot<Js> - Root AST node for JavaScript/TypeScript
  • SgNode<Js> - Individual AST node
  • Edit - Represents a code edit operation
  • Range - Represents a position range in source code

Getting Started

Import utilities directly from their respective modules:
import { getModuleDependencies } from '@nodejs/codemod-utils/ast-grep/module-dependencies';
import { resolveBindingPath } from '@nodejs/codemod-utils/ast-grep/resolve-binding-path';
import removeDependencies from '@nodejs/codemod-utils/remove-dependencies';

Common Patterns

Finding Module Dependencies

const ast = context.getAST();
const fsImports = getModuleDependencies(ast, 'fs');
// Finds: import fs from 'fs'; import { readFile } from 'node:fs';
// Finds: const fs = require('fs')
// Finds: const fs = await import('fs')

Resolving Bindings

// Given: const { types } = require('node:util');
const path = resolveBindingPath(node, '$.types.isNativeError');
// Returns: 'types.isNativeError'

// Given: const util = require('node:util');
const path = resolveBindingPath(node, '$.types.isNativeError');
// Returns: 'util.types.isNativeError'

Removing Bindings

// Given: const { types, isNativeError } = require('node:util');
const result = removeBinding(node, 'isNativeError');
// Edit to: const { types } = require('node:util');

// Given: const { isNativeError } = require('node:util');
const result = removeBinding(node, 'isNativeError');
// Returns: lineToRemove range to remove entire statement

Build docs developers (and LLMs) love