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

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 +7 -110
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -44371,110 +44371,11 @@ const isSameRefCurrentMember = (node, refSymbol, scopes) => {
44371
44371
  return isNodeOfType(receiver, "Identifier") && resolveConstIdentifierAlias(receiver, scopes)?.id === refSymbol.id;
44372
44372
  };
44373
44373
  const isSameRefCurrentAlias = (node, refSymbol, scopes) => {
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);
44374
+ if (isSameRefCurrentMember(node, refSymbol, scopes)) return true;
44375
+ if (!isNodeOfType(node, "Identifier")) return false;
44376
+ const aliasSymbol = scopes.symbolFor(node);
44378
44377
  return aliasSymbol?.kind === "const" && aliasSymbol.initializer !== null && isSameRefCurrentMember(stripParenExpression(aliasSymbol.initializer), refSymbol, scopes);
44379
44378
  };
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
- };
44478
44379
  const isEmptySentinel = (node, scopes) => isNodeOfType(node, "Literal") && node.value === null || isNodeOfType(node, "Identifier") && node.name === "undefined" && scopes.isGlobalReference(node);
44479
44380
  const hasRepeatedExecutionAncestor = (node, stop) => {
44480
44381
  let ancestor = node.parent;
@@ -44523,22 +44424,18 @@ const hasNoPriorCoExecutableWrite = (assignmentExpression, branchRoot, refSymbol
44523
44424
  const isDocumentedLazyInitialization = (assignmentExpression, refSymbol, scopes) => {
44524
44425
  if (assignmentExpression.operator === "??=" || assignmentExpression.operator === "||=") return true;
44525
44426
  if (assignmentExpression.operator !== "=") return false;
44526
- const renderOwner = findRenderPhaseComponentOrHook(assignmentExpression, scopes);
44527
- if (!renderOwner) return false;
44528
44427
  let descendant = assignmentExpression;
44529
44428
  let ancestor = descendant.parent;
44530
44429
  while (ancestor) {
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") && [
44430
+ if (isNodeOfType(ancestor, "IfStatement") && isNodeOfType(ancestor.test, "BinaryExpression") && [
44534
44431
  "===",
44535
44432
  "==",
44536
44433
  "!==",
44537
44434
  "!="
44538
- ].includes(test.operator)) {
44539
- const { left, right } = test;
44435
+ ].includes(ancestor.test.operator)) {
44436
+ const { left, right } = ancestor.test;
44540
44437
  const comparesEmptySentinel = isSameRefCurrentAlias(left, refSymbol, scopes) && isEmptySentinel(right, scopes) || isSameRefCurrentAlias(right, refSymbol, scopes) && isEmptySentinel(left, scopes);
44541
- const guardedBranch = test.operator === "===" || test.operator === "==" ? ancestor.consequent : ancestor.alternate;
44438
+ const guardedBranch = ancestor.test.operator === "===" || ancestor.test.operator === "==" ? ancestor.consequent : ancestor.alternate;
44542
44439
  if (comparesEmptySentinel && guardedBranch === descendant && guardedBranch && !hasRepeatedExecutionAncestor(assignmentExpression, guardedBranch) && hasNoPriorCoExecutableWrite(assignmentExpression, guardedBranch, refSymbol, scopes)) return true;
44543
44440
  }
44544
44441
  descendant = ancestor;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oxlint-plugin-react-doctor",
3
- "version": "0.7.9-dev.d8a20e0",
3
+ "version": "0.7.9-dev.e5d5753",
4
4
  "description": "React Doctor rules for oxlint.",
5
5
  "keywords": [
6
6
  "accessibility",