Assess, plan, evolve.
Reusable compiler-aware skills that help coding agents understand, plan, and safely evolve your codebase.
134 packages
Run all React 19 migration codemods in sequence
Transform React class components to modern function components
This codemod removes `React.FC`, `React.FunctionComponent` and `React.SFC` and replaces the Props as the type of the unique argument in the component definition. This codemod supports: - Inline defined props. - Generics. - Props defined with intersection. - Component modules defined using intersection. - Regular named functions. - Functions that accept a component definition. - Using FC, FunctionComponent and SFC as a named export. ## Before: ```jsx type Props2 = { id: number }; export const MyComponent2: React.FC<Props2> = (props) => { return <span>{props.id}</span> } ``` ## After: ```tsx type Props2 = { id: number }; export const MyComponent2 = (props: Props2) => { return <span>{props.id}</span>; }; ```
## Example This codemod turns X into Y. It also does Z. Note: this is a contrived example. Please modify it. ### Before ```ts import React from 'react'; import PropTypes from 'prop-types'; import { makeStyles, useTheme } from '@material-ui/styles'; import classNames from 'classnames'; import Button from '../../../../components/controls/Button'; import ButtonLoader from '../../../../components/loaders/ButtonLoader'; import makeStateElementName from '../../../../theme-editor/utils/makeStateElementName'; const useStyles = makeStyles((theme) => ({ stakeButton: ({ editorId }) => ({ width: '100%', height: 40, fontWeight: 600, ...theme[editorId], }), stakeButtonDisabled: ({ editorId }) => ({ ...theme[`${makeStateElementName(editorId, 'disabled')}`], }), '@media (hover: hover)': { stakeButtonDisabled: ({ editorId }) => ({ '&:hover': { ...theme[`${makeStateElementName(editorId, 'disabled')}`], }, }), }, loaderContainer: { width: '100%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', }, })); const StakeInputButton = ({ onClick, isDisabled, children, className, isLoading, dataEditorId, }) => { const classes = useStyles({ editorId: dataEditorId }); const theme = useTheme(); return ( < Button elementClasses = { { default: classNames(classes.stakeButton, className), disabled: classes.stakeButtonDisabled, } } disabled = { isDisabled } onClick = { onClick } style = { { padding: 0, } } dataEditorId = { dataEditorId } > { isLoading ? ( < div className = { classes.loaderContainer } > < ButtonLoader color = { theme.brandButton.color } /> < /div> ) : ( children ) } < /Button> ); }; StakeInputButton.propTypes = { dataEditorId: PropTypes.string, }; StakeInputButton.defaultProps = { dataEditorId: 'betslipPlaceBetButton', }; export default StakeInputButton; ``` ### After ```ts import React from 'react'; import PropTypes from 'prop-types'; import { makeStyles, useTheme } from '@material-ui/styles'; import classNames from 'classnames'; import Button from '../../../../components/controls/Button'; import ButtonLoader from '../../../../components/loaders/ButtonLoader'; import makeStateElementName from '../../../../theme-editor/utils/makeStateElementName'; const useStyles = makeStyles((theme) => ({ stakeButton: ({ editorId }) => ({ width: '100%', height: 40, fontWeight: 600, ...theme[editorId], }), stakeButtonDisabled: ({ editorId }) => ({ ...theme[`${makeStateElementName(editorId, 'disabled')}`], }), '@media (hover: hover)': { stakeButtonDisabled: ({ editorId }) => ({ '&:hover': { ...theme[`${makeStateElementName(editorId, 'disabled')}`], }, }), }, loaderContainer: { width: '100%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', }, })); const StakeInputButton = ({ onClick, isDisabled, children, className, isLoading, dataEditorId = 'betslipPlaceBetButton', }) => { const classes = useStyles({ editorId: dataEditorId }); const theme = useTheme(); return ( < Button elementClasses = { { default: classNames(classes.stakeButton, className), disabled: classes.stakeButtonDisabled, } } disabled = { isDisabled } onClick = { onClick } style = { { padding: 0, } } dataEditorId = { dataEditorId } > { isLoading ? ( < div className = { classes.loaderContainer } > < ButtonLoader color = { theme.brandButton.color } /> < /div> ) : ( children ) } < /Button> ); }; StakeInputButton.propTypes = { dataEditorId: PropTypes.string, }; export default StakeInputButton; ``` ,This codemod turns X into Y. It also does Z. Note: this is a contrived example. Please modify it. ### Before ```ts // In react 19 default props should be replaced with js default function parameters import React from 'react'; import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; import { makeStyles } from '@material-ui/styles'; import classNames from 'classnames'; import Button from '../../../components/controls/Button'; import { selectors as betsSelectors } from '../../../redux/ducks/bets'; import useOfflineBooking from '../hooks/useOfflineBooking'; const useStyles = makeStyles({ bookingButton: { width: '100%', fontWeight: 600, }, }); const BookingCodeBookButton = ({ className, dataEditorId }) => { const { makeBooking } = useOfflineBooking(); const { t } = useTranslation(); const classes = useStyles(); const selectionsValid = useSelector(betsSelectors.selectSelectionsValid); return ( < Button className = { classNames(classes.bookingButton, className) } disabled = {!selectionsValid } onClick = { () => (selectionsValid ? makeBooking() : null) } dataEditorId = { dataEditorId } > { t('Book') } < /Button> ); }; BookingCodeBookButton.propTypes = { className: PropTypes.string, dataEditorId: PropTypes.string, }; BookingCodeBookButton.defaultProps = { className: null, dataEditorId: 'betslipShareButton', }; export default BookingCodeBookButton; ``` ### After ```ts import React from 'react'; import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; import { makeStyles } from '@material-ui/styles'; import classNames from 'classnames'; import Button from '../../../components/controls/Button'; import { selectors as betsSelectors } from '../../../redux/ducks/bets'; import useOfflineBooking from '../hooks/useOfflineBooking'; const useStyles = makeStyles({ bookingButton: { width: '100%', fontWeight: 600, }, }); const BookingCodeBookButton = ({ className = null, dataEditorId = 'betslipShareButton', }) => { const { makeBooking } = useOfflineBooking(); const { t } = useTranslation(); const classes = useStyles(); const selectionsValid = useSelector(betsSelectors.selectSelectionsValid); return ( < Button className = { classNames(classes.bookingButton, className) } disabled = {!selectionsValid } onClick = { () => (selectionsValid ? makeBooking() : null) } dataEditorId = { dataEditorId } > { t('Book') } < /Button> ); }; BookingCodeBookButton.propTypes = { className: PropTypes.string, dataEditorId: PropTypes.string, }; export default BookingCodeBookButton; ``` ,This codemod turns X into Y. It also does Z. Note: this is a contrived example. Please modify it. ### Before ```ts // do not add new parameter if default props exist but is not defined in function parameters import React from 'react'; import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; import { makeStyles, useTheme } from '@material-ui/styles'; import ButtonArrow from '../../../../components/controls/ButtonArrow'; import SliderPoints from '../../../../components/controls/SliderPoints'; import BetSlipBonusesSlider from '../../BetSlipBonusesSlider'; import BetSlipEmptyBlock from '../../BetSlipTable/BetSlipEmptyBlock'; const useStyles = makeStyles((theme) => ({ bonusesListContainer: { background: theme.bonusPopup.background, color: theme.bonusPopup.color, paddingBottom: 20, overflowY: 'auto', boxSizing: 'border-box', }, points: { maxWidth: 200, margin: '0 auto', }, topLine: { marginBottom: 8, padding: '8px 16px', }, betSlipEmptyBlock: { minHeight: 275, }, })); const BetSlipBonusesListBase = ({ slides, currentSlide, setCurrentSlide, onCloseButtonClick, className, maxHeight, }) => { const theme = useTheme(); const classes = useStyles(); const { t } = useTranslation(); const arrowButtonBackground = theme.bonusPopup.background; return ( < div className = { `${classes.bonusesListContainer} ${className}` } style = { { maxHeight } } > < div className = { classes.topLine } > < ButtonArrow backgroundColor = { arrowButtonBackground } label = { t('Back') } onClick = { onCloseButtonClick } size = { 32 } direction = 'left' / > < /div> { slides.length > 0 ? ( < > < BetSlipBonusesSlider items = { slides } currentSlide = { currentSlide } setCurrentSlide = { setCurrentSlide } /> { !!slides.length && ( < div className = { classes.points } > < SliderPoints count = { slides.length } activeIndex = { currentSlide } color = { theme.bonusPopup.color } activeColor = { theme.bonusPopup.color } /> < /div> ) } < /> ) : ( < BetSlipEmptyBlock text = { t('No available Bonuses at this moment') } className = { classes.betSlipEmptyBlock } /> ) } < /div> ); }; BetSlipBonusesListBase.propTypes = { className: PropTypes.string, placeholder: PropTypes.string, // for widgets showBonusesForBet: PropTypes.string, toggleChooseBonusBlock: PropTypes.func.isRequired, onUseBonus: PropTypes.func.isRequired, onActivateBonus: PropTypes.func.isRequired, availableBonusesIds: PropTypes.arrayOf(PropTypes.string), bonuses: PropTypes.objectOf(PropTypes.shape({})).isRequired, }; BetSlipBonusesListBase.defaultProps = { placeholder: null, className: null, showBonusesForBet: null, availableBonusesIds: null, }; export default BetSlipBonusesListBase; ``` ### After ```ts import React from 'react'; import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; import { makeStyles, useTheme } from '@material-ui/styles'; import ButtonArrow from '../../../../components/controls/ButtonArrow'; import SliderPoints from '../../../../components/controls/SliderPoints'; import BetSlipBonusesSlider from '../../BetSlipBonusesSlider'; import BetSlipEmptyBlock from '../../BetSlipTable/BetSlipEmptyBlock'; const useStyles = makeStyles((theme) => ({ bonusesListContainer: { background: theme.bonusPopup.background, color: theme.bonusPopup.color, paddingBottom: 20, overflowY: 'auto', boxSizing: 'border-box', }, points: { maxWidth: 200, margin: '0 auto', }, topLine: { marginBottom: 8, padding: '8px 16px', }, betSlipEmptyBlock: { minHeight: 275, }, })); const BetSlipBonusesListBase = ({ slides, currentSlide, setCurrentSlide, onCloseButtonClick, className = null, maxHeight, }) => { const theme = useTheme(); const classes = useStyles(); const { t } = useTranslation(); const arrowButtonBackground = theme.bonusPopup.background; return ( < div className = { `${classes.bonusesListContainer} ${className}` } style = { { maxHeight } } > < div className = { classes.topLine } > < ButtonArrow backgroundColor = { arrowButtonBackground } label = { t('Back') } onClick = { onCloseButtonClick } size = { 32 } direction = 'left' / > < /div> { slides.length > 0 ? ( < > < BetSlipBonusesSlider items = { slides } currentSlide = { currentSlide } setCurrentSlide = { setCurrentSlide } /> { !!slides.length && ( < div className = { classes.points } > < SliderPoints count = { slides.length } activeIndex = { currentSlide } color = { theme.bonusPopup.color } activeColor = { theme.bonusPopup.color } /> < /div> ) } < /> ) : ( < BetSlipEmptyBlock text = { t('No available Bonuses at this moment') } className = { classes.betSlipEmptyBlock } /> ) } < /div> ); }; BetSlipBonusesListBase.propTypes = { className: PropTypes.string, placeholder: PropTypes.string, // for widgets showBonusesForBet: PropTypes.string, toggleChooseBonusBlock: PropTypes.func.isRequired, onUseBonus: PropTypes.func.isRequired, onActivateBonus: PropTypes.func.isRequired, availableBonusesIds: PropTypes.arrayOf(PropTypes.string), bonuses: PropTypes.objectOf(PropTypes.shape({})).isRequired, }; export default BetSlipBonusesListBase; ```
This codemods designed to facilitate the migration of your project from React Router to version 7. Each codemod targets specific changes and improvements introduced in React Router v7, ensuring a smoother transition. ## Included Codemods The following codemods are included in this recipe: 1. **[`react-router/7/relative-links`](https://codemod.com/registry/react-router-7-relative-links)** Updates relative link paths to comply with v7 standards. 2. **[`react-router/7/add_v7_relativeSplatPath_Flag`](https://codemod.com/registry/react-router-7-add_v7_relativeSplatPath_Flag)** Adds the `relativeSplatPath` flag to routes to support relative splat behavior. 3. **[`react-router/7/errorfirst-mutation-reorder`](https://codemod.com/registry/react-router-7-errorfirst-mutation-reorder)** Reorders error-first mutation signatures for compatibility with v7. 4. **[`react-router/7/form-methods-post-get-to-uppercase`](https://codemod.com/registry/react-router-7-form-methods-post-get-to-uppercase)** Converts form method strings (`post`, `get`) to uppercase as required by v7. 5. **[`react-router/7/route-wildcard-to-nested`](https://codemod.com/registry/react-router-7-route-wildcard-to-nested)** Transforms route wildcards into nested routes for improved routing management. 6. **[`react-router/7/add_v7_startTransition_Flag`](https://codemod.com/registry/react-router-7-add-v7-startTransition-flag)** Introduces the `startTransition` flag to enhance transitions in routing. 7. **[`react-router/7/add_v7_fetcherPersist_Flag`](https://codemod.com/registry/react-router-7-add_v7_fetcherPersist_Flag)** Adds the `fetcherPersist` flag to improve data fetching mechanisms. 8. **[`react-router/7/add_v7_normalizeFormMethod`](https://codemod.com/registry/react-router-7-add_v7_normalizeFormMethod)** Normalizes form methods to align with v7 conventions. 9. **[`react-router/7/add_v7_partialHydration_Flag`](https://codemod.com/registry/react-router-7-add_v7_partialHydration_Flag)** Integrates the `partialHydration` flag to support enhanced hydration strategies. 10. **[`react-router/7/add_v7_skipActionStatusRevalidation_Flag`](https://codemod.com/registry/react-router-7-add_v7_skipActionStatusRevalidation_Flag)** Adds the `skipActionStatusRevalidation` flag for improved action handling. ---
Move DOM APIs from react to react-dom
This codemod updates imports of `StaticRouter` to use the `react-router-dom/server` package instead of `react-router-dom`, in line with updated React Router requirements. ### Before ```tsx import { BrowserRouter, Route, StaticRouter } from "react-router-dom"; ``` ### After ```tsx import { BrowserRouter, Route } from "react-router-dom"; import { StaticRouter } from "react-router-dom/server"; ``` This codemod ensures compatibility with the latest React Router version by splitting `StaticRouter` imports into the correct package. Other imports from `react-router-dom` remain unaffected.
Reorder React component methods to match eslint-plugin-react sort-comp rule
In v7 the react-router and react-router-dom packages are combined so this codemod import everything directly from "react-router" except for the RouterProvider exception. ### Before ```ts import { BrowserRouter, Routes, Route, useLocation, Link, } from 'react-router-dom'; import { RouterProvider } from 'react-router-dom'; ``` ### After ```ts import { BrowserRouter, Routes, Route, useLocation, Link } from 'react-router'; import { RouterProvider } from 'react-router/dom'; ```
Transform React components using Material UI JSS APIs (e.g., makeStyles/withStyles/createStyles) into strongly typed `tss-react` hook-based styling (`makeStyles` from `tss-react/mui`) in TypeScript React codebases, improving maintainability and type safety while modernizing legacy styling patterns.
No description available
Run this codemod to replace `Router` using `hashHistory` to `HashRouter` in v4.
- More pages
Ready to evolve your codebase?
Build tailored, compiler-aware skills to assess, plan, and automate complex codebase changes.