Thanks for helping improve Datadog 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 (includes type checking for discovered TS projects)
pnpm run lint
# Lint and auto-fix
pnpm run lint:fix
# Run all codemod package tests (`@codemod/dd-trace-js-v6-*` workspace packages)
pnpm run test
# Typecheck all codemod packages
pnpm run check-types
# Same checks as the push job on main (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-typesUse Node 20 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.
- Pull requests to
main:.github/workflows/ci.ymlinstalls withpnpm install --frozen-lockfile, runs oxfmt / oxlint on changed files,pnpm run docs:linkson tracked Markdown, runs test and check-types only for codemod packages touched by the diff, and enforces changesets (see below). - Pushes to
main: the same workflow runspnpm run docs:linksand full-workspacepnpm run ci(all@codemod/dd-trace-js-v6-*tests and typechecks).
Match that locally before you push.
- Create a branch from
main. - Make your changes and add or update JSSG fixtures under
tests/<case>/. - Run
pnpm run format,pnpm run lint, andpnpm run cito verify everything passes. - Add a changeset when you change a codemod package (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 and then scripts/sync-codemod-versions.sh so codemod.yaml version stays aligned with package.json. Do not edit version in codemod.yaml by hand to cut a release.
- Merge a PR that includes one or more changesets into
main. .github/workflows/release.ymlconsumes changesets, commits Version Packages tomain, syncscodemod.yamlversions, createsname@vversiongit tags for newly versioned packages, and publishes those packages withcodemod/publish-action.
Do not hand-edit the version field in package package.json or codemod.yaml to “simulate” a release — automation owns bumps. The Publish Codemod (Manual) workflow (.github/workflows/publish.yml) is for emergencies: supply the path under codemods/, e.g. apm/nodejs/dd-trace-js/v6/add-link-object-argument or apm/nodejs/dd-trace-js/v6/dd-trace-js-v6-migration-recipe.
New packages live under the layout in README.md, for example:
codemods/<product>/<stack>/<library>/<migration>/<slug>/
scripts/codemod.ts # JSSG transform
tests/ # input / expected fixtures (and metrics.json when needed)
codemod.yaml # manifest (version is synced from package.json on release)
workflow.yaml
package.json
tsconfig.json
README.md
Conventions:
- Prefer the registry naming pattern
@codemod/<sdk>-<destination-major>-<codemod-slug>(example:@codemod/dd-trace-js-v6-flatten-ingestion-optionsfor migrating to dd-trace-js v6) inpackage.json/codemod.yaml. - Prefer aligning the directory slug with the registry suffix after
@codemod/dd-trace-js-v6-(example:move-exp-iast-options/for@codemod/dd-trace-js-v6-move-exp-iast-options). - The Codemod registry limits scoped package names to 50 characters total (including
@codemod/). Shorten the slug when needed (for examplemove-exp-*instead of spellingexperimental). - When the registry name must be shorter than the descriptive folder would imply, the directory may still differ—see
rename-b3-single-header-propagation-style/publishing as@codemod/dd-trace-js-v6-rename-b3-stylein dd-trace-js v6 README. - Keep rewrites conservative. If a step needs a human decision, Datadog account work, or Remote Configuration, prefer a detector, recipe parameter, or issue draft instead of an unsafe transform.
Use an existing sibling codemod in the same migration folder as a template.
Each codemod package should include:
package.jsonwith at leasttestandcheck-types.codemod.yaml,workflow.yaml,tsconfig.json,README.mdscripts/codemod.tstests/<case>/input.*andtests/<case>/expected.*tests/<case>/metrics.jsonwhen the transform records metrics
Keep transformations atomic and verifiable with fixtures.