[![Actions](https://github.com/transferwise/wds-codemods/actions/workflows/ci-cd.yml/badge.svg)](https://github.com/transferwise/wds-codemods/actions)

# WDS Codemods

> WDS Codemods is a collection of codemod scripts designed to automate codebase transformations
> specifically for the Wise Design System. This package provides two types of transforms:
> **[jscodeshift](https://github.com/facebook/jscodeshift)** and **[Claude AI](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk)**,
> enabling large-scale refactoring and updates with minimal manual effort.

## Table of Contents

- [The Repository](#-the-repository)
- [Getting Started](#-getting-started)
- [CLI Options](#cli-options)
- [Transform Engines](#-transform-engines)
  - [jscodeshift Transforms](#jscodeshift-transforms)
  - [AI Transforms](#ai-transforms)
- [Available Transforms](#-available-transforms)
  - [Button Transform](./src/transforms/button/README.md)
  - [ListItem Transform](./src/transforms/list-item/README.md)
- [Key Features](#-key-features)
- [Working with the Project Locally](#-working-with-the-project-locally)
- [Writing Codemod Transforms](#-writing-codemod-transforms)
- [Developer Documentation](#-developer-documentation)
- [Notes on Key Tools](#-notes-on-key-tools)
- [Feedback](#-feedback)

## 👨‍💻 The Repository

The project provides a flexible CLI interface that allows you to run codemods either interactively
via prompts or directly through command-line arguments. It includes intelligent package validation,
monorepo support, and comprehensive reporting for manual review cases.

## 🚀 Getting Started

### Installation

Install globally for convenience:

```bash
# Using npm
npm i -g @wise/wds-codemods

# Using pnpm
pnpm add -g @wise/wds-codemods

# Using yarn
yarn global add @wise/wds-codemods
```

Or run directly without installing:

```bash
# Using npx
npx @wise/wds-codemods

# Using pnpm
pnpm dlx @wise/wds-codemods

# Using yarn
yarn dlx @wise/wds-codemods
```

### Running Codemods

You can run codemods in two ways:

#### Interactive Mode

Run without arguments to get interactive prompts:

```bash
wds-codemods
```

You'll be prompted to:

1. Select a transform (`button` or `list-item`)
2. Enter target directory or file path
3. Choose dry-run mode (preview without writing) (jscodeshift engine only)
4. Choose whether to print transformed output
5. Configure monorepo detection (auto-detected in most cases)
6. Answer transform-specific configuration questions (jscodeshift engine only)

#### Direct CLI Mode

Run with arguments for automation:

```bash
wds-codemods <transform> <targetPath> [options]
```

Example:

```bash
wds-codemods button ./src --dry --print
```

## CLI Options

All codemods support these command-line options:

| Option                  | Description                                                                                                        |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `--print`               | Print transformed source to console                                                                                |
| `--ignore-pattern=GLOB` | Ignore files matching [glob pattern(s)](https://code.visualstudio.com/docs/editor/glob-patterns) (comma-separated) |
| `--monorepo`            | Enable monorepo package checking across workspace folders                                                          |
| `--no-tracking`         | Disable Mixpanel usage tracking for the run                                                                        |
| `--debug`               | Log tracked events to console (works independently of `--no-tracking`)                                             |

Only jscodeshift engine supports the following options (.gitignore is always respected with AI Engine):

| Option                | Description                              |
| --------------------- | ---------------------------------------- |
| `--dry` / `--dry-run` | Preview changes without writing to files |
| `--gitignore`         | Respect `.gitignore` files               |
| `--no-gitignore`      | Ignore `.gitignore` files                |

### Common Examples

```bash
# Basic transform with dry run
wds-codemods button ./src --dry

# Transform with pattern exclusions
wds-codemods button ./src --ignore-pattern="*.test.ts,*.stories.ts"

# Ignore multiple directories and file types
wds-codemods button ./src --ignore-pattern="**/node_modules/**,**/*.test.ts,**/stories/**"

# Ignore specific directories
wds-codemods button ./src --ignore-pattern="dist/**,build/**,coverage/**"

# Monorepo transformation
wds-codemods button ./packages --monorepo

# Print output without writing files
wds-codemods button ./src --print --dry
```

## 🔧 Transform Engines

This project supports two types of transform engines, each suited for different transformation needs:

### jscodeshift Engine

**Best for:** Predictable, rule-based transformations with clear input/output mappings.

**How it works:**

- Parses code into an Abstract Syntax Tree (AST)
- Applies deterministic transformations based on pattern matching
- Guarantees consistent results across runs

**Features:**

- Dry-run mode to preview changes without writing files
- Manual review reports for edge cases
- Fast execution on large codebases

**Prerequisites:**

- Package version requirements (validated automatically)

**Example transforms:** Button migration

### AI Engine

**Best for:** Complex, context-aware transformations that require understanding intent.

**How it works:**

- Uses Claude AI to migrate code based on pregenrated instructions

**Features:**

- Handles ambiguous cases that would require manual review in jscodeshift

**Prerequisites:**

- Access to Wise LLM Gateway
- Claude configured locally
- VPN connection
- Package version requirements (validated automatically)

**Example transforms:** ListItem migration

---

## 💻 Available Transforms

- **[Button](./src/transforms/button/README.md)** - Migrates `Button` and `ActionButton` to the new v2 API using jscodeshift
- **[ListItem](./src/transforms/list-item/README.md)** - Migrates legacy `Option` and `Summary` components to `ListItem` using Claude AI

---

## 🔧 Key Features

### Automatic Package Validation

Before running any transform, the codemod automatically:

- Validates required package versions (e.g., `@transferwise/components >=46.5.0`)
- Checks `package.json`, lockfiles, and `node_modules`
- Supports npm, pnpm, and yarn
- Skips packages that don't meet prerequisites with clear reporting

### Monorepo Support

- Auto-detects monorepo structures (`packages/`, `apps/`, `libs/`, etc.)
- Validates dependencies across all workspace packages
- Provides summary reports showing which packages are ready
- Manual monorepo mode for custom structures

### Manual Review Reporting

**jscodeshift engine:**

- Generates `codemod-report.txt` for cases needing manual attention
- Includes file paths, line numbers, and specific issue descriptions
- Reports spread props, dynamic expressions, and unsupported values
- Auto-removes old reports and provides fresh summaries

**AI engine:**

- No report file generated
- Handles complex cases inline during transformation

### Smart Processing

- Only runs on projects with compatible dependencies
- Efficient directory traversal and file filtering
- Graceful error handling for edge cases
- Performance-optimized for large codebases

---

## 👨‍💻 Working with the Project Locally

To work with the project locally, follow these steps:

1. **Install dependencies**

```bash
pnpm install
```

2. **Build the project**

This compiles the main source and all transform scripts into the `dist` directory:

```bash
pnpm run build
```

3. **Run codemods**

After building, you can run the codemods using the instructions above.

### Requirements

This project uses [pnpm](https://pnpm.io/) and [Node](https://nodejs.org/en/).
Ensure you are using version `9.15.4` for `pnpm`, to install please follow
the [installation guide](https://pnpm.io/installation).

For node make sure you've set you local to the one found in `.nvmrc`. Use
[nvm](https://github.com/nvm-sh/nvm) to manage your local development versions.

---

## ⚛️ Writing Codemod Transforms

Codemod transforms are located in the `src/transforms` directory. Each transform is a
standalone TypeScript file exporting a default function that follows the [jscodeshift](https://github.com/facebook/jscodeshift) transformer API.

### Example: Simple Rename Transform

```ts
import type { API, FileInfo, Options } from 'jscodeshift';
import { validatePackageRequirements } from '../helpers';

// Define package requirements for this transform
export const packageRequirements = [{ name: '@wise/components', version: '>=2.0.0' }];

const transformer = (file: FileInfo, api: API, options: Options) => {
  // Validate package requirements before running
  if (!validatePackageRequirements(options, packageRequirements)) {
    return file.source;
  }

  const j = api.jscodeshift;
  const root = j(file.source);

  // Find all identifiers named 'foo' and rename them to 'bar'
  root.find(j.Identifier, { name: 'foo' }).replaceWith(() => j.identifier('bar'));

  return root.toSource();
};

export default transformer;
```

### Adding a New Transform

1. Create a new `.ts` file in `src/transforms/your-transform-name/`.
2. Create `config.json` file in the same directory and set an object defining required dependencies as well as the type of the codemod.
3. Export a default function following the jscodeshift transformer signature.
4. Use helper utilities from `src/helpers/` for common operations.
5. Write unit tests for your transform using the `createTestTransform` utility.
6. Build the project to compile your transform.
7. Run the codemod runner and select your new transform.

### Package Requirements

Each transform should have `prerequisites` defined in `config.json` that specifies which packages and versions are
required:

```json
{
  "prerequisites": {
    "@wise/components": ">=2.0.0",
    "@wise/icons": "^1.0.0"
  }
}
```

The system will automatically validate these requirements before running the transform, supporting:

- Semantic version ranges (`>=`, `^`, `~`, etc.)
- Multiple package managers (npm, pnpm, yarn)
- Monorepo structures
- Comprehensive dependency checking (dependencies, devDependencies, peerDependencies)

### Helper Utilities

The codemod provides several helper utilities in `src/helpers/`:

- **`hasImport`** - Check for and manipulate import statements
- **`processIconChildren`** - Handle icon component transformations
- **`createReporter`** - Generate manual review reports with detailed context
- **`validatePackageRequirements`** - Check package dependencies
- **JSX Element Utils** - Utilities for manipulating JSX elements and attributes
- **JSX Reporting Utils** - Standardised reporting for common manual review scenarios

Additional utilities are available in `src/controller/utils/` for common operations like file handling, AST
manipulation, and reporting. As this project evolves, we encourage contributors to add new utilities that can benefit the broader codemod ecosystem.

#### Writing Unit Tests for Transforms

It is important that all codemod transforms have corresponding unit tests to ensure correctness and prevent regressions. Use the `createTestTransform` utility to simplify writing tests for your transforms. This utility helps set up the testing environment and provides helpers to run your transform against sample input and verify the output.

**Basic test setup:**

```ts
import { createTestTransform } from '../../../helpers/createTestTransform';
import transform from '../my-transform';

const testTransform = createTestTransform(transform, [
  { name: '@wise/components', version: '2.0.0' },
]);

describe('my-transform', () => {
  it('should transform component', () => {
    const input = `<OldComponent prop="value" />`;
    const expected = `<NewComponent newProp="value" />`;

    expect(testTransform({ source: input })).toBe(expected);
  });
});
```

Example usage of `createTestTransform` can be found in the existing tests under `src/transforms/simple-rename/__tests__/simple-rename.test.ts`.

Make sure to run your tests regularly using:

```bash
pnpm test
```

---

## 📚 Developer Documentation

For comprehensive development details, including transform architecture, helper function documentation, testing patterns, and best practices, see our [Developer Documentation](./DEVELOPER.md).

---

## 📝 Notes on Key Tools

### jscodeshift

[jscodeshift](https://github.com/facebook/jscodeshift) is a toolkit for running codemods over multiple JavaScript or TypeScript files. It provides an API to parse source code into an Abstract Syntax Tree (AST), manipulate it, and print the transformed code back.

jscodeshift is one of two engines to perform code transformations.

### @anthropic-ai/claude-agent-sdk

[@anthropic-ai/claude-agent-sdk](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk) is Anthropic's SDK for building AI-powered agents with Claude. It provides tools for creating context-aware transformations that can understand code semantics and intent.

Claude Agent SDK is one of two engines to perform code transformations

### @inquirer/prompts

[@inquirer/prompts](https://github.com/SBoudrias/Inquirer.js/tree/main/packages/prompts) is a modern, promise-based library for interactive command-line prompts.

This project uses @inquirer/prompts to provide a user-friendly interactive experience when running codemods without CLI arguments, allowing you to select transforms and options easily.

### semver

[semver](https://github.com/npm/node-semver) is used for semantic version parsing and comparison when validating package requirements. This ensures accurate dependency checking across different version specification formats.

---

## ✍️ Feedback

Please ask any questions on this project, you can do so by reaching out on [Slack](https://wise.enterprise.slack.com/archives/CJNBX9CP6) or contributing to any [active issues](https://transferwise.atlassian.net/jira/software/projects/DS/boards/277/backlog).
