npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ts-morph-react

v1.0.6

Published

A collection of transformers for ts-morph to refactor react code

Readme

ts-morph-react

npm version npm downloads License: MIT

A powerful collection of AST transformers for ts-morph to automate React code refactoring. Enforce consistent code patterns, modernize your codebase, and enforce best practices with declarative, composable transformers.

Features

  • 🔄 Enforce Direct Exports - Convert separate export statements to direct exports on function declarations
  • 🎯 Function Components - Automatically convert function declarations to arrow function components with proper typing
  • 📦 Named Imports - Transform default imports to named imports for consistency
  • 🎨 Code Formatting - Format code and organize imports according to your style guide (using ESLint, Prettier or Typescript Language Featues)
  • Composable - Mix and match transformers to create your refactoring pipeline
  • 🛡️ Type-Safe - Built with TypeScript for a fully typed experience
  • 🎭 AST-Powered - Leverage ts-morph for precise, reliable code transformations

Installation

npm install ts-morph-react
# or
pnpm add ts-morph-react
# or
yarn add ts-morph-react

Quick Start

As a Library

import { Project } from 'ts-morph'
import { transform } from 'ts-morph-react'

const project = new Project()
const sourceFile = project.addSourceFileAtPath('src/Button.tsx')

// Run transformers with your configuration
await transform(sourceFile, {
  enforceDirectExports: true,
  enforceFunctionComponent: true,
  enforceNamedImports: true,
  enforceFormat: true,
  enforcePrettier: true,
  enforceEslint: true,
  enforceLineSeparation: true
})

// Save changes
await sourceFile.save()

Transformers

enforceDirectExports

Converts separate export statement to direct exports.

Before:

function Button<ButtonProps>({ label }) {
  return <button>{label}</button>
}

export { Button }

After:

export function Button(props) {
  return <button>{props.label}</button>
}

enforceFunctionComponent

Converts plain function components to properly typed React.FunctionComponent components, preserving prop types.

Before:

function Button(props: ButtonProps) {
  return <button>{props.label}</button>
}

After:

const Button: React.FunctionComponent<ButtonProps> = (props) => {
  return <button>{props.label}</button>
}

enforceNamedImports

Transforms default imports to named imports for better tree-shaking and consistency.

Before:

import * as React from 'react'

export const Button: React.FunctionComponent<ButtonProps> = ({ label }) => {
  return <button>{label}</button>
}

After:

import { FunctionComponent } from 'react'

export const Button: FunctionComponent<ButtonProps> = ({ label }) => {
  return <button>{label}</button>
}

enforceEslint / enforcePrettier / enforceFormat

Formats code and organizes imports according to your style guide. Respects all standard TypeScript formatting options, eslint rules and prettier options.

Usage:

import { transform } from 'ts-morph-react'

await transform(sourceFile, {
  enforceFormat: true,
  enforcePrettier: true,
  enforceEslint: true,
  enforceLineSeparation: true,
  format: {
    indentSize: 2,
    convertTabsToSpaces: true,
    semicolons: ts.SemicolonPreference.Remove
  },
  eslint: {
    '@stylistic/quotes': ['error', 'single']
  },
  prettier: {
    semi: false,
    singleQuote: true
  }
})

Before:

import * as React from 'react';

import { Text } from '@/components/Text';

export const Button: React.FunctionComponent<ButtonProps> = ({
  label
}) => {
  return <button><Text>{label}</Text></button>;
};

After:

import * as React from 'react'
import { Text } from '@/components/Text'

export const Button: React.FunctionComponent<ButtonProps> = ({ label }) => {
  return <button><Text>{label}</Text></button>
}

API Reference

transform(sourceFile: SourceFile, config?: TransformerConfig)

Applies transformers to a source file.

interface TransformerConfig {
  enforceDirectExports: boolean
  enforceFunctionComponent: boolean
  enforceNamedImports: boolean
  enforceFormat: boolean
  enforceLineSeparation: boolean
  enforceEslint: boolean
  enforcePrettier: boolean
  format: {
    baseIndentSize: number
    convertTabsToSpaces: boolean
    ensureNewLineAtEndOfFile: boolean
    indentMultiLineObjectLiteralBeginningOnBlankLine: boolean
    indentSize: number
    indentStyle: IndentStyle
    indentSwitchCase: boolean
    insertSpaceAfterCommaDelimiter: boolean
    insertSpaceAfterConstructor: boolean
    insertSpaceAfterFunctionKeywordForAnonymousFunctions: boolean
    insertSpaceAfterKeywordsInControlFlowStatements: boolean
    insertSpaceAfterOpeningAndBeforeClosingEmptyBraces: boolean
    insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: boolean
    insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: boolean
    insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: boolean
    insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: boolean
    insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: boolean
    insertSpaceAfterSemicolonInForStatements: boolean
    insertSpaceAfterTypeAssertion: boolean
    insertSpaceBeforeAndAfterBinaryOperators: boolean
    insertSpaceBeforeFunctionParenthesis: boolean
    insertSpaceBeforeTypeAnnotation: boolean
    newLineCharacter: string
    placeOpenBraceOnNewLineForControlBlocks: boolean
    placeOpenBraceOnNewLineForFunctions: boolean
    semicolons: SemicolonPreference
    tabSize: number
    trimTrailingWhitespace: boolean
  },
  eslint: {
    '@stylistic/*': ['error'],
    '@typescript-eslint/*': ['error']
  },
  prettier: {
    semi: false,
    singleQuote: true,
    jsxSingleQuote: true,
    arrowParens: 'always',
    bracketSameLine: true,
    objectWrap: 'collapse',
    printWidth: 120
  }
}

Development

# Build the library
pnpm build

# Watch mode during development
pnpm watch

# Run tests
pnpm test

# Watch mode for tests
pnpm test:watch

# Run tests with UI
pnpm test:ui

# Lint and type-check
pnpm lint

# Clean build artifacts
pnpm clean

Testing

The project uses vitest with snapshot testing to ensure transformer behavior is consistent and intentional:

# Run tests once
pnpm test

# Run in watch mode
pnpm test:watch

# Update snapshots after intentional changes
pnpm test -- -u

# Run specific test file
pnpm test enforceFormat

When to Use ts-morph-react

Good for:

  • Enforcing code patterns across your codebase
  • Large-scale refactoring of React components
  • Automating style guide compliance
  • One-time migrations (class → function components, etc.)
  • Building custom code generators and linters

Not ideal for:

  • Real-time code formatting (use Prettier for that)
  • Rename refactoring with complex scope analysis (use your IDE)
  • Performance-critical transformations of very large codebases

Under the Hood

ts-morph-react is built on top of ts-morph, a fantastic library that provides a fluent API for manipulating TypeScript ASTs. If you need lower-level control, you can access the ts-morph APIs directly.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT © Tobias Strebitzer

See Also