Thanks for helping users adopt the latest ESLint features with your codemods!
Using an AI coding agent (Codex, Cursor, Claude Code, Aider, etc.)? See AGENTS.md — it is a short pointer back to this file and the common mistakes to avoid.
This repository uses pnpm (see packageManager in the root package.json), Changesets for releases, and oxfmt + oxlint (not Prettier/ESLint) for formatting and linting.
# Install dependencies (also wires the Husky pre-commit hook)
pnpm install
# Format all files
pnpm run format
# Check formatting without writing
pnpm run format:check
# Lint all files
pnpm run lint
# Lint and auto-fix
pnpm run lint:fix
# Run all codemod package tests
pnpm run test
# Typecheck all codemod packages
pnpm run check-types
# Same checks as CI (tests + typecheck)
pnpm run ci
# Verify URLs in tracked Markdown (also runs in CI)
pnpm run docs:linksRun one workspace package (the pnpm --filter value is the name field in that package's package.json):
pnpm --filter <package-name> test
pnpm --filter <package-name> check-typesFor example:
pnpm --filter @eslint/v8-to-v9-config test
pnpm --filter @eslint/v8-to-v9-custom-rules check-typesUse Node 22 locally (see .nvmrc) to match CI.
After pnpm install, Husky runs lint-staged before each commit: oxfmt and oxlint on staged files, plus targeted pnpm test when you touch codemods/**/scripts/**/*.ts. If something fails, fix or stage the updates and try again.
The hook only inspects staged files. Files you did not touch can still fail a full-repo pnpm run format:check / pnpm run lint — CI focuses on changed paths for pull requests.
Three workflows run on every PR and push to main:
ci.yml— Pull request checks: format, lint, and docs-link checks on changed files;pnpm testandpnpm run check-typesonly for codemod packages touched by the diff.ci.yml— Full workspace (main): on every push tomain, runs fullpnpm run ci(all tests + typechecks) andpnpm run docs:links.ci.yml— Changeset check: warns when a PR touchingcodemods/is missing a changeset for a changed package (or use theskip-changesetlabel to silence the warning).
Match the local checks (pnpm run ci) before you push.
- Issue: Check for an existing issue, or open one first.
- Safety: Codemods must be safe, predictable, and idempotent (running twice should not change code again). Avoid mixing patterns with different safety levels.
- Naming: In
codemod.yaml, the codemod name must start with@eslint, whereeslintis this repo's GitHub org. - Tests: Add multiple fixtures (positive and negative).
- Docs: Update the README for your codemod.
- Create a branch from
main. - Make your changes and add or update fixtures under
tests/<case>/. - Run
pnpm run format,pnpm run lint, andpnpm run cito verify everything passes. - Add a changeset for every codemod package you touched (see below).
- Open a pull request.
This repo uses Changesets for versioning and releases. Every PR that changes a codemod package under codemods/ should include a changeset, unless you use the skip-changeset label (see CI). Details live in .changeset/README.md.
pnpm changesetFollow the prompts:
- Select the affected codemod(s).
- Choose the semver bump — patch for fixes, minor for new features, major for breaking changes.
- Write a short summary.
Commit the new Markdown file under .changeset/ with your PR.
pnpm run version-packages (run by automation on main, not usually by hand) runs changeset version, which bumps version in each affected package.json. Do not edit version in package.json by hand — automation owns that field.
Releases are fully automated via .github/workflows/release.yml on every push to main:
- Merge a PR that includes one or more changesets into
main. - The
releasejob detects the pending changesets and runspnpm run version-packages(changeset version), which bumpsversionin each affectedpackage.json. - The bot opens (or updates) a Version Packages pull request on branch
changeset-release/version-packages— it does not push directly tomain. - Merge that PR (EasyCLA and other required checks apply like any other PR).
- On the next push to
main,scripts/tag-and-publish.shcreates a<name>@v<version>git tag for every bumped package and pushes the tags. - The
publishjob fans out a parallel matrix over the changed directories and publishes each codemod viacodemod/publish-action.
For emergencies (re-publish a specific codemod without a full release cycle), use the Publish Codemod (Manual) workflow (.github/workflows/publish.yml) and supply the tag, e.g. @eslint/v8-to-v9-config@v1.2.0.
Do not hand-edit version in package.json to simulate a release — automation owns bumps.
Scaffold a new codemod with the CLI:
npx codemod initNew packages live under codemods/, for example:
codemods/v9/<slug>/
scripts/codemod.ts # JSSG transform
tests/ # input / expected fixtures
codemod.yaml # manifest
workflow.yaml
package.json
tsconfig.json
README.md
Conventions:
- The codemod name in
codemod.yamlandpackage.jsonmust start with@eslint(e.g.@eslint/v8-to-v9-config). - Keep rewrites conservative. If a step requires a human decision, prefer a detector or recipe parameter over an unsafe transform.
- Use an existing sibling codemod in the same migration folder as a template.
Test your codemod locally against a sample project:
cd /path/to/sample/project
npx codemod workflow run -w /path/to/my-codemod/workflow.yamlEach codemod package should include:
package.jsonwith at leasttestandcheck-typesscripts.codemod.yaml,workflow.yaml,tsconfig.json,README.mdscripts/codemod.tstests/<case>/input.*andtests/<case>/expected.*
Keep transformations atomic and verifiable with fixtures.
| Command | What it does |
|---|---|
pnpm run format |
Auto-format with oxfmt |
pnpm run format:check |
Check formatting (no writes) |
pnpm run lint |
Lint with oxlint (type-aware) |
pnpm run lint:fix |
Lint and auto-fix with oxlint |
pnpm run test |
Run all codemod tests |
pnpm run check-types |
Typecheck all codemod packages |
pnpm run ci |
Full check (test + typecheck) |
- Describe the codemod and its migration use case.
- Follow Conventional Commits:
| Type | Usage |
|---|---|
feat |
New codemod or capability |
fix |
Bugfix in a transform or test |
docs |
Documentation-only changes |
refactor |
Non-feature, non-bugfix code changes |
test |
Add or update fixtures/tests |
chore |
Tooling, CI, formatting, repo hygiene |
By contributing, you agree that your work will be licensed under the MIT License.