oxlint-plugin-react-doctor 0.9.2-dev.5dc936e → 0.9.2-dev.5f23826

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 +66 -362
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -29461,11 +29461,6 @@ const jsCacheStorage = defineRule({
29461
29461
  });
29462
29462
  //#endregion
29463
29463
  //#region src/plugin/rules/js-performance/js-combine-iterations.ts
29464
- const SMALL_ARRAY_NON_MUTATING_METHODS = new Set([
29465
- ...CHAINABLE_ITERATION_METHODS,
29466
- "find",
29467
- "some"
29468
- ]);
29469
29464
  const isIteratorProducingCall = (callExpression, generatorNamesInFile) => {
29470
29465
  const callee = callExpression.callee;
29471
29466
  if (isNodeOfType(callee, "MemberExpression")) {
@@ -29577,34 +29572,21 @@ const isStringSplitRootedChain = (receiverNode) => {
29577
29572
  return false;
29578
29573
  };
29579
29574
  const isSmallLiteralArray = (node) => {
29580
- const arrayNode = stripParenExpression(node);
29581
- if (!isNodeOfType(arrayNode, "ArrayExpression")) return false;
29582
- const elements = arrayNode.elements ?? [];
29583
- if (elements.length === 0 || elements.length > 9) return false;
29575
+ if (!isNodeOfType(node, "ArrayExpression")) return false;
29576
+ const elements = node.elements ?? [];
29577
+ if (elements.length === 0 || elements.length > 8) return false;
29584
29578
  for (const element of elements) {
29585
29579
  if (!element) continue;
29586
29580
  if (isNodeOfType(element, "SpreadElement")) return false;
29587
29581
  }
29588
29582
  return true;
29589
29583
  };
29590
- const isNonMutatingSmallArrayMethodReference = (identifier) => {
29591
- const identifierRoot = findTransparentExpressionRoot(identifier);
29592
- const memberExpression = identifierRoot.parent;
29593
- if (!isNodeOfType(memberExpression, "MemberExpression") || memberExpression.object !== identifierRoot || !isNodeOfType(memberExpression.property, "Identifier") || !SMALL_ARRAY_NON_MUTATING_METHODS.has(memberExpression.property.name)) return false;
29594
- const callExpression = memberExpression.parent;
29595
- return isNodeOfType(callExpression, "CallExpression") && callExpression.callee === memberExpression;
29596
- };
29597
- const isSmallLiteralArrayRootedChain = (receiverNode, scopes) => {
29584
+ const isSmallLiteralArrayRootedChain = (receiverNode, smallConstArrayNames) => {
29598
29585
  let cursor = receiverNode;
29599
29586
  while (cursor) {
29600
29587
  cursor = stripParenExpression(cursor);
29601
29588
  if (isNodeOfType(cursor, "ArrayExpression")) return isSmallLiteralArray(cursor);
29602
- if (isNodeOfType(cursor, "Identifier")) {
29603
- const symbol = scopes.symbolFor(cursor);
29604
- if (!symbol?.initializer || !isSmallLiteralArray(symbol.initializer)) return false;
29605
- if (!isNodeOfType(symbol.declarationNode, "VariableDeclarator") || !isNodeOfType(symbol.declarationNode.id, "Identifier")) return false;
29606
- return (symbol.kind === "const" || symbol.kind === "let" || symbol.kind === "var") && symbol.references.every((reference) => reference.flag === "read" && isNonMutatingSmallArrayMethodReference(reference.identifier));
29607
- }
29589
+ if (isNodeOfType(cursor, "Identifier")) return smallConstArrayNames.has(cursor.name);
29608
29590
  if (!isNodeOfType(cursor, "CallExpression")) return false;
29609
29591
  if (!isChainPassThroughCall(cursor)) return false;
29610
29592
  const nextCallee = cursor.callee;
@@ -29613,6 +29595,22 @@ const isSmallLiteralArrayRootedChain = (receiverNode, scopes) => {
29613
29595
  }
29614
29596
  return false;
29615
29597
  };
29598
+ const collectSmallConstArrayNames = (programNode) => {
29599
+ const names = /* @__PURE__ */ new Set();
29600
+ const statements = programNode.body ?? [];
29601
+ for (const statement of statements) {
29602
+ const declaration = isNodeOfType(statement, "ExportNamedDeclaration") ? statement.declaration : statement;
29603
+ if (!declaration || !isNodeOfType(declaration, "VariableDeclaration")) continue;
29604
+ if (declaration.kind !== "const") continue;
29605
+ for (const declarator of declaration.declarations ?? []) {
29606
+ if (!isNodeOfType(declarator, "VariableDeclarator")) continue;
29607
+ if (!isNodeOfType(declarator.id, "Identifier")) continue;
29608
+ if (!declarator.init || !isSmallLiteralArray(declarator.init)) continue;
29609
+ names.add(declarator.id.name);
29610
+ }
29611
+ }
29612
+ return names;
29613
+ };
29616
29614
  const collectGeneratorNames = (programNode) => {
29617
29615
  const generatorNames = /* @__PURE__ */ new Set();
29618
29616
  walkAst(programNode, (child) => {
@@ -29633,11 +29631,16 @@ const jsCombineIterations = defineRule({
29633
29631
  create: (context) => {
29634
29632
  let programNode = null;
29635
29633
  let generatorNamesInFile = null;
29634
+ let smallConstArrayNames = null;
29636
29635
  const coveredChainCalls = /* @__PURE__ */ new WeakSet();
29637
29636
  const getGeneratorNamesInFile = () => {
29638
29637
  generatorNamesInFile ??= programNode ? collectGeneratorNames(programNode) : /* @__PURE__ */ new Set();
29639
29638
  return generatorNamesInFile;
29640
29639
  };
29640
+ const getSmallConstArrayNames = () => {
29641
+ smallConstArrayNames ??= programNode ? collectSmallConstArrayNames(programNode) : /* @__PURE__ */ new Set();
29642
+ return smallConstArrayNames;
29643
+ };
29641
29644
  return {
29642
29645
  Program(node) {
29643
29646
  programNode = node;
@@ -29667,7 +29670,7 @@ const jsCombineIterations = defineRule({
29667
29670
  if (isTypePredicateArrow(filterArgument)) return;
29668
29671
  }
29669
29672
  if (isReceiverChainIteratorRooted(innerCall.callee.object, getGeneratorNamesInFile())) return;
29670
- if (isSmallLiteralArrayRootedChain(innerCall.callee.object, context.scopes)) return;
29673
+ if (isSmallLiteralArrayRootedChain(innerCall.callee.object, getSmallConstArrayNames())) return;
29671
29674
  if (isStringSplitRootedChain(innerCall.callee.object)) return;
29672
29675
  coveredChainCalls.add(innerCall);
29673
29676
  context.report({
@@ -56087,13 +56090,9 @@ const isInitialOnlyPropName = (propName) => {
56087
56090
  return /^initial[A-Z]/.test(propName) || /^default[A-Z]/.test(propName) || /^seed[A-Z]/.test(propName) || /^starting[A-Z]/.test(propName) || /^baseline[A-Z]/.test(propName) || /^preset[A-Z]/.test(propName);
56088
56091
  };
56089
56092
  //#endregion
56090
- //#region src/plugin/utils/nextjs-page-data-export-names.ts
56091
- const NEXTJS_PAGE_DATA_EXPORT_NAMES = new Set(["getServerSideProps", "getStaticProps"]);
56092
- //#endregion
56093
56093
  //#region src/plugin/rules/state-and-effects/no-derived-use-state.ts
56094
56094
  const isInitialOnlySeedName = (propName) => isInitialOnlyPropName(propName) || propName === "initial" || propName === "autoFocus" || propName === "autoPlay" || propName === "startOpen" || /^initially[A-Z]/.test(propName) || /Initial([A-Z]|$)/.test(propName);
56095
56095
  const SNAPSHOT_STATE_NAME_PATTERN = /^(initial|previous|prev|preserved|saved|original|cached|snapshot|prior|debounced|deferred)([A-Z_]|$)/;
56096
- const INTERNAL_STATE_NAME_PATTERN = /^(internal|uncontrolled)([A-Z_]|$)/;
56097
56096
  const getStateSetterName = (useStateCall) => {
56098
56097
  const declarator = useStateCall.parent;
56099
56098
  if (!isNodeOfType(declarator, "VariableDeclarator")) return null;
@@ -56247,6 +56246,7 @@ const isDraftCommittedToParent = (componentFunction, stateValueName, isPropName)
56247
56246
  });
56248
56247
  return isCommitted;
56249
56248
  };
56249
+ const NEXTJS_PAGE_DATA_EXPORT_NAMES = new Set(["getServerSideProps", "getStaticProps"]);
56250
56250
  const isNextjsDataFetchingPage = (node) => {
56251
56251
  const program = findProgramRoot(node);
56252
56252
  if (!program) return false;
@@ -56290,48 +56290,6 @@ const isInRenderScope = (node, componentFunction) => {
56290
56290
  }
56291
56291
  return true;
56292
56292
  };
56293
- const isReferenceToBinding = (reference, bindingIdentifier, context) => {
56294
- if (!isNodeOfType(reference, "Identifier")) return false;
56295
- const bindingSymbol = context.scopes.symbolFor(bindingIdentifier);
56296
- if (!bindingSymbol) return false;
56297
- return (context.scopes.referenceFor(reference)?.resolvedSymbol)?.id === bindingSymbol.id;
56298
- };
56299
- const isControlledPropFallbackExpression = (expression, stateBinding, isPropName, context) => {
56300
- if (isNodeOfType(expression, "ConditionalExpression")) {
56301
- const consequent = unwrapInitializerSeed(expression.consequent);
56302
- const alternate = unwrapInitializerSeed(expression.alternate);
56303
- return isReferenceToBinding(consequent, stateBinding, context) && isPropDerivedArgument(alternate, isPropName) || isPropDerivedArgument(consequent, isPropName) && isReferenceToBinding(alternate, stateBinding, context);
56304
- }
56305
- return isNodeOfType(expression, "LogicalExpression") && expression.operator === "??" && isPropDerivedArgument(unwrapInitializerSeed(expression.left), isPropName) && isReferenceToBinding(unwrapInitializerSeed(expression.right), stateBinding, context);
56306
- };
56307
- const isUserEditableControlledFallback = (useStateCall, isPropName, context) => {
56308
- const declarator = useStateCall.parent;
56309
- if (!isNodeOfType(declarator, "VariableDeclarator")) return false;
56310
- if (!isNodeOfType(declarator.id, "ArrayPattern")) return false;
56311
- const stateBinding = declarator.id.elements?.[0];
56312
- const setterBinding = declarator.id.elements?.[1];
56313
- if (!isNodeOfType(stateBinding, "Identifier") || !isNodeOfType(setterBinding, "Identifier")) return false;
56314
- if (!INTERNAL_STATE_NAME_PATTERN.test(stateBinding.name)) return false;
56315
- const componentFunction = findEnclosingFunction$1(useStateCall);
56316
- if (!componentFunction) return false;
56317
- let hasControlledFallback = false;
56318
- let hasUserEdit = false;
56319
- walkAst(componentFunction, (child) => {
56320
- if (child !== componentFunction && isFunctionLike$1(child)) return false;
56321
- if (!hasControlledFallback && (isNodeOfType(child, "ConditionalExpression") || isNodeOfType(child, "LogicalExpression")) && isControlledPropFallbackExpression(child, stateBinding, isPropName, context)) hasControlledFallback = true;
56322
- });
56323
- walkAst(componentFunction, (child) => {
56324
- if (hasUserEdit) return false;
56325
- if (!isNodeOfType(child, "CallExpression")) return;
56326
- if (!isReferenceToBinding(child.callee, setterBinding, context)) return;
56327
- if (!isHandlerShapedReseed(child, componentFunction)) return;
56328
- const setterArgument = child.arguments?.[0];
56329
- if (!setterArgument || isPropDerivedArgument(unwrapInitializerSeed(setterArgument), isPropName)) return;
56330
- hasUserEdit = true;
56331
- return false;
56332
- });
56333
- return hasControlledFallback && hasUserEdit;
56334
- };
56335
56293
  const getStateValueName = (useStateCall) => {
56336
56294
  const declarator = useStateCall.parent;
56337
56295
  if (!isNodeOfType(declarator, "VariableDeclarator")) return null;
@@ -56396,7 +56354,6 @@ const noDerivedUseState = defineRule({
56396
56354
  const reportStalePropCopy = (propName) => {
56397
56355
  if (isIntentionalSnapshotState(node)) return;
56398
56356
  if (hasSessionDismissProp(propStackTracker.getCurrentPropNames())) return;
56399
- if (isUserEditableControlledFallback(node, propStackTracker.isPropName, context)) return;
56400
56357
  if (isDraftReseedOrRenderAdjusted(node, propStackTracker.isPropName)) return;
56401
56358
  if (isEffectDrivenResync(node)) return;
56402
56359
  if (isNextjsDataFetchingPage(node)) return;
@@ -67234,124 +67191,6 @@ const isInsideSnapshotHelper = (node) => {
67234
67191
  }
67235
67192
  return false;
67236
67193
  };
67237
- const findEnclosingNextjsPageDataFunction = (node) => {
67238
- let outermostFunction = null;
67239
- let cursor = node.parent;
67240
- while (cursor) {
67241
- if (isFunctionLike$1(cursor)) outermostFunction = cursor;
67242
- if (isNodeOfType(cursor, "Program")) {
67243
- if (!outermostFunction) return null;
67244
- for (const exportName of NEXTJS_PAGE_DATA_EXPORT_NAMES) {
67245
- const exportedValue = findExportedValue(cursor, exportName);
67246
- if (exportedValue && isAstDescendant(outermostFunction, exportedValue)) return outermostFunction;
67247
- }
67248
- return null;
67249
- }
67250
- cursor = cursor.parent ?? null;
67251
- }
67252
- return null;
67253
- };
67254
- const findConditionalReturnExpressionRoot = (node) => {
67255
- let expressionRoot = findTransparentExpressionRoot(node);
67256
- while (expressionRoot.parent && isNodeOfType(expressionRoot.parent, "ConditionalExpression") && (expressionRoot.parent.consequent === expressionRoot || expressionRoot.parent.alternate === expressionRoot)) expressionRoot = findTransparentExpressionRoot(expressionRoot.parent);
67257
- return expressionRoot;
67258
- };
67259
- const isReturnedPageDataResultBinding = (returnExpression, pageDataFunction, context) => {
67260
- const declarator = returnExpression.parent;
67261
- if (!isNodeOfType(declarator, "VariableDeclarator") || declarator.init !== returnExpression || !isNodeOfType(declarator.id, "Identifier") || findEnclosingFunction$1(declarator) !== pageDataFunction) return false;
67262
- const bindingSymbol = context.scopes.symbolFor(declarator.id);
67263
- if (!bindingSymbol || bindingSymbol.references.length !== 1) return false;
67264
- const referenceRoot = findTransparentExpressionRoot(bindingSymbol.references[0].identifier);
67265
- const returnStatement = referenceRoot.parent;
67266
- return isNodeOfType(returnStatement, "ReturnStatement") && returnStatement.argument === referenceRoot && findEnclosingFunction$1(returnStatement) === pageDataFunction;
67267
- };
67268
- const isSameShorthandPropertyValue = (node, property) => property.shorthand && (node === property.key || node === property.value);
67269
- const isValueForwardedThroughLiteralStructure = (node, structure) => {
67270
- const strippedNode = stripParenExpression(node);
67271
- const strippedStructure = stripParenExpression(structure);
67272
- if (strippedNode === strippedStructure) return true;
67273
- if (isNodeOfType(strippedStructure, "ConditionalExpression")) return isValueForwardedThroughLiteralStructure(strippedNode, strippedStructure.consequent) || isValueForwardedThroughLiteralStructure(strippedNode, strippedStructure.alternate);
67274
- if (isNodeOfType(strippedStructure, "ArrayExpression")) return strippedStructure.elements.some((element) => element && !isNodeOfType(element, "SpreadElement") && isValueForwardedThroughLiteralStructure(strippedNode, element));
67275
- if (!isNodeOfType(strippedStructure, "ObjectExpression")) return false;
67276
- return strippedStructure.properties.some((property) => {
67277
- if (isNodeOfType(property, "SpreadElement")) return isValueForwardedThroughLiteralStructure(strippedNode, property.argument);
67278
- if (!isNodeOfType(property, "Property")) return false;
67279
- if (isValueForwardedThroughLiteralStructure(strippedNode, property.value)) return true;
67280
- return isSameShorthandPropertyValue(strippedNode, property);
67281
- });
67282
- };
67283
- const isValueForwardedToPropertyValue = (node, property) => {
67284
- const directValue = findConditionalReturnExpressionRoot(node);
67285
- if (isValueForwardedThroughLiteralStructure(directValue, property.value)) return true;
67286
- return isSameShorthandPropertyValue(directValue, property);
67287
- };
67288
- const isInsideReturnedNextjsProps = (node, pageDataFunction, context) => {
67289
- let cursor = node.parent;
67290
- while (cursor && cursor !== pageDataFunction) {
67291
- if (isNodeOfType(cursor, "Property") && getStaticPropertyKeyName(cursor, { allowComputedString: true }) === "props" && isValueForwardedToPropertyValue(node, cursor)) {
67292
- const propertyContainer = cursor.parent;
67293
- if (!propertyContainer) return false;
67294
- const returnExpression = findConditionalReturnExpressionRoot(propertyContainer);
67295
- const returnStatement = returnExpression.parent;
67296
- if (isNodeOfType(returnStatement, "ReturnStatement") && findEnclosingFunction$1(returnStatement) === pageDataFunction) return true;
67297
- if (isNodeOfType(pageDataFunction, "ArrowFunctionExpression") && !isNodeOfType(pageDataFunction.body, "BlockStatement") && stripParenExpression(pageDataFunction.body) === stripParenExpression(returnExpression)) return true;
67298
- if (isReturnedPageDataResultBinding(returnExpression, pageDataFunction, context)) return true;
67299
- }
67300
- cursor = cursor.parent ?? null;
67301
- }
67302
- return false;
67303
- };
67304
- const isExpressionReturnedByFunction = (node, functionNode) => {
67305
- const returnExpression = findConditionalReturnExpressionRoot(node);
67306
- if (isNodeOfType(functionNode, "ArrowFunctionExpression") && !isNodeOfType(functionNode.body, "BlockStatement")) return stripParenExpression(functionNode.body) === stripParenExpression(returnExpression);
67307
- const returnStatement = returnExpression.parent;
67308
- return isNodeOfType(returnStatement, "ReturnStatement") && returnStatement.argument === returnExpression && findEnclosingFunction$1(returnStatement) === functionNode;
67309
- };
67310
- const isValueForwardedToBindingInitializer = (node, bindingInitializer) => {
67311
- if (isValueForwardedThroughLiteralStructure(findConditionalReturnExpressionRoot(node), bindingInitializer)) return true;
67312
- const initializer = stripParenExpression(bindingInitializer);
67313
- if (!isNodeOfType(initializer, "CallExpression")) return false;
67314
- const callee = stripParenExpression(initializer.callee);
67315
- return isFunctionLike$1(callee) && isExpressionReturnedByFunction(node, callee);
67316
- };
67317
- const findPageDataResultBinding = (node) => {
67318
- let cursor = node.parent;
67319
- while (cursor) {
67320
- if (isNodeOfType(cursor, "VariableDeclarator")) {
67321
- if (cursor.init && isNodeOfType(cursor.id, "Identifier") && isValueForwardedToBindingInitializer(node, cursor.init)) return cursor.id;
67322
- return null;
67323
- }
67324
- cursor = cursor.parent ?? null;
67325
- }
67326
- return null;
67327
- };
67328
- const isUsedToSerializeNextjsPageProps = (node, context) => {
67329
- if (!isInProjectDirectory(context, "pages") || isInProjectDirectory(context, "pages/api")) return false;
67330
- const pageDataFunction = findEnclosingNextjsPageDataFunction(node);
67331
- if (!pageDataFunction) return false;
67332
- if (isInsideReturnedNextjsProps(node, pageDataFunction, context)) return true;
67333
- const bindingIdentifier = findPageDataResultBinding(node);
67334
- const bindingSymbol = bindingIdentifier ? context.scopes.symbolFor(bindingIdentifier) : null;
67335
- if (!bindingSymbol) return false;
67336
- const aliasSymbols = collectConstAliasSymbols(bindingSymbol, context.scopes);
67337
- const aliasSymbolIds = new Set(aliasSymbols.map((aliasSymbol) => aliasSymbol.id));
67338
- let hasPagePropsReference = false;
67339
- for (const aliasSymbol of aliasSymbols) for (const reference of aliasSymbol.references) {
67340
- if (findEnclosingFunction$1(reference.identifier) !== pageDataFunction) return false;
67341
- if (isInsideReturnedNextjsProps(reference.identifier, pageDataFunction, context)) {
67342
- hasPagePropsReference = true;
67343
- continue;
67344
- }
67345
- const referenceRoot = findTransparentExpressionRoot(reference.identifier);
67346
- const declarator = referenceRoot.parent;
67347
- if (isNodeOfType(declarator, "VariableDeclarator") && declarator.init === referenceRoot && isNodeOfType(declarator.id, "Identifier")) {
67348
- const aliasSymbolForReference = context.scopes.symbolFor(declarator.id);
67349
- if (aliasSymbolForReference && aliasSymbolIds.has(aliasSymbolForReference.id)) continue;
67350
- }
67351
- return false;
67352
- }
67353
- return hasPagePropsReference;
67354
- };
67355
67194
  const noJsonParseStringifyClone = defineRule({
67356
67195
  id: "no-json-parse-stringify-clone",
67357
67196
  title: "JSON parse/stringify deep clone",
@@ -67369,7 +67208,6 @@ const noJsonParseStringifyClone = defineRule({
67369
67208
  if (isInsideSnapshotHelper(node)) return;
67370
67209
  if (isAssignedToNormalizationBinding(node)) return;
67371
67210
  if (isCatchParameterRoundTrip(firstArgument)) return;
67372
- if (isUsedToSerializeNextjsPageProps(node, context)) return;
67373
67211
  context.report({
67374
67212
  node,
67375
67213
  message: MESSAGE$35
@@ -79995,23 +79833,16 @@ const MAX_INITIATOR_RESOLUTION_DEPTH = 3;
79995
79833
  const STATE_DISPATCHER_HOOK_NAMES = new Set(["useState", "useReducer"]);
79996
79834
  const REF_HOOK_NAMES = new Set(["useRef"]);
79997
79835
  const MESSAGE$26 = "This promise chain runs in an effect, ends in a `.then` that sets state or mutates a ref, and has no `.catch` or enclosing try/catch, so a rejection leaves the state unset and surfaces as an unhandled rejection. Add a `.catch` handler on the chain (`.finally` does not count).";
79998
- const isKnownNonRejectingHandlerReturn = (expression, context, visitedBindingIdentifiers = /* @__PURE__ */ new Set()) => {
79836
+ const isKnownNonThenableHandlerReturn = (expression, context, visitedBindingIdentifiers = /* @__PURE__ */ new Set()) => {
79999
79837
  const strippedExpression = stripParenExpression(expression);
80000
79838
  if (isDefinitelyNonThenableValue(strippedExpression)) return true;
80001
- if (isNodeOfType(strippedExpression, "CallExpression") && isNodeOfType(strippedExpression.callee, "MemberExpression")) {
80002
- const receiver = stripParenExpression(strippedExpression.callee.object);
80003
- if (isNodeOfType(receiver, "Identifier") && receiver.name === "Promise" && context.scopes.isGlobalReference(receiver) && getStaticPropertyName(strippedExpression.callee) === "resolve") {
80004
- const resolvedValue = strippedExpression.arguments[0];
80005
- return !resolvedValue || !isNodeOfType(resolvedValue, "SpreadElement") && isKnownNonRejectingHandlerReturn(resolvedValue, context, visitedBindingIdentifiers);
80006
- }
80007
- }
80008
79839
  if (!isNodeOfType(strippedExpression, "Identifier")) return false;
80009
79840
  if (strippedExpression.name === "undefined" && context.scopes.isGlobalReference(strippedExpression)) return true;
80010
79841
  const symbol = context.scopes.symbolFor(strippedExpression);
80011
79842
  if (!symbol || visitedBindingIdentifiers.has(symbol.bindingIdentifier)) return false;
80012
79843
  visitedBindingIdentifiers.add(symbol.bindingIdentifier);
80013
79844
  const initializer = getDirectUnreassignedInitializer(symbol);
80014
- return Boolean(initializer && isKnownNonRejectingHandlerReturn(initializer, context, visitedBindingIdentifiers));
79845
+ return Boolean(initializer && isKnownNonThenableHandlerReturn(initializer, context, visitedBindingIdentifiers));
80015
79846
  };
80016
79847
  const isKnownNonRejectingHandler = (argument, context) => {
80017
79848
  if (!argument) return false;
@@ -80026,7 +79857,7 @@ const isKnownNonRejectingHandler = (argument, context) => {
80026
79857
  canReject = true;
80027
79858
  return false;
80028
79859
  }
80029
- if (isNodeOfType(child, "ReturnStatement") && child.argument && !isKnownNonRejectingHandlerReturn(child.argument, context)) {
79860
+ if (isNodeOfType(child, "ReturnStatement") && child.argument && !isKnownNonThenableHandlerReturn(child.argument, context)) {
80030
79861
  if (!isNodeOfType(stripParenExpression(child.argument), "CallExpression")) {
80031
79862
  canReject = true;
80032
79863
  return false;
@@ -80075,28 +79906,6 @@ const handlerHasPotentiallyThrowingMemberRead = (argument, context) => {
80075
79906
  });
80076
79907
  return hasPotentiallyThrowingMemberRead;
80077
79908
  };
80078
- const hasRejectionHandler = (chain, argument, context, allowTerminalCatchBlock) => {
80079
- if (!argument) return false;
80080
- if (!handlerHasPotentiallyThrowingMemberRead(argument, context) && (chainCarriesRejectionHandler(chain, context.scopes) || isKnownNonRejectingHandler(argument, context))) return true;
80081
- if (!allowTerminalCatchBlock) return false;
80082
- const candidate = stripParenExpression(argument);
80083
- const handler = isNodeOfType(candidate, "Identifier") ? resolveExactLocalFunction(candidate, context.scopes) : candidate;
80084
- if (!handler || !isFunctionLike$1(handler)) return isNodeOfType(candidate, "MemberExpression") || isNodeOfType(candidate, "Identifier") && candidate.name !== "undefined";
80085
- if (!isNodeOfType(handler.body, "BlockStatement")) return false;
80086
- let doesExplicitlyReject = false;
80087
- walkOwnFunctionScope(handler, (child) => {
80088
- if (doesExplicitlyReject) return false;
80089
- if (isNodeOfType(child, "ThrowStatement") || isNodeOfType(child, "AwaitExpression")) {
80090
- doesExplicitlyReject = true;
80091
- return false;
80092
- }
80093
- if (isNodeOfType(child, "ReturnStatement") && child.argument && !isKnownNonRejectingHandlerReturn(child.argument, context)) {
80094
- doesExplicitlyReject = true;
80095
- return false;
80096
- }
80097
- });
80098
- return !doesExplicitlyReject;
80099
- };
80100
79909
  const walkPromiseChain = (chainExpression, context) => {
80101
79910
  let cursor = stripParenExpression(chainExpression);
80102
79911
  let hasCatch = false;
@@ -80108,9 +79917,10 @@ const walkPromiseChain = (chainExpression, context) => {
80108
79917
  while (isNodeOfType(cursor, "CallExpression") && isNodeOfType(cursor.callee, "MemberExpression") && PROMISE_METHOD_NAMES.has(getStaticPropertyName(cursor.callee) ?? "")) {
80109
79918
  const methodName = getStaticPropertyName(cursor.callee);
80110
79919
  const rejectionHandlerArgument = methodName === "catch" ? cursor.arguments[0] : cursor.arguments[1];
80111
- if (!didReachTerminalThen && methodName === "catch" && hasRejectionHandler(cursor, rejectionHandlerArgument, context, true)) hasCatch = true;
79920
+ const hasAbsorbingRejectionHandler = !handlerHasPotentiallyThrowingMemberRead(rejectionHandlerArgument, context) && (chainCarriesRejectionHandler(cursor, context.scopes) || isKnownNonRejectingHandler(rejectionHandlerArgument, context));
79921
+ if (!didReachTerminalThen && methodName === "catch" && hasAbsorbingRejectionHandler) hasCatch = true;
80112
79922
  if (methodName === "then") {
80113
- if (!didReachTerminalThen && hasRejectionHandler(cursor, rejectionHandlerArgument, context, false)) hasRejectionHandlerArgument = true;
79923
+ if (!didReachTerminalThen && hasAbsorbingRejectionHandler) hasRejectionHandlerArgument = true;
80114
79924
  didReachTerminalThen = true;
80115
79925
  sawThen = true;
80116
79926
  const callbackArgument = cursor.arguments[0];
@@ -82437,45 +82247,6 @@ const noRefCallbackCleanupBeforeReact19 = defineRule({
82437
82247
  } })
82438
82248
  });
82439
82249
  //#endregion
82440
- //#region src/plugin/utils/contains-non-deterministic-source.ts
82441
- const NON_DETERMINISTIC_MEMBER_CALLS = new Set([
82442
- "Math.random",
82443
- "Date.now",
82444
- "performance.now",
82445
- "crypto.randomUUID",
82446
- "crypto.getRandomValues"
82447
- ]);
82448
- const NON_DETERMINISTIC_ID_GENERATOR_NAMES = new Set([
82449
- "nanoid",
82450
- "uuid",
82451
- "cuid",
82452
- "ulid",
82453
- "createId"
82454
- ]);
82455
- const isZeroArgDateConstruction = (node) => isNodeOfType(node, "NewExpression") && isNodeOfType(node.callee, "Identifier") && node.callee.name === "Date" && (node.arguments?.length ?? 0) === 0;
82456
- const containsNonDeterministicSource = (root) => {
82457
- let found = false;
82458
- walkAst(root, (child) => {
82459
- if (found) return false;
82460
- if (isFunctionLike$1(child)) return false;
82461
- if (isZeroArgDateConstruction(child)) {
82462
- found = true;
82463
- return false;
82464
- }
82465
- if (!isNodeOfType(child, "CallExpression")) return;
82466
- const callee = child.callee;
82467
- if (isNodeOfType(callee, "Identifier") && NON_DETERMINISTIC_ID_GENERATOR_NAMES.has(callee.name)) {
82468
- found = true;
82469
- return false;
82470
- }
82471
- if (isNodeOfType(callee, "MemberExpression") && isNodeOfType(callee.object, "Identifier") && isNodeOfType(callee.property, "Identifier") && NON_DETERMINISTIC_MEMBER_CALLS.has(`${callee.object.name}.${callee.property.name}`)) {
82472
- found = true;
82473
- return false;
82474
- }
82475
- });
82476
- return found;
82477
- };
82478
- //#endregion
82479
82250
  //#region src/plugin/rules/state-and-effects/no-ref-current-in-render.ts
82480
82251
  const REPEATED_ANCESTOR_TYPES = new Set([
82481
82252
  "DoWhileStatement",
@@ -82506,75 +82277,45 @@ const resolveImmutableInitializationValue = (node, scopes, visitedSymbolIds = /*
82506
82277
  };
82507
82278
  const isProvablyTruthyInitializationValue = (node, scopes) => {
82508
82279
  const expression = resolveImmutableInitializationValue(node, scopes);
82509
- if (!expression) return false;
82510
- if (isNodeOfType(expression, "CallExpression")) {
82511
- const callee = stripParenExpression(expression.callee);
82512
- return isNodeOfType(callee, "Identifier") && callee.name.startsWith("create");
82513
- }
82514
- return isNodeOfType(expression, "NewExpression") || isNodeOfType(expression, "ObjectExpression") || isNodeOfType(expression, "ArrayExpression") || isNodeOfType(expression, "ArrowFunctionExpression") || isNodeOfType(expression, "FunctionExpression") || isNodeOfType(expression, "ClassExpression");
82280
+ return Boolean(expression && (isNodeOfType(expression, "NewExpression") || isNodeOfType(expression, "ObjectExpression") || isNodeOfType(expression, "ArrayExpression") || isNodeOfType(expression, "ArrowFunctionExpression") || isNodeOfType(expression, "FunctionExpression") || isNodeOfType(expression, "ClassExpression")));
82515
82281
  };
82516
- const getInitializationValueName = (node, scopes) => {
82282
+ const getInitializationConstructorName = (node, scopes) => {
82517
82283
  const expression = resolveImmutableInitializationValue(node, scopes);
82518
82284
  if (!expression) return null;
82519
- if (isNodeOfType(expression, "NewExpression") || isNodeOfType(expression, "CallExpression")) {
82285
+ if (isNodeOfType(expression, "NewExpression")) {
82520
82286
  const callee = stripParenExpression(expression.callee);
82521
- if (!isNodeOfType(callee, "Identifier")) return null;
82522
- return callee.name.startsWith("create") && callee.name.length > 6 ? callee.name.slice(6) : callee.name;
82287
+ return isNodeOfType(callee, "Identifier") ? callee.name : null;
82523
82288
  }
82524
82289
  return null;
82525
82290
  };
82526
- const isMatchingReturnType = (typeNode, initializationValue, scopes) => {
82527
- if (!isNodeOfType(typeNode, "TSTypeReference")) return false;
82528
- const typeName = typeNode.typeName;
82529
- if (!isNodeOfType(typeName, "Identifier") || typeName.name !== "ReturnType") return false;
82530
- const [returnTypeArgument] = typeNode.typeArguments?.params ?? [];
82531
- if (!returnTypeArgument || !isNodeOfType(returnTypeArgument, "TSTypeQuery")) return false;
82532
- const queriedName = returnTypeArgument.exprName;
82533
- const expression = stripParenExpression(initializationValue);
82534
- if (!isNodeOfType(queriedName, "Identifier") || !isNodeOfType(expression, "CallExpression")) return false;
82535
- const callee = stripParenExpression(expression.callee);
82536
- if (!isNodeOfType(callee, "Identifier")) return false;
82537
- const queriedSymbol = scopes.symbolFor(queriedName);
82538
- const calleeSymbol = scopes.symbolFor(callee);
82539
- return queriedSymbol && calleeSymbol ? queriedSymbol.id === calleeSymbol.id : queriedName.name === callee.name;
82540
- };
82541
82291
  const isClosedTruthyTypeDomain = (typeNode, initializationValue, scopes) => {
82542
82292
  const initializationExpression = stripParenExpression(initializationValue);
82543
82293
  if (isNodeOfType(typeNode, "TSTypeLiteral")) return isNodeOfType(initializationExpression, "ObjectExpression");
82544
82294
  if (isNodeOfType(typeNode, "TSArrayType") || isNodeOfType(typeNode, "TSTupleType")) return isNodeOfType(initializationExpression, "ArrayExpression");
82545
82295
  if (isNodeOfType(typeNode, "TSFunctionType") || isNodeOfType(typeNode, "TSConstructorType")) return isNodeOfType(initializationExpression, "ArrowFunctionExpression") || isNodeOfType(initializationExpression, "FunctionExpression") || isNodeOfType(initializationExpression, "ClassExpression");
82546
82296
  if (isNodeOfType(typeNode, "TSObjectKeyword")) return true;
82547
- if (isNodeOfType(typeNode, "TSIndexedAccessType")) return isNodeOfType(initializationExpression, "ObjectExpression");
82548
82297
  if (!isNodeOfType(typeNode, "TSTypeReference")) return false;
82549
82298
  const typeName = typeNode.typeName;
82550
- if (isNodeOfType(initializationExpression, "ObjectExpression") || isMatchingReturnType(typeNode, initializationExpression, scopes)) return true;
82551
- return isNodeOfType(typeName, "Identifier") && typeName.name === getInitializationValueName(initializationExpression, scopes);
82299
+ return isNodeOfType(typeName, "Identifier") && typeName.name === getInitializationConstructorName(initializationExpression, scopes);
82552
82300
  };
82553
82301
  const refHasClosedFalsySentinelDomain = (refSymbol, initializationValue, scopes) => {
82554
82302
  const initializer = refSymbol.initializer ? stripParenExpression(refSymbol.initializer) : null;
82555
82303
  if (!initializer || !isNodeOfType(initializer, "CallExpression")) return false;
82556
82304
  const [initialValue] = initializer.arguments ?? [];
82557
- if (initialValue && isNodeOfType(initialValue, "SpreadElement") || initialValue && !isEmptySentinel(initialValue, scopes)) return false;
82305
+ if (!initialValue || isNodeOfType(initialValue, "SpreadElement") || !isEmptySentinel(initialValue, scopes)) return false;
82558
82306
  const [declaredType] = initializer.typeArguments?.params ?? [];
82559
- if (!declaredType) return false;
82560
- const domainTypes = isNodeOfType(declaredType, "TSUnionType") ? declaredType.types : [declaredType];
82307
+ if (!declaredType || !isNodeOfType(declaredType, "TSUnionType")) return false;
82308
+ let hasEmptySentinel = false;
82561
82309
  let hasTruthyDomain = false;
82562
- for (const memberType of domainTypes) {
82563
- if (isNodeOfType(memberType, "TSNullKeyword") || isNodeOfType(memberType, "TSUndefinedKeyword")) continue;
82310
+ for (const memberType of declaredType.types ?? []) {
82311
+ if (isNodeOfType(memberType, "TSNullKeyword") || isNodeOfType(memberType, "TSUndefinedKeyword")) {
82312
+ hasEmptySentinel = true;
82313
+ continue;
82314
+ }
82564
82315
  if (!isClosedTruthyTypeDomain(memberType, initializationValue, scopes)) return false;
82565
82316
  hasTruthyDomain = true;
82566
82317
  }
82567
- return hasTruthyDomain;
82568
- };
82569
- const refHasEmptySentinelInitializer = (refSymbol, scopes) => {
82570
- const initializer = refSymbol.initializer ? stripParenExpression(refSymbol.initializer) : null;
82571
- if (!initializer || !isNodeOfType(initializer, "CallExpression")) return false;
82572
- const [initialValue] = initializer.arguments ?? [];
82573
- return Boolean(!initialValue || !isNodeOfType(initialValue, "SpreadElement") && isEmptySentinel(initialValue, scopes));
82574
- };
82575
- const refHasDeclaredType = (refSymbol) => {
82576
- const initializer = refSymbol.initializer ? stripParenExpression(refSymbol.initializer) : null;
82577
- return Boolean(initializer && isNodeOfType(initializer, "CallExpression") && (initializer.typeArguments?.params.length ?? 0) > 0);
82318
+ return hasEmptySentinel && hasTruthyDomain;
82578
82319
  };
82579
82320
  const isSafeRefIdentifierUse = (identifier) => {
82580
82321
  const expressionRoot = findTransparentExpressionRoot(identifier);
@@ -82606,40 +82347,25 @@ const expressionContainsRefCurrent = (expression, refSymbol, scopes) => {
82606
82347
  });
82607
82348
  return didFindRefCurrent;
82608
82349
  };
82609
- const isEmptySentinel = (node, scopes) => {
82610
- const expression = stripParenExpression(node);
82611
- return isNodeOfType(expression, "Literal") && expression.value === null || isNodeOfType(expression, "Identifier") && expression.name === "undefined" && scopes.isGlobalReference(expression);
82612
- };
82613
- const isInitializationInputIndependent = (node, renderOwner, scopes, visitedSymbolIds = /* @__PURE__ */ new Set()) => {
82614
- let isInputIndependent = true;
82615
- walkAst(node, (child) => {
82616
- if (!isInputIndependent) return false;
82617
- if (resolveReactRefSymbol(child, scopes)) return false;
82618
- if (!isNodeOfType(child, "Identifier")) return;
82619
- const symbol = scopes.symbolFor(child);
82620
- if (!symbol) return;
82621
- if (symbol.kind === "import") return false;
82622
- if (symbol.kind === "let" || symbol.kind === "var" || symbol.kind === "using") {
82623
- isInputIndependent = false;
82624
- return false;
82350
+ const hasNoCompetingRefCurrentWrite = (branchRoot, assignmentExpression, refSymbol, scopes) => {
82351
+ let writeCount = 0;
82352
+ walkAst(branchRoot, (child) => {
82353
+ if (writeCount > 1) return false;
82354
+ if (isNodeOfType(child, "AssignmentExpression")) {
82355
+ if (expressionContainsRefCurrent(child.left, refSymbol, scopes)) writeCount++;
82356
+ return;
82625
82357
  }
82626
- if (isOutsideAllFunctions(symbol)) return false;
82627
- if (symbol.kind === "parameter") {
82628
- if (symbol.scope.node === renderOwner) isInputIndependent = false;
82629
- return false;
82358
+ if (isNodeOfType(child, "UpdateExpression") || isNodeOfType(child, "UnaryExpression") && child.operator === "delete") {
82359
+ if (expressionContainsRefCurrent(child.argument, refSymbol, scopes)) writeCount++;
82360
+ return;
82630
82361
  }
82631
- if (!symbol.initializer || symbol.references.some((reference) => reference.flag !== "read")) {
82632
- isInputIndependent = false;
82633
- return false;
82362
+ if (isNodeOfType(child, "ForInStatement") || isNodeOfType(child, "ForOfStatement")) {
82363
+ if (expressionContainsRefCurrent(child.left, refSymbol, scopes)) writeCount++;
82634
82364
  }
82635
- if (visitedSymbolIds.has(symbol.id)) return false;
82636
- visitedSymbolIds.add(symbol.id);
82637
- if (!isInitializationInputIndependent(symbol.initializer, renderOwner, scopes, visitedSymbolIds)) isInputIndependent = false;
82638
- return false;
82639
82365
  });
82640
- return isInputIndependent;
82366
+ return writeCount === 1 && expressionContainsRefCurrent(assignmentExpression.left, refSymbol, scopes);
82641
82367
  };
82642
- const isPredictableInitializationValue = (node, refSymbol, renderOwner, scopes, requiresClosedTruthyDomain) => isInitializationInputIndependent(node, renderOwner, scopes) && !containsNonDeterministicSource(node) && (isProvablyTruthyInitializationValue(node, scopes) && (!requiresClosedTruthyDomain || !refHasDeclaredType(refSymbol)) || refHasClosedFalsySentinelDomain(refSymbol, node, scopes));
82368
+ const isEmptySentinel = (node, scopes) => isNodeOfType(node, "Literal") && node.value === null || isNodeOfType(node, "Identifier") && node.name === "undefined" && scopes.isGlobalReference(node);
82643
82369
  const hasRepeatedExecutionAncestor = (node, stop) => {
82644
82370
  let ancestor = node.parent;
82645
82371
  while (ancestor && ancestor !== stop) {
@@ -82669,27 +82395,6 @@ const canExecuteTogether = (firstConstraints, secondConstraints) => {
82669
82395
  }
82670
82396
  return true;
82671
82397
  };
82672
- const hasNoCoExecutableCompetingWrite = (assignmentExpression, renderOwner, refSymbol, scopes) => {
82673
- const assignmentConstraints = getBranchConstraints(assignmentExpression, renderOwner);
82674
- const synchronouslyInvokedFunctions = collectSynchronouslyEffectInvokedFunctions(renderOwner, scopes);
82675
- let hasCompetingWrite = false;
82676
- walkAst(renderOwner, (child) => {
82677
- if (hasCompetingWrite) return false;
82678
- let writtenExpression = null;
82679
- if (isNodeOfType(child, "AssignmentExpression")) {
82680
- if (child === assignmentExpression) return;
82681
- writtenExpression = child.left;
82682
- } else if (isNodeOfType(child, "UpdateExpression") || isNodeOfType(child, "UnaryExpression") && child.operator === "delete") writtenExpression = child.argument;
82683
- else if (isNodeOfType(child, "ForInStatement") || isNodeOfType(child, "ForOfStatement")) writtenExpression = child.left;
82684
- const deferredExecutionBoundary = findDeferredExecutionBoundary(child);
82685
- const deferredWriteValue = isNodeOfType(child, "AssignmentExpression") && child.operator === "=" ? resolveImmutableInitializationValue(child.right, scopes) : null;
82686
- const isDeferredTruthyWrite = deferredExecutionBoundary !== null && deferredExecutionBoundary !== renderOwner && !synchronouslyInvokedFunctions.has(deferredExecutionBoundary) && !executesDuringRender(deferredExecutionBoundary, scopes) && deferredWriteValue !== null && !isNodeOfType(deferredWriteValue, "CallExpression") && isProvablyTruthyInitializationValue(deferredWriteValue, scopes);
82687
- if (!writtenExpression || isDeferredTruthyWrite || !expressionContainsRefCurrent(writtenExpression, refSymbol, scopes) || !canExecuteTogether(assignmentConstraints, getBranchConstraints(child, renderOwner))) return;
82688
- hasCompetingWrite = true;
82689
- return false;
82690
- });
82691
- return !hasCompetingWrite;
82692
- };
82693
82398
  const hasNoPriorCoExecutableWrite = (assignmentExpression, branchRoot, refSymbol, scopes) => {
82694
82399
  const assignmentConstraints = getBranchConstraints(assignmentExpression, branchRoot);
82695
82400
  const assignmentStart = getRangeStart(assignmentExpression);
@@ -82705,17 +82410,16 @@ const hasNoPriorCoExecutableWrite = (assignmentExpression, branchRoot, refSymbol
82705
82410
  });
82706
82411
  return !hasCoExecutableWrite;
82707
82412
  };
82708
- const isPredictableGuardedInitialization = (assignmentExpression, guardedBranch, renderOwner, refSymbol, scopes, requiresClosedTruthyDomain) => refHasEmptySentinelInitializer(refSymbol, scopes) && isPredictableInitializationValue(assignmentExpression.right, refSymbol, renderOwner, scopes, requiresClosedTruthyDomain) && !hasRepeatedExecutionAncestor(assignmentExpression, guardedBranch) && (guardedBranch === renderOwner || !hasRepeatedExecutionAncestor(guardedBranch, renderOwner)) && hasNoPriorCoExecutableWrite(assignmentExpression, renderOwner, refSymbol, scopes) && hasNoCoExecutableCompetingWrite(assignmentExpression, renderOwner, refSymbol, scopes) && refDoesNotEscape(renderOwner, refSymbol, scopes);
82709
82413
  const isDocumentedLazyInitialization = (assignmentExpression, refSymbol, scopes) => {
82414
+ if (assignmentExpression.operator === "??=" || assignmentExpression.operator === "||=") return true;
82415
+ if (assignmentExpression.operator !== "=") return false;
82710
82416
  const renderOwner = findRenderPhaseComponentOrHook(assignmentExpression, scopes);
82711
82417
  if (!renderOwner) return false;
82712
- if (assignmentExpression.operator === "??=" || assignmentExpression.operator === "||=") return isPredictableGuardedInitialization(assignmentExpression, renderOwner, renderOwner, refSymbol, scopes, assignmentExpression.operator === "||=");
82713
- if (assignmentExpression.operator !== "=") return false;
82714
82418
  let descendant = assignmentExpression;
82715
82419
  let ancestor = descendant.parent;
82716
82420
  while (ancestor) {
82717
82421
  const test = isNodeOfType(ancestor, "IfStatement") ? stripParenExpression(ancestor.test) : null;
82718
- if (isNodeOfType(ancestor, "IfStatement") && test && isNodeOfType(test, "UnaryExpression") && test.operator === "!" && isSameRefCurrentAlias(test.argument, refSymbol, scopes) && ancestor.consequent === descendant && isPredictableGuardedInitialization(assignmentExpression, ancestor.consequent, renderOwner, refSymbol, scopes, true)) return true;
82422
+ if (isNodeOfType(ancestor, "IfStatement") && test && isNodeOfType(test, "UnaryExpression") && test.operator === "!" && isSameRefCurrentAlias(test.argument, refSymbol, scopes) && ancestor.consequent === descendant && isProvablyTruthyInitializationValue(assignmentExpression.right, scopes) && refHasClosedFalsySentinelDomain(refSymbol, assignmentExpression.right, scopes) && !hasRepeatedExecutionAncestor(assignmentExpression, ancestor.consequent) && !hasRepeatedExecutionAncestor(ancestor, renderOwner) && hasNoPriorCoExecutableWrite(assignmentExpression, ancestor.consequent, refSymbol, scopes) && hasNoCompetingRefCurrentWrite(renderOwner, assignmentExpression, refSymbol, scopes) && refDoesNotEscape(renderOwner, refSymbol, scopes)) return true;
82719
82423
  if (isNodeOfType(ancestor, "IfStatement") && isNodeOfType(test, "BinaryExpression") && [
82720
82424
  "===",
82721
82425
  "==",
@@ -82725,7 +82429,7 @@ const isDocumentedLazyInitialization = (assignmentExpression, refSymbol, scopes)
82725
82429
  const { left, right } = test;
82726
82430
  const comparesEmptySentinel = isSameRefCurrentAlias(left, refSymbol, scopes) && isEmptySentinel(right, scopes) || isSameRefCurrentAlias(right, refSymbol, scopes) && isEmptySentinel(left, scopes);
82727
82431
  const guardedBranch = test.operator === "===" || test.operator === "==" ? ancestor.consequent : ancestor.alternate;
82728
- if (comparesEmptySentinel && guardedBranch === descendant && guardedBranch && isPredictableGuardedInitialization(assignmentExpression, guardedBranch, renderOwner, refSymbol, scopes, false)) return true;
82432
+ if (comparesEmptySentinel && guardedBranch === descendant && guardedBranch && !hasRepeatedExecutionAncestor(assignmentExpression, guardedBranch) && hasNoPriorCoExecutableWrite(assignmentExpression, guardedBranch, refSymbol, scopes)) return true;
82729
82433
  }
82730
82434
  descendant = ancestor;
82731
82435
  ancestor = descendant.parent;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oxlint-plugin-react-doctor",
3
- "version": "0.9.2-dev.5dc936e",
3
+ "version": "0.9.2-dev.5f23826",
4
4
  "description": "React Doctor rules for oxlint.",
5
5
  "keywords": [
6
6
  "accessibility",