Skip to content

Commit 1751318

Browse files
authored
Add codemod for deprecated propTypes types (#357)
1 parent 0437b25 commit 1751318

12 files changed

Lines changed: 494 additions & 32 deletions

.changeset/eight-jeans-appear.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
"types-react-codemod": minor
3+
---
4+
5+
Add codemod to replace deprecated React types related to propTypes with their counterpart from the `prop-types` package
6+
7+
```diff
8+
+import * as PropTypes from "prop-types";
9+
import * as React from "react";
10+
-declare const requireable: React.Requireable<React.ReactNode>;
11+
+declare const requireable: PropTypes.Requireable<React.ReactNode>;
12+
-declare const validator: React.Validator<React.ReactNode>;
13+
+declare const requireable: PropTypes.Validator<React.ReactNode>;
14+
-declare const validationMap: React.ValidationMap<{}>;
15+
+declare const requireable: PropTypes.ValidationMap<React.ReactNode>;
16+
-declare const weakValidationMap: React.WeakValidationMap<{}>;
17+
+declare const requireable: PropTypes.WeakValidationMap<React.ReactNode>;
18+
```

README.md

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,13 @@ $ npx types-react-codemod <codemod> <paths...>
3434

3535
Positionals:
3636
codemod [string] [required] [choices: "context-any", "deprecated-legacy-ref",
37-
"deprecated-react-child", "deprecated-react-fragment",
38-
"deprecated-react-node-array", "deprecated-react-text",
39-
"deprecated-react-type", "deprecated-sfc-element", "deprecated-sfc",
40-
"deprecated-stateless-component", "deprecated-void-function-component",
41-
"implicit-children", "preset-18", "preset-19", "refobject-defaults",
42-
"scoped-jsx", "useCallback-implicit-any", "useRef-required-initial"]
37+
"deprecated-prop-types-types", "deprecated-react-child",
38+
"deprecated-react-fragment", "deprecated-react-node-array",
39+
"deprecated-react-text", "deprecated-react-type", "deprecated-sfc-element",
40+
"deprecated-sfc", "deprecated-stateless-component",
41+
"deprecated-void-function-component", "implicit-children", "preset-18",
42+
"preset-19", "refobject-defaults", "scoped-jsx", "useCallback-implicit-any",
43+
"useRef-required-initial"]
4344
paths [string] [required]
4445

4546
Options:
@@ -71,6 +72,7 @@ The reason being that a false-positive can be reverted easily (assuming you have
7172
- `implicit-children`
7273
- `useCallback-implicit-any`
7374
- `preset-19`
75+
- `deprecated-prop-types-types`
7476
- `deprecated-legacy-ref`
7577
- `deprecated-react-child`
7678
- `deprecated-react-text`
@@ -213,6 +215,21 @@ By default, the codemods that are definitely required to upgrade to `@types/reac
213215
The other codemods may or may not be required.
214216
You should select all and audit the changed files regardless.
215217

218+
### `deprecated-prop-types-types`
219+
220+
```diff
221+
+import * as PropTypes from "prop-types";
222+
import * as React from "react";
223+
-declare const requireable: React.Requireable<React.ReactNode>;
224+
+declare const requireable: PropTypes.Requireable<React.ReactNode>;
225+
-declare const validator: React.Validator<React.ReactNode>;
226+
+declare const requireable: PropTypes.Validator<React.ReactNode>;
227+
-declare const validationMap: React.ValidationMap<{}>;
228+
+declare const requireable: PropTypes.ValidationMap<React.ReactNode>;
229+
-declare const weakValidationMap: React.WeakValidationMap<{}>;
230+
+declare const requireable: PropTypes.WeakValidationMap<React.ReactNode>;
231+
```
232+
216233
### `deprecated-legacy-ref`
217234

218235
```diff

bin/__tests__/types-react-codemod.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,13 @@ describe("types-react-codemod", () => {
2222
2323
Positionals:
2424
codemod [string] [required] [choices: "context-any", "deprecated-legacy-ref",
25-
"deprecated-react-child", "deprecated-react-fragment",
26-
"deprecated-react-node-array", "deprecated-react-text",
27-
"deprecated-react-type", "deprecated-sfc-element", "deprecated-sfc",
28-
"deprecated-stateless-component", "deprecated-void-function-component",
29-
"implicit-children", "preset-18", "preset-19", "refobject-defaults",
30-
"scoped-jsx", "useCallback-implicit-any", "useRef-required-initial"]
25+
"deprecated-prop-types-types", "deprecated-react-child",
26+
"deprecated-react-fragment", "deprecated-react-node-array",
27+
"deprecated-react-text", "deprecated-react-type", "deprecated-sfc-element",
28+
"deprecated-sfc", "deprecated-stateless-component",
29+
"deprecated-void-function-component", "implicit-children", "preset-18",
30+
"preset-19", "refobject-defaults", "scoped-jsx", "useCallback-implicit-any",
31+
"useRef-required-initial"]
3132
paths [string] [required]
3233
3334
Options:
Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
const { describe, expect, test } = require("@jest/globals");
2+
const dedent = require("dedent");
3+
const JscodeshiftTestUtils = require("jscodeshift/dist/testUtils");
4+
const deprecatedPropTypesTypesTransform = require("../deprecated-prop-types-types");
5+
6+
function applyTransform(source, options = {}) {
7+
return JscodeshiftTestUtils.applyTransform(
8+
deprecatedPropTypesTypesTransform,
9+
options,
10+
{
11+
path: "test.tsx",
12+
source: dedent(source),
13+
},
14+
);
15+
}
16+
17+
describe("transform deprecated-prop-types-types", () => {
18+
test("not modified", () => {
19+
expect(
20+
applyTransform(`
21+
import * as React from 'react';
22+
interface Props {
23+
children?: ReactNode;
24+
}
25+
`),
26+
).toMatchInlineSnapshot(`
27+
"import * as React from 'react';
28+
interface Props {
29+
children?: ReactNode;
30+
}"
31+
`);
32+
});
33+
34+
test("no import yet", () => {
35+
expect(
36+
applyTransform(`
37+
import * as React from 'react';
38+
declare const requireable: React.Requireable<React.ReactNode>;
39+
declare const validator: React.Validator<React.ReactNode>;
40+
declare const validationMap: React.ValidationMap<{}>;
41+
declare const weakValidationMap: React.WeakValidationMap<{}>;
42+
`),
43+
).toMatchInlineSnapshot(`
44+
"import type * as PropTypes from "prop-types";
45+
import * as React from 'react';
46+
declare const requireable: PropTypes.Requireable<React.ReactNode>;
47+
declare const validator: PropTypes.Validator<React.ReactNode>;
48+
declare const validationMap: PropTypes.ValidationMap<{}>;
49+
declare const weakValidationMap: PropTypes.WeakValidationMap<{}>;"
50+
`);
51+
});
52+
53+
test("existing default import", () => {
54+
expect(
55+
applyTransform(`
56+
import MyPropTypes from 'prop-types';
57+
import React from 'react';
58+
59+
declare const requireable: React.Requireable<React.ReactNode>;
60+
declare const validator: React.Validator<React.ReactNode>;
61+
declare const validationMap: React.ValidationMap<{}>;
62+
declare const weakValidationMap: React.WeakValidationMap<{}>;
63+
`),
64+
).toMatchInlineSnapshot(`
65+
"import MyPropTypes from 'prop-types';
66+
import React from 'react';
67+
68+
declare const requireable: MyPropTypes.Requireable<React.ReactNode>;
69+
declare const validator: MyPropTypes.Validator<React.ReactNode>;
70+
declare const validationMap: MyPropTypes.ValidationMap<{}>;
71+
declare const weakValidationMap: MyPropTypes.WeakValidationMap<{}>;"
72+
`);
73+
});
74+
75+
test("existing type default import", () => {
76+
expect(
77+
applyTransform(`
78+
import type MyPropTypes from 'prop-types';
79+
import type React from 'react';
80+
81+
declare const requireable: React.Requireable<React.ReactNode>;
82+
declare const validator: React.Validator<React.ReactNode>;
83+
declare const validationMap: React.ValidationMap<{}>;
84+
declare const weakValidationMap: React.WeakValidationMap<{}>;
85+
`),
86+
).toMatchInlineSnapshot(`
87+
"import type MyPropTypes from 'prop-types';
88+
import type React from 'react';
89+
90+
declare const requireable: MyPropTypes.Requireable<React.ReactNode>;
91+
declare const validator: MyPropTypes.Validator<React.ReactNode>;
92+
declare const validationMap: MyPropTypes.ValidationMap<{}>;
93+
declare const weakValidationMap: MyPropTypes.WeakValidationMap<{}>;"
94+
`);
95+
});
96+
97+
test("existing namespace import", () => {
98+
expect(
99+
applyTransform(`
100+
import * as MyPropTypes from 'prop-types';
101+
import * as React from 'react';
102+
103+
declare const requireable: React.Requireable<React.ReactNode>;
104+
declare const validator: React.Validator<React.ReactNode>;
105+
declare const validationMap: React.ValidationMap<{}>;
106+
declare const weakValidationMap: React.WeakValidationMap<{}>;
107+
`),
108+
).toMatchInlineSnapshot(`
109+
"import * as MyPropTypes from 'prop-types';
110+
import * as React from 'react';
111+
112+
declare const requireable: MyPropTypes.Requireable<React.ReactNode>;
113+
declare const validator: MyPropTypes.Validator<React.ReactNode>;
114+
declare const validationMap: MyPropTypes.ValidationMap<{}>;
115+
declare const weakValidationMap: MyPropTypes.WeakValidationMap<{}>;"
116+
`);
117+
});
118+
119+
test("existing type namespace import", () => {
120+
expect(
121+
applyTransform(`
122+
import type * as MyPropTypes from 'prop-types';
123+
import type * as React from 'react';
124+
125+
declare const requireable: React.Requireable<React.ReactNode>;
126+
declare const validator: React.Validator<React.ReactNode>;
127+
declare const validationMap: React.ValidationMap<{}>;
128+
declare const weakValidationMap: React.WeakValidationMap<{}>;
129+
`),
130+
).toMatchInlineSnapshot(`
131+
"import type * as MyPropTypes from 'prop-types';
132+
import type * as React from 'react';
133+
134+
declare const requireable: MyPropTypes.Requireable<React.ReactNode>;
135+
declare const validator: MyPropTypes.Validator<React.ReactNode>;
136+
declare const validationMap: MyPropTypes.ValidationMap<{}>;
137+
declare const weakValidationMap: MyPropTypes.WeakValidationMap<{}>;"
138+
`);
139+
});
140+
141+
test("existing named import with other named imports", () => {
142+
expect(
143+
applyTransform(`
144+
import { checkPropTypes, Validator as MyValidator } from 'prop-types';
145+
import { ReactNode, Requireable, Validator, ValidationMap, WeakValidationMap } from 'react';
146+
147+
declare const requireable: Requireable<ReactNode>;
148+
declare const validator: Validator<ReactNode>;
149+
declare const validationMap: ValidationMap<{}>;
150+
declare const weakValidationMap: WeakValidationMap<{}>;
151+
`),
152+
).toMatchInlineSnapshot(`
153+
"import {
154+
checkPropTypes,
155+
Validator as MyValidator,
156+
type Requireable,
157+
type ValidationMap,
158+
type WeakValidationMap,
159+
} from 'prop-types';
160+
import { ReactNode } from 'react';
161+
162+
declare const requireable: Requireable<ReactNode>;
163+
declare const validator: MyValidator<ReactNode>;
164+
declare const validationMap: ValidationMap<{}>;
165+
declare const weakValidationMap: WeakValidationMap<{}>;"
166+
`);
167+
});
168+
169+
test("existing named import with other named type imports", () => {
170+
expect(
171+
applyTransform(`
172+
import { checkPropTypes, type Requireable as MyRequireable} from 'prop-types';
173+
import { type ReactNode, type Requireable, type Validator, type ValidationMap, type WeakValidationMap } from 'react';
174+
175+
declare const requireable: Requireable<ReactNode>;
176+
declare const validator: Validator<ReactNode>;
177+
declare const validationMap: ValidationMap<{}>;
178+
declare const weakValidationMap: WeakValidationMap<{}>;
179+
`),
180+
).toMatchInlineSnapshot(`
181+
"import {
182+
checkPropTypes,
183+
type Requireable as MyRequireable,
184+
type Validator,
185+
type ValidationMap,
186+
type WeakValidationMap,
187+
} from 'prop-types';
188+
import { type ReactNode } from 'react';
189+
190+
declare const requireable: MyRequireable<ReactNode>;
191+
declare const validator: Validator<ReactNode>;
192+
declare const validationMap: ValidationMap<{}>;
193+
declare const weakValidationMap: WeakValidationMap<{}>;"
194+
`);
195+
});
196+
197+
test("existing named import", () => {
198+
expect(
199+
applyTransform(`
200+
import { checkPropTypes, Requireable, Validator, ValidationMap, WeakValidationMap } from 'prop-types';
201+
import { type ReactNode } from 'react';
202+
203+
declare const requireable: Requireable<ReactNode>;
204+
declare const validator: Validator<ReactNode>;
205+
declare const validationMap: ValidationMap<{}>;
206+
declare const weakValidationMap: WeakValidationMap<{}>;
207+
`),
208+
).toMatchInlineSnapshot(`
209+
"import { checkPropTypes, Requireable, Validator, ValidationMap, WeakValidationMap } from 'prop-types';
210+
import { type ReactNode } from 'react';
211+
212+
declare const requireable: Requireable<ReactNode>;
213+
declare const validator: Validator<ReactNode>;
214+
declare const validationMap: ValidationMap<{}>;
215+
declare const weakValidationMap: WeakValidationMap<{}>;"
216+
`);
217+
});
218+
219+
test("existing namespace require", () => {
220+
expect(
221+
applyTransform(`
222+
const PropTypes = require('prop-types')
223+
const React = require('react');
224+
225+
declare const requireable: React.Requireable<React.ReactNode>;
226+
declare const validator: React.Validator<React.ReactNode>;
227+
declare const validationMap: React.ValidationMap<{}>;
228+
declare const weakValidationMap: React.WeakValidationMap<{}>;
229+
`),
230+
).toMatchInlineSnapshot(`
231+
"import type * as PropTypes from "prop-types";
232+
const PropTypes = require('prop-types')
233+
const React = require('react');
234+
235+
declare const requireable: PropTypes.Requireable<React.ReactNode>;
236+
declare const validator: PropTypes.Validator<React.ReactNode>;
237+
declare const validationMap: PropTypes.ValidationMap<{}>;
238+
declare const weakValidationMap: PropTypes.WeakValidationMap<{}>;"
239+
`);
240+
});
241+
242+
test("insert position", () => {
243+
expect(
244+
applyTransform(`
245+
import * as React from 'react';
246+
import {} from '@testing-library/react'
247+
248+
declare const requireable: React.Requireable<React.ReactNode>;
249+
declare const validator: React.Validator<React.ReactNode>;
250+
declare const validationMap: React.ValidationMap<{}>;
251+
declare const weakValidationMap: React.WeakValidationMap<{}>;
252+
253+
declare const element: JSX.Element;
254+
`),
255+
).toMatchInlineSnapshot(`
256+
"import type * as PropTypes from "prop-types";
257+
import * as React from 'react';
258+
import {} from '@testing-library/react'
259+
260+
declare const requireable: PropTypes.Requireable<React.ReactNode>;
261+
declare const validator: PropTypes.Validator<React.ReactNode>;
262+
declare const validationMap: PropTypes.ValidationMap<{}>;
263+
declare const weakValidationMap: PropTypes.WeakValidationMap<{}>;
264+
265+
declare const element: JSX.Element;"
266+
`);
267+
});
268+
269+
test("detects usage in type parameters", () => {
270+
expect(
271+
applyTransform(`
272+
import React from 'react'
273+
274+
[].reduce<React.Validator>((acc, component, i) => {});
275+
[].reduce((acc, component, i) => {})
276+
`),
277+
).toMatchInlineSnapshot(`
278+
"import type * as PropTypes from "prop-types";
279+
import React from 'react'
280+
281+
[].reduce<PropTypes.Validator>((acc, component, i) => {});
282+
[].reduce((acc, component, i) => {})"
283+
`);
284+
});
285+
});

0 commit comments

Comments
 (0)