Codemod Registry
Explore community-led codemods to migrate, optimize, and transform your codebase.
Ready to contribute?
Build your own codemod and share it with the community.
Explore community-led codemods to migrate, optimize, and transform your codebase.
Build your own codemod and share it with the community.
Explore community-led codemods to migrate, optimize, and transform your codebase.
# Correct TypeScript Specifiers This package transforms import specifiers from the old `tsc` (TypeScript's compiler) requirement of using `.js` file extensions in source-code to import files that are actually typescript; the corrected specifiers enable source-code to be runnable by standards-compliant software like Node.js. This is a one-and-done process, and the updated source-code should be committed to your version control (eg git); thereafter, source-code import statements should be authored compliant with the ECMAScript (JavaScript) standard. > [!TIP] > Those using `tsc` to compile will need to enable [`rewriteRelativeImportExtensions`](https://www.typescriptlang.org/tsconfig/#rewriteRelativeImportExtensions); using `tsc` for only type-checking (ex via a lint/test step like `npm run test:types`) needs [`allowImportingTsExtensions`](https://www.typescriptlang.org/tsconfig/#allowImportingTsExtensions) (and some additional compile options—see the cited documentation); This package does not just blindly find & replace file extensions within specifiers: It confirms that the replacement specifier actually exists; in ambiguous cases (such as two files with the same basename in the same location but different relevant file extensions like `/tmp/foo.js` and `/tmp/foo.ts`), it logs an error, skips that specifier, and continues processing. > [!CAUTION] > This package does not confirm that imported modules contain the desired export(s). This _shouldn't_ actually ever result in a problem because ambiguous cases are skipped (so if there is a problem, it existed before the migration started). Merely running your source-code after the mirgration completes will confirm all is well (if there are problems, node will error, citing the problems). > [!TIP] > Node.js requires the `type` keyword be present on type imports. For own code, this package usually handles that. However, in some cases and for node modules, it does not. Robust tooling already exists that will automatically fix this, such as > > * [`use-import-type` via biome](https://biomejs.dev/linter/rules/use-import-type/) > * [`typescript/no-import-type-side-effects` via oxlint](https://oxc.rs/docs/guide/usage/linter/rules/typescript/no-import-type-side-effects) > * [`consistent-type-imports` via typescript-lint](https://typescript-eslint.io/rules/consistent-type-imports) > > If your source code needs that, first run this codemod and then one of those fixers. ## Running > [!CAUTION] > This will change your source-code. Commit any unsaved changes before running this package. > [!IMPORTANT] > [`--experimental-import-meta-resolve`](https://nodejs.org/api/cli.html#--experimental-import-meta-resolve) MUST be enabled; the feature is not really experimental—it's nonstandard because it's not relevant for browsers. ```console $ NODE_OPTIONS="--experimental-import-meta-resolve" \ npx codemod@latest correct-ts-specifiers ``` ### Monorepos For best results, run this _within_ each workspace of the monorepo. ```text project-root/ ├ workspaces/ ├ foo/ ←--------- RUN HERE ├ … ├ package.json └ tsconfig.json └ bar/ ←--------- RUN HERE ├ … ├ package.json └ tsconfig.json └ utils/ ←--------- RUN HERE ├ qux.js └ zed.js ``` ## Supported cases * no file extension → `.cts`, `.mts`, `.js`, `.ts`, `.d.cts`, `.d.mts`, or `.d.ts` * `.cjs` → `.cts`, `.mjs` → `.mts`, `.js` → `.ts` * `.js` → `.d.cts`, `.d.mts`, or `.d.ts` * [Package.json subpath imports](https://nodejs.org/api/packages.html#subpath-imports) * [tsconfig paths](https://www.typescriptlang.org/tsconfig/#paths) (via [`@nodejs-loaders/alias`](https://github.com/JakobJingleheimer/nodejs-loaders/blob/main/packages/alias?tab=readme-ov-file)) * In order to subsequently run code via node, you will need to add this (or another) loader to your own project. Or, switch to [subimports](https://nodejs.org/api/packages.html#subpath-imports). * Commonjs-like directory specifiers Before: ```ts import { URL } from 'node:url'; import { bar } from '@dep/bar'; import { foo } from 'foo'; import { Bird } from './Bird'; // a directory import { Cat } from './Cat.ts'; import { Dog } from '…/Dog/index.mjs'; // tsconfig paths import { baseUrl } from '#config.js'; // package.json imports export { Zed } from './zed'; export const makeLink = (path: URL) => (new URL(path, baseUrl)).href; const nil = await import('./nil.js'); const bird = new Bird('Tweety'); const cat = new Cat('Milo'); const dog = new Dog('Otis'); ``` After: ```ts import { URL } from 'node:url'; import { bar } from '@dep/bar'; import { foo } from 'foo'; import { Bird } from './Bird/index.ts'; import { Cat } from './Cat.ts'; import { Dog } from '…/Dog/index.mts'; // tsconfig paths import { baseUrl } from '#config.js'; // package.json imports export type { Zed } from './zed.d.ts'; export const makeLink = (path: URL) => (new URL(path, baseUrl)).href; const nil = await import('./nil.ts'); const bird = new Bird('Tweety'); const cat = new Cat('Milo'); const dog = new Dog('Otis'); ```
## Example This codemod adds an empty component TS signature to glimmer components ### Before ```ts export default class MyButtonComponent extends Component { ... } ``` ### After ```ts interface MyButtonSignature { // The arguments accepted by the component Args: {}; // Any blocks yielded by the component Blocks: { default: []; }; // The element to which `...attributes` is applied in the component template Element: null; } export default class MyButtonComponent extends Component<MyButtonSignature> { ... } ```
## Example This codemod adds a glint registry declaration in component files if it's not present already. ### Before ```ts export default class MyComponent extends Component { ... } ``` ### After ```ts export default class MyComponent extends Component { ... } declare module '@glint/environment-ember-loose/registry' { export default interface Registry { 'Path::To::MyComponent': typeof MyComponent; } } ```
## Example This codemod transforms @service decorators to use the correct TypeScript syntax ### Before ```ts @service myService; ``` ### After ```ts import { type Registry as Services } from '@ember/service'; ... @service declare myService: Services['myService']; ```
# Correct TypeScript Specifiers This package transforms import specifiers from the old `tsc` (TypeScript's compiler) requirement of using `.js` file extensions in source-code to import files that are actually typescript; the corrected specifiers enable source-code to be runnable by standards-compliant software like Node.js. This is a one-and-done process, and the updated source-code should be committed to your version control (eg git); thereafter, source-code import statements should be authored compliant with the ECMAScript (JavaScript) standard. > [!TIP] > Those using `tsc` to compile will need to enable [`rewriteRelativeImportExtensions`](https://www.typescriptlang.org/tsconfig/#rewriteRelativeImportExtensions); using `tsc` for only type-checking (ex via a lint/test step like `npm run test:types`) needs [`allowImportingTsExtensions`](https://www.typescriptlang.org/tsconfig/#allowImportingTsExtensions) (and some additional compile options—see the cited documentation); This package does not just blindly find & replace file extensions within specifiers: It confirms that the replacement specifier actually exists; in ambiguous cases (such as two files with the same basename in the same location but different relevant file extensions like `/tmp/foo.js` and `/tmp/foo.ts`), it logs an error, skips that specifier, and continues processing. > [!CAUTION] > This package does not confirm that imported modules contain the desired export(s). This _shouldn't_ actually ever result in a problem because ambiguous cases are skipped (so if there is a problem, it existed before the migration started). Merely running your source-code after the mirgration completes will confirm all is well (if there are problems, node will error, citing the problems). > [!TIP] > Node.js requires the `type` keyword be present on type imports. For own code, this package usually handles that. However, in some cases and for node modules, it does not. Robust tooling already exists that will automatically fix this, such as [`consistent-type-imports` via typescript-lint](https://typescript-eslint.io/rules/consistent-type-imports) and [`use-import-type` via biome](https://biomejs.dev/linter/rules/use-import-type/). If your source code needs that, first run this codemod and then one of those fixers. ## Running > [!CAUTION] > This will change your source-code. Commit any unsaved changes before running this package. ```sh NODE_OPTIONS="--experimental-import-meta-resolve" \ npx codemod@latest correct-ts-specifiers ``` ### Monorepos For best results, run this _within_ each workspace of the monorepo. ```text project-root/ ├ workspaces/ ├ foo/ ←--------- RUN HERE ├ … ├ package.json └ tsconfig.json └ bar/ ←--------- RUN HERE ├ … ├ package.json └ tsconfig.json └ utils/ ←--------- RUN HERE ├ qux.js └ zed.js ``` ## Supported cases * no file extension → `.cts`, `.mts`, `.js`, `.ts`, `.d.cts`, `.d.mts`, or `.d.ts` * `.cjs` → `.cts`, `.mjs` → `.mts`, `.js` → `.ts` * `.js` → `.d.cts`, `.d.mts`, or `.d.ts` * [Package.json subimports](https://nodejs.org/api/packages.html#subpath-imports) * [tsconfig paths](https://www.typescriptlang.org/tsconfig/#paths) (via [`@nodejs-loaders/alias`](https://github.com/JakobJingleheimer/nodejs-loaders/blob/main/packages/alias?tab=readme-ov-file)) * In order to subsequently run code via node, you will need to add this (or another) loader to your own project. Or, switch to [subimports](https://nodejs.org/api/packages.html#subpath-imports). * Commonjs-like directory specifiers Before: ```ts import { URL } from 'node:url'; import { bar } from '@dep/bar'; import { foo } from 'foo'; import { Bird } from './Bird'; // a directory import { Cat } from './Cat.ts'; import { Dog } from '…/Dog/index.mjs'; // tsconfig paths import { baseUrl } from '#config.js'; // package.json imports export { Zed } from './zed'; export const makeLink = (path: URL) => (new URL(path, baseUrl)).href; const nil = await import('./nil.js'); const bird = new Bird('Tweety'); const cat = new Cat('Milo'); const dog = new Dog('Otis'); ``` After: ```ts import { URL } from 'node:url'; import { bar } from '@dep/bar'; import { foo } from 'foo'; import { Bird } from './Bird/index.ts'; import { Cat } from './Cat.ts'; import { Dog } from '…/Dog/index.mts'; // tsconfig paths import { baseUrl } from '#config.js'; // package.json imports export type { Zed } from './zed.d.ts'; export const makeLink = (path: URL) => (new URL(path, baseUrl)).href; const nil = await import('./nil.ts'); const bird = new Bird('Tweety'); const cat = new Cat('Milo'); const dog = new Dog('Otis'); ```
This codemod updates import paths and ensures compatibility with changes in library structures. In this example, it modifies the import statement for vitePreprocess to reflect updates in the library's API. ### EXAMPLE ### Before ```ts import { vitePreprocess } from '@sveltejs/kit/vite'; export default { preprocess: vitePreprocess(), }; ``` ### After ```ts // svelte.config.js import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; export default { preprocess: vitePreprocess(), }; ```
# Simplify SvelteKit Import and Path Usage This codemod simplifies the import statements and path resolution in your SvelteKit project. It replaces the usage of `resolvePath` and concatenation with `base` by using the `resolveRoute` function from `$app/paths`. This results in cleaner and more readable code. ## Transformations This codemod performs the following transformations: - **Import Statement**: Transforms: ```typescript import { resolvePath } from '@sveltejs/kit'; import { base } from '$app/paths'; ``` into ```typescript import { resolveRoute } from '$app/paths'; ``` - **Path Resolution**: Transforms: ```typescript const path = base + resolvePath('/blog/[slug]', { slug }); ``` into ```typescript const path = resolveRoute('/blog/[slug]', { slug }); ``` ## Usage To apply this codemod, run the workflow script on your TypeScript files. Ensure you have the necessary dependencies installed and your project is configured to use this codemod. ## Example ### Before ```typescript import { resolvePath } from '@sveltejs/kit'; import { base } from '$app/paths'; const path = base + resolvePath('/blog/[slug]', { slug }); ``` ### After ```typescript import { resolveRoute } from '$app/paths'; const path = resolveRoute('/blog/[slug]', { slug }); ```
## Codemod Description This codemod is designed to replace specific patterns in TypeScript files with updated code logic. It transforms instances of `goto($A)` into `window.location.href = $A;` when the `$A` value is a URL starting with `http://` or `https://`. This refactor makes external navigation more explicit by using `window.location.href`. --- ## Features - **Pattern Matching**: Identifies instances of `goto($A)` in TypeScript files. - **Conditional Replacement**: Applies transformations only when the matched node contains URLs starting with `http://` or `https://`. - **Automated Code Refactoring**: Updates all matching files automatically. - **Logging**: Displays original and transformed code snippets for review. --- ## Workflow Details The codemod works by finding and replacing `goto($A)` with `window.location.href = $A;` based on the condition that `$A` is an external URL starting with `http://` or `https://`. ### Code Transformations: - **Pattern**: `goto($A)` - **Regex Filters**: - `http://` - `https://` - **Replacement**: - `window.location.href = $A;` --- ## Before and After Examples ### Example 1: Internal Navigation (Unchanged) #### Before ```typescript import { goto } from '$app/navigation'; function navigateInternal() { goto('/dashboard', { state: { userId: 42, from: 'home' } }); goto('/dashboard'); } ``` #### After ```typescript import { goto } from '$app/navigation'; function navigateInternal() { goto('/dashboard', { state: { userId: 42, from: 'home' } }); goto('/dashboard'); } ``` - **Explanation**: Internal URLs (like `/dashboard`) remain unchanged, as they do not match the transformation condition. --- ### Example 2: External Navigation with `http://` #### Before ```typescript function navigateExternal() { goto('http://example.com'); } ``` #### After ```typescript function navigateExternal() { window.location.href = 'http://example.com'; } ``` - **Explanation**: External URLs starting with `http://` are transformed into `window.location.href = $A;`. --- ### Example 3: External Navigation with `https://` #### Before ```typescript function navigateExternal() { goto('https://example.com'); } ``` #### After ```typescript function navigateExternal() { window.location.href = 'https://example.com'; } ``` - **Explanation**: External URLs starting with `https://` are also transformed in the same way. --- ## How It Works 1. The script scans all TypeScript files (`*.ts`) in your project. 2. It searches for instances of `goto($A)` and checks if `$A` matches either `http://` or `https://`. 3. When a match is found, the `goto($A)` pattern is replaced with `window.location.href = $A;`. 4. Internal navigation paths are left unchanged, as they do not match the regex condition. --- ## Conclusion This codemod provides an efficient way to refactor external navigation in your TypeScript code by converting `goto($A)` into `window.location.href = $A;` for URLs starting with `http://` or `https://`. It helps make external link handling more explicit and consistent across your project. --- ## License This codemod is open-source and licensed under the MIT License. ```
This codemod transforms import {$A} from '$env/dynamic/public'; and import {$A} from '$env/dynamic/private'; into their static counterparts, replacing them with import {$A} from '$env/static/public'; and import {$A} from '$env/static/private';, respectively. It ensures compatibility for prerendered pages and static deployments. Note: This is a contrived example. Please modify it according to your use case. ### Example ### Before ```ts // $env/dynamic/private import { PRIVATE_API_KEY } from '$env/dynamic/private'; /** @type {import('./$types').PageServerLoad} */ export function load() { const apiKey = PRIVATE_API_KEY; return { apiKey }; } // $env/dynamic/public import { PUBLIC_API_URL } from '$env/dynamic/public'; /** @type {import('./$types').PageLoad} */ export function load() { const apiUrl = PUBLIC_API_URL; return { apiUrl }; } ``` ### After ```ts // $env/static/private import { PRIVATE_API_KEY } from '$env/static/private'; /** @type {import('./$types').PageServerLoad} */ export function load() { const apiKey = PRIVATE_API_KEY; return { apiKey }; } // $env/static/public import { PUBLIC_API_URL } from '$env/static/public'; /** @type {import('./$types').PageLoad} */ export function load() { const apiUrl = PUBLIC_API_URL; return { apiUrl }; } ```
This codemod improves error handling in SvelteKit by updating the way errors are returned in the load function. In SvelteKit 1, errors were handled inconsistently, often missing the status property or failing to trigger the handleError hook. SvelteKit 2 standardizes error handling by automatically including the status and message properties in error responses. ### Change Summary In SvelteKit 1, errors were returned with just the error property. In SvelteKit 2, errors are now returned with both error and status properties, ensuring consistent error handling and making it easier to manage different HTTP statuses. This codemod ensures that all errors returned from the load function are compatible with SvelteKit 2’s enhanced error handling. ### Example ### Before ```ts // Before (SvelteKit 1) import { error } from '@sveltejs/kit'; export async function load({ params }) { try { const data = await fetchData(params.id); if (!data) { throw error(404, 'Data not found'); } return { props: { data } }; } catch (err) { // Errors might not always trigger handleError if (err.status === 404) { console.error("Page not found", err); } return { props: { error: err.message } }; } } ``` ### After ```ts // After (SvelteKit 2) import { error } from '@sveltejs/kit'; export async function load({ params }) { try { const data = await fetchData(params.id); if (!data) { throw error(404, 'Data not found'); } return { props: { data } }; } catch (err) { // With the improved error handling in SvelteKit 2, errors are now consistent // and trigger the handleError hook with status and message. return { props: { error: err.message, status: err.status || 500 } }; } } ```
This codemod automatically adds the enctype="multipart/form-data" attribute to forms containing file input fields. It ensures that forms with file inputs properly handle file uploads during non-JS submissions, which is a requirement for SvelteKit v2. ### What it does Transforms: It identifies forms that contain <input type="file"> but lack the enctype="multipart/form-data" attribute. Adds: The enctype="multipart/form-data" attribute to those forms. ### Why it's necessary If a form contains an <input type="file"> element but does not specify enctype="multipart/form-data", non-JS submissions will omit the file. SvelteKit v2 enforces this requirement and will throw an error if a form like this is encountered during a use:enhance submission. ## Example ### Before ```ts <form use:enhance={handleEnhance}> <input type="text" name="name" /> <input type="file" name="file" /> <button type="submit">Submit</button> </form> ``` ### After ```ts <form use:enhance={handleEnhance} enctype="multipart/form-data"> <input type="text" name="name" /> <input type="file" name="file" /> <button type="submit">Submit</button> </form> ```
# Add Cookie Path to All Methods This codemod adds `{ path: '/' }` to all `cookies` method calls in your TypeScript project. It ensures that cookies are set, deleted, or serialized with the correct path specified, which helps in consistent cookie handling across different environments. ## Transformations This codemod performs the following transformations: - **Set Cookie**: Transforms `cookies.set(key, value)` into `cookies.set(key, value, { path: '/' })`. - **Delete Cookie**: Transforms `cookies.delete(key)` into `cookies.delete(key, { path: '/' })`. - **Serialize Cookie**: Transforms `cookies.serialize(key, value)` into `cookies.serialize(key, value, { path: '/' })`. ## Usage To apply this codemod, run the workflow script on your TypeScript files. Ensure you have the necessary dependencies installed and your project is configured to use this codemod. ## Example ### Before ```typescript cookies.set('session', 'abc123'); cookies.delete('user'); cookies.serialize('token', 'xyz789'); ``` ### After ```ts cookies.set('session', 'abc123', { path: '/' }); cookies.delete('user', { path: '/' }); cookies.serialize('token', 'xyz789', { path: '/' }); ```
Build your own codemod and share it with the community.