Skip to content

Commit 3b5b11f

Browse files
committed
react codemod package
1 parent 2aaba32 commit 3b5b11f

File tree

16 files changed

+411
-0
lines changed

16 files changed

+411
-0
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# add-react-import
2+
3+
Import React if it is missing from a file which uses JSX.
4+
5+
```jsx
6+
/* INPUT */
7+
export const Component = () => <div />
8+
9+
/* OUTPUT */
10+
import React from "react";
11+
export const Component = () => <div />
12+
```
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { applyTransform } from '@codeshift/test-utils';
2+
import * as transformer from './transform';
3+
4+
describe('react@1.0.0 transform', () => {
5+
it('should transform correctly', () => {
6+
const result = applyTransform(
7+
transformer,
8+
`
9+
import foo from '<% packageName %>';
10+
console.log(foo);
11+
`,
12+
{ parser: 'tsx' },
13+
);
14+
15+
expect(result).toMatchInlineSnapshot();
16+
});
17+
});
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { API, FileInfo, Options } from 'jscodeshift';
2+
3+
export default function transformer(
4+
file: FileInfo,
5+
{ jscodeshift: j }: API,
6+
options: Options,
7+
) {
8+
const source = j(file.source);
9+
const containsJsx = source.find(j.JSXIdentifier).length > 0;
10+
11+
const containsReactPackageImport =
12+
source
13+
.find(j.ImportDeclaration)
14+
.filter(
15+
importDeclaration => importDeclaration.node.source.value === 'react',
16+
).length > 0;
17+
18+
const containsReactDefaultImport =
19+
source
20+
.find(j.ImportDefaultSpecifier)
21+
.filter(
22+
importDefaultSpecifier =>
23+
importDefaultSpecifier.node.local!.name === 'React',
24+
).length > 0;
25+
26+
if (
27+
containsJsx &&
28+
!(containsReactPackageImport && containsReactDefaultImport)
29+
) {
30+
source
31+
.get()
32+
.node.program.body.unshift(
33+
j.importDeclaration(
34+
[j.importDefaultSpecifier(j.identifier('React'))],
35+
j.literal('react'),
36+
),
37+
);
38+
}
39+
40+
return source.toSource(options.printOptions);
41+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module.exports = {
2+
maintainers: [],
3+
targets: ['react', 'react-dom'],
4+
description: 'Codemods for react',
5+
transforms: {},
6+
presets: {
7+
'add-react-import': require.resolve('./add-react-import/transform'),
8+
'remove-default-props': require.resolve('./remove-default-props/transform'),
9+
'remove-prop-types': require.resolve('./remove-prop-types/transform'),
10+
'sort-jsx-props': require.resolve('./sort-jsx-props/transform'),
11+
'use-string-literal-props': require.resolve(
12+
'./use-string-literal-props/transform',
13+
),
14+
},
15+
};
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# remove-default-props
2+
3+
Remove use of React defaultProps.
4+
5+
```jsx
6+
/* INPUT */
7+
import React from 'react'
8+
9+
export const Greet = ({ name }) => <span>Hi {name}</span>
10+
Greet.defaultProps = { name: 'Stranger' }
11+
/* OUTPUT */
12+
import React from 'react'
13+
14+
export const Greet = ({ name }) => <span>Hi {name}</span>
15+
```
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { applyTransform } from '@codeshift/test-utils';
2+
import * as transformer from './transform';
3+
4+
describe('react@1.0.0 transform', () => {
5+
it('should transform correctly', () => {
6+
const result = applyTransform(
7+
transformer,
8+
`
9+
import foo from '<% packageName %>';
10+
console.log(foo);
11+
`,
12+
{ parser: 'tsx' },
13+
);
14+
15+
expect(result).toMatchInlineSnapshot();
16+
});
17+
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { API, FileInfo, Options } from 'jscodeshift';
2+
3+
export default function transformer(
4+
file: FileInfo,
5+
{ jscodeshift: j }: API,
6+
options: Options,
7+
) {
8+
const removePath = path => j(path).remove();
9+
const isAssigningDefaultProps = e =>
10+
e.node.left &&
11+
e.node.left.property &&
12+
e.node.left.property.name === 'defaultProps';
13+
14+
return j(file.source)
15+
.find(j.AssignmentExpression)
16+
.filter(isAssigningDefaultProps)
17+
.forEach(removePath)
18+
.toSource(options.printOptions);
19+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# remove-prop-types
2+
3+
Remove use of React PropTypes.
4+
5+
```jsx
6+
/* INPUT */
7+
import React from 'react'
8+
import PropTypes from 'prop-types'
9+
10+
export const Greet = ({ name }) => <span>Hi {name}</span>
11+
Greet.propTypes = { name: PropTypes.string }
12+
/* OUTPUT */
13+
import React from 'react'
14+
15+
export const Greet = ({ name }) => <span>Hi {name}</span>
16+
```
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { applyTransform } from '@codeshift/test-utils';
2+
import * as transformer from './transform';
3+
4+
describe('react@1.0.0 transform', () => {
5+
it('should transform correctly', () => {
6+
const result = applyTransform(
7+
transformer,
8+
`
9+
import foo from '<% packageName %>';
10+
console.log(foo);
11+
`,
12+
{ parser: 'tsx' },
13+
);
14+
15+
expect(result).toMatchInlineSnapshot();
16+
});
17+
});
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { API, FileInfo, Options } from 'jscodeshift';
2+
3+
export default function transformer(
4+
file: FileInfo,
5+
{ jscodeshift: j }: API,
6+
options: Options,
7+
) {
8+
const removePath = path => j(path).remove();
9+
10+
// Obj.proptypes = { ... };
11+
const isAssigningPropTypes = e =>
12+
e.node.left &&
13+
e.node.left.property &&
14+
e.node.left.property.name === 'propTypes';
15+
16+
// import PropTypes from 'prop-types';
17+
const isImportingFromPropTypes = e =>
18+
e.node.source && e.node.source.value === 'prop-types';
19+
20+
// require('prop-types');
21+
const isRequiringFromPropTypes = e =>
22+
e.node.init &&
23+
e.node.init.callee &&
24+
e.node.init.callee.name === 'require' &&
25+
e.node.init.arguments[0].value === 'prop-types';
26+
27+
// _defineProperty(obj, 'propTypes', { ... });
28+
const isDefiningPropType = e =>
29+
e.node.expression &&
30+
e.node.expression.callee &&
31+
e.node.expression.callee.name === '_defineProperty' &&
32+
e.node.expression.arguments &&
33+
e.node.expression.arguments[1] &&
34+
e.node.expression.arguments[1].original &&
35+
e.node.expression.arguments[1].original.value === 'propTypes';
36+
37+
// { propTypes: { foo: PropTypes.string } };
38+
const isObjectProperty = e =>
39+
e.node.key &&
40+
e.node.key.name === 'propTypes' &&
41+
e.node.value &&
42+
e.node.value.type === 'ObjectExpression';
43+
44+
const withoutAssignment = j(file.source)
45+
.find(j.AssignmentExpression)
46+
.filter(isAssigningPropTypes)
47+
.forEach(removePath)
48+
.toSource();
49+
50+
const withoutImport = j(withoutAssignment)
51+
.find(j.ImportDeclaration)
52+
.filter(isImportingFromPropTypes)
53+
.forEach(removePath)
54+
.toSource();
55+
56+
const withoutRequire = j(withoutImport)
57+
.find(j.VariableDeclarator)
58+
.filter(isRequiringFromPropTypes)
59+
.forEach(removePath)
60+
.toSource();
61+
62+
const withoutDefineProperty = j(withoutRequire)
63+
.find(j.ExpressionStatement)
64+
.filter(isDefiningPropType)
65+
.forEach(removePath)
66+
.toSource();
67+
68+
const withoutObjectProperty = j(withoutDefineProperty)
69+
.find(j.Property)
70+
.filter(isObjectProperty)
71+
.forEach(removePath);
72+
73+
return withoutObjectProperty.toSource(options.printOptions);
74+
}

0 commit comments

Comments
 (0)