Thank you for your interest in contributing to this project! We value contributions from the community and want to make the process as smooth as possible.
Caution
Do NOT force-push to your PR branch unless absolutely necessary. A force-push breaks the PR review and will cause significant delays to the review process. A clean branch history is not important for merging the PR: this repository uses squash-merge, so each PR is collapsed into a single commit using the PR's title.
Before you begin, ensure you have the current versions of the following installed:
- node
- npm
Our codebase is organized as follows:
.github/: Contains GitHub files like issue templates and workflowsrecipes/: Contains all the codemodsutils/: An npm workspace with utility functions used by the codemods (including ast-grep utilities)
Each codemod resides in its own directory under recipes/ and should include:
| File | Purpose |
|---|---|
README.md |
Description, purpose, and usage instructions |
package.json |
Package manifest |
src/workflow.ts |
Main entry point using the jssg codemod API |
codemod.yml |
Codemod manifest file |
workflow.yml |
Workflow definition file |
tests/ |
Test suite using jssg testing utilities |
tsconfig.json |
TypeScript configuration |
Note
The workflow.ts naming is conventional but can be changed as needed. Ensure to update the workflow.yml accordingly. We use workflow when there are one step codemods; for multi-step codemods, consider using what-to-change.ts or similar descriptive names.
src/workflow.ts example:
import {
getNodeImportCalls,
getNodeImportStatements,
} from '@nodejs/codemod-utils/ast-grep/import-statement';
import { getNodeRequireCalls } from "@nodejs/codemod-utils/ast-grep/require-call";
import { resolveBindingPath } from '@nodejs/codemod-utils/ast-grep/resolve-binding-path';
import type { SgRoot, Edit } from "@codemod.com/jssg-types/main";
import type JS from "@codemod.com/jssg-types/langs/javascript";
/**
* Transform function that converts deprecated api.fn calls
* to the new api.fn syntax.
*
* Handles:
* 1. api.fn(<args>)
* 2. api.fn(<args>, { recursive: true })
* ...
*/
export default function transform(root: SgRoot<JS>): string | null {
const rootNode = root.root();
const edits: Edit[] = [];
const allStatementNodes = [
...getNodeImportStatements(root, 'api'),
...getNodeRequireCalls(root, 'api')
...getNodeImportCalls(root, 'api'),
];
// No imports or requires for 'api', skip transformation
if (!allStatementNodes.length) return null;
for (const statementNode of allStatementNodes) {
const bindingPath = resolveBindingPath(statementNode, 'api.fn');
// Find all calls to the resolved bindingPath
const callNodes = rootNode.findDescendants((node) => {
return node.isCallExpression() &&
node.getChild('callee')?.getText() === bindingPath;
});
for (const callNode of callNodes) {
// Perform transformation on callNode
// e.g., replace 'api.fn' with 'api.newFn'
edits.push(...);
}
}
if (!edits.length) return null;
return rootNode.commitEdits(edits);
}codemod.yml example:
schema_version: "1.0"
name: "@nodejs/<codemod-name>"
version: 1.0.0
description: <Your codemod description>
author: <Your Name>
license: MIT
workflow: workflow.yaml
category: migration
targets:
languages:
- javascript
- typescript
keywords:
- transformation
- migration
registry:
access: public
visibility: public- Codemod CLI Reference
- Codemod Workflow Documentation
- Codemod Studio Documentation
- JS ast-grep (jssg) API reference
- JS ast-grep Testing Utilities
- JS ast-grep Semantic Analysis
- ast-grep Documentation
Run our comprehensive check suite:
node --run pre-commitThis will:
- Fix formatting and safe linting issues automatically
- Check types
- Run tests Be sure to commit any changes resulting from these automated fixes.
Warning
Some integration tests modify fixtures as they run the entire codemod. Remember to use git restore to revert these files before committing.
Please follow the Conventional Commits specification for your commit messages. This helps with:
- Automatic changelog generation
- Understanding the history of changes
- Semantic versioning
Format:
<type>(<scope>): <description>
type: The type of change (e.g.,feat,fix,docs,chore, etc.)scope: A short, lowercase description of the section of the codebase affected (e.g.,tmpDir-to-tmpdir,esm-migration)description: A concise summary of the change
Examples:
feat(tmpDir-to-tmpdir): add new node.js 18 migration codemodfix(esm-migration): correct type checking in ESM migrationdocs(codemod-usage): improve usage examples
When submitting a pull request:
- Ensure your changes are well-documented
- Run all tests (
node --run pre-commit) - Follow the project's coding standards
- Use the conventional commit format in your PR title and description
- Link to any related issues, using GitHub keywords where applicable.
For a pull request to be merged, it must:
- Receive approval from at least 2 reviewers with write access
- Receive no objections from reviewers with write access
- Pass all tests
- Be open for at least 48 hours to allow for review and discussion
- except hotfixes and trivial corrections (like typos)
By contributing to this project, I certify that:
- (a) The contribution was created in whole or in part by me and I have the right to
submit it under the open source license indicated in the file; or
- (b) The contribution is based upon previous work that, to the best of my knowledge,
is covered under an appropriate open source license and I have the right under that
license to submit that work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am permitted to submit under a
different license), as indicated in the file; or
- (c) The contribution was provided directly to me by some other person who certified
(a), (b) or (c) and I have not modified it.
- (d) I understand and agree that this project and the contribution are public and that
a record of the contribution (including all personal information I submit with it,
including my sign-off) is maintained indefinitely and may be redistributed consistent
with this project or the open source license(s) involved.