Skip to content

cannot replace JSX nodes within render props #565

Open
@json2d

Description

@json2d

i'm having a problem w/ replacing JSX nodes within render props:

https://astexplorer.net/#/gist/870412de2b8bc7bfd6bfa04cd4600680/381203659283e923155a6b62ed4739df11ba0c2d

input:

const MyController = (props) => (
  <Controller
    render={() => (
      <div id="inner" />
    )} 
  />
)

expected output:

const MyController = (props) => (
  <Controller
    render={() => (
     <div id="outer">
        <div id="inner" />
     </div>
    )} 
  />
)

v0.11.0 actual output:

const MyController = (props) => (
  <Controller
    render={() => (
      (<div id="inner" />)
    )} 
  />
)

v0.15.0 actual output:
[input was unmodified]

codemod:

module.exports = function (file, api) {
  const j = api.jscodeshift;
  const root = j(file.source);

  // Find all JSX elements with the name 'Controller'
  const controllerPaths = root.findJSXElements("Controller");

  // Process the found JSX elements
  controllerPaths.forEach((path) => {

    const renderAttribute = path.node.openingElement.attributes.find(
      (attr) => attr.name.name === "render"
    );

    if (
      renderAttribute &&
      renderAttribute.value.type === "JSXExpressionContainer" &&
      renderAttribute.value.expression.type === "ArrowFunctionExpression"
    ) {
      // Find the first JSXElement within the ArrowFunctionExpression
      const renderFunctionBodyNode = renderAttribute.value.expression.body;

      if (renderFunctionBodyNode) {

        const idAttribute = j.jsxAttribute(
          j.jsxIdentifier("id"),
          j.jsxExpressionContainer(j.identifier("outer"))
        );
        // Create a new JSXElement with div as its opening element
        const wrappedRenderFunctionBodyNode = j.jsxElement(
          j.jsxOpeningElement(j.jsxIdentifier("div"), [idAttribute]),
          j.jsxClosingElement(j.jsxIdentifier("div")),
          [renderFunctionBodyNode]
        );

        // Replace the existing JSXElement with the new one
        const renderFunctionBodyPaths = j(renderFunctionBodyNode);
        const renderFunctionBodyPath = renderFunctionBodyPaths.get(0);
        
        renderFunctionBodyPath.replace(wrappedRenderFunctionBodyNode)
      }
    }
  });

  return root.toSource();
};

is the codemod doing something wrong or is this a bug?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions