oxlint-plugin-react-doctor 0.4.1-dev.e181ac1 → 0.4.2-dev.727894a

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 (2) hide show
  1. package/dist/index.js +20 -20
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -14445,6 +14445,14 @@ const isSynchronous = (node, within) => {
14445
14445
  if (isNodeOfType(node, "AwaitExpression") || isNodeOfType(node, "UnaryExpression") && node.operator === "void" || isNodeOfType(node, "FunctionDeclaration") || isNodeOfType(node, "FunctionExpression") || isNodeOfType(node, "ArrowFunctionExpression")) return false;
14446
14446
  return isSynchronous(node.parent, within);
14447
14447
  };
14448
+ const resolveToFunction = (ref) => {
14449
+ const definitionNode = ref.resolved?.defs[0]?.node;
14450
+ if (!definitionNode) return null;
14451
+ if (isFunctionLike$2(definitionNode)) return definitionNode;
14452
+ if (isNodeOfType(definitionNode, "VariableDeclarator") && isFunctionLike$2(definitionNode.init)) return definitionNode.init;
14453
+ return null;
14454
+ };
14455
+ const resolvesToAsyncFunction = (ref) => Boolean(resolveToFunction(ref)?.async);
14448
14456
  const isEventualCallTo = (analysis, ref, predicate) => {
14449
14457
  const callExprRefs = [];
14450
14458
  ascend(analysis, ref, (upRef) => {
@@ -14571,12 +14579,8 @@ const getEffectFn = (analysis, node) => {
14571
14579
  if (!fn) return null;
14572
14580
  if (isNodeOfType(fn, "ArrowFunctionExpression") || isNodeOfType(fn, "FunctionExpression")) return fn;
14573
14581
  if (isNodeOfType(fn, "Identifier")) {
14574
- const definitionNode = getRef(analysis, fn)?.resolved?.defs[0]?.node;
14575
- if (definitionNode && isFunctionLike$2(definitionNode)) return definitionNode;
14576
- if (definitionNode && isNodeOfType(definitionNode, "VariableDeclarator")) {
14577
- const initializer = definitionNode.init;
14578
- if (isNodeOfType(initializer, "ArrowFunctionExpression") || isNodeOfType(initializer, "FunctionExpression")) return initializer;
14579
- }
14582
+ const ref = getRef(analysis, fn);
14583
+ return ref ? resolveToFunction(ref) : null;
14580
14584
  }
14581
14585
  return null;
14582
14586
  };
@@ -14657,6 +14661,7 @@ const isRefCurrent = (ref) => {
14657
14661
  return parent.property.name === "current";
14658
14662
  };
14659
14663
  const isStateSetterCall = (analysis, ref) => isEventualCallTo(analysis, ref, (innerRef) => isStateSetter(analysis, innerRef));
14664
+ const isSyncStateSetterCall = (analysis, ref, effectFn) => isStateSetterCall(analysis, ref) && isSynchronous(ref.identifier, effectFn) && !resolvesToAsyncFunction(ref);
14660
14665
  const isPropCall = (analysis, ref) => isEventualCallTo(analysis, ref, (innerRef) => isPropAlias(analysis, innerRef));
14661
14666
  const isRefCall = (analysis, ref) => isEventualCallTo(analysis, ref, (innerRef) => isRefCurrent(innerRef) || isRef(analysis, innerRef));
14662
14667
  const getUseStateDecl = (analysis, ref) => {
@@ -14668,12 +14673,8 @@ const isCleanupReturnArgument = (analysis, node) => {
14668
14673
  if (isFunctionLike$2(node)) return true;
14669
14674
  if (isNodeOfType(node, "MemberExpression")) return true;
14670
14675
  if (isNodeOfType(node, "Identifier")) {
14671
- const definitionNode = getRef(analysis, node)?.resolved?.defs[0]?.node;
14672
- if (definitionNode && isFunctionLike$2(definitionNode)) return true;
14673
- if (definitionNode && isNodeOfType(definitionNode, "VariableDeclarator")) {
14674
- const initializer = definitionNode.init;
14675
- return isFunctionLike$2(initializer);
14676
- }
14676
+ const ref = getRef(analysis, node);
14677
+ if (ref && resolveToFunction(ref)) return true;
14677
14678
  }
14678
14679
  if (isNodeOfType(node, "ConditionalExpression")) return isCleanupReturnArgument(analysis, node.consequent) || isCleanupReturnArgument(analysis, node.alternate);
14679
14680
  return false;
@@ -14723,8 +14724,7 @@ const noAdjustStateOnPropChange = defineRule({
14723
14724
  if (!effectFn) return;
14724
14725
  if (!depsRefs.flatMap((ref) => getUpstreamRefs(analysis, ref)).some((ref) => isProp(analysis, ref))) return;
14725
14726
  for (const ref of effectFnRefs) {
14726
- if (!isStateSetterCall(analysis, ref)) continue;
14727
- if (!isSynchronous(ref.identifier, effectFn)) continue;
14727
+ if (!isSyncStateSetterCall(analysis, ref, effectFn)) continue;
14728
14728
  const callExpr = getCallExpr(ref);
14729
14729
  if (!callExpr) continue;
14730
14730
  if (getArgsUpstreamRefs(analysis, ref).some((argRef) => isProp(analysis, argRef))) continue;
@@ -15631,8 +15631,7 @@ const noChainStateUpdates = defineRule({
15631
15631
  if (!effectFn) return;
15632
15632
  if (!depsRefs.flatMap((ref) => getUpstreamRefs(analysis, ref)).some((ref) => isState(analysis, ref))) return;
15633
15633
  for (const ref of effectFnRefs) {
15634
- if (!isStateSetterCall(analysis, ref)) continue;
15635
- if (!isSynchronous(ref.identifier, effectFn)) continue;
15634
+ if (!isSyncStateSetterCall(analysis, ref, effectFn)) continue;
15636
15635
  const callExpr = getCallExpr(ref);
15637
15636
  if (!callExpr) continue;
15638
15637
  if (getArgsUpstreamRefs(analysis, ref).some((argRef) => isState(analysis, argRef))) continue;
@@ -16250,8 +16249,7 @@ const noDerivedState = defineRule({
16250
16249
  const effectFn = getEffectFn(analysis, node);
16251
16250
  if (!effectFn) return;
16252
16251
  for (const ref of effectFnRefs) {
16253
- if (!isStateSetterCall(analysis, ref)) continue;
16254
- if (!isSynchronous(ref.identifier, effectFn)) continue;
16252
+ if (!isSyncStateSetterCall(analysis, ref, effectFn)) continue;
16255
16253
  const callExpr = getCallExpr(ref);
16256
16254
  if (!callExpr) continue;
16257
16255
  const stateName = getStateNameForUseStateDecl(getUseStateDecl(analysis, ref)) ?? "<state>";
@@ -18640,8 +18638,7 @@ const noInitializeState = defineRule({
18640
18638
  if (!effectFn) return;
18641
18639
  if (!(depsRefs.filter((ref) => !isStateSetter(analysis, ref)).length === 0)) return;
18642
18640
  for (const ref of effectFnRefs) {
18643
- if (!isStateSetterCall(analysis, ref)) continue;
18644
- if (!isSynchronous(ref.identifier, effectFn)) continue;
18641
+ if (!isSyncStateSetterCall(analysis, ref, effectFn)) continue;
18645
18642
  const callExpr = getCallExpr(ref);
18646
18643
  if (!callExpr || !isNodeOfType(callExpr, "CallExpression")) continue;
18647
18644
  const useStateDecl = getUseStateDecl(analysis, ref);
@@ -27868,6 +27865,7 @@ const rnListCallbackPerRow = defineRule({
27868
27865
  tags: ["test-noise"],
27869
27866
  requires: ["react-native"],
27870
27867
  severity: "warn",
27868
+ disabledBy: ["react-compiler"],
27871
27869
  recommendation: "Move the handler out with useCallback at list scope and pass the row id as a prop. Then memo() rows skip redrawing when their data has not changed.",
27872
27870
  create: (context) => {
27873
27871
  const inspect = (node) => {
@@ -28304,6 +28302,7 @@ const rnNoInlineFlatlistRenderitem = defineRule({
28304
28302
  tags: ["test-noise"],
28305
28303
  requires: ["react-native"],
28306
28304
  severity: "warn",
28305
+ disabledBy: ["react-compiler"],
28307
28306
  recommendation: "Move renderItem to a named function or wrap it in useCallback so it is not rebuilt every time the screen redraws.",
28308
28307
  create: (context) => ({ JSXAttribute(node) {
28309
28308
  if (!isNodeOfType(node.name, "JSXIdentifier") || node.name.name !== "renderItem") return;
@@ -28328,6 +28327,7 @@ const rnNoInlineObjectInListItem = defineRule({
28328
28327
  tags: ["test-noise"],
28329
28328
  requires: ["react-native"],
28330
28329
  severity: "warn",
28330
+ disabledBy: ["react-compiler"],
28331
28331
  recommendation: "Move style and object props out of renderItem (StyleSheet.create, useMemo at list scope, or pass primitives) so memo() rows stop redrawing when their data has not changed.",
28332
28332
  create: (context) => {
28333
28333
  const renderPropStack = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oxlint-plugin-react-doctor",
3
- "version": "0.4.1-dev.e181ac1",
3
+ "version": "0.4.2-dev.727894a",
4
4
  "description": "oxlint plugin for React Doctor: diagnose React codebases for security, performance, correctness, accessibility, bundle-size, and architecture issues",
5
5
  "keywords": [
6
6
  "accessibility",