Skip to content

Commit 5d55d63

Browse files
hbjORbjDmytroHryshyn
authored andcommitted
add react-19-codemods
1 parent 243edf6 commit 5d55d63

File tree

71 files changed

+1604
-122
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+1604
-122
lines changed

README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,47 @@ APIs.
1111
* use the `--dry` option for a dry-run and use `--print` to print the output for comparison
1212

1313
This will start an interactive wizard, and then run the specified transform.
14+
#### Running with `codemod` CLI
15+
`npx codemod <transform> --target <path> [...options]`
16+
* `transform` - name of transform, see available transforms below.
17+
* `path` - directory to transform
18+
19+
Check [codemod docs](https://docs.codemod.com/deploying-codemods/cli]) for the full list of available commands.
1420

1521
### Included Transforms
1622

23+
#### `remove-context-provider`
24+
25+
Converts `Context.Provider` JSX opening and closing elements into `Context`.
26+
27+
```sh
28+
npx react-codemod remove-context-provider <path>
29+
```
30+
31+
#### `remove-forward-ref`
32+
33+
Removes usages of `forwardRef`.
34+
35+
```sh
36+
npx react-codemod remove-forward-ref <path>
37+
```
38+
39+
#### `remove-memoization-hooks`
40+
41+
Removes usages of `useCallback`, `useMemo` and `memo`.
42+
43+
```sh
44+
npx react-codemod remove-memoization-hooks <path>
45+
```
46+
47+
#### `use-context-hook`
48+
49+
Replaces usages of `React.useContext(...)` with `React.use(...)`.
50+
51+
```sh
52+
npx react-codemod use-context-hook <path>
53+
```
54+
1755
#### `create-element-to-jsx`
1856

1957
Converts calls to `React.createElement` into JSX elements.

bin/__tests__/react-codemod-test.js

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,20 +96,20 @@ describe('runTransform', () => {
9696
fs.lstatSync(jscodeshiftExecutable);
9797
});
9898

99-
it('runs jscodeshift for the given transformer', () => {
99+
it('runs jscodeshift for the given existing transformer', () => {
100100
execaReturnValue = { error: null };
101101
console.log = jest.fn();
102102
runTransform({
103103
files: 'src',
104104
flags: {},
105105
parser: 'flow',
106-
transformer: 'rename-unsafe-xyz'
106+
transformer: 'rename-unsafe-lifecycles'
107107
});
108108
expect(console.log).toBeCalledWith(
109109
// eslint-disable-next-line max-len
110110
`Executing command: jscodeshift --verbose=2 --ignore-pattern=**/node_modules/** --parser flow --extensions=jsx,js --transform ${path.join(
111111
transformerDirectory,
112-
'rename-unsafe-xyz.js'
112+
'rename-unsafe-lifecycles.js'
113113
)} src`
114114
);
115115
});
@@ -184,4 +184,21 @@ describe('runTransform', () => {
184184
});
185185
}).toThrowError(transformerError);
186186
});
187+
188+
it('should correctly resolve typescript transform files', () => {
189+
execaReturnValue = { error: null };
190+
console.log = jest.fn();
191+
runTransform({
192+
files: 'src',
193+
flags: {},
194+
parser: 'flow',
195+
transformer: 'remove-context-provider'
196+
});
197+
expect(console.log).toBeCalledWith(
198+
`Executing command: jscodeshift --verbose=2 --ignore-pattern=**/node_modules/** --parser flow --extensions=jsx,js --transform ${path.join(
199+
transformerDirectory,
200+
'remove-context-provider.ts'
201+
)} src`
202+
);
203+
});
187204
});

bin/cli.js

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,13 @@ function checkGitStatus(force) {
4949
}
5050
}
5151

52+
function resolveTransformer(transformerDirectory, transformer) {
53+
return globby.sync(`${transformerDirectory}/${transformer}.{js,ts}`)[0] || null;
54+
}
55+
5256
function runTransform({ files, flags, parser, transformer, answers }) {
53-
const transformerPath = path.join(transformerDirectory, `${transformer}.js`);
57+
58+
const transformerPath = resolveTransformer(transformerDirectory, transformer);
5459

5560
let args = [];
5661

@@ -191,7 +196,27 @@ const TRANSFORMER_INQUIRER_CHOICES = [
191196
{
192197
name: 'update-react-imports: Removes redundant import statements from explicitly importing React to compile JSX and converts default imports to destructured named imports',
193198
value: 'update-react-imports',
194-
}
199+
},
200+
{
201+
name:
202+
'remove-context-provider: Replaces Context.Provider with Context',
203+
value: 'remove-context-provider'
204+
},
205+
{
206+
name:
207+
'remove-forward-ref: Removes forwardRef form functional components and passes ref as prop',
208+
value: 'remove-forward-ref'
209+
},
210+
{
211+
name:
212+
'remove-memoization-hooks: Removes memo, useCallback, useMemo',
213+
value: 'remove-memoization-hooks'
214+
},
215+
{
216+
name:
217+
'use-context-hook: Replaces useContext with React.use',
218+
value: 'use-context-hook'
219+
},
195220
];
196221

197222
const PARSER_INQUIRER_CHOICES = [

package.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,25 @@
2828
"roots": [
2929
"transforms",
3030
"bin"
31-
]
31+
],
32+
"transform": {
33+
"^.+\\.jsx?$": "babel-jest",
34+
"^.+\\.tsx?$": "ts-jest"
35+
}
3236
},
3337
"devDependencies": {
3438
"@babel/core": "^7.6.4",
3539
"@babel/plugin-proposal-object-rest-spread": "^7.6.2",
3640
"@babel/preset-env": "^7.6.3",
41+
"@types/jest": "^24.9.0",
3742
"babel-eslint": "^10.0.3",
3843
"babel-jest": "^24.9.0",
3944
"eslint": "^6.6.0",
4045
"eslint-plugin-react": "^7.16.0",
4146
"fbjs-scripts": "^0.7.1",
42-
"jest": "^24.9.0"
47+
"jest": "^24.9.0",
48+
"ts-jest": "^24.3.0",
49+
"typescript": "4.8.4"
4350
},
4451
"resolutions": {
4552
"colors": "1.3.3"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function App() {
2+
const [theme, setTheme] = useState('light');
3+
4+
return (
5+
<Context value={theme}>
6+
<Page />
7+
</Context>
8+
);
9+
}

transforms/__testfixtures__/remove-context-provider/no-provider.output.js

Whitespace-only changes.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function App({ url }: { url: string }) {
2+
const [theme, setTheme] = useState<'light' | 'dark'>('light');
3+
4+
return (
5+
<Context value={theme}>
6+
<Page />
7+
</Context>
8+
);
9+
}

transforms/__testfixtures__/remove-context-provider/typescript/no-provider.output.js

Whitespace-only changes.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function App({ url }: { url: string }) {
2+
const [theme, setTheme] = useState<'light' | 'dark'>('light');
3+
4+
return (
5+
<Context.Provider value={theme}>
6+
<Page />
7+
</Context.Provider>
8+
);
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function App({ url }: { url: string }) {
2+
const [theme, setTheme] = useState<'light' | 'dark'>('light');
3+
4+
return (
5+
<Context value={theme}>
6+
<Page />
7+
</Context>
8+
);
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function App({ url }: { url: string }) {
2+
const [theme, setTheme] = useState<'light' | 'dark'>('light');
3+
4+
return (
5+
<ThemeContext.Provider value={theme}>
6+
<Page />
7+
</ThemeContext.Provider>
8+
);
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function App({ url }: { url: string }) {
2+
const [theme, setTheme] = useState<'light' | 'dark'>('light');
3+
4+
return (
5+
<ThemeContext value={theme}>
6+
<Page />
7+
</ThemeContext>
8+
);
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function App() {
2+
const [theme, setTheme] = useState('light');
3+
4+
return (
5+
<Context.Provider value={theme}>
6+
<Page />
7+
</Context.Provider>
8+
);
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function App() {
2+
const [theme, setTheme] = useState('light');
3+
4+
return (
5+
<Context value={theme}>
6+
<Page />
7+
</Context>
8+
);
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function App() {
2+
const [theme, setTheme] = useState('light');
3+
4+
return (
5+
<ThemeContext.Provider value={theme}>
6+
<Page />
7+
</ThemeContext.Provider>
8+
);
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function App() {
2+
const [theme, setTheme] = useState('light');
3+
4+
return (
5+
<ThemeContext value={theme}>
6+
<Page />
7+
</ThemeContext>
8+
);
9+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { forwardRef } from 'react';
2+
3+
const MyInput = forwardRef((props, ref) => {
4+
return null;
5+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const MyInput = (
2+
{
3+
ref,
4+
...props
5+
}
6+
) => {
7+
return null;
8+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { forwardRef, useState } from 'react';
2+
3+
const MyInput = forwardRef(function MyInput(props, ref) {
4+
return null;
5+
});
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { useState } from 'react';
2+
3+
const MyInput = function MyInput(
4+
{
5+
ref,
6+
...props
7+
}
8+
) {
9+
return null;
10+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { forwardRef } from 'react';
2+
3+
const MyInput = forwardRef(function MyInput(props, ref) {
4+
return null;
5+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const MyInput = function MyInput(
2+
{
3+
ref,
4+
...props
5+
}
6+
) {
7+
return null;
8+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { forwardRef } from 'react';
2+
3+
const MyInput = forwardRef(function A(props, ref) {
4+
return null;
5+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const MyInput = function A(
2+
{
3+
ref,
4+
...props
5+
}
6+
) {
7+
return null;
8+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { forwardRef } from 'react';
2+
3+
const MyInput = forwardRef(function MyInput(props, ref) {
4+
return <input ref={ref} onChange={props.onChange} />
5+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const MyInput = function MyInput(
2+
{
3+
ref,
4+
...props
5+
}
6+
) {
7+
return <input ref={ref} onChange={props.onChange} />
8+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { forwardRef } from 'react';
2+
3+
const MyInput = forwardRef(function MyInput({ onChange }, ref) {
4+
return <input ref={ref} onChange={onChange} />
5+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const MyInput = function MyInput(
2+
{
3+
ref,
4+
onChange
5+
}
6+
) {
7+
return <input ref={ref} onChange={onChange} />
8+
};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { forwardRef } from 'react';
2+
3+
const MyComponent = forwardRef(function Component(
4+
myProps: Props,
5+
myRef: React.ForwardedRef<HTMLButtonElement>
6+
) {
7+
return null;
8+
});

0 commit comments

Comments
 (0)