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.
- package/dist/index.js +7 -110
- 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
|
-
|
|
44375
|
-
if (
|
|
44376
|
-
|
|
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
|
-
|
|
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;
|