Skip to content

Commit

Permalink
New codemod to help migrating React components "defaultProps" usage (#…
Browse files Browse the repository at this point in the history
…3681)

* feat(codemod): add codemod for migrating react components default props

* refactor(codemod): component props refactoring

* refactor(codemod): first finished version of the default props migration codemod

* chore: add changeset

* docs(codemod): updated readme to include the new codemod

* chore: update changeset

Co-authored-by: Tobias Deekens <[email protected]>

* chore: update changeset

Co-authored-by: Tobias Deekens <[email protected]>

* refactor(codemod): add better component props ts type resolution

* refactor(codemod): improve component default props extraction and transformation

* refactor(codemod): improve default props transformation and substitution

* refactor(codemod): improve components body adjustments and signature refactor

* fix(codemod): fix cli ignore patterns

---------

Co-authored-by: Tobias Deekens <[email protected]>
  • Loading branch information
CarlosCortizasCT and tdeekens authored Dec 20, 2024
1 parent 9504631 commit 1e9e84a
Show file tree
Hide file tree
Showing 5 changed files with 623 additions and 8 deletions.
40 changes: 40 additions & 0 deletions .changeset/purple-panthers-attack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
'@commercetools-frontend/codemod': minor
---

Introduces a new codemod which helps migrating away from React's `defaultProps` to `prop` destructuring.

This is how the change looks like:

```ts
// BEFORE
type TMyComponentProps = {
message: string;
size: string;
}

function MyComponent(props: TMyComponentProps) {
...
}

MyComponent.defaultProps = {
size: 'big'
}


// AFTER
type TMyComponentProps = {
message: string;
size?: string; // <--- Note this property is now defined as optional
}

function MyComponent({ size = 'big', ...props }: TMyComponentProps) {
...
}
```

And here is how the new codemod can be run:

```
$ npx @commercetools-frontend/codemod@latest react-default-props-migration 'src/**/*.{jsx,tsx}'
```
38 changes: 38 additions & 0 deletions packages/codemod/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,41 @@ Remove code related to the old design when using the `useTheme` hook, for exampl
```
$ npx @commercetools-frontend/codemod@latest redesign-cleanup 'src/**/*.{jsx,tsx}'
```

### `react-default-props-migration`

Migrates the way React Components `defaultProps` to use JavaScript default parameters instead. This is needed for React v18 or later.
Example:

```jsx
// BEFORE
function MyComponent(props) {
return (
<ul>
<li>Prop 1: {props.prop1}</li>
<li>Prop 2: {props.prop2}</li>
<li>Prop 3: {props.prop3}</li>
</ul>
);
}
MyComponent.defaultProps = {
prop1: 'My default value',
};

// AFTER
function MyComponent({ prop1: 'My default value', ...props }) {
return (
<ul>
<li>Prop 1: {prop1}</li>
<li>Prop 2: {props.prop2}</li>
<li>Prop 3: {props.prop3}</li>
</ul>
);
}
```

You can run this codemod by using the following command:

```
$ npx @commercetools-frontend/codemod@latest react-default-props-migration 'src/**/*.{jsx,tsx}'
```
25 changes: 18 additions & 7 deletions packages/codemod/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,30 @@ const transforms: { name: TCliTransformName; description: string }[] = [
description:
'Remove code related to the old design when using the "useTheme" hook, for example the usage of "themedValue".',
},
{
name: 'react-default-props-migration',
description:
'Migrate React components using defaultProps as a component property to a destructured object param.',
},
];

const executeCodemod = async (
transform: TCliTransformName,
globPattern: string,
globalOptions: TCliGlobalOptions
) => {
const files = glob.sync(globPattern);
const absoluteGlobPattern = path.resolve(globPattern);
const files = glob.sync(
path.join(absoluteGlobPattern, '**/*.{ts,tsx,js,jsx}'),
{
ignore: [
'**/node_modules/**',
'**/public/**',
'**/dist/**',
'**/build/**',
],
}
);

const runJscodeshift = async (
transformPath: string,
Expand All @@ -49,19 +65,14 @@ const executeCodemod = async (
};
switch (transform) {
case 'redesign-cleanup':
case 'react-default-props-migration':
case 'remove-deprecated-modal-level-props':
case 'rename-js-to-jsx':
case 'rename-mod-css-to-module-css': {
const transformPath = path.join(__dirname, `transforms/${transform}.js`);

await runJscodeshift(transformPath, files, {
extensions: 'tsx,ts,jsx,js',
ignorePattern: [
'**/node_modules/**',
'**/public/**',
'**/dist/**',
'**/build/**',
],
parser: 'tsx',
verbose: 0,
dry: globalOptions.dryRun,
Expand Down
Loading

0 comments on commit 1e9e84a

Please sign in to comment.