Skip to content

Commit 59353ea

Browse files
refactor(react-doctor): extract isFunctionLikeVariableDeclarator to file scope (Bugbot #157 round 4)
The helper was inlined three times with identical bodies in `noDerivedUseState`, `noPropCallbackInEffect`, and the newly added `noMirrorPropEffect`. Bugbot pointed out the divergence risk (low severity but a clear maintenance smell). Hoist to a single file-scope const at the top of the module; the three rules now share the implementation. No behavior change. 511/511 tests still pass. Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
1 parent 4d75d5c commit 59353ea

1 file changed

Lines changed: 10 additions & 21 deletions

File tree

packages/react-doctor/src/plugin/rules/state-and-effects.ts

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@ import {
2323
} from "../helpers.js";
2424
import type { EsTreeNode, Rule, RuleContext } from "../types.js";
2525

26+
// HACK: shared by every rule that pushes an empty barrier frame on a
27+
// non-component arrow / function-expression VariableDeclarator (so
28+
// closed-over names from an outer component don't leak into the
29+
// helper's prop check). Three rules previously inlined an identical
30+
// copy — now they all reference this single source of truth.
31+
const isFunctionLikeVariableDeclarator = (node: EsTreeNode): boolean => {
32+
if (node.type !== "VariableDeclarator") return false;
33+
return node.init?.type === "ArrowFunctionExpression" || node.init?.type === "FunctionExpression";
34+
};
35+
2636
export const noDerivedStateEffect: Rule = {
2737
create: (context: RuleContext) => ({
2838
CallExpression(node: EsTreeNode) {
@@ -178,13 +188,6 @@ export const noDerivedUseState: Rule = {
178188
return false;
179189
};
180190

181-
const isFunctionLikeVariableDeclarator = (node: EsTreeNode): boolean => {
182-
if (node.type !== "VariableDeclarator") return false;
183-
return (
184-
node.init?.type === "ArrowFunctionExpression" || node.init?.type === "FunctionExpression"
185-
);
186-
};
187-
188191
return {
189192
FunctionDeclaration(node: EsTreeNode) {
190193
if (!node.id?.name || !isUppercaseName(node.id.name)) {
@@ -470,13 +473,6 @@ export const noPropCallbackInEffect: Rule = {
470473
return false;
471474
};
472475

473-
const isFunctionLikeVariableDeclarator = (node: EsTreeNode): boolean => {
474-
if (node.type !== "VariableDeclarator") return false;
475-
return (
476-
node.init?.type === "ArrowFunctionExpression" || node.init?.type === "FunctionExpression"
477-
);
478-
};
479-
480476
return {
481477
FunctionDeclaration(node: EsTreeNode) {
482478
if (!node.id?.name || !isUppercaseName(node.id.name)) {
@@ -1530,13 +1526,6 @@ export const noMirrorPropEffect: Rule = {
15301526
return new Set();
15311527
};
15321528

1533-
const isFunctionLikeVariableDeclarator = (node: EsTreeNode): boolean => {
1534-
if (node.type !== "VariableDeclarator") return false;
1535-
return (
1536-
node.init?.type === "ArrowFunctionExpression" || node.init?.type === "FunctionExpression"
1537-
);
1538-
};
1539-
15401529
const checkComponent = (componentBody: EsTreeNode | null | undefined): void => {
15411530
if (!componentBody || componentBody.type !== "BlockStatement") return;
15421531
const propNames = getCurrentPropNames();

0 commit comments

Comments
 (0)