oxlint-plugin-react-doctor 0.2.17-dev.4aadaab → 0.2.18-dev.08e1d55

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.
package/dist/index.js CHANGED
@@ -2574,7 +2574,7 @@ const INTENTIONAL_SEQUENCING_CALLEE_NAMES = new Set([
2574
2574
  * (`FUNCTION_LIKE_TYPES.has(node.type)`) and as a type-guard. The
2575
2575
  * type-guard form covers both shapes without callers paying a cast.
2576
2576
  */
2577
- const isFunctionLike$2 = (node) => Boolean(node && (isNodeOfType(node, "ArrowFunctionExpression") || isNodeOfType(node, "FunctionExpression") || isNodeOfType(node, "FunctionDeclaration")));
2577
+ const isFunctionLike$3 = (node) => Boolean(node && (isNodeOfType(node, "ArrowFunctionExpression") || isNodeOfType(node, "FunctionExpression") || isNodeOfType(node, "FunctionDeclaration")));
2578
2578
  //#endregion
2579
2579
  //#region src/plugin/utils/is-inline-function-expression.ts
2580
2580
  /**
@@ -2597,7 +2597,7 @@ const findFirstAwaitOutsideNestedFunctions = (block) => {
2597
2597
  let firstAwait = null;
2598
2598
  walkAst(block, (child) => {
2599
2599
  if (firstAwait) return false;
2600
- if (child !== block && isFunctionLike$2(child)) return false;
2600
+ if (child !== block && isFunctionLike$3(child)) return false;
2601
2601
  if (isNodeOfType(child, "AwaitExpression")) firstAwait = child;
2602
2602
  });
2603
2603
  return firstAwait;
@@ -3054,13 +3054,13 @@ const asyncDeferAwait = defineRule({
3054
3054
  const inspectAllStatementBlocks = (functionBody) => {
3055
3055
  if (!functionBody) return;
3056
3056
  walkAst(functionBody, (descendant) => {
3057
- if (isFunctionLike$2(descendant)) return false;
3057
+ if (isFunctionLike$3(descendant)) return false;
3058
3058
  if (isNodeOfType(descendant, "BlockStatement")) inspectStatements(descendant.body ?? []);
3059
3059
  else if (isNodeOfType(descendant, "SwitchCase")) inspectStatements(descendant.consequent ?? []);
3060
3060
  });
3061
3061
  };
3062
3062
  const enterFunction = (node) => {
3063
- if (!isFunctionLike$2(node)) return;
3063
+ if (!isFunctionLike$3(node)) return;
3064
3064
  if (!node.async) return;
3065
3065
  if (!isNodeOfType(node.body, "BlockStatement")) return;
3066
3066
  inspectAllStatementBlocks(node.body);
@@ -4509,7 +4509,7 @@ const displayName = defineRule({
4509
4509
  //#region src/plugin/utils/walk-inside-statement-blocks.ts
4510
4510
  const walkInsideStatementBlocks = (node, visitor) => {
4511
4511
  if (!node || typeof node !== "object") return;
4512
- if (isFunctionLike$2(node)) return;
4512
+ if (isFunctionLike$3(node)) return;
4513
4513
  visitor(node);
4514
4514
  const nodeRecord = node;
4515
4515
  for (const key of Object.keys(nodeRecord)) {
@@ -4597,7 +4597,7 @@ const containsReleaseLikeCall = (node, knownCleanupFunctionNames, knownBoundSubs
4597
4597
  let didFindRelease = false;
4598
4598
  walkAst(node, (child) => {
4599
4599
  if (didFindRelease) return false;
4600
- if (child !== node && isFunctionLike$2(child) && !isIteratorCallbackArgument(child)) return false;
4600
+ if (child !== node && isFunctionLike$3(child) && !isIteratorCallbackArgument(child)) return false;
4601
4601
  if (isReleaseLikeCall(child, knownCleanupFunctionNames, knownBoundSubscriptionNames)) {
4602
4602
  didFindRelease = true;
4603
4603
  return false;
@@ -4606,14 +4606,20 @@ const containsReleaseLikeCall = (node, knownCleanupFunctionNames, knownBoundSubs
4606
4606
  return didFindRelease;
4607
4607
  };
4608
4608
  const isCleanupFunctionLike = (node, knownCleanupFunctionNames, knownBoundSubscriptionNames) => {
4609
- if (!isFunctionLike$2(node)) return false;
4609
+ if (!isFunctionLike$3(node)) return false;
4610
4610
  return containsReleaseLikeCall(node.body, knownCleanupFunctionNames, knownBoundSubscriptionNames);
4611
4611
  };
4612
- const isCleanupReturn = (returnedValue, knownCleanupFunctionNames, knownBoundSubscriptionNames) => {
4612
+ const isCleanupReturn = (returnedValue, knownCleanupFunctionNames, knownBoundSubscriptionNames, options = {}) => {
4613
4613
  if (!returnedValue) return false;
4614
4614
  const unwrappedValue = unwrapChainExpression$2(returnedValue);
4615
- if (isNodeOfType(unwrappedValue, "Identifier")) return knownCleanupFunctionNames.has(unwrappedValue.name);
4615
+ if (isNodeOfType(unwrappedValue, "Literal") && unwrappedValue.value === null) return false;
4616
+ if (isNodeOfType(unwrappedValue, "Identifier")) {
4617
+ if (unwrappedValue.name === "undefined") return false;
4618
+ if (knownCleanupFunctionNames.has(unwrappedValue.name)) return true;
4619
+ return options.allowOpaqueReturn === true && !knownBoundSubscriptionNames.has(unwrappedValue.name);
4620
+ }
4616
4621
  if (isCleanupReturningSubscribeLikeCallExpression(unwrappedValue)) return true;
4622
+ if (options.allowOpaqueReturn === true && !isSubscribeLikeCallExpression(unwrappedValue)) return true;
4617
4623
  if (isCleanupFunctionLike(unwrappedValue, knownCleanupFunctionNames, knownBoundSubscriptionNames)) return true;
4618
4624
  return false;
4619
4625
  };
@@ -4634,12 +4640,14 @@ const findSubscribeLikeUsages = (callback) => {
4634
4640
  if (isNodeOfType(child.callee, "Identifier") && TIMER_CALLEE_NAMES_REQUIRING_CLEANUP.has(child.callee.name)) {
4635
4641
  usages.push({
4636
4642
  kind: "timer",
4643
+ node: child,
4637
4644
  resourceName: child.callee.name
4638
4645
  });
4639
4646
  return;
4640
4647
  }
4641
4648
  if (isNodeOfType(child.callee, "MemberExpression") && isNodeOfType(child.callee.property, "Identifier") && SUBSCRIPTION_METHOD_NAMES.has(child.callee.property.name)) usages.push({
4642
4649
  kind: "subscribe",
4650
+ node: child,
4643
4651
  resourceName: child.callee.property.name
4644
4652
  });
4645
4653
  });
@@ -4686,7 +4694,20 @@ const collectCleanupBindings = (effectCallback) => {
4686
4694
  });
4687
4695
  return bindings;
4688
4696
  };
4689
- const effectHasCleanupRelease = (callback) => {
4697
+ const getRangeStart = (node) => {
4698
+ const rangeStart = node.range?.[0];
4699
+ return typeof rangeStart === "number" ? rangeStart : null;
4700
+ };
4701
+ const cleanupReturnRunsAfterUsage = (returnStatement, usages) => {
4702
+ if (returnStatement.argument && isCleanupReturningSubscribeLikeCallExpression(returnStatement.argument)) return true;
4703
+ const returnStart = getRangeStart(returnStatement);
4704
+ if (returnStart === null) return true;
4705
+ return usages.some((usage) => {
4706
+ const usageStart = getRangeStart(usage.node);
4707
+ return usageStart === null || usageStart < returnStart;
4708
+ });
4709
+ };
4710
+ const effectHasCleanupReturn = (callback, usages) => {
4690
4711
  if (!isNodeOfType(callback, "ArrowFunctionExpression") && !isNodeOfType(callback, "FunctionExpression")) return false;
4691
4712
  if (!isNodeOfType(callback.body, "BlockStatement")) return isCleanupReturningSubscribeLikeCallExpression(callback.body);
4692
4713
  const cleanupBindings = collectCleanupBindings(callback);
@@ -4694,7 +4715,8 @@ const effectHasCleanupRelease = (callback) => {
4694
4715
  walkInsideStatementBlocks(callback.body, (child) => {
4695
4716
  if (didFindCleanupReturn) return;
4696
4717
  if (!isNodeOfType(child, "ReturnStatement")) return;
4697
- if (isCleanupReturn(child.argument, cleanupBindings.cleanupFunctionNames, cleanupBindings.subscriptionNames)) didFindCleanupReturn = true;
4718
+ if (!cleanupReturnRunsAfterUsage(child, usages)) return;
4719
+ if (isCleanupReturn(child.argument, cleanupBindings.cleanupFunctionNames, cleanupBindings.subscriptionNames, { allowOpaqueReturn: true })) didFindCleanupReturn = true;
4698
4720
  });
4699
4721
  return didFindCleanupReturn;
4700
4722
  };
@@ -4710,7 +4732,7 @@ const effectNeedsCleanup = defineRule({
4710
4732
  if (!callback) return;
4711
4733
  const usages = findSubscribeLikeUsages(callback);
4712
4734
  if (usages.length === 0) return;
4713
- if (effectHasCleanupRelease(callback)) return;
4735
+ if (effectHasCleanupReturn(callback, usages)) return;
4714
4736
  const firstUsage = usages[0];
4715
4737
  const verb = firstUsage.kind === "timer" ? "schedules" : "subscribes via";
4716
4738
  context.report({
@@ -4848,7 +4870,7 @@ const recordReference = (state, identifier, flag) => {
4848
4870
  };
4849
4871
  const isFunctionBodyBlock = (block) => {
4850
4872
  if (!block.parent) return false;
4851
- return isFunctionLike$2(block.parent);
4873
+ return isFunctionLike$3(block.parent);
4852
4874
  };
4853
4875
  const isCatchClauseBlock = (block) => block.parent !== null && block.parent !== void 0 && block.parent.type === "CatchClause";
4854
4876
  const handleVariableDeclaration = (declaration, state) => {
@@ -5003,7 +5025,7 @@ const walkParameterReferences = (pattern, state) => {
5003
5025
  if (isNodeOfType(pattern, "RestElement")) walkParameterReferences(pattern.argument, state);
5004
5026
  };
5005
5027
  const walk = (node, state) => {
5006
- if (isFunctionLike$2(node)) {
5028
+ if (isFunctionLike$3(node)) {
5007
5029
  if (isNodeOfType(node, "FunctionDeclaration") && node.id) handleFunctionDeclaration(node, state);
5008
5030
  setNodeScope(node, state);
5009
5031
  const fnScope = pushScope(node.type === "ArrowFunctionExpression" ? "arrow-function" : "function", node, state);
@@ -5249,7 +5271,7 @@ const closureCaptures = (functionNode, scopes) => {
5249
5271
  const out = [];
5250
5272
  const seen = /* @__PURE__ */ new Set();
5251
5273
  const visit = (node) => {
5252
- if (node !== functionNode && isFunctionLike$2(node)) {
5274
+ if (node !== functionNode && isFunctionLike$3(node)) {
5253
5275
  const innerCaptures = closureCaptures(node, scopes);
5254
5276
  for (const reference of innerCaptures) if (reference.resolvedSymbol && !isDescendantScope(reference.resolvedSymbol.scope, functionScope)) {
5255
5277
  if (!seen.has(reference.id)) {
@@ -7369,7 +7391,7 @@ const isAtomFromJotai = (callExpression) => {
7369
7391
  if (!isImportedFromModule(callExpression, localName, "jotai")) return false;
7370
7392
  return getImportedNameFromModule(callExpression, localName, "jotai") === "atom";
7371
7393
  };
7372
- const isFunctionLike$1 = (node) => Boolean(node && (isNodeOfType(node, "ArrowFunctionExpression") || isNodeOfType(node, "FunctionExpression")));
7394
+ const isFunctionLike$2 = (node) => Boolean(node && (isNodeOfType(node, "ArrowFunctionExpression") || isNodeOfType(node, "FunctionExpression")));
7373
7395
  const getFirstParameterName = (fn) => {
7374
7396
  const parameters = fn.params ?? [];
7375
7397
  if (parameters.length !== 1) return null;
@@ -7488,7 +7510,7 @@ const jotaiDerivedAtomReturnsFreshObject = defineRule({
7488
7510
  const args = node.arguments ?? [];
7489
7511
  if (args.length === 0) return;
7490
7512
  const reader = args[0];
7491
- if (!isFunctionLike$1(reader)) return;
7513
+ if (!isFunctionLike$2(reader)) return;
7492
7514
  const getParameterName = getFirstParameterName(reader);
7493
7515
  if (!getParameterName) return;
7494
7516
  const freshReturn = getFreshReturnForFunction(reader);
@@ -7744,7 +7766,7 @@ const isInsideLoopContext = (node) => {
7744
7766
  let current = node.parent;
7745
7767
  while (current) {
7746
7768
  if (isNodeOfType(current, "ForStatement") || isNodeOfType(current, "ForInStatement") || isNodeOfType(current, "ForOfStatement") || isNodeOfType(current, "WhileStatement") || isNodeOfType(current, "DoWhileStatement")) return true;
7747
- if (isFunctionLike$2(current)) {
7769
+ if (isFunctionLike$3(current)) {
7748
7770
  if (isIteratorCallback(current)) return true;
7749
7771
  return false;
7750
7772
  }
@@ -8105,7 +8127,7 @@ const jsHoistIntl = defineRule({
8105
8127
  let cursor = node.parent ?? null;
8106
8128
  let inFunctionBody = false;
8107
8129
  while (cursor) {
8108
- if (isFunctionLike$2(cursor)) {
8130
+ if (isFunctionLike$3(cursor)) {
8109
8131
  inFunctionBody = true;
8110
8132
  const fnParent = cursor.parent;
8111
8133
  if (fnParent && isNodeOfType(fnParent, "CallExpression") && fnParent.arguments?.[0] === cursor) {
@@ -9703,6 +9725,7 @@ const jsxNoConstructedContextValues = defineRule({
9703
9725
  title: "Unstable context provider value",
9704
9726
  tags: ["react-jsx-only"],
9705
9727
  severity: "warn",
9728
+ disabledBy: ["react-compiler"],
9706
9729
  recommendation: "Wrap the context value in `useMemo`, or move it outside the component.",
9707
9730
  category: "Performance",
9708
9731
  create: (context) => {
@@ -13059,7 +13082,7 @@ const collectChainedGetHandlerBodies = (initNode) => {
13059
13082
  };
13060
13083
  const resolveBodiesFromExpression = (expression, resolveBinding, remainingDepth) => {
13061
13084
  if (remainingDepth <= 0) return [];
13062
- if (isFunctionLike$2(expression)) return expression.body ? [expression.body] : [];
13085
+ if (isFunctionLike$3(expression)) return expression.body ? [expression.body] : [];
13063
13086
  if (isNodeOfType(expression, "CallExpression")) {
13064
13087
  for (const callArgument of expression.arguments ?? []) {
13065
13088
  if (isNodeOfType(callArgument, "ArrowFunctionExpression") || isNodeOfType(callArgument, "FunctionExpression")) {
@@ -13529,7 +13552,7 @@ const getEffectFn = (analysis, node) => {
13529
13552
  if (isNodeOfType(fn, "ArrowFunctionExpression") || isNodeOfType(fn, "FunctionExpression")) return fn;
13530
13553
  if (isNodeOfType(fn, "Identifier")) {
13531
13554
  const definitionNode = getRef(analysis, fn)?.resolved?.defs[0]?.node;
13532
- if (definitionNode && isFunctionLike$2(definitionNode)) return definitionNode;
13555
+ if (definitionNode && isFunctionLike$3(definitionNode)) return definitionNode;
13533
13556
  if (definitionNode && isNodeOfType(definitionNode, "VariableDeclarator")) {
13534
13557
  const initializer = definitionNode.init;
13535
13558
  if (isNodeOfType(initializer, "ArrowFunctionExpression") || isNodeOfType(initializer, "FunctionExpression")) return initializer;
@@ -13622,14 +13645,14 @@ const getUseStateDecl = (analysis, ref) => {
13622
13645
  return node ?? null;
13623
13646
  };
13624
13647
  const isCleanupReturnArgument = (analysis, node) => {
13625
- if (isFunctionLike$2(node)) return true;
13648
+ if (isFunctionLike$3(node)) return true;
13626
13649
  if (isNodeOfType(node, "MemberExpression")) return true;
13627
13650
  if (isNodeOfType(node, "Identifier")) {
13628
13651
  const definitionNode = getRef(analysis, node)?.resolved?.defs[0]?.node;
13629
- if (definitionNode && isFunctionLike$2(definitionNode)) return true;
13652
+ if (definitionNode && isFunctionLike$3(definitionNode)) return true;
13630
13653
  if (definitionNode && isNodeOfType(definitionNode, "VariableDeclarator")) {
13631
13654
  const initializer = definitionNode.init;
13632
- return isFunctionLike$2(initializer);
13655
+ return isFunctionLike$3(initializer);
13633
13656
  }
13634
13657
  }
13635
13658
  if (isNodeOfType(node, "ConditionalExpression")) return isCleanupReturnArgument(analysis, node.consequent) || isCleanupReturnArgument(analysis, node.alternate);
@@ -13639,7 +13662,7 @@ const hasCleanupReturn = (analysis, node, visited = /* @__PURE__ */ new WeakSet(
13639
13662
  if (visited.has(node)) return false;
13640
13663
  visited.add(node);
13641
13664
  if (isNodeOfType(node, "ReturnStatement") && node.argument != null) return isCleanupReturnArgument(analysis, node.argument);
13642
- if (!isNodeOfType(node, "BlockStatement") && isFunctionLike$2(node)) return false;
13665
+ if (!isNodeOfType(node, "BlockStatement") && isFunctionLike$3(node)) return false;
13643
13666
  const record = node;
13644
13667
  for (const [key, value] of Object.entries(record)) {
13645
13668
  if (key === "parent") continue;
@@ -13651,7 +13674,7 @@ const hasCleanupReturn = (analysis, node, visited = /* @__PURE__ */ new WeakSet(
13651
13674
  };
13652
13675
  const hasCleanup = (analysis, node) => {
13653
13676
  const fn = getEffectFn(analysis, node);
13654
- if (!isFunctionLike$2(fn)) return false;
13677
+ if (!isFunctionLike$3(fn)) return false;
13655
13678
  if (!isNodeOfType(fn.body, "BlockStatement")) return false;
13656
13679
  return hasCleanupReturn(analysis, fn.body);
13657
13680
  };
@@ -14001,7 +14024,7 @@ const isInsideStaticPlaceholderMap = (node) => {
14001
14024
  let current = node;
14002
14025
  while (current.parent) {
14003
14026
  const parent = current.parent;
14004
- if (isFunctionLike$2(current) && isNodeOfType(parent, "CallExpression") && parent.arguments.includes(current)) {
14027
+ if (isFunctionLike$3(current) && isNodeOfType(parent, "CallExpression") && parent.arguments.includes(current)) {
14005
14028
  const callee = parent.callee;
14006
14029
  if (isNodeOfType(callee, "MemberExpression") && isNodeOfType(callee.property, "Identifier") && (callee.property.name === "map" || callee.property.name === "flatMap" || callee.property.name === "forEach")) return isStaticPlaceholderReceiver(callee.object);
14007
14030
  if (isArrayFromCall(parent) && parent.arguments.length >= 2 && parent.arguments[1] === current) return isArrayFromLengthObjectCall(parent);
@@ -14020,7 +14043,7 @@ const findIteratorItemName$1 = (node) => {
14020
14043
  let current = node;
14021
14044
  while (current.parent) {
14022
14045
  const parent = current.parent;
14023
- if (isFunctionLike$2(current) && isNodeOfType(parent, "CallExpression") && parent.arguments.includes(current)) {
14046
+ if (isFunctionLike$3(current) && isNodeOfType(parent, "CallExpression") && parent.arguments.includes(current)) {
14024
14047
  const callee = parent.callee;
14025
14048
  const isIteratorMethodCall = isNodeOfType(callee, "MemberExpression") && isNodeOfType(callee.property, "Identifier") && (callee.property.name === "map" || callee.property.name === "flatMap" || callee.property.name === "forEach");
14026
14049
  const isArrayFromCallback = isArrayFromCall(parent) && parent.arguments.length >= 2 && parent.arguments[1] === current;
@@ -14965,7 +14988,7 @@ const componentOrHookDisplayNameForFunction = (functionNode) => {
14965
14988
  const nearestEnclosingFunction = (node) => {
14966
14989
  let cursor = node.parent;
14967
14990
  while (cursor) {
14968
- if (isFunctionLike$2(cursor)) return cursor;
14991
+ if (isFunctionLike$3(cursor)) return cursor;
14969
14992
  cursor = cursor.parent ?? null;
14970
14993
  }
14971
14994
  return null;
@@ -15648,7 +15671,7 @@ const extractDestructuredPropNames = (params) => {
15648
15671
  };
15649
15672
  const getInlineFunctionNode = (node) => {
15650
15673
  if (!node) return null;
15651
- if (isFunctionLike$2(node)) return node;
15674
+ if (isFunctionLike$3(node)) return node;
15652
15675
  if (!isNodeOfType(node, "CallExpression")) return null;
15653
15676
  for (const argument of node.arguments ?? []) {
15654
15677
  const inlineFunctionNode = getInlineFunctionNode(argument);
@@ -15659,7 +15682,7 @@ const getInlineFunctionNode = (node) => {
15659
15682
  const getNearestComponentFunction = (node) => {
15660
15683
  let cursor = node.parent ?? null;
15661
15684
  while (cursor) {
15662
- if (isFunctionLike$2(cursor)) return cursor;
15685
+ if (isFunctionLike$3(cursor)) return cursor;
15663
15686
  cursor = cursor.parent ?? null;
15664
15687
  }
15665
15688
  return null;
@@ -15989,7 +16012,7 @@ const collectFunctionLocalBindings = (functionNode) => {
15989
16012
  const walkComponentRespectingShadows = (node, shadowedStateNames, visit) => {
15990
16013
  if (!node || typeof node !== "object") return;
15991
16014
  let nextShadowedStateNames = shadowedStateNames;
15992
- if (isFunctionLike$2(node)) {
16015
+ if (isFunctionLike$3(node)) {
15993
16016
  const localBindings = collectFunctionLocalBindings(node);
15994
16017
  if (localBindings.size > 0) {
15995
16018
  const merged = new Set(shadowedStateNames);
@@ -18246,7 +18269,7 @@ const isInsideClassBody = (node) => {
18246
18269
  let current = node.parent;
18247
18270
  while (current) {
18248
18271
  if (isNodeOfType(current, "ClassBody")) return true;
18249
- if (isFunctionLike$2(current)) return false;
18272
+ if (isFunctionLike$3(current)) return false;
18250
18273
  current = current.parent;
18251
18274
  }
18252
18275
  return false;
@@ -18950,7 +18973,7 @@ const isLodashMutatorCall = (callExpression) => {
18950
18973
  };
18951
18974
  //#endregion
18952
18975
  //#region src/plugin/utils/find-exported-function-body.ts
18953
- const isFunctionLike = (node) => {
18976
+ const isFunctionLike$1 = (node) => {
18954
18977
  if (!node) return false;
18955
18978
  return isNodeOfType(node, "FunctionDeclaration") || isNodeOfType(node, "FunctionExpression") || isNodeOfType(node, "ArrowFunctionExpression");
18956
18979
  };
@@ -18965,7 +18988,7 @@ const findExportedFunctionBody = (programRoot, exportedName) => {
18965
18988
  if (!isNodeOfType(declarator, "VariableDeclarator")) continue;
18966
18989
  if (!isNodeOfType(declarator.id, "Identifier")) continue;
18967
18990
  const initializer = declarator.init ? stripParenExpression(declarator.init) : null;
18968
- if (initializer && isFunctionLike(initializer)) localBindings.set(declarator.id.name, initializer);
18991
+ if (initializer && isFunctionLike$1(initializer)) localBindings.set(declarator.id.name, initializer);
18969
18992
  }
18970
18993
  };
18971
18994
  for (const statement of programRoot.body ?? []) {
@@ -19009,7 +19032,7 @@ const findExportedFunctionBody = (programRoot, exportedName) => {
19009
19032
  defaultExport = declaration;
19010
19033
  continue;
19011
19034
  }
19012
- if (isFunctionLike(declaration)) {
19035
+ if (isFunctionLike$1(declaration)) {
19013
19036
  defaultExport = declaration;
19014
19037
  continue;
19015
19038
  }
@@ -19170,7 +19193,7 @@ const resolveCrossFileFunctionExport = (fromFilename, source, exportedName) => {
19170
19193
  const resolveReducerFunction = (node, currentFilename) => {
19171
19194
  if (!node) return null;
19172
19195
  const unwrappedNode = stripParenExpression(node);
19173
- if (isFunctionLike$2(unwrappedNode)) return {
19196
+ if (isFunctionLike$3(unwrappedNode)) return {
19174
19197
  functionNode: unwrappedNode,
19175
19198
  crossFileSourceDisplay: null
19176
19199
  };
@@ -19178,7 +19201,7 @@ const resolveReducerFunction = (node, currentFilename) => {
19178
19201
  const initializer = findVariableInitializer(unwrappedNode, unwrappedNode.name)?.initializer;
19179
19202
  if (!initializer) return null;
19180
19203
  const unwrappedInitializer = stripParenExpression(initializer);
19181
- if (isFunctionLike$2(unwrappedInitializer)) return {
19204
+ if (isFunctionLike$3(unwrappedInitializer)) return {
19182
19205
  functionNode: unwrappedInitializer,
19183
19206
  crossFileSourceDisplay: null
19184
19207
  };
@@ -19292,11 +19315,11 @@ const canExpressionReturnOriginalReducerStateReference = (node, state) => {
19292
19315
  return false;
19293
19316
  };
19294
19317
  const collectReducerStateMutationsInExpressionOrStatement = (node, state) => {
19295
- if (isFunctionLike$2(node)) return [];
19318
+ if (isFunctionLike$3(node)) return [];
19296
19319
  const mutations = [];
19297
19320
  walkAst(node, (child) => {
19298
19321
  const unwrappedChild = stripParenExpression(child);
19299
- if (child !== node && isFunctionLike$2(unwrappedChild)) return false;
19322
+ if (child !== node && isFunctionLike$3(unwrappedChild)) return false;
19300
19323
  if (isNodeOfType(unwrappedChild, "AssignmentExpression")) {
19301
19324
  if (isNodeOfType(stripParenExpression(unwrappedChild.left), "MemberExpression") && isExpressionRootedInMutableReducerStateSource(unwrappedChild.left, state)) mutations.push({ node: unwrappedChild });
19302
19325
  return;
@@ -19401,7 +19424,7 @@ const updateReducerStateIdentityForIdentifierAssignment = (assignment, state) =>
19401
19424
  if (isExpressionReachableFromOriginalReducerState(assignment.right, state)) state.mutableStateSourceNames.add(name);
19402
19425
  };
19403
19426
  const analyzeReactUseReducerFunctionForStateMutation = (context, functionNode, reportedNodes, options) => {
19404
- if (!isFunctionLike$2(functionNode) || !isNodeOfType(functionNode.body, "BlockStatement")) return;
19427
+ if (!isFunctionLike$3(functionNode) || !isNodeOfType(functionNode.body, "BlockStatement")) return;
19405
19428
  const firstParam = functionNode.params?.[0];
19406
19429
  const stateName = isNodeOfType(firstParam, "Identifier") ? firstParam.name : isNodeOfType(firstParam, "AssignmentPattern") && isNodeOfType(firstParam.left, "Identifier") ? firstParam.left.name : null;
19407
19430
  if (!stateName) return;
@@ -20179,6 +20202,12 @@ const getReactDoctorStringSetting = (settings, settingName) => {
20179
20202
  const settingValue = readOwnPropertyValue(bag, settingName);
20180
20203
  return typeof settingValue === "string" ? settingValue : void 0;
20181
20204
  };
20205
+ const getReactDoctorNumberSetting = (settings, settingName) => {
20206
+ const bag = readReactDoctorSettingsBag(settings);
20207
+ if (!bag) return void 0;
20208
+ const settingValue = readOwnPropertyValue(bag, settingName);
20209
+ return typeof settingValue === "number" && Number.isFinite(settingValue) ? settingValue : void 0;
20210
+ };
20182
20211
  const getReactDoctorStringArraySetting = (settings, settingName) => {
20183
20212
  const bag = readReactDoctorSettingsBag(settings);
20184
20213
  if (!bag) return [];
@@ -21244,7 +21273,7 @@ const isTanStackServerFnHandler = (node) => {
21244
21273
  const isInsideServerOnlyScope = (node) => {
21245
21274
  let currentNode = node.parent ?? null;
21246
21275
  while (currentNode) {
21247
- if (isFunctionLike$2(currentNode)) {
21276
+ if (isFunctionLike$3(currentNode)) {
21248
21277
  if (hasUseServerDirective(currentNode) || isTanStackServerFnHandler(currentNode)) return true;
21249
21278
  }
21250
21279
  currentNode = currentNode.parent ?? null;
@@ -23399,7 +23428,7 @@ const isReactClassComponent = (classNode) => {
23399
23428
  const findEnclosingComponent = (node) => {
23400
23429
  let walker = node.parent;
23401
23430
  while (walker) {
23402
- if (isFunctionLike$2(walker)) {
23431
+ if (isFunctionLike$3(walker)) {
23403
23432
  const componentName = inferFunctionLikeName(walker);
23404
23433
  if (componentName && isReactComponentName(componentName) && expressionContainsJsxOrCreateElement(walker)) return {
23405
23434
  component: walker,
@@ -23651,6 +23680,35 @@ const noUsememoSimpleExpression = defineRule({
23651
23680
  });
23652
23681
  //#endregion
23653
23682
  //#region src/plugin/rules/design/no-wide-letter-spacing.ts
23683
+ const getJsxAttributeStringValue = (attributeValue) => {
23684
+ if (!attributeValue) return null;
23685
+ if (isNodeOfType(attributeValue, "Literal") && typeof attributeValue.value === "string") return attributeValue.value;
23686
+ if (isNodeOfType(attributeValue, "JSXExpressionContainer")) {
23687
+ const expression = attributeValue.expression;
23688
+ if (isNodeOfType(expression, "Literal") && typeof expression.value === "string") return expression.value;
23689
+ }
23690
+ return null;
23691
+ };
23692
+ const isTruthyBooleanJsxAttribute = (attributeValue) => {
23693
+ if (attributeValue === null) return true;
23694
+ if (isNodeOfType(attributeValue, "JSXExpressionContainer")) {
23695
+ const expression = attributeValue.expression;
23696
+ return isNodeOfType(expression, "Literal") && expression.value === true;
23697
+ }
23698
+ return false;
23699
+ };
23700
+ const hasUppercaseSiblingProp = (styleAttribute) => {
23701
+ const openingElement = styleAttribute.parent;
23702
+ if (!openingElement || !isNodeOfType(openingElement, "JSXOpeningElement")) return false;
23703
+ for (const attribute of openingElement.attributes ?? []) {
23704
+ if (!isNodeOfType(attribute, "JSXAttribute")) continue;
23705
+ if (!isNodeOfType(attribute.name, "JSXIdentifier")) continue;
23706
+ const attributeName = attribute.name.name;
23707
+ if (attributeName === "uppercase" && isTruthyBooleanJsxAttribute(attribute.value)) return true;
23708
+ if (attributeName === "textTransform" && getJsxAttributeStringValue(attribute.value) === "uppercase") return true;
23709
+ }
23710
+ return false;
23711
+ };
23654
23712
  const noWideLetterSpacing = defineRule({
23655
23713
  id: "no-wide-letter-spacing",
23656
23714
  title: "Wide letter spacing on body text",
@@ -23660,6 +23718,7 @@ const noWideLetterSpacing = defineRule({
23660
23718
  create: (context) => ({ JSXAttribute(node) {
23661
23719
  const expression = getInlineStyleExpression(node);
23662
23720
  if (!expression) return;
23721
+ if (hasUppercaseSiblingProp(node)) return;
23663
23722
  let isUppercase = false;
23664
23723
  let letterSpacingProperty = null;
23665
23724
  let letterSpacingEm = null;
@@ -24822,6 +24881,7 @@ const preferModuleScopeStaticValue = defineRule({
24822
24881
  tags: ["test-noise"],
24823
24882
  severity: "warn",
24824
24883
  category: "Architecture",
24884
+ disabledBy: ["react-compiler"],
24825
24885
  recommendation: "Move the value above the component, at the top of the file. It doesn't use local state, so rebuilding it each update is wasted and makes it look new every time.",
24826
24886
  create: (context) => ({ VariableDeclarator(node) {
24827
24887
  if (!isNodeOfType(node.id, "Identifier")) return;
@@ -25634,7 +25694,7 @@ const reduxUseselectorInlineDerivation = defineRule({
25634
25694
  if (!body) return;
25635
25695
  const returnedExpressions = [];
25636
25696
  if (isNodeOfType(body, "BlockStatement")) walkAst(body, (node) => {
25637
- if (node !== body && isFunctionLike$2(node)) return false;
25697
+ if (node !== body && isFunctionLike$3(node)) return false;
25638
25698
  if (isNodeOfType(node, "ReturnStatement")) {
25639
25699
  if (node.argument) returnedExpressions.push(node.argument);
25640
25700
  return false;
@@ -25977,7 +26037,7 @@ const hasOwnAwait = (functionBody) => {
25977
26037
  let found = false;
25978
26038
  walkAst(functionBody, (child) => {
25979
26039
  if (found) return;
25980
- if (child !== functionBody && isFunctionLike$2(child)) return false;
26040
+ if (child !== functionBody && isFunctionLike$3(child)) return false;
25981
26041
  if (isNodeOfType(child, "AwaitExpression")) found = true;
25982
26042
  });
25983
26043
  return found;
@@ -25996,7 +26056,7 @@ const setterIsCalledInAsyncContext = (componentBody, setterName) => {
25996
26056
  let found = false;
25997
26057
  walkAst(componentBody, (child) => {
25998
26058
  if (found) return;
25999
- if (!isFunctionLike$2(child)) return;
26059
+ if (!isFunctionLike$3(child)) return;
26000
26060
  const functionBody = child.body;
26001
26061
  if (!(Boolean(child.async) || hasOwnAwait(functionBody))) return;
26002
26062
  if (callsIdentifier(functionBody, setterName)) found = true;
@@ -26779,7 +26839,8 @@ const rerenderTransitionsScroll = defineRule({
26779
26839
  });
26780
26840
  //#endregion
26781
26841
  //#region src/plugin/rules/react-native/rn-animate-layout-property.ts
26782
- const REANIMATED_LAYOUT_KEYS = new Set([
26842
+ const REANIMATED_MODULE = "react-native-reanimated";
26843
+ const REANIMATED_LAYOUT_STYLE_PROPERTIES = new Set([
26783
26844
  "width",
26784
26845
  "height",
26785
26846
  "top",
@@ -26817,12 +26878,91 @@ const REANIMATED_LAYOUT_KEYS = new Set([
26817
26878
  "lineHeight",
26818
26879
  "letterSpacing"
26819
26880
  ]);
26881
+ const REANIMATED_ANIMATION_HELPERS = new Set([
26882
+ "withTiming",
26883
+ "withSpring",
26884
+ "withDecay",
26885
+ "withDelay",
26886
+ "withRepeat",
26887
+ "withSequence",
26888
+ "withClamp"
26889
+ ]);
26890
+ const findImportDeclaration = (symbol) => {
26891
+ let currentNode = symbol.declarationNode.parent;
26892
+ while (currentNode && !isNodeOfType(currentNode, "ImportDeclaration")) currentNode = currentNode.parent ?? null;
26893
+ return currentNode && isNodeOfType(currentNode, "ImportDeclaration") ? currentNode : null;
26894
+ };
26895
+ const isReanimatedImport = (symbol) => {
26896
+ const importDeclaration = findImportDeclaration(symbol);
26897
+ if (!importDeclaration) return false;
26898
+ return importDeclaration.source.value === REANIMATED_MODULE;
26899
+ };
26900
+ const getReanimatedNamedImport = (node, context) => {
26901
+ if (!isNodeOfType(node, "Identifier")) return null;
26902
+ const symbol = context.scopes.symbolFor(node);
26903
+ if (!symbol || symbol.kind !== "import") return null;
26904
+ if (!isReanimatedImport(symbol)) return null;
26905
+ const declarationNode = symbol.declarationNode;
26906
+ if (!isNodeOfType(declarationNode, "ImportSpecifier")) return null;
26907
+ const importedName = declarationNode.imported;
26908
+ if (isNodeOfType(importedName, "Identifier")) return importedName.name;
26909
+ if (isNodeOfType(importedName, "Literal") && typeof importedName.value === "string") return importedName.value;
26910
+ return null;
26911
+ };
26912
+ const isReanimatedNamespace = (node, context) => {
26913
+ if (!isNodeOfType(node, "Identifier")) return false;
26914
+ const symbol = context.scopes.symbolFor(node);
26915
+ if (!symbol || symbol.kind !== "import") return false;
26916
+ if (!isReanimatedImport(symbol)) return false;
26917
+ return isNodeOfType(symbol.declarationNode, "ImportNamespaceSpecifier");
26918
+ };
26919
+ const isUseAnimatedStyleCallee = (callee, context) => {
26920
+ if (isNodeOfType(callee, "Identifier")) return getReanimatedNamedImport(callee, context) === "useAnimatedStyle";
26921
+ if (!isNodeOfType(callee, "MemberExpression") || callee.computed) return false;
26922
+ if (!isNodeOfType(callee.property, "Identifier")) return false;
26923
+ if (callee.property.name !== "useAnimatedStyle") return false;
26924
+ return isReanimatedNamespace(callee.object, context);
26925
+ };
26926
+ const isReanimatedAnimationHelperCallee = (callee, context) => {
26927
+ if (isNodeOfType(callee, "Identifier")) {
26928
+ const importedName = getReanimatedNamedImport(callee, context);
26929
+ return importedName !== null && REANIMATED_ANIMATION_HELPERS.has(importedName);
26930
+ }
26931
+ if (!isNodeOfType(callee, "MemberExpression") || callee.computed) return false;
26932
+ if (!isNodeOfType(callee.property, "Identifier")) return false;
26933
+ if (!REANIMATED_ANIMATION_HELPERS.has(callee.property.name)) return false;
26934
+ return isReanimatedNamespace(callee.object, context);
26935
+ };
26936
+ const isFunctionLike = (node) => isNodeOfType(node, "ArrowFunctionExpression") || isNodeOfType(node, "FunctionExpression") || isNodeOfType(node, "FunctionDeclaration");
26937
+ const containsReanimatedAnimationHelperCall = (expression, context) => {
26938
+ const rootExpression = stripParenExpression(expression);
26939
+ let didFindAnimationHelper = false;
26940
+ walkAst(rootExpression, (node) => {
26941
+ if (didFindAnimationHelper) return false;
26942
+ if (node !== rootExpression && isFunctionLike(node)) return false;
26943
+ if (isNodeOfType(node, "CallExpression") && isReanimatedAnimationHelperCallee(node.callee, context)) {
26944
+ didFindAnimationHelper = true;
26945
+ return false;
26946
+ }
26947
+ });
26948
+ return didFindAnimationHelper;
26949
+ };
26820
26950
  const findReturnedObject = (callback) => {
26821
26951
  if (!isNodeOfType(callback, "ArrowFunctionExpression") && !isNodeOfType(callback, "FunctionExpression")) return null;
26822
- const body = callback.body;
26952
+ const body = stripParenExpression(callback.body);
26823
26953
  if (isNodeOfType(body, "ObjectExpression")) return body;
26824
26954
  if (!isNodeOfType(body, "BlockStatement")) return null;
26825
- for (const stmt of body.body ?? []) if (isNodeOfType(stmt, "ReturnStatement") && isNodeOfType(stmt.argument, "ObjectExpression")) return stmt.argument;
26955
+ for (const statement of body.body ?? []) {
26956
+ if (!isNodeOfType(statement, "ReturnStatement")) continue;
26957
+ if (!statement.argument) continue;
26958
+ const returnArgument = stripParenExpression(statement.argument);
26959
+ if (isNodeOfType(returnArgument, "ObjectExpression")) return returnArgument;
26960
+ }
26961
+ return null;
26962
+ };
26963
+ const getStaticPropertyName$1 = (property) => {
26964
+ if (!property.computed && isNodeOfType(property.key, "Identifier")) return property.key.name;
26965
+ if (isNodeOfType(property.key, "Literal") && typeof property.key.value === "string") return property.key.value;
26826
26966
  return null;
26827
26967
  };
26828
26968
  const rnAnimateLayoutProperty = defineRule({
@@ -26830,21 +26970,25 @@ const rnAnimateLayoutProperty = defineRule({
26830
26970
  title: "Animating a layout property",
26831
26971
  tags: ["test-noise"],
26832
26972
  requires: ["react-native"],
26833
- severity: "error",
26834
- recommendation: "Animating size or position props runs on the JS thread and can stutter. Animate `transform: [{ translateX/Y }, { scale }]` or `opacity` instead, which run on the GPU.",
26973
+ severity: "warn",
26974
+ category: "Performance",
26975
+ recommendation: "Prefer transform or opacity when a Reanimated animation helper drives purely visual motion; use layout-affecting styles only when the layout itself must change.",
26835
26976
  create: (context) => ({ CallExpression(node) {
26836
- if (!isNodeOfType(node.callee, "Identifier") || node.callee.name !== "useAnimatedStyle") return;
26977
+ if (!isUseAnimatedStyleCallee(node.callee, context)) return;
26837
26978
  const callback = node.arguments?.[0];
26838
26979
  if (!callback) return;
26839
26980
  const returnedObject = findReturnedObject(callback);
26840
26981
  if (!returnedObject) return;
26841
26982
  for (const property of returnedObject.properties ?? []) {
26842
26983
  if (!isNodeOfType(property, "Property")) continue;
26843
- if (!isNodeOfType(property.key, "Identifier")) continue;
26844
- if (!REANIMATED_LAYOUT_KEYS.has(property.key.name)) continue;
26984
+ const propertyName = getStaticPropertyName$1(property);
26985
+ if (propertyName === null) continue;
26986
+ if (!REANIMATED_LAYOUT_STYLE_PROPERTIES.has(propertyName)) continue;
26987
+ const propertyValue = property.value;
26988
+ if (!containsReanimatedAnimationHelperCall(propertyValue, context)) continue;
26845
26989
  context.report({
26846
26990
  node: property,
26847
- message: `Your users see stutter when useAnimatedStyle animates "${property.key.name}" on the layout thread.`
26991
+ message: `Reanimated can animate "${propertyName}", but this layout-affecting style recalculates layout while the animation runs; prefer transform or opacity when the motion is only visual.`
26848
26992
  });
26849
26993
  }
26850
26994
  } })
@@ -27052,7 +27196,6 @@ const LEGACY_EXPO_PACKAGE_REPLACEMENTS = new Map([
27052
27196
  ["expo-av", "expo-audio for audio and expo-video for video"],
27053
27197
  ["expo-permissions", "the permissions API in each module (e.g. Camera.requestPermissionsAsync())"],
27054
27198
  ["expo-app-loading", "expo-splash-screen"],
27055
- ["expo-linear-gradient", "the `backgroundImage` CSS gradient style prop (New Architecture) or expo-linear-gradient's successor"],
27056
27199
  ["react-native-fast-image", "expo-image (drop-in with caching, placeholders, and crossfades)"]
27057
27200
  ]);
27058
27201
  const EXPO_UI_MODULE_SOURCES = new Set([
@@ -27207,6 +27350,10 @@ const RECYCLABLE_LIST_PACKAGES = {
27207
27350
  LegendList: ["@legendapp/list"]
27208
27351
  };
27209
27352
  const SIZING_HINT_ATTRIBUTE_NAMES = new Set(["estimatedItemSize", "estimatedListSize"]);
27353
+ const isFlashListV2OrNewer = (context) => {
27354
+ const flashListMajorVersion = getReactDoctorNumberSetting(context.settings, "shopifyFlashListMajorVersion");
27355
+ return flashListMajorVersion !== void 0 && flashListMajorVersion >= 2;
27356
+ };
27210
27357
  const isEmptyArrayLiteral = (node) => {
27211
27358
  if (!isNodeOfType(node.value, "JSXExpressionContainer")) return false;
27212
27359
  const expression = node.value.expression;
@@ -27228,6 +27375,7 @@ const rnListMissingEstimatedItemSize = defineRule({
27228
27375
  break;
27229
27376
  }
27230
27377
  if (!canonicalRecyclerName) return;
27378
+ if (canonicalRecyclerName === "FlashList" && isFlashListV2OrNewer(context)) return;
27231
27379
  let hasSizingHint = false;
27232
27380
  let dataIsEmptyLiteral = false;
27233
27381
  let hasDataProp = false;
@@ -28170,37 +28318,22 @@ const rnNoSingleElementStyleArray = defineRule({
28170
28318
  } })
28171
28319
  });
28172
28320
  //#endregion
28173
- //#region src/plugin/rules/react-native/utils/scrollview_names.ts
28174
- const SCROLLVIEW_NAMES = new Set([
28175
- "ScrollView",
28176
- "FlatList",
28177
- "SectionList",
28178
- "VirtualizedList",
28179
- "KeyboardAwareScrollView"
28180
- ]);
28321
+ //#region src/plugin/utils/define-retired-rule.ts
28322
+ const defineRetiredRule = (rule) => defineRule({
28323
+ ...rule,
28324
+ defaultEnabled: false,
28325
+ lifecycle: "retired",
28326
+ create: () => ({})
28327
+ });
28181
28328
  //#endregion
28182
28329
  //#region src/plugin/rules/react-native/rn-prefer-content-inset-adjustment.ts
28183
- const rnPreferContentInsetAdjustment = defineRule({
28330
+ const rnPreferContentInsetAdjustment = defineRetiredRule({
28184
28331
  id: "rn-prefer-content-inset-adjustment",
28185
- title: "SafeAreaView instead of contentInsetAdjustment",
28332
+ title: "Manual safe-area inset adjustment",
28186
28333
  tags: ["test-noise"],
28187
28334
  requires: ["react-native"],
28188
28335
  severity: "warn",
28189
- recommendation: "Drop the SafeAreaView wrapper and set `contentInsetAdjustmentBehavior=\"automatic\"` on the ScrollView so the OS handles the safe area.",
28190
- create: (context) => ({ JSXElement(node) {
28191
- if (resolveJsxElementName(node.openingElement) !== "SafeAreaView") return;
28192
- for (const child of node.children ?? []) {
28193
- if (!isNodeOfType(child, "JSXElement")) continue;
28194
- const childName = resolveJsxElementName(child.openingElement);
28195
- if (!childName || !SCROLLVIEW_NAMES.has(childName)) continue;
28196
- if (childName === "KeyboardAwareScrollView") continue;
28197
- context.report({
28198
- node,
28199
- message: `Your users render an extra wrapper view from <SafeAreaView> around <${childName}>.`
28200
- });
28201
- return;
28202
- }
28203
- } })
28336
+ recommendation: "Prefer native content inset adjustment only when it replaces manual inset plumbing; SafeAreaView wrappers are valid and intentionally ignored."
28204
28337
  });
28205
28338
  //#endregion
28206
28339
  //#region src/react-native-dependency-names.ts
@@ -28586,6 +28719,15 @@ const rnPressableSharedValueMutation = defineRule({
28586
28719
  }
28587
28720
  });
28588
28721
  //#endregion
28722
+ //#region src/plugin/rules/react-native/utils/scrollview_names.ts
28723
+ const SCROLLVIEW_NAMES = new Set([
28724
+ "ScrollView",
28725
+ "FlatList",
28726
+ "SectionList",
28727
+ "VirtualizedList",
28728
+ "KeyboardAwareScrollView"
28729
+ ]);
28730
+ //#endregion
28589
28731
  //#region src/plugin/rules/react-native/rn-scrollview-dynamic-padding.ts
28590
28732
  const rnScrollviewDynamicPadding = defineRule({
28591
28733
  id: "rn-scrollview-dynamic-padding",
@@ -32281,7 +32423,7 @@ const isUseEffectEventSymbol = (symbol) => {
32281
32423
  const findEnclosingComponentOrHookFunction = (node) => {
32282
32424
  let current = node.parent;
32283
32425
  while (current) {
32284
- if (isFunctionLike$2(current)) {
32426
+ if (isFunctionLike$3(current)) {
32285
32427
  const resolvedName = inferFunctionName(current);
32286
32428
  if (resolvedName !== null && isReactComponentOrHookName(resolvedName)) return current;
32287
32429
  }
@@ -32302,7 +32444,7 @@ const isCallbackArgumentForAllowedEffectEventHook = (functionNode, additionalEff
32302
32444
  const isInsideAllowedEffectEventCallback = (node, additionalEffectHooksRegex) => {
32303
32445
  let current = node.parent;
32304
32446
  while (current) {
32305
- if (isFunctionLike$2(current) && isCallbackArgumentForAllowedEffectEventHook(current, additionalEffectHooksRegex)) return true;
32447
+ if (isFunctionLike$3(current) && isCallbackArgumentForAllowedEffectEventHook(current, additionalEffectHooksRegex)) return true;
32306
32448
  current = current.parent ?? null;
32307
32449
  }
32308
32450
  return false;
@@ -32640,7 +32782,7 @@ const containsAuthCheck = (rootNodes, allowedFunctionNames, genericMethodNames)
32640
32782
  let foundAuthCall = false;
32641
32783
  for (const rootNode of rootNodes) walkAst(rootNode, (child) => {
32642
32784
  if (foundAuthCall) return;
32643
- if (isFunctionLike$2(child)) return false;
32785
+ if (isFunctionLike$3(child)) return false;
32644
32786
  if (!isNodeOfType(child, "CallExpression")) return;
32645
32787
  if (getAuthCallName(child, allowedFunctionNames, genericMethodNames)) foundAuthCall = true;
32646
32788
  });
@@ -37254,7 +37396,7 @@ const reactDoctorRules = [
37254
37396
  rule: {
37255
37397
  ...rnAnimateLayoutProperty,
37256
37398
  framework: "react-native",
37257
- category: "Bugs",
37399
+ category: "Performance",
37258
37400
  tags: [...new Set(["react-native", ...rnAnimateLayoutProperty.tags ?? []])]
37259
37401
  }
37260
37402
  },
@@ -38119,7 +38261,7 @@ const appendNode = (builder, block, node) => {
38119
38261
  };
38120
38262
  const mapDescendantsToBlock = (builder, node, block) => {
38121
38263
  builder.nodeBlock.set(node, block);
38122
- if (isFunctionLike$2(node)) return;
38264
+ if (isFunctionLike$3(node)) return;
38123
38265
  const record = node;
38124
38266
  for (const key of Object.keys(record)) {
38125
38267
  if (key === "parent") continue;
@@ -38457,7 +38599,7 @@ const analyzeControlFlow = (program) => {
38457
38599
  body: program.body
38458
38600
  });
38459
38601
  const visit = (node) => {
38460
- if (isFunctionLike$2(node)) {
38602
+ if (isFunctionLike$3(node)) {
38461
38603
  const body = node.body;
38462
38604
  if (body) buildFor(node, body);
38463
38605
  }
@@ -38474,7 +38616,7 @@ const analyzeControlFlow = (program) => {
38474
38616
  const enclosingFunction = (node) => {
38475
38617
  let current = node;
38476
38618
  while (current) {
38477
- if (isFunctionLike$2(current)) return current;
38619
+ if (isFunctionLike$3(current)) return current;
38478
38620
  if (isNodeOfType(current, "Program")) return current;
38479
38621
  current = current.parent ?? null;
38480
38622
  }