oxlint-plugin-react-doctor 0.7.9-dev.d7d38d7 → 0.7.9-dev.d8a20e0

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 +167 -47
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -19996,6 +19996,28 @@ const jsLengthCheckFirst = defineRule({
19996
19996
  } })
19997
19997
  });
19998
19998
  //#endregion
19999
+ //#region src/plugin/utils/is-proven-global-namespace-reference.ts
20000
+ const isProvenGlobalObjectReference = (expression, scopes, visitedSymbolIds = /* @__PURE__ */ new Set()) => {
20001
+ const strippedExpression = stripParenExpression(expression);
20002
+ if (!isNodeOfType(strippedExpression, "Identifier")) return false;
20003
+ if ((strippedExpression.name === "globalThis" || strippedExpression.name === "window" || strippedExpression.name === "self" || strippedExpression.name === "global") && scopes.isGlobalReference(strippedExpression)) return true;
20004
+ const symbol = scopes.symbolFor(strippedExpression);
20005
+ if (!symbol?.initializer || symbol.kind !== "const" || visitedSymbolIds.has(symbol.id)) return false;
20006
+ visitedSymbolIds.add(symbol.id);
20007
+ return isProvenGlobalObjectReference(symbol.initializer, scopes, visitedSymbolIds);
20008
+ };
20009
+ const isProvenGlobalNamespaceReference = (expression, namespaceName, scopes, visitedSymbolIds = /* @__PURE__ */ new Set()) => {
20010
+ const strippedExpression = stripParenExpression(expression);
20011
+ if (isNodeOfType(strippedExpression, "Identifier")) {
20012
+ if (strippedExpression.name === namespaceName && scopes.isGlobalReference(strippedExpression)) return true;
20013
+ const symbol = scopes.symbolFor(strippedExpression);
20014
+ if (!symbol?.initializer || symbol.kind !== "const" || visitedSymbolIds.has(symbol.id)) return false;
20015
+ visitedSymbolIds.add(symbol.id);
20016
+ return isProvenGlobalNamespaceReference(symbol.initializer, namespaceName, scopes, visitedSymbolIds);
20017
+ }
20018
+ return isNodeOfType(strippedExpression, "MemberExpression") && getStaticPropertyName(strippedExpression) === namespaceName && isProvenGlobalObjectReference(strippedExpression.object, scopes);
20019
+ };
20020
+ //#endregion
19999
20021
  //#region src/plugin/rules/js-performance/js-min-max-loop.ts
20000
20022
  const builtinMutationByProgram = /* @__PURE__ */ new WeakMap();
20001
20023
  const RUNTIMELESS_SYMBOL_KINDS = new Set(["ts-interface", "ts-type-alias"]);
@@ -20052,26 +20074,6 @@ const isSafeFreshNumericArray = (arrayExpression) => {
20052
20074
  }
20053
20075
  return !(didFindPositiveZero && didFindNegativeZero);
20054
20076
  };
20055
- const isGlobalObjectReference = (expression, scopes, visitedSymbols = /* @__PURE__ */ new Set()) => {
20056
- const strippedExpression = stripParenExpression(expression);
20057
- if (!isNodeOfType(strippedExpression, "Identifier")) return false;
20058
- if ((strippedExpression.name === "globalThis" || strippedExpression.name === "window" || strippedExpression.name === "self" || strippedExpression.name === "global") && scopes.isGlobalReference(strippedExpression)) return true;
20059
- const symbol = scopes.symbolFor(strippedExpression);
20060
- if (!symbol?.initializer || symbol.kind !== "const" || visitedSymbols.has(symbol.id)) return false;
20061
- visitedSymbols.add(symbol.id);
20062
- return isGlobalObjectReference(symbol.initializer, scopes, visitedSymbols);
20063
- };
20064
- const resolvesToGlobalNamespace = (expression, namespaceName, scopes, visitedSymbols = /* @__PURE__ */ new Set()) => {
20065
- const strippedExpression = stripParenExpression(expression);
20066
- if (isNodeOfType(strippedExpression, "Identifier")) {
20067
- if (strippedExpression.name === namespaceName && scopes.isGlobalReference(strippedExpression)) return true;
20068
- const symbol = scopes.symbolFor(strippedExpression);
20069
- if (!symbol?.initializer || symbol.kind !== "const" || visitedSymbols.has(symbol.id)) return false;
20070
- visitedSymbols.add(symbol.id);
20071
- return resolvesToGlobalNamespace(symbol.initializer, namespaceName, scopes, visitedSymbols);
20072
- }
20073
- return isNodeOfType(strippedExpression, "MemberExpression") && getStaticPropertyName(strippedExpression) === namespaceName && isGlobalObjectReference(strippedExpression.object, scopes);
20074
- };
20075
20077
  const resolvesToGlobalMethod = (expression, namespaceName, methodNames, scopes, visitedSymbols = /* @__PURE__ */ new Set()) => {
20076
20078
  const strippedExpression = stripParenExpression(expression);
20077
20079
  if (isNodeOfType(strippedExpression, "Identifier")) {
@@ -20080,7 +20082,7 @@ const resolvesToGlobalMethod = (expression, namespaceName, methodNames, scopes,
20080
20082
  visitedSymbols.add(symbol.id);
20081
20083
  return resolvesToGlobalMethod(symbol.initializer, namespaceName, methodNames, scopes, visitedSymbols);
20082
20084
  }
20083
- return isNodeOfType(strippedExpression, "MemberExpression") && methodNames.has(getStaticPropertyName(strippedExpression) ?? "") && resolvesToGlobalNamespace(strippedExpression.object, namespaceName, scopes);
20085
+ return isNodeOfType(strippedExpression, "MemberExpression") && methodNames.has(getStaticPropertyName(strippedExpression) ?? "") && isProvenGlobalNamespaceReference(strippedExpression.object, namespaceName, scopes);
20084
20086
  };
20085
20087
  const resolvesToNativeArrayPrototype = (expression, scopes, visitedSymbols = /* @__PURE__ */ new Set()) => {
20086
20088
  const strippedExpression = stripParenExpression(expression);
@@ -20092,7 +20094,7 @@ const resolvesToNativeArrayPrototype = (expression, scopes, visitedSymbols = /*
20092
20094
  }
20093
20095
  if (isNodeOfType(strippedExpression, "MemberExpression")) {
20094
20096
  const propertyName = getStaticPropertyName(strippedExpression);
20095
- if (propertyName === "prototype") return resolvesToGlobalNamespace(strippedExpression.object, "Array", scopes);
20097
+ if (propertyName === "prototype") return isProvenGlobalNamespaceReference(strippedExpression.object, "Array", scopes);
20096
20098
  return propertyName === "__proto__" && isNodeOfType(stripParenExpression(strippedExpression.object), "ArrayExpression");
20097
20099
  }
20098
20100
  if (!isNodeOfType(strippedExpression, "CallExpression")) return false;
@@ -20103,23 +20105,23 @@ const resolvesToNativeArrayPrototype = (expression, scopes, visitedSymbols = /*
20103
20105
  const isGlobalNamespaceReplacementTarget = (target, namespaceName, scopes) => {
20104
20106
  const strippedTarget = stripParenExpression(target);
20105
20107
  if (isNodeOfType(strippedTarget, "Identifier")) return strippedTarget.name === namespaceName && scopes.isGlobalReference(strippedTarget);
20106
- return isNodeOfType(strippedTarget, "MemberExpression") && getStaticPropertyName(strippedTarget) === namespaceName && isGlobalObjectReference(strippedTarget.object, scopes);
20108
+ return isNodeOfType(strippedTarget, "MemberExpression") && getStaticPropertyName(strippedTarget) === namespaceName && isProvenGlobalObjectReference(strippedTarget.object, scopes);
20107
20109
  };
20108
20110
  const isUnsafeBuiltinMemberTarget = (target, targetFunction, scopes) => {
20109
20111
  const strippedTarget = stripParenExpression(target);
20110
20112
  if (!isNodeOfType(strippedTarget, "MemberExpression")) return false;
20111
20113
  const propertyName = getStaticPropertyName(strippedTarget);
20112
20114
  if (resolvesToNativeArrayPrototype(strippedTarget.object, scopes)) return propertyName === null || propertyName === "sort";
20113
- if (resolvesToGlobalNamespace(strippedTarget.object, "Math", scopes)) return propertyName === null || propertyName === targetFunction;
20114
- return isGlobalObjectReference(strippedTarget.object, scopes) && (propertyName === null || propertyName === "Math");
20115
+ if (isProvenGlobalNamespaceReference(strippedTarget.object, "Math", scopes)) return propertyName === null || propertyName === targetFunction;
20116
+ return isProvenGlobalObjectReference(strippedTarget.object, scopes) && (propertyName === null || propertyName === "Math");
20115
20117
  };
20116
20118
  const isUnsafeBuiltinMutationApiCall = (callExpression, targetFunction, scopes) => {
20117
20119
  const target = callExpression.arguments[0];
20118
20120
  if (!target) return false;
20119
20121
  let propertyName = null;
20120
20122
  if (resolvesToNativeArrayPrototype(target, scopes)) propertyName = "sort";
20121
- else if (resolvesToGlobalNamespace(target, "Math", scopes)) propertyName = targetFunction;
20122
- else if (isGlobalObjectReference(target, scopes)) propertyName = "Math";
20123
+ else if (isProvenGlobalNamespaceReference(target, "Math", scopes)) propertyName = targetFunction;
20124
+ else if (isProvenGlobalObjectReference(target, scopes)) propertyName = "Math";
20123
20125
  if (!propertyName) return false;
20124
20126
  const canObjectExpressionSetProperty = (properties) => {
20125
20127
  if (!isNodeOfType(properties, "ObjectExpression")) return true;
@@ -20170,7 +20172,7 @@ const hasUnsafeMathBinding = (node, scopes) => {
20170
20172
  let scope = scopes.scopeFor(node);
20171
20173
  while (scope) {
20172
20174
  const symbol = scope.symbolsByName.get("Math");
20173
- if (symbol && !RUNTIMELESS_SYMBOL_KINDS.has(symbol.kind)) return !(symbol.kind === "const" && symbol.initializer && resolvesToGlobalNamespace(symbol.initializer, "Math", scopes));
20175
+ if (symbol && !RUNTIMELESS_SYMBOL_KINDS.has(symbol.kind)) return !(symbol.kind === "const" && symbol.initializer && isProvenGlobalNamespaceReference(symbol.initializer, "Math", scopes));
20174
20176
  scope = scope.parent;
20175
20177
  }
20176
20178
  return false;
@@ -44369,11 +44371,110 @@ const isSameRefCurrentMember = (node, refSymbol, scopes) => {
44369
44371
  return isNodeOfType(receiver, "Identifier") && resolveConstIdentifierAlias(receiver, scopes)?.id === refSymbol.id;
44370
44372
  };
44371
44373
  const isSameRefCurrentAlias = (node, refSymbol, scopes) => {
44372
- if (isSameRefCurrentMember(node, refSymbol, scopes)) return true;
44373
- if (!isNodeOfType(node, "Identifier")) return false;
44374
- const aliasSymbol = scopes.symbolFor(node);
44374
+ const expression = stripParenExpression(node);
44375
+ if (isSameRefCurrentMember(expression, refSymbol, scopes)) return true;
44376
+ if (!isNodeOfType(expression, "Identifier")) return false;
44377
+ const aliasSymbol = scopes.symbolFor(expression);
44375
44378
  return aliasSymbol?.kind === "const" && aliasSymbol.initializer !== null && isSameRefCurrentMember(stripParenExpression(aliasSymbol.initializer), refSymbol, scopes);
44376
44379
  };
44380
+ const resolveImmutableInitializationValue = (node, scopes, visitedSymbolIds = /* @__PURE__ */ new Set()) => {
44381
+ const expression = stripParenExpression(node);
44382
+ if (!isNodeOfType(expression, "Identifier")) return expression;
44383
+ const symbol = scopes.symbolFor(expression);
44384
+ if (!symbol || symbol.kind !== "const" || !symbol.initializer || symbol.references.some((reference) => reference.flag !== "read") || visitedSymbolIds.has(symbol.id)) return null;
44385
+ visitedSymbolIds.add(symbol.id);
44386
+ return resolveImmutableInitializationValue(symbol.initializer, scopes, visitedSymbolIds);
44387
+ };
44388
+ const isProvablyTruthyInitializationValue = (node, scopes) => {
44389
+ const expression = resolveImmutableInitializationValue(node, scopes);
44390
+ return Boolean(expression && (isNodeOfType(expression, "NewExpression") || isNodeOfType(expression, "ObjectExpression") || isNodeOfType(expression, "ArrayExpression") || isNodeOfType(expression, "ArrowFunctionExpression") || isNodeOfType(expression, "FunctionExpression") || isNodeOfType(expression, "ClassExpression")));
44391
+ };
44392
+ const getInitializationConstructorName = (node, scopes) => {
44393
+ const expression = resolveImmutableInitializationValue(node, scopes);
44394
+ if (!expression) return null;
44395
+ if (isNodeOfType(expression, "NewExpression")) {
44396
+ const callee = stripParenExpression(expression.callee);
44397
+ return isNodeOfType(callee, "Identifier") ? callee.name : null;
44398
+ }
44399
+ return null;
44400
+ };
44401
+ const isClosedTruthyTypeDomain = (typeNode, initializationValue, scopes) => {
44402
+ const initializationExpression = stripParenExpression(initializationValue);
44403
+ if (isNodeOfType(typeNode, "TSTypeLiteral")) return isNodeOfType(initializationExpression, "ObjectExpression");
44404
+ if (isNodeOfType(typeNode, "TSArrayType") || isNodeOfType(typeNode, "TSTupleType")) return isNodeOfType(initializationExpression, "ArrayExpression");
44405
+ if (isNodeOfType(typeNode, "TSFunctionType") || isNodeOfType(typeNode, "TSConstructorType")) return isNodeOfType(initializationExpression, "ArrowFunctionExpression") || isNodeOfType(initializationExpression, "FunctionExpression") || isNodeOfType(initializationExpression, "ClassExpression");
44406
+ if (isNodeOfType(typeNode, "TSObjectKeyword")) return true;
44407
+ if (!isNodeOfType(typeNode, "TSTypeReference")) return false;
44408
+ const typeName = typeNode.typeName;
44409
+ return isNodeOfType(typeName, "Identifier") && typeName.name === getInitializationConstructorName(initializationExpression, scopes);
44410
+ };
44411
+ const refHasClosedFalsySentinelDomain = (refSymbol, initializationValue, scopes) => {
44412
+ const initializer = refSymbol.initializer ? stripParenExpression(refSymbol.initializer) : null;
44413
+ if (!initializer || !isNodeOfType(initializer, "CallExpression")) return false;
44414
+ const [initialValue] = initializer.arguments ?? [];
44415
+ if (!initialValue || isNodeOfType(initialValue, "SpreadElement") || !isEmptySentinel(initialValue, scopes)) return false;
44416
+ const [declaredType] = initializer.typeArguments?.params ?? [];
44417
+ if (!declaredType || !isNodeOfType(declaredType, "TSUnionType")) return false;
44418
+ let hasEmptySentinel = false;
44419
+ let hasTruthyDomain = false;
44420
+ for (const memberType of declaredType.types ?? []) {
44421
+ if (isNodeOfType(memberType, "TSNullKeyword") || isNodeOfType(memberType, "TSUndefinedKeyword")) {
44422
+ hasEmptySentinel = true;
44423
+ continue;
44424
+ }
44425
+ if (!isClosedTruthyTypeDomain(memberType, initializationValue, scopes)) return false;
44426
+ hasTruthyDomain = true;
44427
+ }
44428
+ return hasEmptySentinel && hasTruthyDomain;
44429
+ };
44430
+ const isSafeRefIdentifierUse = (identifier) => {
44431
+ const expressionRoot = findTransparentExpressionRoot(identifier);
44432
+ const parent = expressionRoot.parent;
44433
+ if (parent && isNodeOfType(parent, "VariableDeclarator") && parent.id === expressionRoot && parent.parent !== null && isNodeOfType(parent.parent, "VariableDeclaration") && parent.parent.kind === "const") return true;
44434
+ if (parent && isNodeOfType(parent, "MemberExpression") && parent.object === expressionRoot && getStaticPropertyName(parent) === "current") return true;
44435
+ if (!parent || !isNodeOfType(parent, "VariableDeclarator") || parent.init !== expressionRoot) return false;
44436
+ return isNodeOfType(parent.id, "Identifier") && parent.parent !== null && isNodeOfType(parent.parent, "VariableDeclaration") && parent.parent.kind === "const";
44437
+ };
44438
+ const refDoesNotEscape = (branchRoot, refSymbol, scopes) => {
44439
+ let didEscape = false;
44440
+ walkAst(branchRoot, (child) => {
44441
+ if (didEscape) return false;
44442
+ if (!isNodeOfType(child, "Identifier")) return;
44443
+ if (resolveConstIdentifierAlias(child, scopes)?.id !== refSymbol.id) return;
44444
+ if (child === refSymbol.bindingIdentifier || isSafeRefIdentifierUse(child)) return;
44445
+ didEscape = true;
44446
+ return false;
44447
+ });
44448
+ return !didEscape;
44449
+ };
44450
+ const expressionContainsRefCurrent = (expression, refSymbol, scopes) => {
44451
+ let didFindRefCurrent = false;
44452
+ walkAst(expression, (child) => {
44453
+ if (didFindRefCurrent) return false;
44454
+ if (resolveReactRefSymbol(child, scopes)?.id !== refSymbol.id) return;
44455
+ didFindRefCurrent = true;
44456
+ return false;
44457
+ });
44458
+ return didFindRefCurrent;
44459
+ };
44460
+ const hasNoCompetingRefCurrentWrite = (branchRoot, assignmentExpression, refSymbol, scopes) => {
44461
+ let writeCount = 0;
44462
+ walkAst(branchRoot, (child) => {
44463
+ if (writeCount > 1) return false;
44464
+ if (isNodeOfType(child, "AssignmentExpression")) {
44465
+ if (expressionContainsRefCurrent(child.left, refSymbol, scopes)) writeCount++;
44466
+ return;
44467
+ }
44468
+ if (isNodeOfType(child, "UpdateExpression") || isNodeOfType(child, "UnaryExpression") && child.operator === "delete") {
44469
+ if (expressionContainsRefCurrent(child.argument, refSymbol, scopes)) writeCount++;
44470
+ return;
44471
+ }
44472
+ if (isNodeOfType(child, "ForInStatement") || isNodeOfType(child, "ForOfStatement")) {
44473
+ if (expressionContainsRefCurrent(child.left, refSymbol, scopes)) writeCount++;
44474
+ }
44475
+ });
44476
+ return writeCount === 1 && expressionContainsRefCurrent(assignmentExpression.left, refSymbol, scopes);
44477
+ };
44377
44478
  const isEmptySentinel = (node, scopes) => isNodeOfType(node, "Literal") && node.value === null || isNodeOfType(node, "Identifier") && node.name === "undefined" && scopes.isGlobalReference(node);
44378
44479
  const hasRepeatedExecutionAncestor = (node, stop) => {
44379
44480
  let ancestor = node.parent;
@@ -44422,18 +44523,22 @@ const hasNoPriorCoExecutableWrite = (assignmentExpression, branchRoot, refSymbol
44422
44523
  const isDocumentedLazyInitialization = (assignmentExpression, refSymbol, scopes) => {
44423
44524
  if (assignmentExpression.operator === "??=" || assignmentExpression.operator === "||=") return true;
44424
44525
  if (assignmentExpression.operator !== "=") return false;
44526
+ const renderOwner = findRenderPhaseComponentOrHook(assignmentExpression, scopes);
44527
+ if (!renderOwner) return false;
44425
44528
  let descendant = assignmentExpression;
44426
44529
  let ancestor = descendant.parent;
44427
44530
  while (ancestor) {
44428
- if (isNodeOfType(ancestor, "IfStatement") && isNodeOfType(ancestor.test, "BinaryExpression") && [
44531
+ const test = isNodeOfType(ancestor, "IfStatement") ? stripParenExpression(ancestor.test) : null;
44532
+ 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;
44533
+ if (isNodeOfType(ancestor, "IfStatement") && isNodeOfType(test, "BinaryExpression") && [
44429
44534
  "===",
44430
44535
  "==",
44431
44536
  "!==",
44432
44537
  "!="
44433
- ].includes(ancestor.test.operator)) {
44434
- const { left, right } = ancestor.test;
44538
+ ].includes(test.operator)) {
44539
+ const { left, right } = test;
44435
44540
  const comparesEmptySentinel = isSameRefCurrentAlias(left, refSymbol, scopes) && isEmptySentinel(right, scopes) || isSameRefCurrentAlias(right, refSymbol, scopes) && isEmptySentinel(left, scopes);
44436
- const guardedBranch = ancestor.test.operator === "===" || ancestor.test.operator === "==" ? ancestor.consequent : ancestor.alternate;
44541
+ const guardedBranch = test.operator === "===" || test.operator === "==" ? ancestor.consequent : ancestor.alternate;
44437
44542
  if (comparesEmptySentinel && guardedBranch === descendant && guardedBranch && !hasRepeatedExecutionAncestor(assignmentExpression, guardedBranch) && hasNoPriorCoExecutableWrite(assignmentExpression, guardedBranch, refSymbol, scopes)) return true;
44438
44543
  }
44439
44544
  descendant = ancestor;
@@ -51558,6 +51663,31 @@ const preferModuleScopePureFunction = defineRule({
51558
51663
  }
51559
51664
  });
51560
51665
  //#endregion
51666
+ //#region src/plugin/utils/get-require-call-source.ts
51667
+ const getRequireCallSource = (expression) => {
51668
+ const unwrappedExpression = stripParenExpression(expression);
51669
+ if (isNodeOfType(unwrappedExpression, "MemberExpression")) return getRequireCallSource(unwrappedExpression.object);
51670
+ if (!isNodeOfType(unwrappedExpression, "CallExpression")) return null;
51671
+ if (!isNodeOfType(unwrappedExpression.callee, "Identifier") || unwrappedExpression.callee.name !== "require") return null;
51672
+ const [firstArgument] = unwrappedExpression.arguments ?? [];
51673
+ if (!firstArgument || !isNodeOfType(firstArgument, "Literal")) return null;
51674
+ return typeof firstArgument.value === "string" ? firstArgument.value : null;
51675
+ };
51676
+ //#endregion
51677
+ //#region src/plugin/utils/is-proven-node-crypto-namespace-reference.ts
51678
+ const NODE_CRYPTO_MODULE_SOURCES = new Set(["crypto", "node:crypto"]);
51679
+ const isProvenNodeCryptoNamespaceReference = (expression, scopes) => {
51680
+ const identifier = stripParenExpression(expression);
51681
+ if (!isNodeOfType(identifier, "Identifier")) return false;
51682
+ const symbol = resolveConstIdentifierAlias(identifier, scopes);
51683
+ if (!symbol) return false;
51684
+ if (symbol.kind === "import") {
51685
+ const importBinding = getImportBindingForName(identifier, symbol.name);
51686
+ return Boolean(importBinding && NODE_CRYPTO_MODULE_SOURCES.has(importBinding.source));
51687
+ }
51688
+ return Boolean(symbol.kind === "const" && symbol.initializer && NODE_CRYPTO_MODULE_SOURCES.has(getRequireCallSource(symbol.initializer) ?? ""));
51689
+ };
51690
+ //#endregion
51561
51691
  //#region src/plugin/rules/architecture/prefer-module-scope-static-value.ts
51562
51692
  const MUTATING_RECEIVER_METHOD_NAMES = new Set([...MUTATING_ARRAY_METHODS, ...MUTATING_COLLECTION_METHODS]);
51563
51693
  const isMutationContext = (referenceIdentifier) => {
@@ -51671,9 +51801,9 @@ const isImpureCall = (node, scopes) => {
51671
51801
  const callee = node.callee;
51672
51802
  if (isNodeOfType(callee, "Identifier")) return isImpureBareCallee(callee, scopes);
51673
51803
  if (!isNodeOfType(callee, "MemberExpression") || callee.computed) return false;
51674
- if (!isNodeOfType(callee.object, "Identifier")) return false;
51675
51804
  if (!isNodeOfType(callee.property, "Identifier")) return false;
51676
- return Boolean(IMPURE_MEMBER_RECEIVERS.get(callee.object.name)?.has(callee.property.name));
51805
+ for (const [receiverName, receiverMethodNames] of IMPURE_MEMBER_RECEIVERS) if (receiverMethodNames.has(callee.property.name) && (isProvenGlobalNamespaceReference(callee.object, receiverName, scopes) || receiverName === "crypto" && isProvenNodeCryptoNamespaceReference(callee.object, scopes))) return true;
51806
+ return false;
51677
51807
  };
51678
51808
  const containsImpureExpression = (expression, scopes) => {
51679
51809
  let foundImpure = false;
@@ -56442,16 +56572,6 @@ const rnListCallbackPerRow = defineRule({
56442
56572
  }
56443
56573
  });
56444
56574
  //#endregion
56445
- //#region src/plugin/utils/get-require-call-source.ts
56446
- const getRequireCallSource = (expression) => {
56447
- if (isNodeOfType(expression, "MemberExpression")) return getRequireCallSource(expression.object);
56448
- if (!isNodeOfType(expression, "CallExpression")) return null;
56449
- if (!isNodeOfType(expression.callee, "Identifier") || expression.callee.name !== "require") return null;
56450
- const [firstArgument] = expression.arguments ?? [];
56451
- if (!firstArgument || !isNodeOfType(firstArgument, "Literal")) return null;
56452
- return typeof firstArgument.value === "string" ? firstArgument.value : null;
56453
- };
56454
- //#endregion
56455
56575
  //#region src/plugin/utils/get-initializer-module-source.ts
56456
56576
  const getInitializerModuleSource = (contextNode, initializer) => {
56457
56577
  const requireSource = getRequireCallSource(initializer);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oxlint-plugin-react-doctor",
3
- "version": "0.7.9-dev.d7d38d7",
3
+ "version": "0.7.9-dev.d8a20e0",
4
4
  "description": "React Doctor rules for oxlint.",
5
5
  "keywords": [
6
6
  "accessibility",