oxlint-plugin-react-doctor 0.7.8-dev.9256423 → 0.7.8-dev.ece35b3

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 +2 -416
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -22317,7 +22317,7 @@ const isReactSlotType = (typeNode, environment, activeDeclarations) => {
22317
22317
  }
22318
22318
  return environment.reactSlotTypeBindings.has(typeName);
22319
22319
  };
22320
- const getPropertyName$1 = (property) => {
22320
+ const getPropertyName = (property) => {
22321
22321
  if (!isNodeOfType(property, "TSPropertySignature") || property.computed) return null;
22322
22322
  if (isNodeOfType(property.key, "Identifier")) return property.key.name;
22323
22323
  if (isNodeOfType(property.key, "Literal") && typeof property.key.value === "string") return property.key.value;
@@ -22329,7 +22329,7 @@ const collectSlotPropertyNames = (propsType, environment, slotPropertyNames, act
22329
22329
  if (isNodeOfType(propsType, "TSInterfaceDeclaration")) members = propsType.body.body;
22330
22330
  if (members) {
22331
22331
  for (const member of members) {
22332
- const propertyName = getPropertyName$1(member);
22332
+ const propertyName = getPropertyName(member);
22333
22333
  if (!propertyName || !isNodeOfType(member, "TSPropertySignature")) continue;
22334
22334
  const annotation = member.typeAnnotation;
22335
22335
  if (annotation && isNodeOfType(annotation, "TSTypeAnnotation") && isReactSlotType(annotation.typeAnnotation, environment, /* @__PURE__ */ new Set())) slotPropertyNames.add(propertyName);
@@ -42992,31 +42992,6 @@ const noRenderReturnValue = defineRule({
42992
42992
  });
42993
42993
  //#endregion
42994
42994
  //#region src/plugin/rules/state-and-effects/no-reset-all-state-on-prop-change.ts
42995
- const SYNCHRONOUS_ARRAY_CALLBACK_METHOD_NAMES = new Set([
42996
- "every",
42997
- "filter",
42998
- "find",
42999
- "findIndex",
43000
- "flatMap",
43001
- "forEach",
43002
- "map",
43003
- "reduce",
43004
- "reduceRight",
43005
- "some"
43006
- ]);
43007
- const createConstantFormula = (constantValue) => ({
43008
- kind: "constant",
43009
- constantValue
43010
- });
43011
- const createNotFormula = (formula) => ({
43012
- kind: "not",
43013
- left: formula
43014
- });
43015
- const createBinaryFormula = (kind, left, right) => ({
43016
- kind,
43017
- left,
43018
- right
43019
- });
43020
42995
  const isUndefinedNode = (node) => {
43021
42996
  if (node === null || node === void 0) return true;
43022
42997
  return isNodeOfType(node, "Identifier") && node.name === "undefined";
@@ -43078,241 +43053,6 @@ const getLivePropExpressionIdentity = (analysis, context, node, visitedSymbolIds
43078
43053
  }
43079
43054
  return null;
43080
43055
  };
43081
- const getLivePropAtomKey = (identity) => `prop:${identity.propSymbolId}:${JSON.stringify(identity.memberPath)}:${identity.booleanNormalization}`;
43082
- const getBooleanFormula$1 = (analysis, context, node, protectedSymbolIds, visitedSymbolIds = /* @__PURE__ */ new Set()) => {
43083
- const expression = stripParenExpression(node);
43084
- if (isNodeOfType(expression, "Literal")) return createConstantFormula(Boolean(expression.value));
43085
- if (isNodeOfType(expression, "Identifier")) {
43086
- if (expression.name === "undefined" && context.scopes.isGlobalReference(expression)) return createConstantFormula(false);
43087
- const symbol = context.scopes.symbolFor(expression);
43088
- if (!symbol) return null;
43089
- if (!protectedSymbolIds.has(symbol.id) && symbol.kind === "const" && !visitedSymbolIds.has(symbol.id) && isNodeOfType(symbol.declarationNode, "VariableDeclarator") && symbol.declarationNode.id === symbol.bindingIdentifier) {
43090
- const initializer = getDirectConstInitializer(symbol);
43091
- if (initializer) {
43092
- visitedSymbolIds.add(symbol.id);
43093
- const initializerFormula = getBooleanFormula$1(analysis, context, initializer, protectedSymbolIds, visitedSymbolIds);
43094
- if (initializerFormula) return initializerFormula;
43095
- }
43096
- }
43097
- return {
43098
- kind: "atom",
43099
- atomKey: `symbol:${symbol.id}`
43100
- };
43101
- }
43102
- if (isNodeOfType(expression, "MemberExpression")) {
43103
- const identity = getLivePropExpressionIdentity(analysis, context, expression);
43104
- return identity ? {
43105
- kind: "atom",
43106
- atomKey: getLivePropAtomKey(identity)
43107
- } : null;
43108
- }
43109
- if (isNodeOfType(expression, "UnaryExpression") && expression.operator === "!") {
43110
- const argumentFormula = getBooleanFormula$1(analysis, context, expression.argument, protectedSymbolIds, visitedSymbolIds);
43111
- return argumentFormula ? createNotFormula(argumentFormula) : null;
43112
- }
43113
- if (isNodeOfType(expression, "CallExpression") && isNodeOfType(expression.callee, "Identifier") && expression.callee.name === "Boolean" && context.scopes.isGlobalReference(expression.callee) && expression.arguments.length === 1 && !isNodeOfType(expression.arguments[0], "SpreadElement")) return getBooleanFormula$1(analysis, context, expression.arguments[0], protectedSymbolIds, visitedSymbolIds);
43114
- if (isNodeOfType(expression, "LogicalExpression") && (expression.operator === "&&" || expression.operator === "||")) {
43115
- const leftFormula = getBooleanFormula$1(analysis, context, expression.left, protectedSymbolIds, new Set(visitedSymbolIds));
43116
- const rightFormula = getBooleanFormula$1(analysis, context, expression.right, protectedSymbolIds, new Set(visitedSymbolIds));
43117
- if (!leftFormula || !rightFormula) return null;
43118
- return createBinaryFormula(expression.operator === "&&" ? "and" : "or", leftFormula, rightFormula);
43119
- }
43120
- if (isNodeOfType(expression, "ConditionalExpression")) {
43121
- const testFormula = getBooleanFormula$1(analysis, context, expression.test, protectedSymbolIds, new Set(visitedSymbolIds));
43122
- const consequentFormula = getBooleanFormula$1(analysis, context, expression.consequent, protectedSymbolIds, new Set(visitedSymbolIds));
43123
- const alternateFormula = getBooleanFormula$1(analysis, context, expression.alternate, protectedSymbolIds, new Set(visitedSymbolIds));
43124
- if (!testFormula || !consequentFormula || !alternateFormula) return null;
43125
- return createBinaryFormula("or", createBinaryFormula("and", testFormula, consequentFormula), createBinaryFormula("and", createNotFormula(testFormula), alternateFormula));
43126
- }
43127
- if (isNodeOfType(expression, "BinaryExpression") && (expression.operator === "===" || expression.operator === "==" || expression.operator === "!==" || expression.operator === "!=")) {
43128
- const leftIsBoolean = isNodeOfType(expression.left, "Literal") && typeof expression.left.value === "boolean";
43129
- if (leftIsBoolean === (isNodeOfType(expression.right, "Literal") && typeof expression.right.value === "boolean")) return null;
43130
- const booleanLiteral = leftIsBoolean ? expression.left : expression.right;
43131
- const comparedFormula = getBooleanFormula$1(analysis, context, leftIsBoolean ? expression.right : expression.left, protectedSymbolIds, visitedSymbolIds);
43132
- if (!comparedFormula || !isNodeOfType(booleanLiteral, "Literal")) return null;
43133
- return (expression.operator === "===" || expression.operator === "==" ? booleanLiteral.value : !booleanLiteral.value) ? comparedFormula : createNotFormula(comparedFormula);
43134
- }
43135
- return null;
43136
- };
43137
- const getRequiredTruthyConditions = (analysis, context, node, protectedSymbolIds) => {
43138
- const formula = getBooleanFormula$1(analysis, context, node, protectedSymbolIds);
43139
- if (formula) return [formula];
43140
- const expression = stripParenExpression(node);
43141
- if (!isNodeOfType(expression, "LogicalExpression") || expression.operator !== "&&") return [];
43142
- return [...getRequiredTruthyConditions(analysis, context, expression.left, protectedSymbolIds), ...getRequiredTruthyConditions(analysis, context, expression.right, protectedSymbolIds)];
43143
- };
43144
- const evaluateBooleanFormula$1 = (formula, assignments) => {
43145
- if (formula.kind === "constant") return formula.constantValue ?? null;
43146
- if (formula.kind === "atom") return formula.atomKey === void 0 ? null : assignments.get(formula.atomKey) ?? null;
43147
- if (formula.kind === "not") {
43148
- if (!formula.left) return null;
43149
- const value = evaluateBooleanFormula$1(formula.left, assignments);
43150
- return value === null ? null : !value;
43151
- }
43152
- if (!formula.left || !formula.right) return null;
43153
- const leftValue = evaluateBooleanFormula$1(formula.left, assignments);
43154
- const rightValue = evaluateBooleanFormula$1(formula.right, assignments);
43155
- if (formula.kind === "and") {
43156
- if (leftValue === false || rightValue === false) return false;
43157
- return leftValue === true && rightValue === true ? true : null;
43158
- }
43159
- if (leftValue === true || rightValue === true) return true;
43160
- return leftValue === false && rightValue === false ? false : null;
43161
- };
43162
- const assignBooleanFact = (facts, atomKey, value) => {
43163
- const existingValue = facts.assignments.get(atomKey);
43164
- if (existingValue === void 0) {
43165
- facts.assignments.set(atomKey, value);
43166
- facts.didChange = true;
43167
- } else if (existingValue !== value) facts.didConflict = true;
43168
- };
43169
- const addRequiredBooleanFacts = (formula, expectedValue, facts) => {
43170
- const existingValue = evaluateBooleanFormula$1(formula, facts.assignments);
43171
- if (existingValue !== null) {
43172
- if (existingValue !== expectedValue) facts.didConflict = true;
43173
- return;
43174
- }
43175
- if (formula.kind === "atom" && formula.atomKey !== void 0) {
43176
- assignBooleanFact(facts, formula.atomKey, expectedValue);
43177
- return;
43178
- }
43179
- if (formula.kind === "not" && formula.left) {
43180
- addRequiredBooleanFacts(formula.left, !expectedValue, facts);
43181
- return;
43182
- }
43183
- if (!formula.left || !formula.right) return;
43184
- if (formula.kind === "and") {
43185
- if (expectedValue) {
43186
- addRequiredBooleanFacts(formula.left, true, facts);
43187
- addRequiredBooleanFacts(formula.right, true, facts);
43188
- return;
43189
- }
43190
- const leftValue = evaluateBooleanFormula$1(formula.left, facts.assignments);
43191
- const rightValue = evaluateBooleanFormula$1(formula.right, facts.assignments);
43192
- if (leftValue === true) addRequiredBooleanFacts(formula.right, false, facts);
43193
- if (rightValue === true) addRequiredBooleanFacts(formula.left, false, facts);
43194
- return;
43195
- }
43196
- if (!expectedValue) {
43197
- addRequiredBooleanFacts(formula.left, false, facts);
43198
- addRequiredBooleanFacts(formula.right, false, facts);
43199
- return;
43200
- }
43201
- const leftValue = evaluateBooleanFormula$1(formula.left, facts.assignments);
43202
- const rightValue = evaluateBooleanFormula$1(formula.right, facts.assignments);
43203
- if (leftValue === false) addRequiredBooleanFacts(formula.right, true, facts);
43204
- if (rightValue === false) addRequiredBooleanFacts(formula.left, true, facts);
43205
- };
43206
- const doConditionsImplyFormula = (conditions, target) => {
43207
- const facts = {
43208
- assignments: /* @__PURE__ */ new Map(),
43209
- didConflict: false,
43210
- didChange: true
43211
- };
43212
- while (facts.didChange && !facts.didConflict) {
43213
- facts.didChange = false;
43214
- for (const condition of conditions) addRequiredBooleanFacts(condition, true, facts);
43215
- }
43216
- return facts.didConflict || evaluateBooleanFormula$1(target, facts.assignments) === true;
43217
- };
43218
- const getFunctionBindingSymbol = (functionNode, scopes) => {
43219
- if (isNodeOfType(functionNode, "FunctionDeclaration") && functionNode.id) return scopes.symbolFor(functionNode.id);
43220
- const parent = functionNode.parent;
43221
- if ((isNodeOfType(functionNode, "ArrowFunctionExpression") || isNodeOfType(functionNode, "FunctionExpression")) && isNodeOfType(parent, "VariableDeclarator") && parent.init === functionNode && isNodeOfType(parent.id, "Identifier")) return scopes.symbolFor(parent.id);
43222
- return null;
43223
- };
43224
- const getComponentFunctionNode = (containingNode) => {
43225
- if (isFunctionLike$1(containingNode)) return containingNode;
43226
- if (!isNodeOfType(containingNode, "VariableDeclarator") || !containingNode.init) return null;
43227
- const initializer = stripParenExpression(containingNode.init);
43228
- if (isFunctionLike$1(initializer)) return initializer;
43229
- if (!isNodeOfType(initializer, "CallExpression")) return null;
43230
- const firstArgument = initializer.arguments[0];
43231
- return firstArgument && !isNodeOfType(firstArgument, "SpreadElement") && isFunctionLike$1(firstArgument) ? firstArgument : null;
43232
- };
43233
- const isReferenceDirectlyCalled = (identifier) => {
43234
- const unwrappedIdentifier = stripParenExpression(identifier);
43235
- const parent = unwrappedIdentifier.parent;
43236
- return isNodeOfType(parent, "CallExpression") && parent.callee === unwrappedIdentifier ? parent : null;
43237
- };
43238
- const getSynchronousCallbackCall = (functionNode) => {
43239
- const callExpression = functionNode.parent;
43240
- if (!isNodeOfType(callExpression, "CallExpression") || !callExpression.arguments.some((argument) => argument === functionNode) || !isNodeOfType(callExpression.callee, "MemberExpression")) return null;
43241
- const methodName = getStaticMemberPropertyName(callExpression.callee);
43242
- return methodName && SYNCHRONOUS_ARRAY_CALLBACK_METHOD_NAMES.has(methodName) ? callExpression : null;
43243
- };
43244
- const isNodeEvaluatedDuringRender = (node, componentNode, scopes, visitedFunctionSymbolIds = /* @__PURE__ */ new Set()) => {
43245
- const functionNode = findEnclosingFunction$1(node);
43246
- if (!functionNode) return false;
43247
- if (functionNode === componentNode) return true;
43248
- const synchronousCallbackCall = getSynchronousCallbackCall(functionNode);
43249
- if (synchronousCallbackCall) return isNodeEvaluatedDuringRender(synchronousCallbackCall, componentNode, scopes, visitedFunctionSymbolIds);
43250
- if (executesDuringRender(functionNode, scopes)) return isNodeEvaluatedDuringRender(functionNode.parent ?? functionNode, componentNode, scopes, visitedFunctionSymbolIds);
43251
- const functionSymbol = getFunctionBindingSymbol(functionNode, scopes);
43252
- if (!functionSymbol || visitedFunctionSymbolIds.has(functionSymbol.id)) return false;
43253
- visitedFunctionSymbolIds.add(functionSymbol.id);
43254
- let callCount = 0;
43255
- for (const reference of functionSymbol.references) {
43256
- const callExpression = isReferenceDirectlyCalled(reference.identifier);
43257
- if (!callExpression) return false;
43258
- if (!isNodeEvaluatedDuringRender(callExpression, componentNode, scopes, new Set(visitedFunctionSymbolIds))) return false;
43259
- callCount += 1;
43260
- }
43261
- return callCount > 0;
43262
- };
43263
- const isInlineJsxCallback = (functionNode) => {
43264
- let ancestor = functionNode.parent;
43265
- while (ancestor) {
43266
- if (isNodeOfType(ancestor, "JSXAttribute")) return true;
43267
- if (isFunctionLike$1(ancestor) || isNodeOfType(ancestor, "Program")) return false;
43268
- ancestor = ancestor.parent;
43269
- }
43270
- return false;
43271
- };
43272
- const collectExposureConditions = (analysis, context, node, componentNode, protectedSymbolIds) => {
43273
- const conditions = [];
43274
- let child = node;
43275
- let parent = node.parent;
43276
- while (parent) {
43277
- if (isNodeOfType(parent, "LogicalExpression") && parent.right === child) {
43278
- if (parent.operator === "&&") conditions.push(...getRequiredTruthyConditions(analysis, context, parent.left, protectedSymbolIds));
43279
- if (parent.operator === "||") {
43280
- const leftFormula = getBooleanFormula$1(analysis, context, parent.left, protectedSymbolIds);
43281
- if (leftFormula) conditions.push(createNotFormula(leftFormula));
43282
- }
43283
- } else if (isNodeOfType(parent, "ConditionalExpression")) {
43284
- const testFormula = getBooleanFormula$1(analysis, context, parent.test, protectedSymbolIds);
43285
- if (testFormula && parent.consequent === child) conditions.push(testFormula);
43286
- if (testFormula && parent.alternate === child) conditions.push(createNotFormula(testFormula));
43287
- } else if (isNodeOfType(parent, "IfStatement")) {
43288
- const testFormula = getBooleanFormula$1(analysis, context, parent.test, protectedSymbolIds);
43289
- if (testFormula && parent.consequent === child) conditions.push(testFormula);
43290
- if (testFormula && parent.alternate === child) conditions.push(createNotFormula(testFormula));
43291
- }
43292
- if (parent === componentNode) break;
43293
- if (isFunctionLike$1(parent) && parent !== componentNode && !isInlineJsxCallback(parent)) {
43294
- const synchronousCallbackCall = getSynchronousCallbackCall(parent);
43295
- if (synchronousCallbackCall) {
43296
- child = synchronousCallbackCall;
43297
- parent = synchronousCallbackCall.parent;
43298
- continue;
43299
- }
43300
- const functionSymbol = getFunctionBindingSymbol(parent, context.scopes);
43301
- if (functionSymbol?.references.length === 1) {
43302
- const callExpression = isReferenceDirectlyCalled(functionSymbol.references[0].identifier);
43303
- if (callExpression) {
43304
- child = callExpression;
43305
- parent = callExpression.parent;
43306
- continue;
43307
- }
43308
- }
43309
- break;
43310
- }
43311
- child = parent;
43312
- parent = parent.parent;
43313
- }
43314
- return conditions;
43315
- };
43316
43056
  const isMountSnapshotInitializer = (context, node) => {
43317
43057
  if (!isReactApiCall(node, "useMemo", context.scopes, { resolveNamedAliases: true }) || !isNodeOfType(node, "CallExpression")) return false;
43318
43058
  const dependencies = node.arguments?.[1];
@@ -43388,158 +43128,6 @@ const countUseStates = (analysis, componentNode) => {
43388
43128
  for (const ref of getDownstreamRefs(analysis, componentNode)) if (isState(analysis, ref)) stateVariables.add(ref.resolved);
43389
43129
  return stateVariables.size;
43390
43130
  };
43391
- const getStateSymbolForSetter = (analysis, context, setterReference) => {
43392
- const useStateDeclaration = getUseStateDecl(analysis, setterReference);
43393
- if (!useStateDeclaration || !isNodeOfType(useStateDeclaration, "VariableDeclarator") || !isNodeOfType(useStateDeclaration.id, "ArrayPattern")) return null;
43394
- const stateBinding = useStateDeclaration.id.elements[0];
43395
- return stateBinding && isNodeOfType(stateBinding, "Identifier") ? context.scopes.symbolFor(stateBinding) : null;
43396
- };
43397
- const getPropertyName = (node) => {
43398
- if (isNodeOfType(node, "Identifier")) return node.name;
43399
- return isNodeOfType(node, "Literal") && typeof node.value === "string" ? node.value : null;
43400
- };
43401
- const isBooleanTypeNode = (node) => {
43402
- if (!node) return false;
43403
- if (isNodeOfType(node, "TSBooleanKeyword")) return true;
43404
- if (!isNodeOfType(node, "TSUnionType")) return false;
43405
- return node.types.every((typeNode) => isNodeOfType(typeNode, "TSBooleanKeyword") || isNodeOfType(typeNode, "TSUndefinedKeyword") || isNodeOfType(typeNode, "TSNullKeyword"));
43406
- };
43407
- const getBooleanPropertyType = (typeNode, propertyName, referenceNode) => {
43408
- const unwrappedType = isNodeOfType(typeNode, "TSTypeAnnotation") ? typeNode.typeAnnotation : typeNode;
43409
- if (isNodeOfType(unwrappedType, "TSTypeLiteral")) return unwrappedType.members.some((member) => isNodeOfType(member, "TSPropertySignature") && getPropertyName(member.key) === propertyName && isBooleanTypeNode(member.typeAnnotation?.typeAnnotation));
43410
- if (!isNodeOfType(unwrappedType, "TSTypeReference") || !isNodeOfType(unwrappedType.typeName, "Identifier")) return false;
43411
- const typeName = unwrappedType.typeName.name;
43412
- if (hasEnclosingTypeParameterNamed(referenceNode, typeName)) return false;
43413
- const programNode = findProgramNode(referenceNode);
43414
- if (!isNodeOfType(programNode, "Program")) return false;
43415
- const matchingInterfaces = programNode.body.flatMap((statement) => {
43416
- const declaration = isNodeOfType(statement, "ExportNamedDeclaration") ? statement.declaration : statement;
43417
- return isNodeOfType(declaration, "TSInterfaceDeclaration") && declaration.id.name === typeName ? [declaration] : [];
43418
- });
43419
- if (matchingInterfaces.length !== 1) return false;
43420
- let sameNameTypeBindingCount = 0;
43421
- walkAst(programNode, (candidate) => {
43422
- const identifier = isNodeOfType(candidate, "TSInterfaceDeclaration") || isNodeOfType(candidate, "TSTypeAliasDeclaration") || isNodeOfType(candidate, "ClassDeclaration") || isNodeOfType(candidate, "ClassExpression") || isNodeOfType(candidate, "TSEnumDeclaration") ? candidate.id : isNodeOfType(candidate, "TSTypeParameter") ? candidate.name : null;
43423
- if (isNodeOfType(identifier, "Identifier") && identifier.name === typeName) sameNameTypeBindingCount += 1;
43424
- });
43425
- if (sameNameTypeBindingCount !== 1) return false;
43426
- return matchingInterfaces[0].body.body.some((member) => isNodeOfType(member, "TSPropertySignature") && getPropertyName(member.key) === propertyName && isBooleanTypeNode(member.typeAnnotation?.typeAnnotation));
43427
- };
43428
- const findProgramNode = (node) => {
43429
- let currentNode = node;
43430
- while (currentNode.parent) currentNode = currentNode.parent;
43431
- return currentNode;
43432
- };
43433
- const hasBooleanBindingAnnotation = (symbol, identifier) => {
43434
- const property = symbol.bindingIdentifier.parent;
43435
- const objectPattern = property?.parent;
43436
- if (!isNodeOfType(property, "Property") || !isNodeOfType(objectPattern, "ObjectPattern") || !objectPattern.typeAnnotation) return false;
43437
- const propertyName = getPropertyName(property.key);
43438
- return Boolean(propertyName && getBooleanPropertyType(objectPattern.typeAnnotation, propertyName, identifier));
43439
- };
43440
- const isBooleanExpression$1 = (context, node, visitedSymbolIds = /* @__PURE__ */ new Set()) => {
43441
- const expression = stripParenExpression(node);
43442
- if (isNodeOfType(expression, "Literal")) return typeof expression.value === "boolean";
43443
- if (isNodeOfType(expression, "UnaryExpression") && expression.operator === "!") return true;
43444
- if (isNodeOfType(expression, "BinaryExpression")) return [
43445
- "==",
43446
- "===",
43447
- "!=",
43448
- "!==",
43449
- "<",
43450
- "<=",
43451
- ">",
43452
- ">="
43453
- ].includes(expression.operator);
43454
- if (isNodeOfType(expression, "CallExpression") && isNodeOfType(expression.callee, "Identifier") && expression.callee.name === "Boolean" && context.scopes.isGlobalReference(expression.callee)) return true;
43455
- if (isNodeOfType(expression, "LogicalExpression")) return isBooleanExpression$1(context, expression.left, new Set(visitedSymbolIds)) && isBooleanExpression$1(context, expression.right, new Set(visitedSymbolIds));
43456
- if (isNodeOfType(expression, "ConditionalExpression")) return isBooleanExpression$1(context, expression.consequent, new Set(visitedSymbolIds)) && isBooleanExpression$1(context, expression.alternate, new Set(visitedSymbolIds));
43457
- if (!isNodeOfType(expression, "Identifier")) return false;
43458
- const symbol = context.scopes.symbolFor(expression);
43459
- if (!symbol || visitedSymbolIds.has(symbol.id)) return false;
43460
- if (hasBooleanBindingAnnotation(symbol, expression)) return true;
43461
- visitedSymbolIds.add(symbol.id);
43462
- const initializer = getDirectConstInitializer(symbol);
43463
- return Boolean(initializer && isBooleanExpression$1(context, initializer, visitedSymbolIds));
43464
- };
43465
- const getPropDerivedDependencySymbols = (analysis, context, dependencyReferences) => {
43466
- const symbolsById = /* @__PURE__ */ new Map();
43467
- for (const dependencyReference of dependencyReferences) {
43468
- if (!getUpstreamRefs(analysis, dependencyReference).some((upstreamReference) => isProp(analysis, upstreamReference))) continue;
43469
- const symbol = context.scopes.symbolFor(dependencyReference.identifier);
43470
- if (symbol) symbolsById.set(symbol.id, symbol);
43471
- }
43472
- return [...symbolsById.values()];
43473
- };
43474
- const getImpliedDependencyValue = (conditions, dependencyFormulas) => {
43475
- const impliesTrue = dependencyFormulas.some((dependencyFormula) => doConditionsImplyFormula(conditions, dependencyFormula));
43476
- if (impliesTrue === dependencyFormulas.some((dependencyFormula) => doConditionsImplyFormula(conditions, createNotFormula(dependencyFormula)))) return null;
43477
- return impliesTrue;
43478
- };
43479
- const getSetterExposureConditions = (analysis, context, setterReference, componentNode, protectedSymbolIds) => {
43480
- const functionNode = findEnclosingFunction$1(setterReference.identifier);
43481
- if (!functionNode) return null;
43482
- if (isInlineJsxCallback(functionNode)) return [collectExposureConditions(analysis, context, functionNode, componentNode, protectedSymbolIds)];
43483
- const functionSymbol = getFunctionBindingSymbol(functionNode, context.scopes);
43484
- if (!functionSymbol || functionSymbol.references.length === 0) return null;
43485
- const conditionsByReference = [];
43486
- for (const reference of functionSymbol.references) {
43487
- if (isReferenceDirectlyCalled(reference.identifier)) return null;
43488
- let ancestor = reference.identifier.parent;
43489
- while (ancestor && !isNodeOfType(ancestor, "JSXAttribute") && !isFunctionLike$1(ancestor)) ancestor = ancestor.parent;
43490
- if (!isNodeOfType(ancestor, "JSXAttribute")) return null;
43491
- conditionsByReference.push(collectExposureConditions(analysis, context, reference.identifier, componentNode, protectedSymbolIds));
43492
- }
43493
- return conditionsByReference;
43494
- };
43495
- const areAllSetterWritesVisibilityGuarded = (analysis, context, componentNode, resetSetterReferences, dependencySymbolIds, dependencyFormulas, visibleDependencyValue) => {
43496
- const resetIdentifiers = new Set(resetSetterReferences.map((setterReference) => setterReference.identifier));
43497
- const setterVariables = new Set(resetSetterReferences.map((reference) => reference.resolved));
43498
- for (const setterVariable of setterVariables) {
43499
- if (!setterVariable) return false;
43500
- for (const setterReference of setterVariable.references) {
43501
- if (setterVariable.identifiers.some((identifier) => identifier === setterReference.identifier)) continue;
43502
- if (resetIdentifiers.has(setterReference.identifier)) continue;
43503
- if (!getCallExpr(setterReference)) return false;
43504
- const conditionsByExposure = getSetterExposureConditions(analysis, context, setterReference, componentNode, dependencySymbolIds);
43505
- if (!conditionsByExposure || conditionsByExposure.some((conditions) => getImpliedDependencyValue(conditions, dependencyFormulas) !== visibleDependencyValue)) return false;
43506
- }
43507
- }
43508
- return true;
43509
- };
43510
- const areAllResetStateReadsHiddenUntilReset = (analysis, context, componentNode, setterReferences, dependencyReferences) => {
43511
- if (dependencyReferences.length !== 1) return false;
43512
- const dependencySymbols = getPropDerivedDependencySymbols(analysis, context, dependencyReferences);
43513
- if (dependencySymbols.length === 0 || dependencySymbols.some((symbol) => !isBooleanExpression$1(context, symbol.bindingIdentifier) || symbol.references.some((reference) => reference.flag !== "read"))) return false;
43514
- const dependencySymbolIds = new Set(dependencySymbols.map((symbol) => symbol.id));
43515
- const dependencyFormulas = dependencySymbols.map((symbol) => ({
43516
- kind: "atom",
43517
- atomKey: `symbol:${symbol.id}`
43518
- }));
43519
- const resetStateSymbolsById = /* @__PURE__ */ new Map();
43520
- for (const setterReference of setterReferences) {
43521
- const stateSymbol = getStateSymbolForSetter(analysis, context, setterReference);
43522
- if (!stateSymbol) return false;
43523
- resetStateSymbolsById.set(stateSymbol.id, stateSymbol);
43524
- }
43525
- let visibleDependencyValue = null;
43526
- for (const stateSymbol of resetStateSymbolsById.values()) {
43527
- let exposedReadCount = 0;
43528
- for (const reference of stateSymbol.references) {
43529
- if (reference.flag === "write") continue;
43530
- const isRenderRead = isNodeEvaluatedDuringRender(reference.identifier, componentNode, context.scopes);
43531
- const functionNode = findEnclosingFunction$1(reference.identifier);
43532
- if (!isRenderRead && functionNode && !isInlineJsxCallback(functionNode)) return false;
43533
- const referenceDependencyValue = getImpliedDependencyValue(collectExposureConditions(analysis, context, reference.identifier, componentNode, dependencySymbolIds), dependencyFormulas);
43534
- if (referenceDependencyValue === null) return false;
43535
- if (visibleDependencyValue !== null && visibleDependencyValue !== referenceDependencyValue) return false;
43536
- visibleDependencyValue = referenceDependencyValue;
43537
- exposedReadCount += 1;
43538
- }
43539
- if (exposedReadCount === 0) return false;
43540
- }
43541
- return Boolean(resetStateSymbolsById.size > 0 && visibleDependencyValue !== null && areAllSetterWritesVisibilityGuarded(analysis, context, componentNode, setterReferences, dependencySymbolIds, dependencyFormulas, visibleDependencyValue));
43542
- };
43543
43131
  const findPropUsedToResetAllState = (analysis, context, effectFnRefs, depsRefs, useEffectNode, effectFn) => {
43544
43132
  const stateSetterRefs = effectFnRefs.filter((ref) => isSyncStateSetterCall(analysis, ref, effectFn));
43545
43133
  if (stateSetterRefs.length === 0) return null;
@@ -43547,8 +43135,6 @@ const findPropUsedToResetAllState = (analysis, context, effectFnRefs, depsRefs,
43547
43135
  if (stateSetterRefs.every((setterRef) => effectFnRefs.some((otherRef) => otherRef !== setterRef && otherRef.resolved === setterRef.resolved && Boolean(getCallExpr(otherRef)) && !isSyncStateSetterCall(analysis, otherRef, effectFn)))) return null;
43548
43136
  const containing = findContainingNode(analysis, useEffectNode);
43549
43137
  if (new Set(stateSetterRefs.map((setterRef) => setterRef.resolved)).size !== countUseStates(analysis, containing)) return null;
43550
- const componentFunctionNode = containing ? getComponentFunctionNode(containing) : null;
43551
- if (componentFunctionNode && areAllResetStateReadsHiddenUntilReset(analysis, context, componentFunctionNode, stateSetterRefs, depsRefs)) return null;
43552
43138
  for (const depRef of depsRefs) for (const upRef of getUpstreamRefs(analysis, depRef)) if (isProp(analysis, upRef)) return upRef;
43553
43139
  return null;
43554
43140
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oxlint-plugin-react-doctor",
3
- "version": "0.7.8-dev.9256423",
3
+ "version": "0.7.8-dev.ece35b3",
4
4
  "description": "React Doctor rules for oxlint.",
5
5
  "keywords": [
6
6
  "accessibility",