Skip to content

Commit 7a2724b

Browse files
committed
extend functionality of removing default props
1 parent e6e1c1b commit 7a2724b

File tree

7 files changed

+367
-232
lines changed

7 files changed

+367
-232
lines changed

community/react/remove-default-props/README.md

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,26 @@ _Credit_: [https://github.com/reactjs/react-codemod](https://github.com/reactjs/
66

77
```jsx
88
/* INPUT */
9-
import React from 'react'
9+
import React from 'react';
1010

11-
export const Greet = ({ name }) => <span>Hi {name}</span>
12-
Greet.defaultProps = { name: 'Stranger' }
11+
export const Greet = ({ name }) => <span>Hi {name}</span>;
12+
Greet.defaultProps = { text: 'Stranger' };
1313

1414
/* OUTPUT */
15-
import React from 'react'
15+
import React from 'react';
1616

17-
export const Greet = ({ name }) => <span>Hi {name}</span>
17+
export const Greet = ({ name, text = 'Stranger' }) => <span>Hi {name}</span>;
1818
```
19+
20+
```jsx
21+
/* INPUT */
22+
import React from 'react';
23+
24+
export const Greet = (props) => <span>Hi {name}</span>;
25+
Greet.defaultProps = { text: 'Stranger' };
26+
27+
/* OUTPUT */
28+
import React from 'react';
29+
30+
export const Greet = ({ ...props, text = 'Stranger' }) => <span>Hi {name}</span>;
31+
```
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import {
2+
JSCodeshift,
3+
FunctionDeclaration,
4+
ASTPath,
5+
ArrowFunctionExpression,
6+
} from 'jscodeshift';
7+
8+
export function getNewParams(
9+
j: JSCodeshift,
10+
component: ASTPath<FunctionDeclaration | ArrowFunctionExpression>,
11+
defaultParams: any,
12+
) {
13+
const params = component.node.params;
14+
15+
const existingSingleProp = params.find(param => param.type === 'Identifier');
16+
17+
const destructuredProps = params.find(
18+
param => param.type === 'ObjectPattern',
19+
);
20+
21+
const noExistingProps = params.length === 0;
22+
23+
let newParams: FunctionDeclaration['params'] = [];
24+
25+
if (noExistingProps) {
26+
newParams = [j.objectPattern(defaultParams)];
27+
} else if (existingSingleProp) {
28+
newParams = [
29+
j.objectPattern([
30+
// @ts-ignore
31+
j.spreadProperty(existingSingleProp),
32+
...defaultParams,
33+
]),
34+
];
35+
} else {
36+
newParams = getNewDestructuredParams(destructuredProps, j, defaultParams);
37+
}
38+
return newParams;
39+
}
40+
function getNewDestructuredParams(
41+
existingPropsParam: FunctionDeclaration['params'][number] | undefined,
42+
j: JSCodeshift,
43+
defaultParams: any,
44+
) {
45+
if (existingPropsParam && 'properties' in existingPropsParam) {
46+
const restProp = existingPropsParam.properties.find(
47+
// @ts-expect-error for some reason it does not exist
48+
prop => prop.type === 'RestElement',
49+
);
50+
51+
const existingPropsDestructuredProps = existingPropsParam.properties
52+
.filter(prop => prop.type !== restProp?.type)
53+
.map(prop => j.property('init', (prop as any).key, (prop as any).value))
54+
.filter(Boolean);
55+
56+
const restPropArg =
57+
restProp && 'argument' in restProp
58+
? restProp.argument
59+
: j.identifier('rest');
60+
61+
const newParams = [
62+
j.objectPattern([
63+
...existingPropsDestructuredProps,
64+
...defaultParams,
65+
// @ts-expect-error RestElement is not assignable as above
66+
...(restProp ? [j.restProperty(restPropArg)] : []),
67+
]),
68+
];
69+
return newParams;
70+
}
71+
72+
return [];
73+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { Collection, JSCodeshift } from 'jscodeshift';
2+
import { getNewParams } from './getNewParams';
3+
4+
export function moveDefaultPropsToArrowFunctionExpression(
5+
j: JSCodeshift,
6+
source: Collection<any>,
7+
) {
8+
source.find(j.VariableDeclarator).forEach(component => {
9+
const defaultProps = source.find(j.AssignmentExpression, {
10+
left: {
11+
// @ts-ignore
12+
object: { name: component.node.id?.name },
13+
property: { name: 'defaultProps' },
14+
},
15+
});
16+
17+
const defaultValues = defaultProps.get('right').value.properties;
18+
19+
if (defaultProps.length === 0) return;
20+
21+
// Generate a new function parameter for each default prop
22+
const defaultParams = defaultValues.map((prop: any) => {
23+
const key = prop.key.name;
24+
const value = prop.value.value;
25+
return j.objectProperty(
26+
j.identifier(key),
27+
j.assignmentPattern(j.identifier(key), j.literal(value)),
28+
);
29+
});
30+
31+
const arrowFunction = component.get('init');
32+
33+
const newParams = getNewParams(j, arrowFunction, defaultParams);
34+
35+
j(component).replaceWith(
36+
j.variableDeclarator(
37+
// @ts-ignore
38+
j.identifier(component.node.id.name),
39+
j.arrowFunctionExpression(newParams!, j.blockStatement([])),
40+
),
41+
);
42+
});
43+
}
Lines changed: 6 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import { JSCodeshift, FunctionDeclaration, Collection } from 'jscodeshift';
1+
import { JSCodeshift, Collection } from 'jscodeshift';
2+
import { getNewParams } from './getNewParams';
23

34
export function moveDefaultPropsToFunctionDeclaration(
4-
source: Collection<any>,
55
j: JSCodeshift,
6+
source: Collection<any>,
67
) {
78
source
89
.find(j.FunctionDeclaration)
910
.forEach(component => {
10-
// Find the defaultProps assignment expression
1111
const defaultProps = source.find(j.AssignmentExpression, {
1212
left: {
1313
object: { name: component.node.id?.name },
@@ -30,45 +30,13 @@ export function moveDefaultPropsToFunctionDeclaration(
3030
j.assignmentPattern(j.identifier(key), j.literal(value)),
3131
);
3232
});
33-
34-
const params = component.node.params;
35-
36-
const existingSingleProp = params.find(
37-
param => param.type === 'Identifier',
38-
);
39-
40-
// Destructured params
41-
const destructuredProps = params.find(
42-
param => param.type === 'ObjectPattern',
43-
);
44-
45-
const noExistingProps = params.length === 0;
46-
47-
let newParams: FunctionDeclaration['params'] = [];
48-
49-
if (noExistingProps) {
50-
newParams = [j.objectPattern(defaultParams)];
51-
} else if (existingSingleProp) {
52-
newParams = [
53-
j.objectPattern([
54-
// @ts-ignore
55-
j.spreadProperty(existingSingleProp),
56-
...defaultParams,
57-
]),
58-
];
59-
} else {
60-
newParams = getNewDestructuredParams(
61-
destructuredProps,
62-
j,
63-
defaultParams,
64-
);
65-
}
66-
33+
// Find the defaultProps assignment expression
34+
const newParams = getNewParams(j, component, defaultParams);
6735
// Replace the original function declaration with a new one
6836
j(component).replaceWith(nodePath =>
6937
j.functionDeclaration(
7038
nodePath.node.id,
71-
newParams,
39+
newParams!,
7240
nodePath.node.body,
7341
nodePath.node.generator,
7442
nodePath.node.async,
@@ -83,38 +51,3 @@ export function moveDefaultPropsToFunctionDeclaration(
8351
})
8452
.toSource();
8553
}
86-
87-
function getNewDestructuredParams(
88-
existingPropsParam: FunctionDeclaration['params'][number] | undefined,
89-
j: JSCodeshift,
90-
defaultParams: any,
91-
) {
92-
if (existingPropsParam && 'properties' in existingPropsParam) {
93-
const restProp = existingPropsParam.properties.find(
94-
// @ts-expect-error for some reason it does not exist
95-
prop => prop.type === 'RestElement',
96-
);
97-
98-
const existingPropsDestructuredProps = existingPropsParam.properties
99-
.filter(prop => prop.type !== restProp?.type)
100-
.map(prop => j.property('init', (prop as any).key, (prop as any).value))
101-
.filter(Boolean);
102-
103-
const restPropArg =
104-
restProp && 'argument' in restProp
105-
? restProp.argument
106-
: j.identifier('rest');
107-
108-
const newParams = [
109-
j.objectPattern([
110-
...existingPropsDestructuredProps,
111-
...defaultParams,
112-
// @ts-expect-error RestElement is not assignable as above
113-
...(restProp ? [j.restProperty(restPropArg)] : []),
114-
]),
115-
];
116-
return newParams;
117-
}
118-
119-
return [];
120-
}

community/react/remove-default-props/motions/removeDefaultPropsAssignment.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { JSCodeshift } from 'jscodeshift';
22
import { Collection } from 'jscodeshift/src/Collection';
33

44
export function removeDefaultPropsAssignment(
5-
source: Collection<any>,
65
j: JSCodeshift,
6+
source: Collection<any>,
77
) {
88
const removePath = (path: any) => j(path).remove();
99
const isAssigningDefaultProps = (e: any) =>

0 commit comments

Comments
 (0)