Skip to content

vish288/move-prop-types

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

127 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

move-prop-types

npm version TypeScript License: MIT

A modern, TypeScript-based CLI tool that automatically refactors your React codebase to use the standalone prop-types package instead of the deprecated React.PropTypes. Supports JavaScript, JSX, TypeScript, and TSX files with robust transformation capabilities.

πŸš€ Why move-prop-types?

When React v15.5 was released in 2017, PropTypes was deprecated from the core React package and moved to a separate prop-types package. Many legacy React projects still use the old React.PropTypes syntax, which is no longer supported in modern React versions.

This CLI tool automates the migration process by:

  • βœ… Detecting legacy PropTypes usage - Scans for React.PropTypes patterns
  • βœ… Removing PropTypes from React imports - Cleans up import { PropTypes } from React
  • βœ… Adding standalone prop-types import - Adds import PropTypes from 'prop-types'
  • βœ… Replacing usage patterns - Changes React.PropTypes.string to PropTypes.string
  • βœ… Handling complex nested patterns - Supports complex PropTypes like PropTypes.arrayOf(PropTypes.shape(...))
  • βœ… Processing entire codebases - Recursively processes directories and subdirectories
  • βœ… Installing dependencies - Optionally installs the prop-types package automatically
  • βœ… TypeScript & JSX Support - Works with .js, .jsx, .ts, and .tsx files
  • βœ… Advanced Pattern Recognition - Handles complex import patterns and edge cases

πŸ“¦ Installation

Global Installation (Recommended)

npm install -g move-prop-types
# or with pnpm
pnpm add -g move-prop-types
# or with yarn
yarn global add move-prop-types

Local Installation

npm install --save-dev move-prop-types
# or with pnpm
pnpm add --save-dev move-prop-types
# or with yarn
yarn add --dev move-prop-types

πŸ› οΈ Usage

Usage: move-prop-types|mpt [options] [file|folder]

Options:
  -V, --version          output the version number
  -I, --install          install prop-types package and continue with transformation
  -P, --path <path>      transform a specific file
  -F, --folder <folder>  transform all .js/.jsx/.ts/.tsx files in a folder (recursive)
  -h, --help             display help for command

πŸ“– Examples

Transform a Single File

# Transform JavaScript/JSX files
mpt -P src/components/UserProfile.jsx
mpt -P src/utils/validators.js

# Transform TypeScript/TSX files
mpt -P src/components/UserProfile.tsx
mpt -P src/types/PropTypes.ts

# Transform with automatic prop-types installation
mpt -I -P src/components/UserProfile.tsx

# Transform a file with relative path
mpt -P ./components/Header.ts

# Transform multiple files (run command for each)
mpt -P src/components/Button.jsx
mpt -P src/components/Modal.tsx
mpt -P src/utils/validators.ts

Transform an Entire Directory

# Transform all .js/.jsx/.ts/.tsx files in src directory recursively
mpt -F src

# Transform entire project with prop-types installation
mpt -I -F .

# Transform specific subdirectories
mpt -F src/components
mpt -F src/pages
mpt -F src/utils

# Large TypeScript project with automatic dependency installation
mpt -I -F src

Real-World Migration Scenarios

Legacy React Project

# 1. Install move-prop-types globally
npm install -g move-prop-types

# 2. Navigate to your React project
cd my-react-project

# 3. Install prop-types and transform entire codebase
mpt -I -F src

# 4. Verify changes and test your application
npm test

Migrating Specific Components

# Transform only component files
mpt -F src/components

# Transform only utility files that use PropTypes
mpt -P src/utils/propTypeValidators.js
mpt -P src/hoc/withPropTypes.js

Before and After Examples

Simple Component Migration

Before transformation:

import React, { Component, PropTypes } from 'react';

class UserProfile extends Component {
  render() {
    const { name, email, age, isActive } = this.props;
    return (
      <div className="user-profile">
        <h2>{name}</h2>
        <p>Email: {email}</p>
        <p>Age: {age}</p>
        {isActive && <span className="active">Active User</span>}
      </div>
    );
  }
}

UserProfile.propTypes = {
  name: React.PropTypes.string.isRequired,
  email: React.PropTypes.string.isRequired,
  age: React.PropTypes.number,
  isActive: React.PropTypes.bool
};

UserProfile.defaultProps = {
  age: 0,
  isActive: false
};

export default UserProfile;

After transformation:

import React, { Component } from 'react';
import PropTypes from 'prop-types';

class UserProfile extends Component {
  render() {
    const { name, email, age, isActive } = this.props;
    return (
      <div className="user-profile">
        <h2>{name}</h2>
        <p>Email: {email}</p>
        <p>Age: {age}</p>
        {isActive && <span className="active">Active User</span>}
      </div>
    );
  }
}

UserProfile.propTypes = {
  name: PropTypes.string.isRequired,
  email: PropTypes.string.isRequired,
  age: PropTypes.number,
  isActive: PropTypes.bool
};

UserProfile.defaultProps = {
  age: 0,
  isActive: false
};

export default UserProfile;

Complex PropTypes Migration

Before transformation:

import React, { PropTypes } from 'react';

const DataTable = ({ data, columns, onRowClick, pagination, loading }) => {
  // Component implementation
  return <div>DataTable Component</div>;
};

DataTable.propTypes = {
  data: React.PropTypes.arrayOf(React.PropTypes.object).isRequired,
  columns: React.PropTypes.arrayOf(React.PropTypes.shape({
    key: React.PropTypes.string.isRequired,
    title: React.PropTypes.string.isRequired,
    render: React.PropTypes.func,
    sortable: React.PropTypes.bool
  })).isRequired,
  onRowClick: React.PropTypes.func,
  pagination: React.PropTypes.oneOfType([
    React.PropTypes.bool,
    React.PropTypes.shape({
      page: React.PropTypes.number,
      pageSize: React.PropTypes.number,
      total: React.PropTypes.number
    })
  ]),
  loading: React.PropTypes.bool
};

export default DataTable;

After transformation:

import React from 'react';
import PropTypes from 'prop-types';

const DataTable = ({ data, columns, onRowClick, pagination, loading }) => {
  // Component implementation
  return <div>DataTable Component</div>;
};

DataTable.propTypes = {
  data: PropTypes.arrayOf(PropTypes.object).isRequired,
  columns: PropTypes.arrayOf(PropTypes.shape({
    key: PropTypes.string.isRequired,
    title: PropTypes.string.isRequired,
    render: PropTypes.func,
    sortable: PropTypes.bool
  })).isRequired,
  onRowClick: PropTypes.func,
  pagination: PropTypes.oneOfType([
    PropTypes.bool,
    PropTypes.shape({
      page: PropTypes.number,
      pageSize: PropTypes.number,
      total: PropTypes.number
    })
  ]),
  loading: PropTypes.bool
};

export default DataTable;

Functional Component Migration

Before transformation:

import React, { PropTypes } from 'react';

function Button({ label, onClick, disabled, variant, size }) {
  return (
    <button 
      onClick={onClick} 
      disabled={disabled}
      className={`btn btn-${variant} btn-${size}`}
    >
      {label}
    </button>
  );
}

Button.propTypes = {
  label: React.PropTypes.string.isRequired,
  onClick: React.PropTypes.func.isRequired,
  disabled: React.PropTypes.bool,
  variant: React.PropTypes.oneOf(['primary', 'secondary', 'danger']),
  size: React.PropTypes.oneOf(['small', 'medium', 'large'])
};

Button.defaultProps = {
  disabled: false,
  variant: 'primary',
  size: 'medium'
};

export default Button;

After transformation:

import React from 'react';
import PropTypes from 'prop-types';

function Button({ label, onClick, disabled, variant, size }) {
  return (
    <button 
      onClick={onClick} 
      disabled={disabled}
      className={`btn btn-${variant} btn-${size}`}
    >
      {label}
    </button>
  );
}

Button.propTypes = {
  label: PropTypes.string.isRequired,
  onClick: PropTypes.func.isRequired,
  disabled: PropTypes.bool,
  variant: PropTypes.oneOf(['primary', 'secondary', 'danger']),
  size: PropTypes.oneOf(['small', 'medium', 'large'])
};

Button.defaultProps = {
  disabled: false,
  variant: 'primary',
  size: 'medium'
};

export default Button;

TypeScript Component Migration

Before transformation:

import React, { FC, PropTypes } from 'react';

interface MyComponentProps {
  title: string;
  count?: number;
  onClick: (id: number) => void;
}

const MyComponent: FC<MyComponentProps> = ({ title, count = 0, onClick }) => {
  return (
    <div>
      <h2>{title}</h2>
      <p>Count: {count}</p>
      <button onClick={() => onClick(count)}>Click me</button>
    </div>
  );
};

MyComponent.propTypes = {
  title: React.PropTypes.string.isRequired,
  count: React.PropTypes.number,
  onClick: React.PropTypes.func.isRequired
};

export default MyComponent;

After transformation:

import React, { FC } from 'react';
import PropTypes from 'prop-types';

interface MyComponentProps {
  title: string;
  count?: number;
  onClick: (id: number) => void;
}

const MyComponent: FC<MyComponentProps> = ({ title, count = 0, onClick }) => {
  return (
    <div>
      <h2>{title}</h2>
      <p>Count: {count}</p>
      <button onClick={() => onClick(count)}>Click me</button>
    </div>
  );
};

MyComponent.propTypes = {
  title: PropTypes.string.isRequired,
  count: PropTypes.number,
  onClick: PropTypes.func.isRequired
};

export default MyComponent;

πŸ—οΈ Features

  • TypeScript Support: Built with TypeScript for better reliability and type safety
  • Modern Tooling: Uses latest ESLint, Prettier, and build tools
  • Comprehensive Testing: Full test suite with unit and integration tests
  • Recursive Processing: Handles entire directory structures
  • Smart Detection: Only processes files that actually use PropTypes
  • Safe Transformations: Preserves existing prop-types imports
  • Multiple Import Patterns: Handles various React import styles
  • TypeScript Compatibility: Preserves TypeScript syntax, interfaces, and type annotations
  • Advanced Pattern Detection: Handles complex PropTypes patterns including middle-position imports

πŸ§ͺ Development

Prerequisites

  • Node.js 18+
  • pnpm (recommended) or npm

Setup

# Clone the repository
git clone https://github.com/vish288/move-prop-types.git
cd move-prop-types

# Install dependencies
pnpm install

# Build the project
pnpm run build

# Run tests
pnpm test

# Run linting
pnpm run lint

Project Structure

src/
β”œβ”€β”€ core.ts           # CLI command setup and argument parsing
β”œβ”€β”€ helper.ts         # Core transformation logic with TypeScript support
β”œβ”€β”€ ast-helper.ts     # Advanced AST-based transformation (experimental)
β”œβ”€β”€ ast-transformer.ts # AST parsing and transformation utilities
β”œβ”€β”€ constants.ts      # Regular expressions and transformation patterns
β”œβ”€β”€ types.ts          # TypeScript type definitions
└── updateFile.ts     # Build utility for adding shebang

test/
β”œβ”€β”€ unit/            # Unit tests for individual modules
β”‚   β”œβ”€β”€ helper.test.ts
β”‚   β”œβ”€β”€ ast-transformer.test.ts
β”‚   β”œβ”€β”€ constants.test.ts
β”‚   └── core.test.ts
β”œβ”€β”€ integration/     # Integration tests for real-world scenarios
└── fixtures/        # Test files for various transformation scenarios

🀝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

πŸ“¦ Release Status & NPM Publishing

Current Releases

  • βœ… v1.0.0 - Stable release with full TypeScript support
  • βœ… v0.20.1-beta.1 - Beta release with TypeScript support
  • πŸ”„ NPM Publishing - Automatic publishing configured

Missing NPM Versions

The following GitHub releases are ready but not yet published to npm:

  • v0.20.1-beta.1 (TypeScript support beta)
  • v1.0.0 (stable release with TypeScript support)

These will be automatically published once the repository maintainer configures the NPM_TOKEN secret.

Automatic Publishing System

This repository includes an automated system to:

  • βœ… Detect missing versions between GitHub releases and npm
  • βœ… Publish automatically when NPM_TOKEN is configured
  • βœ… Daily checks for any missing versions
  • βœ… Manual triggers available via GitHub Actions

For maintainers: See docs/NPM_PUBLISHING.md for setup instructions.

πŸ“‹ Requirements

  • Node.js: Version 18 or higher
  • File Types: Supports .js, .jsx, .ts, and .tsx files
  • React Versions: Compatible with all React versions that used React.PropTypes

πŸ› Issues

If you encounter any issues or have feature requests, please open an issue on GitHub.

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ™ Acknowledgments

  • React team for the smooth transition process
  • The community for feedback and contributions
  • All users who have helped improve this tool

About

Quick way to move PropTypes from core react.js package to prop-types package in any large scale project

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors