Repository: facebook/react
File: compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts (TypeScript)

Code before:
  node.traverse({
    JSX() {
      createsJsx = true;
    },
    CallExpression(call) {
      const callee = call.get('callee');
      if (callee.isExpression() && isHook(callee, hookPattern)) {
        invokesHooks = true;
      }
    },
    ArrowFunctionExpression: skipNestedFunctions(node),
    FunctionExpression: skipNestedFunctions(node),
    FunctionDeclaration: skipNestedFunctions(node),
  });

  return invokesHooks || createsJsx;
}

function returnsNonNode(
  node: NodePath<
    t.FunctionDeclaration | t.ArrowFunctionExpression | t.FunctionExpression
  >,
): boolean {
  if (node.type === 'ArrowFunctionExpression' && node.node.body.type === 'JSXElement') {
    return false
  }

  let hasReturn = false;
  let returnsNonNode = false;

  node.traverse({
    ReturnStatement(ret) {
      hasReturn = true;
      const argument = ret.node.argument;
      if (argument == null) {
        returnsNonNode = true;
      } else {
        switch (argument.type) {
          case 'ObjectExpression':
          case 'ArrowFunctionExpression':
          case 'FunctionExpression':
          case 'BigIntLiteral':
          case 'ClassExpression':
          case 'NewExpression': // technically `new Array()` is legit, but unlikely
            returnsNonNode = true;
        }
      }
    },
    // Skip traversing all nested functions and their return statements
    ArrowFunctionExpression: skipNestedFunctions(node),
    FunctionExpression: skipNestedFunctions(node),

Review comment (refactor):
I missed this PR the first time around, my apologies. This is an overly narrow solution and needs to be more robust. Let's do the following:

1. Extract out a helper that takes an Expression and returns a boolean for whether its possibly a React node or not. This can reuse the `switch (argument.type) { ... }` from the current ReturnStatement case.
2. Reuse this helper in the existing ReturnStatement case
3. Expand the ArrowFunctionExpression case to check if the body is an expresssion, and if so use the new helper. otherwise traverse with skipNestedFunctions.

Code after:
    if (fn.node !== node.node) {
      fn.skip();
    }
  };
}

function callsHooksOrCreatesJsx(
  node: NodePath<
    t.FunctionDeclaration | t.ArrowFunctionExpression | t.FunctionExpression
  >,
  hookPattern: string | null,
): boolean {
  let invokesHooks = false;
  let createsJsx = false;

  node.traverse({
    JSX() {
      createsJsx = true;
    },
    CallExpression(call) {
      const callee = call.get('callee');
      if (callee.isExpression() && isHook(callee, hookPattern)) {
        invokesHooks = true;
      }
    },
    ArrowFunctionExpression: skipNestedFunctions(node),
    FunctionExpression: skipNestedFunctions(node),
    FunctionDeclaration: skipNestedFunctions(node),
  });

  return invokesHooks || createsJsx;
}

function isNonNode(node?: t.Expression | null): boolean {
  if (!node) {
    return true;
  }
  switch (node.type) {
    case 'ObjectExpression':
    case 'ArrowFunctionExpression':
    case 'FunctionExpression':
    case 'BigIntLiteral':
    case 'ClassExpression':
    case 'NewExpression': // technically `new Array()` is legit, but unlikely
      return true;
  }
  return false;
}

function returnsNonNode(
  node: NodePath<