@kernlang/review 3.2.3 → 3.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/dist/cache.js +140 -3
  2. package/dist/cache.js.map +1 -1
  3. package/dist/call-graph.d.ts +4 -1
  4. package/dist/call-graph.js +290 -25
  5. package/dist/call-graph.js.map +1 -1
  6. package/dist/concept-rules/contract-drift.d.ts +21 -0
  7. package/dist/concept-rules/contract-drift.js +66 -0
  8. package/dist/concept-rules/contract-drift.js.map +1 -0
  9. package/dist/concept-rules/cross-stack-utils.d.ts +50 -0
  10. package/dist/concept-rules/cross-stack-utils.js +98 -0
  11. package/dist/concept-rules/cross-stack-utils.js.map +1 -0
  12. package/dist/concept-rules/index.js +12 -1
  13. package/dist/concept-rules/index.js.map +1 -1
  14. package/dist/concept-rules/tainted-across-wire.d.ts +33 -0
  15. package/dist/concept-rules/tainted-across-wire.js +98 -0
  16. package/dist/concept-rules/tainted-across-wire.js.map +1 -0
  17. package/dist/concept-rules/untyped-api-response.d.ts +30 -0
  18. package/dist/concept-rules/untyped-api-response.js +71 -0
  19. package/dist/concept-rules/untyped-api-response.js.map +1 -0
  20. package/dist/external-tools.d.ts +36 -4
  21. package/dist/external-tools.js +79 -12
  22. package/dist/external-tools.js.map +1 -1
  23. package/dist/graph.js +149 -39
  24. package/dist/graph.js.map +1 -1
  25. package/dist/index.d.ts +29 -4
  26. package/dist/index.js +329 -47
  27. package/dist/index.js.map +1 -1
  28. package/dist/inferrer.d.ts +5 -0
  29. package/dist/inferrer.js +1 -1
  30. package/dist/inferrer.js.map +1 -1
  31. package/dist/llm-bridge.d.ts +26 -1
  32. package/dist/llm-bridge.js +42 -6
  33. package/dist/llm-bridge.js.map +1 -1
  34. package/dist/llm-review.js +29 -11
  35. package/dist/llm-review.js.map +1 -1
  36. package/dist/mappers/ts-concepts.js +278 -7
  37. package/dist/mappers/ts-concepts.js.map +1 -1
  38. package/dist/public-api.d.ts +73 -0
  39. package/dist/public-api.js +351 -0
  40. package/dist/public-api.js.map +1 -0
  41. package/dist/reporter.d.ts +5 -0
  42. package/dist/reporter.js +119 -84
  43. package/dist/reporter.js.map +1 -1
  44. package/dist/review-health.d.ts +38 -0
  45. package/dist/review-health.js +60 -0
  46. package/dist/review-health.js.map +1 -0
  47. package/dist/rules/async.js +4 -16
  48. package/dist/rules/async.js.map +1 -1
  49. package/dist/rules/base.js +112 -87
  50. package/dist/rules/base.js.map +1 -1
  51. package/dist/rules/confidence.d.ts +2 -2
  52. package/dist/rules/confidence.js +32 -15
  53. package/dist/rules/confidence.js.map +1 -1
  54. package/dist/rules/dead-code.d.ts +2 -1
  55. package/dist/rules/dead-code.js +49 -3
  56. package/dist/rules/dead-code.js.map +1 -1
  57. package/dist/rules/index.js +131 -0
  58. package/dist/rules/index.js.map +1 -1
  59. package/dist/rules/kern-source-cross-file.d.ts +2 -0
  60. package/dist/rules/kern-source-cross-file.js +102 -0
  61. package/dist/rules/kern-source-cross-file.js.map +1 -0
  62. package/dist/rules/kern-source.js +86 -9
  63. package/dist/rules/kern-source.js.map +1 -1
  64. package/dist/rules/nextjs-app-router.js +936 -31
  65. package/dist/rules/nextjs-app-router.js.map +1 -1
  66. package/dist/rules/nextjs.js +193 -10
  67. package/dist/rules/nextjs.js.map +1 -1
  68. package/dist/rules/react-composition.js +442 -61
  69. package/dist/rules/react-composition.js.map +1 -1
  70. package/dist/rules/react-hooks.js +51 -2
  71. package/dist/rules/react-hooks.js.map +1 -1
  72. package/dist/rules/react.js +265 -49
  73. package/dist/rules/react.js.map +1 -1
  74. package/dist/rules/utils.d.ts +37 -2
  75. package/dist/rules/utils.js +113 -0
  76. package/dist/rules/utils.js.map +1 -1
  77. package/dist/semantic-diff.js +1 -1
  78. package/dist/semantic-diff.js.map +1 -1
  79. package/dist/taint-ast.js +228 -4
  80. package/dist/taint-ast.js.map +1 -1
  81. package/dist/taint-crossfile.d.ts +30 -2
  82. package/dist/taint-crossfile.js +280 -59
  83. package/dist/taint-crossfile.js.map +1 -1
  84. package/dist/taint-types.d.ts +2 -1
  85. package/dist/taint-types.js +32 -2
  86. package/dist/taint-types.js.map +1 -1
  87. package/dist/taint.d.ts +1 -1
  88. package/dist/taint.js +1 -1
  89. package/dist/taint.js.map +1 -1
  90. package/dist/types.d.ts +80 -0
  91. package/dist/types.js.map +1 -1
  92. package/package.json +3 -3
@@ -6,7 +6,7 @@
6
6
  * correctness; this layer catches the common footguns with high precision.
7
7
  */
8
8
  import { Node, SyntaxKind } from 'ts-morph';
9
- import { finding, nodeSpan } from './utils.js';
9
+ import { finding, nodeSpan, shouldSkipHookRules } from './utils.js';
10
10
  const EFFECT_HOOKS = new Set(['useEffect', 'useLayoutEffect']);
11
11
  const MEMO_HOOKS = new Set(['useMemo', 'useCallback']);
12
12
  const REACT_HOOK_NAMES = new Set([
@@ -375,6 +375,55 @@ function stateDerivedFromProps(ctx) {
375
375
  }
376
376
  return findings;
377
377
  }
378
+ // ── Rule: usecallback-no-benefit ─────────────────────────────────────────
379
+ // useCallback used only as a host-element event handler provides no memoized
380
+ // consumer and usually just adds indirection.
381
+ function useCallbackNoBenefit(ctx) {
382
+ const findings = [];
383
+ for (const decl of ctx.sourceFile.getDescendantsOfKind(SyntaxKind.VariableDeclaration)) {
384
+ const init = decl.getInitializer();
385
+ if (!init || !Node.isCallExpression(init))
386
+ continue;
387
+ const calleeText = init.getExpression().getText();
388
+ const calleeName = calleeText.includes('.') ? calleeText.split('.').pop() : calleeText;
389
+ if (calleeName !== 'useCallback')
390
+ continue;
391
+ const nameNode = decl.getNameNode();
392
+ if (!Node.isIdentifier(nameNode))
393
+ continue;
394
+ const callbackName = nameNode.getText();
395
+ const refs = ctx.sourceFile
396
+ .getDescendantsOfKind(SyntaxKind.Identifier)
397
+ .filter((id) => id.getText() === callbackName && id !== nameNode);
398
+ if (refs.length !== 1)
399
+ continue;
400
+ const onlyRef = refs[0];
401
+ const jsxAttr = onlyRef.getFirstAncestorByKind(SyntaxKind.JsxAttribute);
402
+ if (!jsxAttr)
403
+ continue;
404
+ const jsxTag = jsxAttr.getFirstAncestorByKind(SyntaxKind.JsxSelfClosingElement) ||
405
+ jsxAttr.getFirstAncestorByKind(SyntaxKind.JsxOpeningElement);
406
+ if (!jsxTag)
407
+ continue;
408
+ const tagName = jsxTag.getTagNameNode().getText();
409
+ if (!/^[a-z]/.test(tagName))
410
+ continue; // only intrinsic DOM tags
411
+ findings.push(finding('usecallback-no-benefit', 'info', 'pattern', `'${callbackName}' is wrapped in useCallback but is only used as a '${jsxAttr.getNameNode().getText()}' handler on <${tagName}> — this adds memoization overhead without a memoized consumer`, ctx.filePath, decl.getStartLineNumber(), 1, {
412
+ suggestion: 'Inline the handler in JSX or use a normal local function. Keep useCallback for memoized children, hook dependency stability, or imperative subscription APIs that need stable identity',
413
+ }));
414
+ }
415
+ return findings;
416
+ }
378
417
  // ── Exported React Hooks Rules ───────────────────────────────────────────
379
- export const reactHooksRules = [exhaustiveDeps, refInDeps, stateDerivedFromProps];
418
+ /** All rules in this file assume a client runtime — skip on server/api/middleware
419
+ * unless the file still has React content (JSX / react import / hook call). */
420
+ function clientOnly(fn) {
421
+ return ((ctx) => (shouldSkipHookRules(ctx) ? [] : fn(ctx)));
422
+ }
423
+ export const reactHooksRules = [
424
+ clientOnly(exhaustiveDeps),
425
+ clientOnly(refInDeps),
426
+ clientOnly(stateDerivedFromProps),
427
+ clientOnly(useCallbackNoBenefit),
428
+ ];
380
429
  //# sourceMappingURL=react-hooks.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"react-hooks.js","sourceRoot":"","sources":["../../src/rules/react-hooks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"react-hooks.js","sourceRoot":"","sources":["../../src/rules/react-hooks.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,16 @@
4
4
  * Catches React-specific bugs that KERN IR + AST can detect mechanically.
5
5
  */
6
6
  import { Node, SyntaxKind } from 'ts-morph';
7
- import { finding } from './utils.js';
7
+ import { cleanupExpressionMatches, escapeRegex, findAssignedIdentifier, finding, getTopLevelCleanupExpressions, shouldSkipHookRules, } from './utils.js';
8
+ /**
9
+ * Wrap a hook-specific rule so it short-circuits on server/api/middleware
10
+ * files — unless the file still has React content (JSX / react import /
11
+ * hook call), which means the boundary classifier is wrong for this file
12
+ * (common on `/routes/` and `/controllers/` React components).
13
+ */
14
+ function clientOnly(fn) {
15
+ return ((ctx) => (shouldSkipHookRules(ctx) ? [] : fn(ctx)));
16
+ }
8
17
  /**
9
18
  * Check if a file is actually a React file — has JSX syntax or React imports.
10
19
  * Backend/utility files in a React-targeted project should not trigger React rules.
@@ -21,6 +30,36 @@ function isReactFile(ctx) {
21
30
  return true;
22
31
  return false;
23
32
  }
33
+ function unwrapJsxExpression(node) {
34
+ let current = node;
35
+ while (Node.isParenthesizedExpression(current) ||
36
+ Node.isAsExpression(current) ||
37
+ Node.isTypeAssertion(current) ||
38
+ Node.isNonNullExpression(current) ||
39
+ Node.isSatisfiesExpression(current)) {
40
+ current = current.getExpression();
41
+ }
42
+ return current;
43
+ }
44
+ function getMapCallbackRootJsx(callback) {
45
+ const body = callback.getBody();
46
+ if (Node.isBlock(body)) {
47
+ const returnStmt = body.getStatements().find((stmt) => Node.isReturnStatement(stmt));
48
+ const expr = returnStmt?.getExpression();
49
+ if (!expr)
50
+ return undefined;
51
+ const unwrapped = unwrapJsxExpression(expr);
52
+ if (Node.isJsxElement(unwrapped) || Node.isJsxSelfClosingElement(unwrapped) || Node.isJsxFragment(unwrapped)) {
53
+ return unwrapped;
54
+ }
55
+ return undefined;
56
+ }
57
+ const unwrapped = unwrapJsxExpression(body);
58
+ if (Node.isJsxElement(unwrapped) || Node.isJsxSelfClosingElement(unwrapped) || Node.isJsxFragment(unwrapped)) {
59
+ return unwrapped;
60
+ }
61
+ return undefined;
62
+ }
24
63
  // ── Rule 11: async-effect ────────────────────────────────────────────────
25
64
  // useEffect(async () => ...) — React doesn't support async effect callbacks
26
65
  function asyncEffect(ctx) {
@@ -106,6 +145,25 @@ function renderSideEffect(ctx) {
106
145
  }
107
146
  // ── Rule 13: unstable-key ────────────────────────────────────────────────
108
147
  // Missing key or key={index} in .map() JSX expressions
148
+ function mappedFragmentKey(ctx) {
149
+ const findings = [];
150
+ for (const call of ctx.sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)) {
151
+ const callee = call.getExpression();
152
+ if (!Node.isPropertyAccessExpression(callee) || callee.getName() !== 'map')
153
+ continue;
154
+ const args = call.getArguments();
155
+ if (args.length === 0)
156
+ continue;
157
+ const callback = args[0];
158
+ if (!Node.isArrowFunction(callback) && !Node.isFunctionExpression(callback))
159
+ continue;
160
+ const rootJsx = getMapCallbackRootJsx(callback);
161
+ if (!rootJsx || !Node.isJsxFragment(rootJsx))
162
+ continue;
163
+ findings.push(finding('mapped-fragment-key', 'warning', 'bug', 'JSX fragment returned from .map() cannot carry a key — use <Fragment key={...}> or a keyed element', ctx.filePath, rootJsx.getStartLineNumber(), 1, { suggestion: 'Replace <>...</> with <Fragment key={item.id}>...</Fragment> or wrap in a keyed element' }));
164
+ }
165
+ return findings;
166
+ }
109
167
  function unstableKey(ctx) {
110
168
  const findings = [];
111
169
  // AST-based: walk CallExpressions where callee is .map()
@@ -121,27 +179,23 @@ function unstableKey(ctx) {
121
179
  if (args.length === 0)
122
180
  continue;
123
181
  const callback = args[0];
124
- if (callback.getKind() !== SyntaxKind.ArrowFunction && callback.getKind() !== SyntaxKind.FunctionExpression)
182
+ if (!Node.isArrowFunction(callback) && !Node.isFunctionExpression(callback))
125
183
  continue;
126
184
  // Get the index parameter (second param of the callback)
127
185
  const params = callback.getKind() === SyntaxKind.ArrowFunction
128
186
  ? callback.getParameters()
129
187
  : callback.getParameters();
130
188
  const indexParam = params.length >= 2 ? params[1].getName() : null;
131
- // Walk callback descendants for JSX elements
132
- const jsxElements = [
133
- ...callback.getDescendantsOfKind(SyntaxKind.JsxOpeningElement),
134
- ...callback.getDescendantsOfKind(SyntaxKind.JsxSelfClosingElement),
135
- ];
136
- if (jsxElements.length === 0)
189
+ const rootJsx = getMapCallbackRootJsx(callback);
190
+ if (!rootJsx)
137
191
  continue; // No JSX → skip (fixes non-JSX .map() FP)
138
- // Check the FIRST (root) JSX element for key prop
139
- const firstJsx = jsxElements.sort((a, b) => a.getStart() - b.getStart())[0];
192
+ if (Node.isJsxFragment(rootJsx))
193
+ continue; // handled by mapped-fragment-key
140
194
  const line = call.getStartLineNumber();
141
195
  // Get attributes from the first JSX element
142
- const attributes = firstJsx.getKind() === SyntaxKind.JsxSelfClosingElement
143
- ? firstJsx.getAttributes()
144
- : firstJsx.getAttributes();
196
+ const attributes = rootJsx.getKind() === SyntaxKind.JsxSelfClosingElement
197
+ ? rootJsx.getAttributes()
198
+ : rootJsx.getOpeningElement().getAttributes();
145
199
  let hasKey = false;
146
200
  let usesIndexKey = false;
147
201
  for (const attr of attributes) {
@@ -358,6 +412,71 @@ function effectSelfUpdateLoop(ctx) {
358
412
  // ── Rule: missing-effect-cleanup ─────────────────────────────────────────
359
413
  // useEffect with setInterval/addEventListener but no cleanup return function
360
414
  function missingEffectCleanup(ctx) {
415
+ const buildEffectLeakSpecs = (callback) => {
416
+ const specs = [];
417
+ for (const desc of callback.getDescendantsOfKind(SyntaxKind.CallExpression)) {
418
+ const callee = desc.getExpression();
419
+ if (Node.isIdentifier(callee)) {
420
+ const name = callee.getText();
421
+ const assignedName = findAssignedIdentifier(desc);
422
+ if (name === 'setInterval' || name === 'setTimeout') {
423
+ const clearName = name === 'setInterval' ? 'clearInterval' : 'clearTimeout';
424
+ specs.push({
425
+ label: name,
426
+ line: desc.getStartLineNumber(),
427
+ cleanupPatterns: assignedName
428
+ ? [new RegExp(`\\b${clearName}\\s*\\(\\s*${escapeRegex(assignedName)}\\s*\\)`)]
429
+ : [new RegExp(`\\b${clearName}\\s*\\(`)],
430
+ });
431
+ }
432
+ continue;
433
+ }
434
+ if (!Node.isPropertyAccessExpression(callee))
435
+ continue;
436
+ const method = callee.getName();
437
+ const targetText = callee.getExpression().getText();
438
+ const assignedName = findAssignedIdentifier(desc);
439
+ if (method === 'addEventListener') {
440
+ specs.push({
441
+ label: 'addEventListener',
442
+ line: desc.getStartLineNumber(),
443
+ cleanupPatterns: [new RegExp(`${escapeRegex(targetText)}\\s*\\.\\s*removeEventListener\\s*\\(`)],
444
+ });
445
+ continue;
446
+ }
447
+ if (method === 'on') {
448
+ specs.push({
449
+ label: 'on',
450
+ line: desc.getStartLineNumber(),
451
+ cleanupPatterns: assignedName
452
+ ? [
453
+ new RegExp(`\\b${escapeRegex(assignedName)}\\s*\\(`),
454
+ new RegExp(`\\b${escapeRegex(assignedName)}\\s*\\.\\s*(?:unsubscribe|dispose|destroy|off|removeListener)\\s*\\(`),
455
+ new RegExp(`${escapeRegex(targetText)}\\s*\\.\\s*(?:off|removeListener|unsubscribe)\\s*\\(`),
456
+ ]
457
+ : [/\.\s*(?:off|removeListener|unsubscribe|dispose|destroy)\s*\(/],
458
+ cleanupReturnIdentifiers: assignedName ? [assignedName] : [],
459
+ cleanupReturnCallPattern: /\.\s*on\s*\(/,
460
+ });
461
+ continue;
462
+ }
463
+ if (method === 'subscribe') {
464
+ specs.push({
465
+ label: 'subscribe',
466
+ line: desc.getStartLineNumber(),
467
+ cleanupPatterns: assignedName
468
+ ? [
469
+ new RegExp(`\\b${escapeRegex(assignedName)}\\s*\\(`),
470
+ new RegExp(`\\b${escapeRegex(assignedName)}\\s*\\.\\s*(?:unsubscribe|dispose|destroy|off)\\s*\\(`),
471
+ ]
472
+ : [/\.\s*(?:unsubscribe|dispose|destroy|off)\s*\(/],
473
+ cleanupReturnIdentifiers: assignedName ? [assignedName] : [],
474
+ cleanupReturnCallPattern: /\.\s*subscribe\s*\(/,
475
+ });
476
+ }
477
+ }
478
+ return specs;
479
+ };
361
480
  const findings = [];
362
481
  for (const call of ctx.sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)) {
363
482
  const callee = call.getExpression().getText();
@@ -369,24 +488,13 @@ function missingEffectCleanup(ctx) {
369
488
  const callback = args[0];
370
489
  if (!Node.isArrowFunction(callback) && !Node.isFunctionExpression(callback))
371
490
  continue;
372
- const body = callback.getBody();
373
- let hasCleanup = false;
374
- if (Node.isBlock(body)) {
375
- hasCleanup = body.getStatements().some((s) => {
376
- if (!Node.isReturnStatement(s))
377
- return false;
378
- const expr = s.getExpression();
379
- return (expr != null && (Node.isArrowFunction(expr) || Node.isFunctionExpression(expr) || Node.isIdentifier(expr)));
380
- });
381
- }
382
- if (hasCleanup)
491
+ const leakSpecs = buildEffectLeakSpecs(callback).filter((spec, index, specs) => specs.findIndex((candidate) => candidate.label === spec.label && candidate.line === spec.line) === index);
492
+ if (leakSpecs.length === 0)
383
493
  continue;
384
- const leakyCalls = callback.getDescendantsOfKind(SyntaxKind.CallExpression).filter((c) => {
385
- const name = c.getExpression().getText();
386
- return (name === 'setInterval' || name === 'setTimeout' || name.endsWith('.addEventListener') || name.endsWith('.on'));
387
- });
388
- if (leakyCalls.length > 0) {
389
- findings.push(finding('missing-effect-cleanup', 'warning', 'bug', `useEffect uses '${leakyCalls[0].getExpression().getText()}' but is missing a cleanup return function`, ctx.filePath, call.getStartLineNumber(), 1, { suggestion: 'Return a cleanup function: return () => clearInterval(id);' }));
494
+ const cleanupExprs = getTopLevelCleanupExpressions(callback.getBody());
495
+ const leakedSpec = leakSpecs.find((spec) => !cleanupExprs.some((expr) => cleanupExpressionMatches(expr, spec)));
496
+ if (leakedSpec) {
497
+ findings.push(finding('missing-effect-cleanup', 'warning', 'bug', `useEffect uses '${leakedSpec.label}' but is missing matching cleanup`, ctx.filePath, call.getStartLineNumber(), 1, { suggestion: 'Return a cleanup function: return () => clearInterval(id);' }));
390
498
  }
391
499
  }
392
500
  return findings;
@@ -465,6 +573,110 @@ function refInRender(ctx) {
465
573
  }
466
574
  return false;
467
575
  }
576
+ function getNearestNestedFunctionScope(node) {
577
+ let cur = node.getParent();
578
+ while (cur) {
579
+ if (Node.isArrowFunction(cur) || Node.isFunctionExpression(cur) || Node.isFunctionDeclaration(cur)) {
580
+ const outer = cur.getFirstAncestor((ancestor) => Node.isArrowFunction(ancestor) ||
581
+ Node.isFunctionExpression(ancestor) ||
582
+ Node.isFunctionDeclaration(ancestor));
583
+ return outer ? cur : undefined;
584
+ }
585
+ cur = cur.getParent();
586
+ }
587
+ return undefined;
588
+ }
589
+ function getEnclosingFunctionScope(node) {
590
+ let cur = node.getParent();
591
+ while (cur) {
592
+ if (Node.isArrowFunction(cur) || Node.isFunctionExpression(cur) || Node.isFunctionDeclaration(cur)) {
593
+ return cur;
594
+ }
595
+ cur = cur.getParent();
596
+ }
597
+ return undefined;
598
+ }
599
+ function getFunctionBindingName(fn) {
600
+ if (Node.isFunctionDeclaration(fn)) {
601
+ const nameNode = fn.getNameNode();
602
+ return nameNode && Node.isIdentifier(nameNode) ? nameNode : undefined;
603
+ }
604
+ const parent = fn.getParent();
605
+ if (Node.isVariableDeclaration(parent)) {
606
+ const nameNode = parent.getNameNode();
607
+ return Node.isIdentifier(nameNode) ? nameNode : undefined;
608
+ }
609
+ return undefined;
610
+ }
611
+ function hasRenderTimeInvocation(fn) {
612
+ const binding = getFunctionBindingName(fn);
613
+ if (!binding)
614
+ return true;
615
+ const declarations = binding.getSymbol()?.getDeclarations() ?? [];
616
+ if (declarations.length === 0)
617
+ return true;
618
+ for (const candidate of ctx.sourceFile.getDescendantsOfKind(SyntaxKind.Identifier)) {
619
+ if (candidate === binding)
620
+ continue;
621
+ if (candidate.getText() !== binding.getText())
622
+ continue;
623
+ if (candidate.getStart() >= fn.getStart() && candidate.getEnd() <= fn.getEnd())
624
+ continue;
625
+ const candidateDeclarations = candidate.getSymbol()?.getDeclarations() ?? [];
626
+ if (!candidateDeclarations.some((decl) => declarations.includes(decl)))
627
+ continue;
628
+ const parent = candidate.getParent();
629
+ const isDirectInvocation = (Node.isCallExpression(parent) && parent.getExpression() === candidate) ||
630
+ (Node.isNewExpression(parent) && parent.getExpression() === candidate) ||
631
+ (Node.isTaggedTemplateExpression(parent) && parent.getTag() === candidate);
632
+ if (!isDirectInvocation)
633
+ continue;
634
+ if (isInSafeScope(candidate))
635
+ continue;
636
+ return true;
637
+ }
638
+ return false;
639
+ }
640
+ function isGuardedLazyRefInitialization(prop, refName) {
641
+ const ifAncestor = prop.getFirstAncestorByKind(SyntaxKind.IfStatement);
642
+ if (!ifAncestor)
643
+ return false;
644
+ const condText = ifAncestor.getExpression().getText().replace(/\s+/g, '');
645
+ const escapedRef = refName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
646
+ const patterns = [
647
+ new RegExp(`\\b${escapedRef}\\.current\\b.*(?:===|==|!==|!=).*(?:null|undefined)`),
648
+ new RegExp(`(?:null|undefined).*(?:===|==|!==|!=).*\\b${escapedRef}\\.current\\b`),
649
+ new RegExp(`!${escapedRef}\\.current\\b`),
650
+ new RegExp(`\\b${escapedRef}\\.current\\.length===0\\b`),
651
+ new RegExp(`\\b${escapedRef}\\.current\\.length==0\\b`),
652
+ new RegExp(`!${escapedRef}\\.current\\.length\\b`),
653
+ ];
654
+ return patterns.some((pattern) => pattern.test(condText));
655
+ }
656
+ function scopeHasGuardedLazyInitializationReadAllowance(scope, refName) {
657
+ const escapedRef = refName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
658
+ for (const ifStmt of scope.getDescendantsOfKind(SyntaxKind.IfStatement)) {
659
+ const condText = ifStmt.getExpression().getText().replace(/\s+/g, '');
660
+ const guardPatterns = [
661
+ new RegExp(`\\b${escapedRef}\\.current\\b.*(?:===|==|!==|!=).*(?:null|undefined)`),
662
+ new RegExp(`(?:null|undefined).*(?:===|==|!==|!=).*\\b${escapedRef}\\.current\\b`),
663
+ new RegExp(`!${escapedRef}\\.current\\b`),
664
+ new RegExp(`\\b${escapedRef}\\.current\\.length===0\\b`),
665
+ new RegExp(`\\b${escapedRef}\\.current\\.length==0\\b`),
666
+ new RegExp(`!${escapedRef}\\.current\\.length\\b`),
667
+ ];
668
+ if (!guardPatterns.some((pattern) => pattern.test(condText)))
669
+ continue;
670
+ const writesInThen = ifStmt
671
+ .getThenStatement()
672
+ .getDescendantsOfKind(SyntaxKind.BinaryExpression)
673
+ .some((expr) => expr.getLeft().getText() === `${refName}.current` &&
674
+ expr.getOperatorToken().getKind() === SyntaxKind.EqualsToken);
675
+ if (writesInThen)
676
+ return true;
677
+ }
678
+ return false;
679
+ }
468
680
  // Find .current access on ref variables
469
681
  for (const prop of ctx.sourceFile.getDescendantsOfKind(SyntaxKind.PropertyAccessExpression)) {
470
682
  if (prop.getName() !== 'current')
@@ -479,21 +691,24 @@ function refInRender(ctx) {
479
691
  continue;
480
692
  // Skip lazy initialization pattern: if (ref.current === null) ref.current = x
481
693
  // React explicitly allows this during render (react.dev/reference/react/useRef)
482
- const ifAncestor = prop.getFirstAncestorByKind(SyntaxKind.IfStatement);
483
- if (ifAncestor) {
484
- const condText = ifAncestor.getExpression().getText();
485
- const refName = obj.getText();
486
- if (condText.includes(`${refName}.current`) &&
487
- (condText.includes('null') || condText.includes('undefined') || condText.startsWith('!'))) {
488
- continue;
489
- }
490
- }
694
+ if (isGuardedLazyRefInitialization(prop, obj.getText()))
695
+ continue;
696
+ // Writes inside nested local callbacks are not render-time unless the
697
+ // callback is actually invoked during render.
698
+ const nestedFunctionScope = getNearestNestedFunctionScope(prop);
699
+ if (nestedFunctionScope && !hasRenderTimeInvocation(nestedFunctionScope))
700
+ continue;
491
701
  // Check if this is a read or write
492
702
  const parent = prop.getParent();
493
703
  const isWrite = parent &&
494
704
  Node.isBinaryExpression(parent) &&
495
705
  parent.getLeft() === prop &&
496
706
  parent.getOperatorToken().getKind() === SyntaxKind.EqualsToken;
707
+ if (!isWrite) {
708
+ const enclosingScope = getEnclosingFunctionScope(prop);
709
+ if (enclosingScope && scopeHasGuardedLazyInitializationReadAllowance(enclosingScope, obj.getText()))
710
+ continue;
711
+ }
497
712
  const action = isWrite ? 'written to' : 'read';
498
713
  findings.push(finding('ref-in-render', 'error', 'bug', `ref.current ${action} during render — refs are not tracked by React and may be stale`, ctx.filePath, prop.getStartLineNumber(), 1, {
499
714
  suggestion: isWrite
@@ -613,17 +828,18 @@ function reducerMutation(ctx) {
613
828
  }
614
829
  // ── Exported React Rules ─────────────────────────────────────────────────
615
830
  export const reactRules = [
616
- asyncEffect,
617
- renderSideEffect,
831
+ clientOnly(asyncEffect),
832
+ clientOnly(renderSideEffect),
833
+ mappedFragmentKey,
618
834
  unstableKey,
619
- staleClosure,
620
- stateExplosion,
621
- hookOrder,
622
- effectSelfUpdateLoop,
623
- missingEffectCleanup,
835
+ clientOnly(staleClosure),
836
+ clientOnly(stateExplosion),
837
+ clientOnly(hookOrder),
838
+ clientOnly(effectSelfUpdateLoop),
839
+ clientOnly(missingEffectCleanup),
624
840
  inlineContextValue,
625
- refInRender,
626
- missingMemoDeps,
627
- reducerMutation,
841
+ clientOnly(refInRender),
842
+ clientOnly(missingMemoDeps),
843
+ clientOnly(reducerMutation),
628
844
  ];
629
845
  //# sourceMappingURL=react.js.map