Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions community/react/remove-default-props/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,26 @@ _Credit_: [https://github.com/reactjs/react-codemod](https://github.com/reactjs/

```jsx
/* INPUT */
import React from 'react'
import React from 'react';

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

/* OUTPUT */
import React from 'react'
import React from 'react';

export const Greet = ({ name }) => <span>Hi {name}</span>
export const Greet = ({ name, text = 'Stranger' }) => <span>Hi {name}</span>;
```

```jsx
/* INPUT */
import React from 'react';

export const Greet = (props) => <span>Hi {name}</span>;
Greet.defaultProps = { text: 'Stranger' };

/* OUTPUT */
import React from 'react';

export const Greet = ({ ...props, text = 'Stranger' }) => <span>Hi {name}</span>;
```
73 changes: 73 additions & 0 deletions community/react/remove-default-props/motions/getNewParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import {
JSCodeshift,
FunctionDeclaration,
ASTPath,
ArrowFunctionExpression,
} from 'jscodeshift';

export function getNewParams(
j: JSCodeshift,
component: ASTPath<FunctionDeclaration | ArrowFunctionExpression>,
defaultParams: any,
) {
const params = component.node.params;

const existingSingleProp = params.find(param => param.type === 'Identifier');

const destructuredProps = params.find(
param => param.type === 'ObjectPattern',
);

const noExistingProps = params.length === 0;

let newParams: FunctionDeclaration['params'] = [];

if (noExistingProps) {
newParams = [j.objectPattern(defaultParams)];
} else if (existingSingleProp) {
newParams = [
j.objectPattern([
// @ts-ignore
j.spreadProperty(existingSingleProp),
...defaultParams,
]),
];
} else {
newParams = getNewDestructuredParams(destructuredProps, j, defaultParams);
}
return newParams;
}
function getNewDestructuredParams(
existingPropsParam: FunctionDeclaration['params'][number] | undefined,
j: JSCodeshift,
defaultParams: any,
) {
if (existingPropsParam && 'properties' in existingPropsParam) {
const restProp = existingPropsParam.properties.find(
// @ts-expect-error for some reason it does not exist
prop => prop.type === 'RestElement',
);

const existingPropsDestructuredProps = existingPropsParam.properties
.filter(prop => prop.type !== restProp?.type)
.map(prop => j.property('init', (prop as any).key, (prop as any).value))
.filter(Boolean);

const restPropArg =
restProp && 'argument' in restProp
? restProp.argument
: j.identifier('rest');

const newParams = [
j.objectPattern([
...existingPropsDestructuredProps,
...defaultParams,
// @ts-expect-error RestElement is not assignable as above
...(restProp ? [j.restProperty(restPropArg)] : []),
]),
];
return newParams;
}

return [];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Collection, JSCodeshift } from 'jscodeshift';
import { getNewParams } from './getNewParams';

export function moveDefaultPropsToArrowFunctionExpression(
j: JSCodeshift,
source: Collection<any>,
) {
source.find(j.VariableDeclarator).forEach(component => {
const defaultProps = source.find(j.AssignmentExpression, {
left: {
// @ts-ignore
object: { name: component.node.id?.name },
property: { name: 'defaultProps' },
},
});

const defaultValues = defaultProps.get('right').value.properties;

if (defaultProps.length === 0) return;

// Generate a new function parameter for each default prop
const defaultParams = defaultValues.map((prop: any) => {
const key = prop.key.name;
const value = prop.value.value;
return j.objectProperty(
j.identifier(key),
j.assignmentPattern(j.identifier(key), j.literal(value)),
);
});

const arrowFunction = component.get('init');

const newParams = getNewParams(j, arrowFunction, defaultParams);

j(component).replaceWith(
j.variableDeclarator(
// @ts-ignore
j.identifier(component.node.id.name),
j.arrowFunctionExpression(newParams!, j.blockStatement([])),
),
);
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { JSCodeshift, Collection } from 'jscodeshift';
import { getNewParams } from './getNewParams';

export function moveDefaultPropsToFunctionDeclaration(
j: JSCodeshift,
source: Collection<any>,
) {
source
.find(j.FunctionDeclaration)
.forEach(component => {
const defaultProps = source.find(j.AssignmentExpression, {
left: {
object: { name: component.node.id?.name },
property: { name: 'defaultProps' },
},
});

if (defaultProps.length === 0) return;

// Extract the default props object
const defaultValues = defaultProps.get('right').value.properties;

// Generate a new function parameter for each default prop
const defaultParams = defaultValues.map((prop: any) => {
const key = prop.key.name;
const value = prop.value.value;
// return j.objectPattern(`${key}=${JSON.stringify(value)}`);
return j.objectProperty(
j.identifier(key),
j.assignmentPattern(j.identifier(key), j.literal(value)),
);
});
// Find the defaultProps assignment expression
const newParams = getNewParams(j, component, defaultParams);
// Replace the original function declaration with a new one
j(component).replaceWith(nodePath =>
j.functionDeclaration(
nodePath.node.id,
newParams!,
nodePath.node.body,
nodePath.node.generator,
nodePath.node.async,
),
);
})
.find(j.AssignmentExpression, {
left: {
object: { type: 'Identifier' },
property: { name: 'defaultProps' },
},
})
.toSource();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { JSCodeshift } from 'jscodeshift';
import { Collection } from 'jscodeshift/src/Collection';

export function removeDefaultPropsAssignment(
j: JSCodeshift,
source: Collection<any>,
) {
const removePath = (path: any) => j(path).remove();
const isAssigningDefaultProps = (e: any) =>
e.node.left &&
e.node.left.property &&
e.node.left.property.name === 'defaultProps';

return source
.find(j.AssignmentExpression)
.filter(isAssigningDefaultProps)
.forEach(removePath);
}
Loading