Skip to content

fix(linter/react): no only-export-components false positive on nested components - #24915

Open
veksa wants to merge 1 commit into
oxc-project:mainfrom
veksa:fix/only-export-components-nested-24854
Open

fix(linter/react): no only-export-components false positive on nested components#24915
veksa wants to merge 1 commit into
oxc-project:mainfrom
veksa:fix/only-export-components-nested-24854

Conversation

@veksa

@veksa veksa commented Jul 25, 2026

Copy link
Copy Markdown

What this does

Fixes a false positive in react/only-export-components where a non-exported, nested PascalCase function was flagged as a Fast Refresh violation.

Closes #24854

The problem

Given code like this, oxlint incorrectly warned about Inner:

export const helper = 1;

function factory() {
  return function Inner() {
    return <span />;
  };
}

Inner is never exported, so it can't possibly affect Fast Refresh, and the upstream eslint-plugin-react-refresh correctly stays silent here. The pattern shows up in real code, for example factory helpers that build Recharts components.

The cause

find_local_components was iterating over every node in the semantic tree, which meant it also picked up components declared deep inside other functions. The reference implementation only ever looks at program.body, so it never considers anything below the top level.

The fix

I limited local component detection to top-level declarations by keeping only nodes whose parent is the Program. Nested function expressions and declarations live under a ReturnStatement, BlockStatement, etc., so they're no longer collected.

Once that filter is in place the old is_exported helper becomes redundant: a node whose parent is the Program can't sit under an export declaration, since inline exports always wrap their declaration in an ExportNamedDeclaration or ExportDefaultDeclaration. So I dropped that helper and its now-unused NodeId import.

I also added a couple of pass tests covering the reproduction from the issue, both with a nested named function expression and a nested arrow function.

AI disclosure

This change was written with the help of an AI assistant, and I've reviewed and tested it myself before submitting.

@veksa
veksa requested a review from camc314 as a code owner July 25, 2026 09:03
@camc314 camc314 added the A-linter Area - Linter label Jul 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-linter Area - Linter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

linter: react/only-export-components false positive on non-exported nested PascalCase component

2 participants