function transform(file, { j }) { const root = j(file.source); // Find all imports from 'react' root.find(j.ImportDeclaration, { source: { value: 'react' } }) .forEach(path => { // Remove the `forwardRef` specifier from the import path.value.specifiers = path.value.specifiers.filter(specifier => specifier.imported.name !== 'forwardRef'); }); // Find usage of forwardRef function root.find(j.CallExpression, { callee: { name: 'forwardRef' } }) .forEach(path => { // Get the component definition passed to forwardRef const componentFunction = path.node.arguments[0]; if (j.ArrowFunctionExpression.check(componentFunction) || j.FunctionExpression.check(componentFunction)) { // Replace the forwardRef call with the function, using props.ref instead of ref const params = componentFunction.params; if (params.length === 2) { // Replace (props, ref) with just (props) componentFunction.params = [params[0]]; // Replace ref with props.ref within the function body j(componentFunction.body) .find(j.JSXAttribute, { name: { name: 'ref' }}) .replaceWith( j.jsxAttribute( j.jsxIdentifier('ref'), j.jsxExpressionContainer( j.memberExpression(j.identifier('props'), j.identifier('ref')) ) ) ); // Replace the CallExpression with just the function j(path).replaceWith(componentFunction); } } }); return root.toSource(); } export default transform;
Input
import { forwardRef } from 'react'; const Button = forwardRef((props, ref) => { return ( <button ref={ref} {...props}> {props.label} </button> ); }); const Banner = forwardRef(function BannerInner(props, ref) { return ( <div ref={ref} {...props}> {props.children} </div> ); });
Output
loading
Read-only