oxlint-plugin-react-doctor 0.9.2-dev.2992a03 → 0.9.2-dev.3bc63ea
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 +174 -1697
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -665,6 +665,19 @@ const TRIVIAL_INITIALIZER_NAMES = new Set([
|
|
|
665
665
|
"parseInt",
|
|
666
666
|
"parseFloat"
|
|
667
667
|
]);
|
|
668
|
+
const TRIVIAL_CONSTRUCTOR_NAMES = new Set([
|
|
669
|
+
"Date",
|
|
670
|
+
"Map",
|
|
671
|
+
"Set",
|
|
672
|
+
"WeakMap",
|
|
673
|
+
"WeakSet",
|
|
674
|
+
"WeakRef",
|
|
675
|
+
"RegExp",
|
|
676
|
+
"Error",
|
|
677
|
+
"URL",
|
|
678
|
+
"URLSearchParams",
|
|
679
|
+
"AbortController"
|
|
680
|
+
]);
|
|
668
681
|
const SETTER_PATTERN = /^set[A-Z]/;
|
|
669
682
|
const RENDER_FUNCTION_PATTERN = /^render[A-Z]/;
|
|
670
683
|
const UPPERCASE_PATTERN = /^[A-Z]/;
|
|
@@ -17999,14 +18012,6 @@ const findRenderPhaseComponentOrHook = (node, scopes) => {
|
|
|
17999
18012
|
//#region src/plugin/utils/is-event-handler-attribute.ts
|
|
18000
18013
|
const isEventHandlerAttribute = (node) => isNodeOfType(node, "JSXAttribute") && isNodeOfType(node.name, "JSXIdentifier") && /^on[A-Z]/.test(node.name.name);
|
|
18001
18014
|
//#endregion
|
|
18002
|
-
//#region src/plugin/utils/is-early-exit-statement.ts
|
|
18003
|
-
const isEarlyExitStatement$1 = (statement) => {
|
|
18004
|
-
if (!statement) return false;
|
|
18005
|
-
if (statementAlwaysExits$1(statement)) return true;
|
|
18006
|
-
if (isNodeOfType(statement, "BlockStatement")) return isEarlyExitStatement$1(statement.body.at(-1));
|
|
18007
|
-
return isNodeOfType(statement, "ContinueStatement") || isNodeOfType(statement, "BreakStatement");
|
|
18008
|
-
};
|
|
18009
|
-
//#endregion
|
|
18010
18015
|
//#region src/plugin/utils/is-ast-descendant.ts
|
|
18011
18016
|
/**
|
|
18012
18017
|
* True when `inner` is `outer` itself or any descendant in the AST
|
|
@@ -18225,15 +18230,13 @@ const isSynchronousIteratorCall = (callNode, callbackArgument, scopes) => {
|
|
|
18225
18230
|
}
|
|
18226
18231
|
return Boolean(methodName && EAGER_ITERATOR_METHOD_NAMES.has(methodName) && callNode.arguments[0] === callbackArgument && !isProvablyEmptyEagerCollection(callee.object, scopes) && (methodName === "forEach" ? isProvablyEagerForEachCollection(callee.object, scopes) : isProvablyEagerCollection(callee.object, scopes)));
|
|
18227
18232
|
};
|
|
18228
|
-
const isSynchronousIteratorCallbackCall = (callNode, callbackArgument) => {
|
|
18229
|
-
const callee = stripParenExpression(callNode.callee);
|
|
18230
|
-
if (!isNodeOfType(callee, "MemberExpression") || callee.computed || !isNodeOfType(callee.property, "Identifier")) return false;
|
|
18231
|
-
if (isNodeOfType(callee.object, "Identifier") && callee.object.name === "Array" && callee.property.name === "from") return callNode.arguments[1] === callbackArgument;
|
|
18232
|
-
return SYNCHRONOUS_ITERATOR_METHOD_NAMES$2.has(callee.property.name) && callNode.arguments[0] === callbackArgument;
|
|
18233
|
-
};
|
|
18234
18233
|
const isSynchronousIteratorCallback = (functionNode) => {
|
|
18235
18234
|
const callNode = functionNode.parent;
|
|
18236
|
-
|
|
18235
|
+
if (!isNodeOfType(callNode, "CallExpression")) return false;
|
|
18236
|
+
const callee = stripParenExpression(callNode.callee);
|
|
18237
|
+
if (!isNodeOfType(callee, "MemberExpression") || callee.computed || !isNodeOfType(callee.property, "Identifier")) return false;
|
|
18238
|
+
if (isNodeOfType(callee.object, "Identifier") && callee.object.name === "Array" && callee.property.name === "from") return callNode.arguments[1] === functionNode;
|
|
18239
|
+
return SYNCHRONOUS_ITERATOR_METHOD_NAMES$2.has(callee.property.name) && callNode.arguments[0] === functionNode;
|
|
18237
18240
|
};
|
|
18238
18241
|
//#endregion
|
|
18239
18242
|
//#region src/plugin/utils/is-within-assignment-target.ts
|
|
@@ -18353,35 +18356,11 @@ const resolveEventListenerCaptureValueIdentityKey = (expression, context) => {
|
|
|
18353
18356
|
const rightIdentityKey = resolveEventListenerCaptureValueIdentityKey(unwrappedExpression.right, context);
|
|
18354
18357
|
return leftIdentityKey && rightIdentityKey ? `${unwrappedExpression.type}:${unwrappedExpression.operator}:${leftIdentityKey}:${rightIdentityKey}` : null;
|
|
18355
18358
|
};
|
|
18356
|
-
const resolveReadOnlyEventListenerOptions = (optionsNode, context) => {
|
|
18357
|
-
const unwrappedOptions = stripParenExpression(optionsNode);
|
|
18358
|
-
if (!isNodeOfType(unwrappedOptions, "Identifier")) return resolveStableValue(unwrappedOptions, context);
|
|
18359
|
-
const optionsSymbol = context.scopes.symbolFor(unwrappedOptions);
|
|
18360
|
-
const initializer = optionsSymbol?.initializer ? stripParenExpression(optionsSymbol.initializer) : null;
|
|
18361
|
-
if (!optionsSymbol || !initializer) return resolveStableValue(unwrappedOptions, context);
|
|
18362
|
-
if (!isNodeOfType(initializer, "ObjectExpression")) {
|
|
18363
|
-
if (isNodeOfType(initializer, "Identifier") || isNodeOfType(initializer, "MemberExpression")) return null;
|
|
18364
|
-
return resolveStableValue(unwrappedOptions, context);
|
|
18365
|
-
}
|
|
18366
|
-
if (optionsSymbol.kind !== "const") return null;
|
|
18367
|
-
return optionsSymbol.references.every((reference) => {
|
|
18368
|
-
if (reference.flag !== "read" || isWithinAssignmentTarget(reference.identifier)) return false;
|
|
18369
|
-
const referenceRoot = findTransparentExpressionRoot(reference.identifier);
|
|
18370
|
-
const callNode = referenceRoot.parent;
|
|
18371
|
-
if (!isNodeOfType(callNode, "CallExpression") || callNode.arguments[2] !== referenceRoot) return false;
|
|
18372
|
-
const callee = stripParenExpression(callNode.callee);
|
|
18373
|
-
if (!isNodeOfType(callee, "MemberExpression")) return false;
|
|
18374
|
-
const methodName = getStaticPropertyKeyName(callee);
|
|
18375
|
-
return methodName === "addEventListener" || methodName === "removeEventListener";
|
|
18376
|
-
}) ? initializer : null;
|
|
18377
|
-
};
|
|
18378
18359
|
const resolveEventListenerCaptureIdentityKey = (optionsNode, context, allowOpaqueOptionsIdentity) => {
|
|
18379
|
-
const
|
|
18380
|
-
if (optionsNode && !stableOptionsNode) return null;
|
|
18381
|
-
const capture = resolveEventListenerCapture(stableOptionsNode, { allowIndeterminateEntries: true });
|
|
18360
|
+
const capture = resolveEventListenerCapture(optionsNode, { allowIndeterminateEntries: true });
|
|
18382
18361
|
if (capture !== null) return `capture:${String(capture)}`;
|
|
18383
|
-
if (!
|
|
18384
|
-
const unwrappedOptions = stripParenExpression(
|
|
18362
|
+
if (!optionsNode) return null;
|
|
18363
|
+
const unwrappedOptions = stripParenExpression(optionsNode);
|
|
18385
18364
|
if (!isNodeOfType(unwrappedOptions, "ObjectExpression")) {
|
|
18386
18365
|
const optionsKey = allowOpaqueOptionsIdentity ? resolveEventListenerCaptureValueIdentityKey(unwrappedOptions, context) : null;
|
|
18387
18366
|
return optionsKey ? `options:${optionsKey}` : null;
|
|
@@ -18428,8 +18407,12 @@ const doEventListenerCapturesMatch = (registrationOptions, releaseOptions, conte
|
|
|
18428
18407
|
return registrationCaptureKey !== null && registrationCaptureKey === resolveEventListenerCaptureIdentityKey(releaseOptions, context, allowOpaqueOptionsIdentity);
|
|
18429
18408
|
};
|
|
18430
18409
|
const findAssignedResourceKey = (resourceNode, context) => {
|
|
18431
|
-
|
|
18432
|
-
|
|
18410
|
+
let currentNode = resourceNode;
|
|
18411
|
+
let parentNode = currentNode.parent;
|
|
18412
|
+
while (isNodeOfType(parentNode, "ChainExpression")) {
|
|
18413
|
+
currentNode = parentNode;
|
|
18414
|
+
parentNode = currentNode.parent;
|
|
18415
|
+
}
|
|
18433
18416
|
if (isNodeOfType(parentNode, "VariableDeclarator") && parentNode.init === currentNode) return resolveExpressionKey(parentNode.id, context);
|
|
18434
18417
|
if (isNodeOfType(parentNode, "AssignmentExpression") && parentNode.right === currentNode) return resolveExpressionKey(parentNode.left, context);
|
|
18435
18418
|
return null;
|
|
@@ -18700,18 +18683,6 @@ const resolveIteratorCollectionKey = (expression, context) => {
|
|
|
18700
18683
|
}
|
|
18701
18684
|
return null;
|
|
18702
18685
|
};
|
|
18703
|
-
const resolveReceiverIteratorCollectionKey = (expression, context) => {
|
|
18704
|
-
if (!expression) return null;
|
|
18705
|
-
const unwrappedExpression = stripParenExpression(expression);
|
|
18706
|
-
if (!isNodeOfType(unwrappedExpression, "Identifier")) return null;
|
|
18707
|
-
const collectionExpression = findForOfStatementForIteratorExpression(unwrappedExpression, context)?.right;
|
|
18708
|
-
if (!collectionExpression) return null;
|
|
18709
|
-
const collectionIdentifier = stripParenExpression(collectionExpression);
|
|
18710
|
-
if (!isNodeOfType(collectionIdentifier, "Identifier") || !isPrivatePlainConstIdentifier(collectionIdentifier, context)) return null;
|
|
18711
|
-
const collectionSymbol = context.scopes.symbolFor(collectionIdentifier);
|
|
18712
|
-
const initializer = collectionSymbol?.initializer ? stripParenExpression(collectionSymbol.initializer) : null;
|
|
18713
|
-
return collectionSymbol && isNodeOfType(initializer, "ArrayExpression") && hasOnlyReplayableCollectionReferences(collectionIdentifier, context, /* @__PURE__ */ new Set()) ? `symbol:${collectionSymbol.id}` : null;
|
|
18714
|
-
};
|
|
18715
18686
|
const isStableLoopReceiver = (expression, context) => {
|
|
18716
18687
|
if (!expression) return false;
|
|
18717
18688
|
const unwrappedExpression = stripParenExpression(expression);
|
|
@@ -19482,28 +19453,6 @@ const isFunctionReturnedFromReactHook = (functionNode, context, requireRefProper
|
|
|
19482
19453
|
});
|
|
19483
19454
|
};
|
|
19484
19455
|
const isFunctionUsedAsReactRef = (functionNode, context) => isFunctionForwardedToReactRef(functionNode, context) || isFunctionReturnedFromReactHook(functionNode, context, true);
|
|
19485
|
-
const findCallbackRefReplacementReleaseGuard = (releaseCall, ownerFunction, releaseReceiverKey, registrationReceiverKey, context) => {
|
|
19486
|
-
let descendant = releaseCall;
|
|
19487
|
-
let ancestor = descendant.parent;
|
|
19488
|
-
while (ancestor && ancestor !== ownerFunction) {
|
|
19489
|
-
if (isNodeOfType(ancestor, "IfStatement") && ancestor.consequent === descendant && ancestor.alternate === null) {
|
|
19490
|
-
const test = stripParenExpression(ancestor.test);
|
|
19491
|
-
if (!isNodeOfType(test, "LogicalExpression") || test.operator !== "&&") return null;
|
|
19492
|
-
const operands = [stripParenExpression(test.left), stripParenExpression(test.right)];
|
|
19493
|
-
const hasLiveReceiverTest = operands.some((operand) => doesTestRequireLiveExpressionKey(operand, releaseReceiverKey, context));
|
|
19494
|
-
const hasDifferentReceiverTest = operands.some((operand) => {
|
|
19495
|
-
if (!isNodeOfType(operand, "BinaryExpression") || operand.operator !== "!==" && operand.operator !== "!=") return false;
|
|
19496
|
-
const leftKey = resolveExpressionKey(operand.left, context);
|
|
19497
|
-
const rightKey = resolveExpressionKey(operand.right, context);
|
|
19498
|
-
return leftKey === releaseReceiverKey && rightKey === registrationReceiverKey || rightKey === releaseReceiverKey && leftKey === registrationReceiverKey;
|
|
19499
|
-
});
|
|
19500
|
-
return hasLiveReceiverTest && hasDifferentReceiverTest ? ancestor : null;
|
|
19501
|
-
}
|
|
19502
|
-
descendant = ancestor;
|
|
19503
|
-
ancestor = descendant.parent;
|
|
19504
|
-
}
|
|
19505
|
-
return null;
|
|
19506
|
-
};
|
|
19507
19456
|
const isReactRefListenerReplacementRelease = (releaseCall, usage, context) => {
|
|
19508
19457
|
if (!isNodeOfType(usage.node, "CallExpression")) return false;
|
|
19509
19458
|
const usageFunction = findEnclosingFunction$1(usage.node);
|
|
@@ -19524,7 +19473,7 @@ const isReactRefListenerReplacementRelease = (releaseCall, usage, context) => {
|
|
|
19524
19473
|
if (child !== usageFunctionBody && isFunctionLike$1(child)) return false;
|
|
19525
19474
|
if (isNodeOfType(child, "AssignmentExpression") && child.operator === "=" && resolveReactRefSymbol(stripParenExpression(child.left), context.scopes)?.id === releaseRefSymbol.id && resolveExpressionKey(child.right, context) === registrationReceiverKey && releaseStart !== null && (getRangeStart(child) ?? -1) > releaseStart) matchingOwnershipAssignments.push(child);
|
|
19526
19475
|
});
|
|
19527
|
-
const releaseAnchor = findLiveExpressionGuardForRelease(releaseCall, usageFunction, releaseReceiverKey, context) ??
|
|
19476
|
+
const releaseAnchor = findLiveExpressionGuardForRelease(releaseCall, usageFunction, releaseReceiverKey, context) ?? releaseCall;
|
|
19528
19477
|
const safeOwnershipAssignments = matchingOwnershipAssignments.filter((assignment) => doMatchingNodesCoverEveryPathBeforeUsage(assignment, [releaseAnchor], usageFunction, context));
|
|
19529
19478
|
return doNodesCoverEveryPathFromFunctionEntry(usageFunction, [releaseAnchor], context) && doMatchingNodesCoverEveryPathBeforeUsage(usage.node, safeOwnershipAssignments, usageFunction, context);
|
|
19530
19479
|
};
|
|
@@ -19674,21 +19623,14 @@ const doesReleaseCallMatchUsage = (node, usage, context) => {
|
|
|
19674
19623
|
if (usage.kind === "socket") return usage.handleKey !== null && releaseReceiverKey === usage.handleKey && (SOCKET_RELEASE_VERB_NAMES.has(releaseVerbName) || UNIVERSAL_RELEASE_VERB_NAMES.has(releaseVerbName));
|
|
19675
19624
|
if (usage.handleKey !== null && releaseReceiverKey === usage.handleKey && (releaseVerbName === "unsubscribe" || releaseVerbName === "unsub" || releaseVerbName === "close" || releaseVerbName === "unwatch" || releaseVerbName === "unlisten" || BOUND_RESOURCE_RELEASE_METHOD_NAMES.has(releaseVerbName))) return true;
|
|
19676
19625
|
if (releaseVerbName === "abort" && releaseReceiverKey === getListenerAbortControllerKey(usage, context)) return true;
|
|
19626
|
+
if (usage.registrationVerbName === "addListener" && isNodeOfType(usage.node, "CallExpression") && usage.node.arguments?.length === 1) return isProvenLegacyMediaQueryListMethodCall(usage.node, "addListener", context) && releaseVerbName === "removeListener" && isProvenLegacyMediaQueryListMethodCall(callNode, "removeListener", context) && usage.receiverKey !== null && resolveStableMediaQueryListenerIdentityKey(callee.object, context) === usage.receiverKey && usage.handlerKey !== null && resolveStableMediaQueryListenerIdentityKey(callNode.arguments?.[0], context) === usage.handlerKey;
|
|
19677
19627
|
if (releaseVerbName === "abort" && isRetainedAbortControllerRefRelease(callee.object, usage, context)) return true;
|
|
19678
|
-
if (usage.registrationVerbName === "addListener" && releaseVerbName === "removeListener" && isNodeOfType(usage.node, "CallExpression") && usage.node.arguments?.length === 1) {
|
|
19679
|
-
if (callNode.arguments?.length !== 1) return false;
|
|
19680
|
-
const registrationHandler = resolveStableValue(usage.node.arguments[0], context);
|
|
19681
|
-
if (!isProvenLegacyMediaQueryListMethodCall(usage.node, "addListener", context) && !isFunctionLike$1(registrationHandler)) return false;
|
|
19682
|
-
}
|
|
19683
19628
|
if (usage.registrationVerbName === "addEventListener" && releaseVerbName === "removeEventListener" && isNodeOfType(usage.node, "CallExpression")) {
|
|
19684
19629
|
if (!isNodeOfType(stripParenExpression(usage.node.callee), "MemberExpression")) return false;
|
|
19685
19630
|
if (!doEventListenerCapturesMatch(usage.node.arguments?.[2], callNode.arguments?.[2], context, true)) return false;
|
|
19686
19631
|
}
|
|
19687
19632
|
if (isNodeOfType(usage.node, "CallExpression") && !hasSafeForEachProjectionCleanup(usage.node, callNode, context)) return false;
|
|
19688
|
-
|
|
19689
|
-
const registrationReceiverCollectionKey = isNodeOfType(registrationCallee, "MemberExpression") ? resolveReceiverIteratorCollectionKey(registrationCallee.object, context) : null;
|
|
19690
|
-
const releaseReceiverCollectionKeyForPair = resolveReceiverIteratorCollectionKey(callee.object, context);
|
|
19691
|
-
if (!(registrationReceiverCollectionKey !== null && registrationReceiverCollectionKey === releaseReceiverCollectionKeyForPair) && (usage.receiverKey === null || releaseReceiverKey !== usage.receiverKey)) return false;
|
|
19633
|
+
if (usage.receiverKey === null || releaseReceiverKey !== usage.receiverKey) return false;
|
|
19692
19634
|
if (usage.registrationVerbName === "subscribe" && (releaseVerbName === "unsubscribe" || releaseVerbName === "unsub") && usage.handleKey !== null && resolveExpressionKey(callNode.arguments?.[0], context) === usage.handleKey) return true;
|
|
19693
19635
|
const pairedVerbNames = usage.registrationVerbName ? PAIRED_RELEASE_VERB_NAMES_BY_REGISTRATION_VERB.get(usage.registrationVerbName) : null;
|
|
19694
19636
|
if (!pairedVerbNames || !matchesPairedReleaseVerb(releaseVerbName, pairedVerbNames)) return false;
|
|
@@ -19725,7 +19667,7 @@ const doesReleaseCallMatchUsage = (node, usage, context) => {
|
|
|
19725
19667
|
const usesUnaryListenerSignatureForCalls = isNodeOfType(usage.node, "CallExpression") && usesUnaryListenerSignature(usage.node, callNode);
|
|
19726
19668
|
const releaseHandler = usesUnaryListenerSignatureForCalls ? callNode.arguments?.[0] : callNode.arguments?.[1];
|
|
19727
19669
|
if (!releaseHandler) return releaseVerbName === "off";
|
|
19728
|
-
const expectedHandlerKey = usesUnaryListenerSignatureForCalls ? usage.
|
|
19670
|
+
const expectedHandlerKey = usesUnaryListenerSignatureForCalls ? usage.eventKey : usage.handlerKey;
|
|
19729
19671
|
const registrationHandler = isNodeOfType(usage.node, "CallExpression") ? usage.node.arguments?.[usesUnaryListenerSignatureForCalls ? 0 : 1] : null;
|
|
19730
19672
|
return expectedHandlerKey !== null && resolveResourceIdentityKey(releaseHandler, context) === expectedHandlerKey || registrationHandler !== null && resolveStableValue(releaseHandler, context) === resolveStableValue(registrationHandler, context);
|
|
19731
19673
|
}
|
|
@@ -20199,7 +20141,6 @@ const findRetainedFunctionLeak = (retainedFunction, context, options) => {
|
|
|
20199
20141
|
walkAst(body, (child) => {
|
|
20200
20142
|
if (leak !== null) return false;
|
|
20201
20143
|
if (isFunctionLike$1(child)) return false;
|
|
20202
|
-
if (!isNodeReachableWithinFunction(child, context)) return false;
|
|
20203
20144
|
if (isSocketConstruction(child) && !doesResourceResultEscape(child, allowReturnedSocketEscape, false, context)) {
|
|
20204
20145
|
const socketUsage = {
|
|
20205
20146
|
kind: "socket",
|
|
@@ -20452,164 +20393,6 @@ const isInlineRetainedHandlerFunction = (functionNode, context) => {
|
|
|
20452
20393
|
const objectParent = objectExpression.parent;
|
|
20453
20394
|
return (isNodeOfType(objectParent, "CallExpression") && objectParent.arguments.some((argument) => argument === objectExpression) || isNodeOfType(objectParent, "JSXExpressionContainer")) && findRenderPhaseComponentOrHook(parentNode, context.scopes) !== null;
|
|
20454
20395
|
};
|
|
20455
|
-
const readInvocationArgumentValue = (expression, context) => {
|
|
20456
|
-
if (!expression) return {
|
|
20457
|
-
isDefinitelyUndefined: true,
|
|
20458
|
-
truthiness: "falsy"
|
|
20459
|
-
};
|
|
20460
|
-
const target = stripParenExpression(expression);
|
|
20461
|
-
if (isNodeOfType(target, "Literal")) return {
|
|
20462
|
-
isDefinitelyUndefined: false,
|
|
20463
|
-
truthiness: target.value ? "truthy" : "falsy"
|
|
20464
|
-
};
|
|
20465
|
-
if (isNodeOfType(target, "Identifier") && target.name === "undefined" && context.scopes.isGlobalReference(target)) return {
|
|
20466
|
-
isDefinitelyUndefined: true,
|
|
20467
|
-
truthiness: "falsy"
|
|
20468
|
-
};
|
|
20469
|
-
if (isNodeOfType(target, "UnaryExpression") && target.operator === "void") return {
|
|
20470
|
-
isDefinitelyUndefined: true,
|
|
20471
|
-
truthiness: "falsy"
|
|
20472
|
-
};
|
|
20473
|
-
if (isNodeOfType(target, "ArrayExpression") || isNodeOfType(target, "ArrowFunctionExpression") || isNodeOfType(target, "ClassExpression") || isNodeOfType(target, "FunctionExpression") || isNodeOfType(target, "NewExpression") || isNodeOfType(target, "ObjectExpression")) return {
|
|
20474
|
-
isDefinitelyUndefined: false,
|
|
20475
|
-
truthiness: "truthy"
|
|
20476
|
-
};
|
|
20477
|
-
return {
|
|
20478
|
-
isDefinitelyUndefined: false,
|
|
20479
|
-
truthiness: "unknown"
|
|
20480
|
-
};
|
|
20481
|
-
};
|
|
20482
|
-
const readInvocationConditionTruthiness = (expression, parameterValues, context) => {
|
|
20483
|
-
const target = stripParenExpression(expression);
|
|
20484
|
-
const atomicValue = readInvocationArgumentValue(target, context);
|
|
20485
|
-
if (atomicValue.truthiness !== "unknown") return atomicValue.truthiness;
|
|
20486
|
-
if (isNodeOfType(target, "Identifier")) {
|
|
20487
|
-
const symbol = context.scopes.symbolFor(target);
|
|
20488
|
-
return symbol ? parameterValues.get(symbol.id)?.truthiness ?? "unknown" : "unknown";
|
|
20489
|
-
}
|
|
20490
|
-
if (isNodeOfType(target, "UnaryExpression") && target.operator === "!") {
|
|
20491
|
-
const argumentTruthiness = readInvocationConditionTruthiness(target.argument, parameterValues, context);
|
|
20492
|
-
return argumentTruthiness === "truthy" ? "falsy" : argumentTruthiness === "falsy" ? "truthy" : "unknown";
|
|
20493
|
-
}
|
|
20494
|
-
if (isNodeOfType(target, "LogicalExpression")) {
|
|
20495
|
-
const leftTruthiness = readInvocationConditionTruthiness(target.left, parameterValues, context);
|
|
20496
|
-
const rightTruthiness = readInvocationConditionTruthiness(target.right, parameterValues, context);
|
|
20497
|
-
if (target.operator === "&&") {
|
|
20498
|
-
if (leftTruthiness === "falsy" || rightTruthiness === "falsy") return "falsy";
|
|
20499
|
-
return leftTruthiness === "truthy" && rightTruthiness === "truthy" ? "truthy" : "unknown";
|
|
20500
|
-
}
|
|
20501
|
-
if (target.operator === "||") {
|
|
20502
|
-
if (leftTruthiness === "truthy" || rightTruthiness === "truthy") return "truthy";
|
|
20503
|
-
return leftTruthiness === "falsy" && rightTruthiness === "falsy" ? "falsy" : "unknown";
|
|
20504
|
-
}
|
|
20505
|
-
return "unknown";
|
|
20506
|
-
}
|
|
20507
|
-
if (isNodeOfType(target, "ConditionalExpression")) {
|
|
20508
|
-
const testTruthiness = readInvocationConditionTruthiness(target.test, parameterValues, context);
|
|
20509
|
-
if (testTruthiness === "truthy") return readInvocationConditionTruthiness(target.consequent, parameterValues, context);
|
|
20510
|
-
if (testTruthiness === "falsy") return readInvocationConditionTruthiness(target.alternate, parameterValues, context);
|
|
20511
|
-
const consequentTruthiness = readInvocationConditionTruthiness(target.consequent, parameterValues, context);
|
|
20512
|
-
return consequentTruthiness === readInvocationConditionTruthiness(target.alternate, parameterValues, context) ? consequentTruthiness : "unknown";
|
|
20513
|
-
}
|
|
20514
|
-
if (isNodeOfType(target, "CallExpression") && isNodeOfType(target.callee, "Identifier") && target.callee.name === "Boolean" && context.scopes.isGlobalReference(target.callee) && target.arguments[0] && isAstNode(target.arguments[0])) return readInvocationConditionTruthiness(target.arguments[0], parameterValues, context);
|
|
20515
|
-
return "unknown";
|
|
20516
|
-
};
|
|
20517
|
-
const getInvocationParameterValues = (retainedFunction, invocation, leakNode, context) => {
|
|
20518
|
-
const parameterValues = /* @__PURE__ */ new Map();
|
|
20519
|
-
if (!isFunctionLike$1(retainedFunction) || !invocation.isDirect) return parameterValues;
|
|
20520
|
-
for (const [parameterIndex, parameter] of retainedFunction.params.entries()) {
|
|
20521
|
-
const argument = invocation.call.arguments[parameterIndex];
|
|
20522
|
-
const argumentExpression = argument && isAstNode(argument) ? argument : null;
|
|
20523
|
-
let parameterIdentifier = null;
|
|
20524
|
-
let parameterValue = readInvocationArgumentValue(argumentExpression, context);
|
|
20525
|
-
if (isNodeOfType(parameter, "Identifier")) parameterIdentifier = parameter;
|
|
20526
|
-
else if (isNodeOfType(parameter, "AssignmentPattern") && isNodeOfType(parameter.left, "Identifier")) {
|
|
20527
|
-
parameterIdentifier = parameter.left;
|
|
20528
|
-
if (parameterValue.isDefinitelyUndefined) parameterValue = readInvocationArgumentValue(parameter.right, context);
|
|
20529
|
-
} else if (isNodeOfType(parameter, "RestElement") && isNodeOfType(parameter.argument, "Identifier")) {
|
|
20530
|
-
parameterIdentifier = parameter.argument;
|
|
20531
|
-
parameterValue = {
|
|
20532
|
-
isDefinitelyUndefined: false,
|
|
20533
|
-
truthiness: "truthy"
|
|
20534
|
-
};
|
|
20535
|
-
}
|
|
20536
|
-
if (!parameterIdentifier) continue;
|
|
20537
|
-
const parameterSymbol = context.scopes.symbolFor(parameterIdentifier);
|
|
20538
|
-
if (!parameterSymbol) continue;
|
|
20539
|
-
const isWrittenBeforeLeak = parameterSymbol.references.some((reference) => reference.flag !== "read" && reference.identifier.range[0] < leakNode.range[0]);
|
|
20540
|
-
parameterValues.set(parameterSymbol.id, isWrittenBeforeLeak ? {
|
|
20541
|
-
isDefinitelyUndefined: false,
|
|
20542
|
-
truthiness: "unknown"
|
|
20543
|
-
} : parameterValue);
|
|
20544
|
-
}
|
|
20545
|
-
return parameterValues;
|
|
20546
|
-
};
|
|
20547
|
-
const isLeakPathDisabledForInvocation = (retainedFunction, leakNode, invocation, context) => {
|
|
20548
|
-
if (!invocation.isDirect) return false;
|
|
20549
|
-
const parameterValues = getInvocationParameterValues(retainedFunction, invocation, leakNode, context);
|
|
20550
|
-
let child = leakNode;
|
|
20551
|
-
let ancestor = leakNode.parent ?? null;
|
|
20552
|
-
while (ancestor && ancestor !== retainedFunction) {
|
|
20553
|
-
if (isNodeOfType(ancestor, "BlockStatement")) {
|
|
20554
|
-
const childIndex = ancestor.body.findIndex((statement) => statement === child);
|
|
20555
|
-
for (const precedingStatement of ancestor.body.slice(0, childIndex)) {
|
|
20556
|
-
if (!isNodeOfType(precedingStatement, "IfStatement") || precedingStatement.alternate || !isEarlyExitStatement$1(precedingStatement.consequent)) continue;
|
|
20557
|
-
if (readInvocationConditionTruthiness(precedingStatement.test, parameterValues, context) === "truthy") return true;
|
|
20558
|
-
}
|
|
20559
|
-
}
|
|
20560
|
-
let requiredTruthiness = null;
|
|
20561
|
-
let condition = null;
|
|
20562
|
-
if (isNodeOfType(ancestor, "IfStatement")) {
|
|
20563
|
-
condition = ancestor.test;
|
|
20564
|
-
requiredTruthiness = ancestor.consequent === child ? "truthy" : "falsy";
|
|
20565
|
-
} else if (isNodeOfType(ancestor, "ConditionalExpression")) {
|
|
20566
|
-
condition = ancestor.test;
|
|
20567
|
-
requiredTruthiness = ancestor.consequent === child ? "truthy" : "falsy";
|
|
20568
|
-
} else if (isNodeOfType(ancestor, "LogicalExpression") && ancestor.right === child && ancestor.operator !== "??") {
|
|
20569
|
-
condition = ancestor.left;
|
|
20570
|
-
requiredTruthiness = ancestor.operator === "&&" ? "truthy" : "falsy";
|
|
20571
|
-
} else if ((isNodeOfType(ancestor, "WhileStatement") || isNodeOfType(ancestor, "DoWhileStatement")) && ancestor.body === child) {
|
|
20572
|
-
condition = ancestor.test;
|
|
20573
|
-
requiredTruthiness = "truthy";
|
|
20574
|
-
} else if (isNodeOfType(ancestor, "ForStatement") && ancestor.body === child && ancestor.test) {
|
|
20575
|
-
condition = ancestor.test;
|
|
20576
|
-
requiredTruthiness = "truthy";
|
|
20577
|
-
}
|
|
20578
|
-
if (condition && requiredTruthiness) {
|
|
20579
|
-
const conditionTruthiness = readInvocationConditionTruthiness(condition, parameterValues, context);
|
|
20580
|
-
if (conditionTruthiness !== "unknown" && conditionTruthiness !== requiredTruthiness) return true;
|
|
20581
|
-
}
|
|
20582
|
-
child = ancestor;
|
|
20583
|
-
ancestor = ancestor.parent ?? null;
|
|
20584
|
-
}
|
|
20585
|
-
return false;
|
|
20586
|
-
};
|
|
20587
|
-
const getEffectRetainedInvocations = (retainedFunction, context) => {
|
|
20588
|
-
if (!isFunctionLike$1(retainedFunction)) return [];
|
|
20589
|
-
const componentFunction = findEnclosingFunction$1(retainedFunction);
|
|
20590
|
-
if (!componentFunction || !isFunctionLike$1(componentFunction)) return [];
|
|
20591
|
-
const invocations = [];
|
|
20592
|
-
walkAst(componentFunction.body, (child) => {
|
|
20593
|
-
if (!isNodeOfType(child, "CallExpression") || findEnclosingFunction$1(child) !== componentFunction || !isReactHookCall(child, CLEANUP_EFFECT_HOOK_NAMES, context.scopes)) return;
|
|
20594
|
-
const effectCallback = getEffectCallback(child);
|
|
20595
|
-
if (!effectCallback || !isFunctionLike$1(effectCallback)) return;
|
|
20596
|
-
walkAst(effectCallback.body, (effectChild) => {
|
|
20597
|
-
if (effectChild !== effectCallback.body && isFunctionLike$1(effectChild)) return false;
|
|
20598
|
-
if (!isNodeOfType(effectChild, "CallExpression") || !isNodeReachableWithinFunction(effectChild, context)) return;
|
|
20599
|
-
const isDirectInvocation = resolveRefOwnedCleanupFunction(effectChild.callee, context) === retainedFunction;
|
|
20600
|
-
const isSynchronousIteratorInvocation = effectChild.arguments.some((argument) => isAstNode(argument) && resolveRefOwnedCleanupFunction(argument, context) === retainedFunction && isSynchronousIteratorCallbackCall(effectChild, argument));
|
|
20601
|
-
if (isDirectInvocation) invocations.push({
|
|
20602
|
-
call: effectChild,
|
|
20603
|
-
isDirect: true
|
|
20604
|
-
});
|
|
20605
|
-
if (isSynchronousIteratorInvocation) invocations.push({
|
|
20606
|
-
call: effectChild,
|
|
20607
|
-
isDirect: false
|
|
20608
|
-
});
|
|
20609
|
-
});
|
|
20610
|
-
});
|
|
20611
|
-
return invocations;
|
|
20612
|
-
};
|
|
20613
20396
|
const effectNeedsCleanup = defineRule({
|
|
20614
20397
|
id: "effect-needs-cleanup",
|
|
20615
20398
|
title: "Effect subscription or timer never cleaned up",
|
|
@@ -20620,19 +20403,13 @@ const effectNeedsCleanup = defineRule({
|
|
|
20620
20403
|
const reportRetainedLeak = (retainedFunction) => {
|
|
20621
20404
|
const refEffectUsage = getReactRefEffectUsage(retainedFunction, context);
|
|
20622
20405
|
if (!refEffectUsage && !isPotentiallyReachableFunction(retainedFunction, context)) return;
|
|
20623
|
-
const effectInvocations = getEffectRetainedInvocations(retainedFunction, context);
|
|
20624
|
-
const isEffectInvoked = effectInvocations.length > 0;
|
|
20625
20406
|
const leak = findRetainedFunctionLeak(retainedFunction, context, refEffectUsage ? {
|
|
20626
20407
|
allowReturnedResourceEscape: refEffectUsage.doesEffectOwnEveryResult,
|
|
20627
20408
|
allowReturnedTimerEscape: false,
|
|
20628
20409
|
includeOneShotTimers: true,
|
|
20629
20410
|
requireCallableReturnedResource: true
|
|
20630
|
-
} : isEffectInvoked ? {
|
|
20631
|
-
allowReturnedTimerEscape: false,
|
|
20632
|
-
includeOneShotTimers: true
|
|
20633
20411
|
} : void 0);
|
|
20634
20412
|
if (!leak) return;
|
|
20635
|
-
if (isEffectInvoked && leak.resourceName === "setTimeout" && (!isNodeReachableWithinFunction(leak.node, context) || isFunctionLike$1(retainedFunction) && retainedFunction.params.length > 0 && !context.cfg.isUnconditionalFromEntry(leak.node) && effectInvocations.every((invocation) => isLeakPathDisabledForInvocation(retainedFunction, leak.node, invocation, context)))) return;
|
|
20636
20413
|
const resourceNoun = RESOURCE_NOUN_BY_KIND[leak.kind];
|
|
20637
20414
|
context.report({
|
|
20638
20415
|
node: leak.node,
|
|
@@ -25052,14 +24829,14 @@ const getFirstLegendChild = (children, targetNode) => {
|
|
|
25052
24829
|
if (isNodeOfType(child, "JSXExpressionContainer")) {
|
|
25053
24830
|
const potentialLegends = [];
|
|
25054
24831
|
collectPotentialLegends(child.expression, potentialLegends);
|
|
25055
|
-
const containingLegend = potentialLegends.find((legend) => isDescendantOf
|
|
24832
|
+
const containingLegend = potentialLegends.find((legend) => isDescendantOf(targetNode, legend));
|
|
25056
24833
|
if (containingLegend) return containingLegend;
|
|
25057
24834
|
if (potentialLegends[0]) return potentialLegends[0];
|
|
25058
24835
|
}
|
|
25059
24836
|
}
|
|
25060
24837
|
return null;
|
|
25061
24838
|
};
|
|
25062
|
-
const isDescendantOf
|
|
24839
|
+
const isDescendantOf = (node, ancestor) => {
|
|
25063
24840
|
let current = node.parent;
|
|
25064
24841
|
while (current) {
|
|
25065
24842
|
if (current === ancestor) return true;
|
|
@@ -25084,7 +24861,7 @@ const isDisabledByFieldsetAncestor = (node, context) => {
|
|
|
25084
24861
|
while (ancestor) {
|
|
25085
24862
|
if (isNodeOfType(ancestor, "JSXElement") && resolveJsxElementType(ancestor.openingElement) === "fieldset" && openingElementMayBeDisabled(ancestor.openingElement, context)) {
|
|
25086
24863
|
const firstLegend = getFirstLegendChild(ancestor.children, node);
|
|
25087
|
-
if (!firstLegend || !isDescendantOf
|
|
24864
|
+
if (!firstLegend || !isDescendantOf(node, firstLegend)) return true;
|
|
25088
24865
|
}
|
|
25089
24866
|
ancestor = ancestor.parent;
|
|
25090
24867
|
}
|
|
@@ -45603,6 +45380,14 @@ const noAriaInvalidWithoutDescription = defineRule({
|
|
|
45603
45380
|
} })
|
|
45604
45381
|
});
|
|
45605
45382
|
//#endregion
|
|
45383
|
+
//#region src/plugin/utils/is-early-exit-statement.ts
|
|
45384
|
+
const isEarlyExitStatement$1 = (statement) => {
|
|
45385
|
+
if (!statement) return false;
|
|
45386
|
+
if (statementAlwaysExits$1(statement)) return true;
|
|
45387
|
+
if (isNodeOfType(statement, "BlockStatement")) return isEarlyExitStatement$1(statement.body.at(-1));
|
|
45388
|
+
return isNodeOfType(statement, "ContinueStatement") || isNodeOfType(statement, "BreakStatement");
|
|
45389
|
+
};
|
|
45390
|
+
//#endregion
|
|
45606
45391
|
//#region src/plugin/utils/unwrap-negative-guard-form.ts
|
|
45607
45392
|
const unwrapNegativeGuardForm = (test) => {
|
|
45608
45393
|
const expression = stripParenExpression(test);
|
|
@@ -56090,9 +55875,6 @@ const isInitialOnlyPropName = (propName) => {
|
|
|
56090
55875
|
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);
|
|
56091
55876
|
};
|
|
56092
55877
|
//#endregion
|
|
56093
|
-
//#region src/plugin/utils/nextjs-page-data-export-names.ts
|
|
56094
|
-
const NEXTJS_PAGE_DATA_EXPORT_NAMES = new Set(["getServerSideProps", "getStaticProps"]);
|
|
56095
|
-
//#endregion
|
|
56096
55878
|
//#region src/plugin/rules/state-and-effects/no-derived-use-state.ts
|
|
56097
55879
|
const isInitialOnlySeedName = (propName) => isInitialOnlyPropName(propName) || propName === "initial" || propName === "autoFocus" || propName === "autoPlay" || propName === "startOpen" || /^initially[A-Z]/.test(propName) || /Initial([A-Z]|$)/.test(propName);
|
|
56098
55880
|
const SNAPSHOT_STATE_NAME_PATTERN = /^(initial|previous|prev|preserved|saved|original|cached|snapshot|prior|debounced|deferred)([A-Z_]|$)/;
|
|
@@ -56249,6 +56031,7 @@ const isDraftCommittedToParent = (componentFunction, stateValueName, isPropName)
|
|
|
56249
56031
|
});
|
|
56250
56032
|
return isCommitted;
|
|
56251
56033
|
};
|
|
56034
|
+
const NEXTJS_PAGE_DATA_EXPORT_NAMES = new Set(["getServerSideProps", "getStaticProps"]);
|
|
56252
56035
|
const isNextjsDataFetchingPage = (node) => {
|
|
56253
56036
|
const program = findProgramRoot(node);
|
|
56254
56037
|
if (!program) return false;
|
|
@@ -64500,106 +64283,6 @@ const isGatedByFalsyInitialState = (node, scopes) => {
|
|
|
64500
64283
|
};
|
|
64501
64284
|
//#endregion
|
|
64502
64285
|
//#region src/plugin/rules/performance/no-hydration-branch-on-browser-global.ts
|
|
64503
|
-
const findGuardingIfStatements = (node, functionBoundary) => {
|
|
64504
|
-
const guardingIfStatements = [];
|
|
64505
|
-
let currentNode = node.parent;
|
|
64506
|
-
while (currentNode && currentNode !== functionBoundary) {
|
|
64507
|
-
if (isNodeOfType(currentNode, "IfStatement")) guardingIfStatements.push(currentNode);
|
|
64508
|
-
currentNode = currentNode.parent;
|
|
64509
|
-
}
|
|
64510
|
-
return guardingIfStatements;
|
|
64511
|
-
};
|
|
64512
|
-
const doesNodeReadSymbol = (node, symbol) => {
|
|
64513
|
-
let doesReadSymbol = false;
|
|
64514
|
-
walkAst(node, (childNode) => {
|
|
64515
|
-
if (isNodeOfType(childNode, "Identifier") && symbol.references.some((reference) => reference.identifier === childNode && reference.flag !== "write")) {
|
|
64516
|
-
doesReadSymbol = true;
|
|
64517
|
-
return false;
|
|
64518
|
-
}
|
|
64519
|
-
});
|
|
64520
|
-
return doesReadSymbol;
|
|
64521
|
-
};
|
|
64522
|
-
const collectWrittenSymbols = (node, scopes) => {
|
|
64523
|
-
const writtenSymbols = /* @__PURE__ */ new Set();
|
|
64524
|
-
walkAst(node, (childNode) => {
|
|
64525
|
-
if (childNode !== node && isFunctionLike$1(childNode)) return false;
|
|
64526
|
-
if (!isNodeOfType(childNode, "Identifier")) return;
|
|
64527
|
-
const reference = scopes.referenceFor(childNode);
|
|
64528
|
-
if (!reference || reference.flag === "read" || !reference.resolvedSymbol) return;
|
|
64529
|
-
writtenSymbols.add(reference.resolvedSymbol);
|
|
64530
|
-
});
|
|
64531
|
-
return writtenSymbols;
|
|
64532
|
-
};
|
|
64533
|
-
const isDescendantOf = (node, ancestorNode) => {
|
|
64534
|
-
let currentNode = node.parent;
|
|
64535
|
-
while (currentNode) {
|
|
64536
|
-
if (currentNode === ancestorNode) return true;
|
|
64537
|
-
currentNode = currentNode.parent;
|
|
64538
|
-
}
|
|
64539
|
-
return false;
|
|
64540
|
-
};
|
|
64541
|
-
const getAssignedValue = (identifier) => {
|
|
64542
|
-
const assignmentExpression = identifier.parent;
|
|
64543
|
-
return isNodeOfType(assignmentExpression, "AssignmentExpression") && assignmentExpression.operator === "=" && assignmentExpression.left === identifier ? assignmentExpression.right : null;
|
|
64544
|
-
};
|
|
64545
|
-
const doesGuardPreserveInitialSymbolValue = (symbol, guardingIfStatement, scopes) => {
|
|
64546
|
-
const initialValue = symbol.initializer;
|
|
64547
|
-
if (!initialValue) return false;
|
|
64548
|
-
const guardedWrites = symbol.references.filter((reference) => reference.flag !== "read" && isDescendantOf(reference.identifier, guardingIfStatement));
|
|
64549
|
-
return guardedWrites.length > 0 && guardedWrites.every((reference) => {
|
|
64550
|
-
const assignedValue = getAssignedValue(reference.identifier);
|
|
64551
|
-
return Boolean(assignedValue && areExpressionsStructurallyEqual(initialValue, assignedValue) && doEquivalentExpressionBindingsMatch(initialValue, assignedValue, scopes));
|
|
64552
|
-
});
|
|
64553
|
-
};
|
|
64554
|
-
const isWriteOverwrittenBefore = (symbol, writeIdentifier, guardingIfStatement, readIdentifier, context) => symbol.references.some((reference) => reference.flag !== "read" && reference.identifier !== writeIdentifier && !isDescendantOf(reference.identifier, guardingIfStatement) && isNodeReachableWithinFunction(reference.identifier, context) && isUnconditionalOrStaticallySelected(reference.identifier, context) && getNodeStartIndex(reference.identifier) > getNodeStartIndex(writeIdentifier) && getNodeStartIndex(reference.identifier) < getNodeStartIndex(readIdentifier));
|
|
64555
|
-
const isUnconditionalOrStaticallySelected = (node, context) => {
|
|
64556
|
-
if (context.cfg.isUnconditionalFromEntry(node)) return true;
|
|
64557
|
-
let currentNode = node;
|
|
64558
|
-
let outermostStaticIfStatement = null;
|
|
64559
|
-
let parentNode = currentNode.parent;
|
|
64560
|
-
while (parentNode) {
|
|
64561
|
-
if (isFunctionLike$1(parentNode)) break;
|
|
64562
|
-
if (isNodeOfType(parentNode, "IfStatement")) {
|
|
64563
|
-
const staticResult = readInitialStateBoolean(parentNode.test, context.scopes);
|
|
64564
|
-
let selectedBranch = null;
|
|
64565
|
-
if (staticResult === true) selectedBranch = parentNode.consequent;
|
|
64566
|
-
if (staticResult === false) selectedBranch = parentNode.alternate;
|
|
64567
|
-
if (!selectedBranch || currentNode !== selectedBranch && !isDescendantOf(currentNode, selectedBranch)) return false;
|
|
64568
|
-
outermostStaticIfStatement = parentNode;
|
|
64569
|
-
}
|
|
64570
|
-
currentNode = parentNode;
|
|
64571
|
-
parentNode = currentNode.parent;
|
|
64572
|
-
}
|
|
64573
|
-
return Boolean(outermostStaticIfStatement && context.cfg.isUnconditionalFromEntry(outermostStaticIfStatement));
|
|
64574
|
-
};
|
|
64575
|
-
const containsExplicitReactRuntimeReference = (node, scopes) => {
|
|
64576
|
-
let hasRuntimeReference = false;
|
|
64577
|
-
walkAst(node, (childNode) => {
|
|
64578
|
-
if (isNodeOfType(childNode, "ImportDeclaration") && typeof childNode.source.value === "string" && REACT_RUNTIME_MODULE_SOURCES.has(childNode.source.value)) {
|
|
64579
|
-
hasRuntimeReference = true;
|
|
64580
|
-
return false;
|
|
64581
|
-
}
|
|
64582
|
-
if (!isNodeOfType(childNode, "CallExpression")) return;
|
|
64583
|
-
const sourceArgument = (childNode.arguments ?? [])[0];
|
|
64584
|
-
if (!isNodeOfType(childNode.callee, "Identifier") || childNode.callee.name !== "require" || !scopes.isGlobalReference(childNode.callee) || !isNodeOfType(sourceArgument, "Literal") || typeof sourceArgument.value !== "string" || !REACT_RUNTIME_MODULE_SOURCES.has(sourceArgument.value)) return;
|
|
64585
|
-
hasRuntimeReference = true;
|
|
64586
|
-
return false;
|
|
64587
|
-
});
|
|
64588
|
-
return hasRuntimeReference;
|
|
64589
|
-
};
|
|
64590
|
-
const findComponentRenderingLocalFunctionResult = (functionNode, scopes) => {
|
|
64591
|
-
const bindingIdentifier = getDirectFunctionBindingIdentifier(functionNode);
|
|
64592
|
-
if (!isNodeOfType(bindingIdentifier, "Identifier")) return null;
|
|
64593
|
-
const functionSymbol = scopes.symbolFor(bindingIdentifier);
|
|
64594
|
-
if (!functionSymbol) return null;
|
|
64595
|
-
for (const reference of functionSymbol.references) {
|
|
64596
|
-
const callExpression = reference.identifier.parent;
|
|
64597
|
-
if (!isNodeOfType(callExpression, "CallExpression") || callExpression.callee !== reference.identifier) continue;
|
|
64598
|
-
const componentOrHookNode = findRenderPhaseComponentOrHook(callExpression, scopes);
|
|
64599
|
-
if (componentOrHookNode && isInRenderedOutput(callExpression, componentOrHookNode, scopes)) return componentOrHookNode;
|
|
64600
|
-
}
|
|
64601
|
-
return null;
|
|
64602
|
-
};
|
|
64603
64286
|
const evaluateEquality$1 = (operator, left, right) => {
|
|
64604
64287
|
if (operator === "===" || operator === "==") return left === right;
|
|
64605
64288
|
if (operator === "!==" || operator === "!=") return left !== right;
|
|
@@ -64650,107 +64333,6 @@ const readLogicalConditionResult = (operator, leftResult, rightResult) => {
|
|
|
64650
64333
|
if (leftResult === false && rightResult === false) return false;
|
|
64651
64334
|
return null;
|
|
64652
64335
|
};
|
|
64653
|
-
const areLooselyEqualPrimitiveResults = (left, right) => {
|
|
64654
|
-
if (left.kind === right.kind) return left.value === right.value;
|
|
64655
|
-
if (left.kind === "null" && right.kind === "undefined" || left.kind === "undefined" && right.kind === "null") return true;
|
|
64656
|
-
if (left.kind === "boolean") return areLooselyEqualPrimitiveResults({
|
|
64657
|
-
kind: "number",
|
|
64658
|
-
value: left.value ? 1 : 0
|
|
64659
|
-
}, right);
|
|
64660
|
-
if (right.kind === "boolean") return areLooselyEqualPrimitiveResults(left, {
|
|
64661
|
-
kind: "number",
|
|
64662
|
-
value: right.value ? 1 : 0
|
|
64663
|
-
});
|
|
64664
|
-
if (left.kind === "number" && right.kind === "string") return left.value === Number(right.value);
|
|
64665
|
-
if (left.kind === "string" && right.kind === "number") return Number(left.value) === right.value;
|
|
64666
|
-
return false;
|
|
64667
|
-
};
|
|
64668
|
-
const readHydrationPrimitiveResult = (expression, context, runtime, state) => {
|
|
64669
|
-
const unwrappedExpression = stripParenExpression(expression);
|
|
64670
|
-
const predicateMatch = matchBrowserPredicate(unwrappedExpression, context);
|
|
64671
|
-
if (predicateMatch) return {
|
|
64672
|
-
kind: "boolean",
|
|
64673
|
-
value: predicateMatch[`${runtime}Result`]
|
|
64674
|
-
};
|
|
64675
|
-
if (isNodeOfType(unwrappedExpression, "Literal")) {
|
|
64676
|
-
const value = unwrappedExpression.value;
|
|
64677
|
-
if (value === null) return {
|
|
64678
|
-
kind: "null",
|
|
64679
|
-
value
|
|
64680
|
-
};
|
|
64681
|
-
if (typeof value === "boolean") return {
|
|
64682
|
-
kind: "boolean",
|
|
64683
|
-
value
|
|
64684
|
-
};
|
|
64685
|
-
if (typeof value === "number") return {
|
|
64686
|
-
kind: "number",
|
|
64687
|
-
value
|
|
64688
|
-
};
|
|
64689
|
-
if (typeof value === "string") return {
|
|
64690
|
-
kind: "string",
|
|
64691
|
-
value
|
|
64692
|
-
};
|
|
64693
|
-
return null;
|
|
64694
|
-
}
|
|
64695
|
-
if (isNodeOfType(unwrappedExpression, "Identifier") && unwrappedExpression.name === "undefined" && context.scopes.isGlobalReference(unwrappedExpression)) return {
|
|
64696
|
-
kind: "undefined",
|
|
64697
|
-
value: void 0
|
|
64698
|
-
};
|
|
64699
|
-
if (isNodeOfType(unwrappedExpression, "Identifier")) {
|
|
64700
|
-
const symbol = context.scopes.symbolFor(unwrappedExpression);
|
|
64701
|
-
const parameterValue = symbol ? state.parameterValuesBySymbolId.get(symbol.id) : null;
|
|
64702
|
-
if (symbol && parameterValue && !state.visitedSymbolIds.has(symbol.id)) {
|
|
64703
|
-
state.visitedSymbolIds.add(symbol.id);
|
|
64704
|
-
const result = readHydrationPrimitiveResult(parameterValue, context, runtime, state);
|
|
64705
|
-
state.visitedSymbolIds.delete(symbol.id);
|
|
64706
|
-
return result;
|
|
64707
|
-
}
|
|
64708
|
-
if (symbol && symbol.kind === "const" && symbol.initializer && symbol.references.every((reference) => reference.flag === "read") && !state.visitedSymbolIds.has(symbol.id)) {
|
|
64709
|
-
state.visitedSymbolIds.add(symbol.id);
|
|
64710
|
-
const result = readHydrationPrimitiveResult(symbol.initializer, context, runtime, state);
|
|
64711
|
-
state.visitedSymbolIds.delete(symbol.id);
|
|
64712
|
-
return result;
|
|
64713
|
-
}
|
|
64714
|
-
}
|
|
64715
|
-
if (isNodeOfType(unwrappedExpression, "UnaryExpression") && unwrappedExpression.operator === "!") {
|
|
64716
|
-
const argumentResult = readHydrationConditionResult(unwrappedExpression.argument, context, runtime, state);
|
|
64717
|
-
return argumentResult === null ? null : {
|
|
64718
|
-
kind: "boolean",
|
|
64719
|
-
value: !argumentResult
|
|
64720
|
-
};
|
|
64721
|
-
}
|
|
64722
|
-
if (isNodeOfType(unwrappedExpression, "BinaryExpression")) {
|
|
64723
|
-
const leftResult = readHydrationPrimitiveResult(unwrappedExpression.left, context, runtime, state);
|
|
64724
|
-
const rightResult = readHydrationPrimitiveResult(unwrappedExpression.right, context, runtime, state);
|
|
64725
|
-
if (!leftResult || !rightResult) return null;
|
|
64726
|
-
if (unwrappedExpression.operator === "===" || unwrappedExpression.operator === "!==") {
|
|
64727
|
-
const areEqual = leftResult.kind === rightResult.kind && leftResult.value === rightResult.value;
|
|
64728
|
-
return {
|
|
64729
|
-
kind: "boolean",
|
|
64730
|
-
value: unwrappedExpression.operator === "===" ? areEqual : !areEqual
|
|
64731
|
-
};
|
|
64732
|
-
}
|
|
64733
|
-
if (unwrappedExpression.operator === "==" || unwrappedExpression.operator === "!=") {
|
|
64734
|
-
const areEqual = areLooselyEqualPrimitiveResults(leftResult, rightResult);
|
|
64735
|
-
return {
|
|
64736
|
-
kind: "boolean",
|
|
64737
|
-
value: unwrappedExpression.operator === "==" ? areEqual : !areEqual
|
|
64738
|
-
};
|
|
64739
|
-
}
|
|
64740
|
-
}
|
|
64741
|
-
if (isNodeOfType(unwrappedExpression, "CallExpression")) {
|
|
64742
|
-
const callArguments = unwrappedExpression.arguments ?? [];
|
|
64743
|
-
const callee = stripParenExpression(unwrappedExpression.callee);
|
|
64744
|
-
if (isNodeOfType(callee, "Identifier") && callee.name === "Boolean" && context.scopes.isGlobalReference(callee) && callArguments.length === 1 && !isNodeOfType(callArguments[0], "SpreadElement")) {
|
|
64745
|
-
const argumentResult = readHydrationConditionResult(callArguments[0], context, runtime, state);
|
|
64746
|
-
return argumentResult === null ? null : {
|
|
64747
|
-
kind: "boolean",
|
|
64748
|
-
value: argumentResult
|
|
64749
|
-
};
|
|
64750
|
-
}
|
|
64751
|
-
}
|
|
64752
|
-
return null;
|
|
64753
|
-
};
|
|
64754
64336
|
const readHydrationConditionResult = (expression, context, runtime, state) => {
|
|
64755
64337
|
const unwrappedExpression = stripParenExpression(expression);
|
|
64756
64338
|
const predicateMatch = matchBrowserPredicate(unwrappedExpression, context);
|
|
@@ -64799,10 +64381,6 @@ const readHydrationConditionResult = (expression, context, runtime, state) => {
|
|
|
64799
64381
|
parameterValuesBySymbolId
|
|
64800
64382
|
});
|
|
64801
64383
|
}
|
|
64802
|
-
if (isNodeOfType(unwrappedExpression, "BinaryExpression")) {
|
|
64803
|
-
const result = readHydrationPrimitiveResult(unwrappedExpression, context, runtime, state);
|
|
64804
|
-
return result?.kind === "boolean" && typeof result.value === "boolean" ? result.value : null;
|
|
64805
|
-
}
|
|
64806
64384
|
if (isNodeOfType(unwrappedExpression, "UnaryExpression") && unwrappedExpression.operator === "!") {
|
|
64807
64385
|
const argumentResult = readHydrationConditionResult(unwrappedExpression.argument, context, runtime, state);
|
|
64808
64386
|
return argumentResult === null ? null : !argumentResult;
|
|
@@ -64863,19 +64441,13 @@ const doEquivalentExpressionBindingsMatch = (leftExpression, rightExpression, sc
|
|
|
64863
64441
|
const rightSymbol = scopes.symbolFor(right);
|
|
64864
64442
|
return leftSymbol || rightSymbol ? leftSymbol?.id === rightSymbol?.id : true;
|
|
64865
64443
|
}
|
|
64866
|
-
|
|
64867
|
-
|
|
64868
|
-
|
|
64869
|
-
|
|
64870
|
-
|
|
64871
|
-
|
|
64872
|
-
|
|
64873
|
-
}
|
|
64874
|
-
if (!Array.isArray(leftValue)) continue;
|
|
64875
|
-
if (!Array.isArray(rightValue)) return false;
|
|
64876
|
-
const leftNodes = leftValue.filter(isAstNode);
|
|
64877
|
-
const rightNodes = rightValue.filter(isAstNode);
|
|
64878
|
-
if (leftNodes.length !== rightNodes.length || leftNodes.some((leftNode, index) => !rightNodes[index] || !doEquivalentExpressionBindingsMatch(leftNode, rightNodes[index], scopes))) return false;
|
|
64444
|
+
if (isNodeOfType(left, "MemberExpression") && isNodeOfType(right, "MemberExpression")) return doEquivalentExpressionBindingsMatch(left.object, right.object, scopes) && (!left.computed || doEquivalentExpressionBindingsMatch(left.property, right.property, scopes));
|
|
64445
|
+
if (isNodeOfType(left, "CallExpression") && isNodeOfType(right, "CallExpression")) {
|
|
64446
|
+
const rightArguments = right.arguments ?? [];
|
|
64447
|
+
return doEquivalentExpressionBindingsMatch(left.callee, right.callee, scopes) && (left.arguments ?? []).every((argument, index) => {
|
|
64448
|
+
const rightArgument = rightArguments[index];
|
|
64449
|
+
return Boolean(rightArgument && doEquivalentExpressionBindingsMatch(argument, rightArgument, scopes));
|
|
64450
|
+
});
|
|
64879
64451
|
}
|
|
64880
64452
|
return true;
|
|
64881
64453
|
};
|
|
@@ -64889,57 +64461,6 @@ const doHelperReturnValuesDiffer = (leftValues, rightValues, context) => {
|
|
|
64889
64461
|
const everyValueHasEquivalent = (values, candidateValues) => values.every((value) => candidateValues.some((candidateValue) => areHelperReturnValuesEquivalent(value, candidateValue, context)));
|
|
64890
64462
|
return !everyValueHasEquivalent(leftValues, rightValues) || !everyValueHasEquivalent(rightValues, leftValues);
|
|
64891
64463
|
};
|
|
64892
|
-
const isExpressionProvablyReflexive = (expression, context, visitedSymbolIds = /* @__PURE__ */ new Set()) => {
|
|
64893
|
-
const unwrappedExpression = stripParenExpression(expression);
|
|
64894
|
-
if (matchBrowserPredicate(unwrappedExpression, context)) return true;
|
|
64895
|
-
if (isNodeOfType(unwrappedExpression, "Literal")) return typeof unwrappedExpression.value !== "number" || !Number.isNaN(unwrappedExpression.value);
|
|
64896
|
-
if (isNodeOfType(unwrappedExpression, "Identifier") && unwrappedExpression.name === "undefined" && context.scopes.isGlobalReference(unwrappedExpression)) return true;
|
|
64897
|
-
if (isNodeOfType(unwrappedExpression, "Identifier")) {
|
|
64898
|
-
const symbol = context.scopes.symbolFor(unwrappedExpression);
|
|
64899
|
-
if (!symbol || visitedSymbolIds.has(symbol.id) || !symbol.initializer) return false;
|
|
64900
|
-
visitedSymbolIds.add(symbol.id);
|
|
64901
|
-
const assignedValues = symbol.references.filter((reference) => reference.flag !== "read").map((reference) => getAssignedValue(reference.identifier));
|
|
64902
|
-
const isReflexive = isExpressionProvablyReflexive(symbol.initializer, context, visitedSymbolIds) && assignedValues.every((assignedValue) => Boolean(assignedValue && isExpressionProvablyReflexive(assignedValue, context, visitedSymbolIds)));
|
|
64903
|
-
visitedSymbolIds.delete(symbol.id);
|
|
64904
|
-
return isReflexive;
|
|
64905
|
-
}
|
|
64906
|
-
if (isNodeOfType(unwrappedExpression, "ConditionalExpression")) return isExpressionProvablyReflexive(unwrappedExpression.consequent, context, visitedSymbolIds) && isExpressionProvablyReflexive(unwrappedExpression.alternate, context, visitedSymbolIds);
|
|
64907
|
-
if (isNodeOfType(unwrappedExpression, "UnaryExpression") && (unwrappedExpression.operator === "!" || unwrappedExpression.operator === "typeof" || unwrappedExpression.operator === "void")) return true;
|
|
64908
|
-
if (isNodeOfType(unwrappedExpression, "BinaryExpression")) return unwrappedExpression.operator === "===" || unwrappedExpression.operator === "!==" || unwrappedExpression.operator === "==" || unwrappedExpression.operator === "!=";
|
|
64909
|
-
if (isNodeOfType(unwrappedExpression, "ArrayExpression") || isNodeOfType(unwrappedExpression, "ObjectExpression") || isNodeOfType(unwrappedExpression, "FunctionExpression") || isNodeOfType(unwrappedExpression, "ArrowFunctionExpression") || isNodeOfType(unwrappedExpression, "TemplateLiteral")) return true;
|
|
64910
|
-
if (!isNodeOfType(unwrappedExpression, "CallExpression")) return false;
|
|
64911
|
-
const callee = stripParenExpression(unwrappedExpression.callee);
|
|
64912
|
-
return isNodeOfType(callee, "Identifier") && callee.name === "Boolean" && context.scopes.isGlobalReference(callee);
|
|
64913
|
-
};
|
|
64914
|
-
const getReturnedObjectPropertyValues = (node, propertyName, scopes) => {
|
|
64915
|
-
if (isNodeOfType(node, "ReturnStatement")) return node.argument ? getReturnedObjectPropertyValues(node.argument, propertyName, scopes) : [];
|
|
64916
|
-
if (isNodeOfType(node, "ObjectExpression")) return node.properties.flatMap((property) => isNodeOfType(property, "Property") && property.kind === "init" && getResolvedStaticPropertyName(property, scopes) === propertyName ? [property.value] : []);
|
|
64917
|
-
if (isNodeOfType(node, "IfStatement")) return [...getReturnedObjectPropertyValues(node.consequent, propertyName, scopes), ...node.alternate ? getReturnedObjectPropertyValues(node.alternate, propertyName, scopes) : []];
|
|
64918
|
-
if (isNodeOfType(node, "TryStatement")) return [
|
|
64919
|
-
...getReturnedObjectPropertyValues(node.block, propertyName, scopes),
|
|
64920
|
-
...node.handler ? getReturnedObjectPropertyValues(node.handler.body, propertyName, scopes) : [],
|
|
64921
|
-
...node.finalizer ? getReturnedObjectPropertyValues(node.finalizer, propertyName, scopes) : []
|
|
64922
|
-
];
|
|
64923
|
-
if (!isNodeOfType(node, "BlockStatement")) return [];
|
|
64924
|
-
const propertyValues = [];
|
|
64925
|
-
for (const childStatement of node.body) {
|
|
64926
|
-
propertyValues.push(...getReturnedObjectPropertyValues(childStatement, propertyName, scopes));
|
|
64927
|
-
if (statementAlwaysExits$1(childStatement)) break;
|
|
64928
|
-
}
|
|
64929
|
-
return propertyValues;
|
|
64930
|
-
};
|
|
64931
|
-
const matchHydrationFunctionPropertyResult = (functionNode, propertyName, context, state) => {
|
|
64932
|
-
if (!isFunctionLike$1(functionNode) || state.visitedFunctionNodes.has(functionNode)) return null;
|
|
64933
|
-
state.visitedFunctionNodes.add(functionNode);
|
|
64934
|
-
const propertyValues = getReturnedObjectPropertyValues(functionNode.body, propertyName, context.scopes);
|
|
64935
|
-
let match = null;
|
|
64936
|
-
for (const propertyValue of propertyValues) {
|
|
64937
|
-
match = matchHydrationConditionInternal(propertyValue, context, state);
|
|
64938
|
-
if (match) break;
|
|
64939
|
-
}
|
|
64940
|
-
state.visitedFunctionNodes.delete(functionNode);
|
|
64941
|
-
return match;
|
|
64942
|
-
};
|
|
64943
64464
|
const matchHydrationConditionInternal = (expression, context, state) => {
|
|
64944
64465
|
const unwrappedExpression = stripParenExpression(expression);
|
|
64945
64466
|
const predicateMatch = matchBrowserPredicate(unwrappedExpression, context);
|
|
@@ -64956,90 +64477,14 @@ const matchHydrationConditionInternal = (expression, context, state) => {
|
|
|
64956
64477
|
state.visitedSymbolIds.delete(symbol.id);
|
|
64957
64478
|
return match;
|
|
64958
64479
|
}
|
|
64959
|
-
if (symbol && (symbol.kind === "let" || symbol.kind === "var") && !state.visitedSymbolIds.has(symbol.id)) {
|
|
64960
|
-
state.visitedSymbolIds.add(symbol.id);
|
|
64961
|
-
if (symbol.initializer && symbol.references.every((reference) => reference.flag === "read")) {
|
|
64962
|
-
const match = matchHydrationConditionInternal(symbol.initializer, context, state);
|
|
64963
|
-
state.visitedSymbolIds.delete(symbol.id);
|
|
64964
|
-
return match;
|
|
64965
|
-
}
|
|
64966
|
-
for (const reference of symbol.references) {
|
|
64967
|
-
if (reference.flag === "read") continue;
|
|
64968
|
-
if (!isNodeReachableWithinFunction(reference.identifier, context)) continue;
|
|
64969
|
-
const enclosingFunction = findEnclosingFunction$1(reference.identifier);
|
|
64970
|
-
if (!enclosingFunction) continue;
|
|
64971
|
-
for (const guardingIfStatement of findGuardingIfStatements(reference.identifier, enclosingFunction)) {
|
|
64972
|
-
if (doesGuardPreserveInitialSymbolValue(symbol, guardingIfStatement, context.scopes) || isWriteOverwrittenBefore(symbol, reference.identifier, guardingIfStatement, unwrappedExpression, context)) continue;
|
|
64973
|
-
const match = matchHydrationConditionInternal(guardingIfStatement.test, context, state);
|
|
64974
|
-
if (match) {
|
|
64975
|
-
state.visitedSymbolIds.delete(symbol.id);
|
|
64976
|
-
return match;
|
|
64977
|
-
}
|
|
64978
|
-
}
|
|
64979
|
-
}
|
|
64980
|
-
const readingFunction = findEnclosingFunction$1(unwrappedExpression);
|
|
64981
|
-
for (const reference of symbol.references) {
|
|
64982
|
-
if (reference.flag === "read") continue;
|
|
64983
|
-
const writingFunction = findEnclosingFunction$1(reference.identifier);
|
|
64984
|
-
if (!readingFunction || !isFunctionLike$1(writingFunction) || writingFunction === readingFunction || writingFunction.async || writingFunction.params.length > 0 || isNodeOfType(writingFunction, "FunctionDeclaration") && writingFunction.generator || isNodeOfType(writingFunction, "FunctionExpression") && writingFunction.generator) continue;
|
|
64985
|
-
const assignedValue = getAssignedValue(reference.identifier);
|
|
64986
|
-
if (symbol.initializer && assignedValue && areExpressionsStructurallyEqual(symbol.initializer, assignedValue) && doEquivalentExpressionBindingsMatch(symbol.initializer, assignedValue, context.scopes)) continue;
|
|
64987
|
-
const functionBinding = getDirectFunctionBindingIdentifier(writingFunction);
|
|
64988
|
-
if (!isNodeOfType(functionBinding, "Identifier")) continue;
|
|
64989
|
-
const functionSymbol = context.scopes.symbolFor(functionBinding);
|
|
64990
|
-
if (!functionSymbol) continue;
|
|
64991
|
-
for (const functionReference of functionSymbol.references) {
|
|
64992
|
-
const callExpression = functionReference.identifier.parent;
|
|
64993
|
-
if (!isNodeOfType(callExpression, "CallExpression") || callExpression.callee !== functionReference.identifier || (callExpression.arguments ?? []).length > 0 || findEnclosingFunction$1(callExpression) !== readingFunction || !isNodeReachableWithinFunction(callExpression, context) || getNodeStartIndex(callExpression) >= getNodeStartIndex(unwrappedExpression)) continue;
|
|
64994
|
-
for (const guardingIfStatement of findGuardingIfStatements(callExpression, readingFunction)) {
|
|
64995
|
-
if (isWriteOverwrittenBefore(symbol, callExpression, guardingIfStatement, unwrappedExpression, context)) continue;
|
|
64996
|
-
const match = matchHydrationConditionInternal(guardingIfStatement.test, context, state);
|
|
64997
|
-
if (match) {
|
|
64998
|
-
state.visitedSymbolIds.delete(symbol.id);
|
|
64999
|
-
return match;
|
|
65000
|
-
}
|
|
65001
|
-
}
|
|
65002
|
-
}
|
|
65003
|
-
}
|
|
65004
|
-
state.visitedSymbolIds.delete(symbol.id);
|
|
65005
|
-
}
|
|
65006
64480
|
if (!symbol || symbol.kind !== "const" || !symbol.initializer || symbol.references.some((reference) => reference.flag !== "read") || state.visitedSymbolIds.has(symbol.id)) return null;
|
|
65007
64481
|
state.visitedSymbolIds.add(symbol.id);
|
|
65008
64482
|
const match = matchHydrationConditionInternal(symbol.initializer, context, state);
|
|
65009
64483
|
state.visitedSymbolIds.delete(symbol.id);
|
|
65010
64484
|
return match;
|
|
65011
64485
|
}
|
|
65012
|
-
if (isNodeOfType(unwrappedExpression, "MemberExpression")) {
|
|
65013
|
-
const propertyName = getResolvedStaticPropertyName(unwrappedExpression, context.scopes, {
|
|
65014
|
-
allowConstNumericLiteral: true,
|
|
65015
|
-
stringifyNonStringLiterals: true
|
|
65016
|
-
});
|
|
65017
|
-
const object = stripParenExpression(unwrappedExpression.object);
|
|
65018
|
-
if (propertyName === null || !isNodeOfType(object, "CallExpression")) return null;
|
|
65019
|
-
const callArguments = object.arguments ?? [];
|
|
65020
|
-
if (isReactApiCall(object, "useMemo", context.scopes, {
|
|
65021
|
-
allowGlobalReactNamespace: true,
|
|
65022
|
-
resolveNamedAliases: true
|
|
65023
|
-
})) {
|
|
65024
|
-
const callbackArgument = callArguments[0];
|
|
65025
|
-
if (!callbackArgument || isNodeOfType(callbackArgument, "SpreadElement")) return null;
|
|
65026
|
-
const callbackFunction = resolveExactLocalFunction(callbackArgument, context.scopes);
|
|
65027
|
-
return isFunctionLike$1(callbackFunction) && callbackFunction.params.length === 0 ? matchHydrationFunctionPropertyResult(callbackFunction, propertyName, context, state) : null;
|
|
65028
|
-
}
|
|
65029
|
-
const helperFunction = resolveExactLocalFunction(object.callee, context.scopes);
|
|
65030
|
-
return isFunctionLike$1(helperFunction) && helperFunction.params.length === 0 && callArguments.length === 0 ? matchHydrationFunctionPropertyResult(helperFunction, propertyName, context, state) : null;
|
|
65031
|
-
}
|
|
65032
64486
|
if (isNodeOfType(unwrappedExpression, "CallExpression")) {
|
|
65033
64487
|
const callArguments = unwrappedExpression.arguments ?? [];
|
|
65034
|
-
if (isReactApiCall(unwrappedExpression, "useState", context.scopes, {
|
|
65035
|
-
allowGlobalReactNamespace: true,
|
|
65036
|
-
resolveNamedAliases: true
|
|
65037
|
-
})) {
|
|
65038
|
-
const initialState = callArguments[0];
|
|
65039
|
-
if (!initialState || isNodeOfType(initialState, "SpreadElement")) return null;
|
|
65040
|
-
const lazyInitializer = resolveExactLocalFunction(initialState, context.scopes);
|
|
65041
|
-
return isFunctionLike$1(lazyInitializer) && lazyInitializer.params.length === 0 ? matchHydrationFunctionResult(lazyInitializer, context, state) : matchHydrationConditionInternal(initialState, context, state);
|
|
65042
|
-
}
|
|
65043
64488
|
if (isReactApiCall(unwrappedExpression, "useMemo", context.scopes, {
|
|
65044
64489
|
allowGlobalReactNamespace: true,
|
|
65045
64490
|
resolveNamedAliases: true
|
|
@@ -65067,22 +64512,6 @@ const matchHydrationConditionInternal = (expression, context, state) => {
|
|
|
65067
64512
|
});
|
|
65068
64513
|
}
|
|
65069
64514
|
if (isNodeOfType(unwrappedExpression, "UnaryExpression") && unwrappedExpression.operator === "!") return matchHydrationConditionInternal(unwrappedExpression.argument, context, state);
|
|
65070
|
-
if (isNodeOfType(unwrappedExpression, "ConditionalExpression")) {
|
|
65071
|
-
const staticTestResult = readInitialStateBoolean(unwrappedExpression.test, context.scopes);
|
|
65072
|
-
if (staticTestResult !== null) return matchHydrationConditionInternal(staticTestResult ? unwrappedExpression.consequent : unwrappedExpression.alternate, context, state);
|
|
65073
|
-
return matchHydrationConditionInternal(unwrappedExpression.test, context, state) ?? matchHydrationConditionInternal(unwrappedExpression.consequent, context, state) ?? matchHydrationConditionInternal(unwrappedExpression.alternate, context, state);
|
|
65074
|
-
}
|
|
65075
|
-
if (isNodeOfType(unwrappedExpression, "BinaryExpression")) {
|
|
65076
|
-
if (unwrappedExpression.operator !== "===" && unwrappedExpression.operator !== "!==" && unwrappedExpression.operator !== "==" && unwrappedExpression.operator !== "!=") return null;
|
|
65077
|
-
const leftMatch = matchHydrationConditionInternal(unwrappedExpression.left, context, state);
|
|
65078
|
-
const rightMatch = matchHydrationConditionInternal(unwrappedExpression.right, context, state);
|
|
65079
|
-
const nestedMatch = leftMatch ?? rightMatch;
|
|
65080
|
-
if (!nestedMatch) return null;
|
|
65081
|
-
const clientResult = readHydrationConditionResult(unwrappedExpression, context, "client", state);
|
|
65082
|
-
const serverResult = readHydrationConditionResult(unwrappedExpression, context, "server", state);
|
|
65083
|
-
if (clientResult !== null && serverResult !== null) return clientResult !== serverResult ? nestedMatch : null;
|
|
65084
|
-
return leftMatch && rightMatch && areExpressionsStructurallyEqual(unwrappedExpression.left, unwrappedExpression.right) && doEquivalentExpressionBindingsMatch(unwrappedExpression.left, unwrappedExpression.right, context.scopes) && isExpressionProvablyReflexive(unwrappedExpression.left, context) ? null : nestedMatch;
|
|
65085
|
-
}
|
|
65086
64515
|
if (!isNodeOfType(unwrappedExpression, "LogicalExpression") || unwrappedExpression.operator !== "&&" && unwrappedExpression.operator !== "||") return null;
|
|
65087
64516
|
const leftMatch = matchHydrationConditionInternal(unwrappedExpression.left, context, state);
|
|
65088
64517
|
const rightMatch = matchHydrationConditionInternal(unwrappedExpression.right, context, state);
|
|
@@ -65099,13 +64528,8 @@ const matchHydrationReturningStatement = (statement, context, state) => {
|
|
|
65099
64528
|
const consequentValues = getReturnedValues(statement.consequent);
|
|
65100
64529
|
const alternateValues = statement.alternate ? getReturnedValues(statement.alternate) : findFollowingReturnedValues(statement);
|
|
65101
64530
|
if (conditionMatch && consequentValues.length > 0 && alternateValues.length > 0 && doHelperReturnValuesDiffer(consequentValues, alternateValues, context)) return conditionMatch;
|
|
65102
|
-
if (conditionMatch) {
|
|
65103
|
-
const followingReturnedValues = findFollowingReturnedValues(statement);
|
|
65104
|
-
if ([...new Set([...collectWrittenSymbols(statement.consequent, context.scopes), ...statement.alternate ? collectWrittenSymbols(statement.alternate, context.scopes) : []])].some((symbol) => !doesGuardPreserveInitialSymbolValue(symbol, statement, context.scopes) && followingReturnedValues.some((value) => doesNodeReadSymbol(value, symbol)))) return conditionMatch;
|
|
65105
|
-
}
|
|
65106
64531
|
return matchHydrationReturningStatement(statement.consequent, context, state) ?? (statement.alternate ? matchHydrationReturningStatement(statement.alternate, context, state) : null);
|
|
65107
64532
|
}
|
|
65108
|
-
if (isNodeOfType(statement, "TryStatement")) return matchHydrationReturningStatement(statement.block, context, state) ?? (statement.handler ? matchHydrationReturningStatement(statement.handler.body, context, state) : null) ?? (statement.finalizer ? matchHydrationReturningStatement(statement.finalizer, context, state) : null);
|
|
65109
64533
|
if (!isNodeOfType(statement, "BlockStatement")) return null;
|
|
65110
64534
|
for (const childStatement of statement.body) {
|
|
65111
64535
|
const match = matchHydrationReturningStatement(childStatement, context, state);
|
|
@@ -65126,62 +64550,47 @@ const matchHydrationCondition = (expression, context) => matchHydrationCondition
|
|
|
65126
64550
|
visitedFunctionNodes: /* @__PURE__ */ new Set(),
|
|
65127
64551
|
visitedSymbolIds: /* @__PURE__ */ new Set()
|
|
65128
64552
|
});
|
|
65129
|
-
const areNodeArraysEquivalent = (leftNodes, rightNodes
|
|
65130
|
-
const areRenderedBranchesEquivalent = (leftNode, rightNode
|
|
64553
|
+
const areNodeArraysEquivalent = (leftNodes, rightNodes) => leftNodes.length === rightNodes.length && leftNodes.every((leftNode, index) => areRenderedBranchesEquivalent(leftNode, rightNodes[index]));
|
|
64554
|
+
const areRenderedBranchesEquivalent = (leftNode, rightNode) => {
|
|
65131
64555
|
if (!leftNode || !rightNode) return leftNode === rightNode;
|
|
65132
64556
|
const left = stripParenExpression(leftNode);
|
|
65133
64557
|
const right = stripParenExpression(rightNode);
|
|
65134
|
-
if (areExpressionsStructurallyEqual(left, right)) return
|
|
64558
|
+
if (areExpressionsStructurallyEqual(left, right)) return true;
|
|
65135
64559
|
if (left.type !== right.type) return false;
|
|
65136
64560
|
if (isNodeOfType(left, "JSXText") && isNodeOfType(right, "JSXText")) return left.value === right.value;
|
|
65137
64561
|
if (isNodeOfType(left, "JSXExpressionContainer") && isNodeOfType(right, "JSXExpressionContainer")) {
|
|
65138
64562
|
if (!isAstNode(left.expression) || !isAstNode(right.expression)) return left.expression.type === right.expression.type;
|
|
65139
|
-
return areRenderedBranchesEquivalent(left.expression, right.expression
|
|
64563
|
+
return areRenderedBranchesEquivalent(left.expression, right.expression);
|
|
65140
64564
|
}
|
|
65141
64565
|
if (isNodeOfType(left, "JSXElement") && isNodeOfType(right, "JSXElement")) {
|
|
65142
64566
|
if (flattenJsxName$1(left.openingElement.name) !== flattenJsxName$1(right.openingElement.name)) return false;
|
|
65143
|
-
if (!areNodeArraysEquivalent(left.openingElement.attributes, right.openingElement.attributes
|
|
65144
|
-
return areNodeArraysEquivalent(left.children, right.children
|
|
64567
|
+
if (!areNodeArraysEquivalent(left.openingElement.attributes, right.openingElement.attributes)) return false;
|
|
64568
|
+
return areNodeArraysEquivalent(left.children, right.children);
|
|
65145
64569
|
}
|
|
65146
|
-
if (isNodeOfType(left, "JSXFragment") && isNodeOfType(right, "JSXFragment")) return areNodeArraysEquivalent(left.children, right.children
|
|
64570
|
+
if (isNodeOfType(left, "JSXFragment") && isNodeOfType(right, "JSXFragment")) return areNodeArraysEquivalent(left.children, right.children);
|
|
65147
64571
|
if (isNodeOfType(left, "JSXAttribute") && isNodeOfType(right, "JSXAttribute")) {
|
|
65148
64572
|
if (flattenJsxName$1(left.name) !== flattenJsxName$1(right.name)) return false;
|
|
65149
|
-
return areRenderedBranchesEquivalent(left.value, right.value
|
|
64573
|
+
return areRenderedBranchesEquivalent(left.value, right.value);
|
|
65150
64574
|
}
|
|
65151
|
-
if (isNodeOfType(left, "JSXSpreadAttribute") && isNodeOfType(right, "JSXSpreadAttribute")) return areRenderedBranchesEquivalent(left.argument, right.argument
|
|
64575
|
+
if (isNodeOfType(left, "JSXSpreadAttribute") && isNodeOfType(right, "JSXSpreadAttribute")) return areRenderedBranchesEquivalent(left.argument, right.argument);
|
|
65152
64576
|
if (isNodeOfType(left, "TemplateLiteral") && isNodeOfType(right, "TemplateLiteral")) {
|
|
65153
64577
|
if (left.quasis.length !== right.quasis.length) return false;
|
|
65154
64578
|
if (!left.quasis.every((quasi, index) => quasi.value.cooked === right.quasis[index]?.value.cooked && quasi.value.raw === right.quasis[index]?.value.raw)) return false;
|
|
65155
|
-
return areNodeArraysEquivalent(left.expressions, right.expressions
|
|
64579
|
+
return areNodeArraysEquivalent(left.expressions, right.expressions);
|
|
65156
64580
|
}
|
|
65157
64581
|
return false;
|
|
65158
64582
|
};
|
|
65159
|
-
const
|
|
65160
|
-
if (isReactApiCall(node, "createElement", scopes, {
|
|
65161
|
-
allowGlobalReactNamespace: true,
|
|
65162
|
-
resolveNamedAliases: true
|
|
65163
|
-
})) return true;
|
|
65164
|
-
if (!isNodeOfType(node, "CallExpression")) return false;
|
|
65165
|
-
const callee = stripParenExpression(node.callee);
|
|
65166
|
-
if (!isNodeOfType(callee, "MemberExpression") || callee.computed || !isNodeOfType(callee.property, "Identifier") || callee.property.name !== "createElement") return false;
|
|
65167
|
-
const receiver = stripParenExpression(callee.object);
|
|
65168
|
-
const namespaceIdentifier = isNodeOfType(receiver, "MemberExpression") && !receiver.computed && isNodeOfType(receiver.property, "Identifier") && receiver.property.name === "default" ? stripParenExpression(receiver.object) : receiver;
|
|
65169
|
-
if (!isNodeOfType(namespaceIdentifier, "Identifier")) return false;
|
|
65170
|
-
const namespaceSymbol = scopes.symbolFor(namespaceIdentifier);
|
|
65171
|
-
return Boolean(namespaceSymbol?.initializer && namespaceSymbol.references.every((reference) => reference.flag === "read") && containsExplicitReactRuntimeReference(namespaceSymbol.initializer, scopes));
|
|
65172
|
-
};
|
|
65173
|
-
const isRenderedValue = (node, scopes) => {
|
|
64583
|
+
const isRenderedValue = (node) => {
|
|
65174
64584
|
const unwrappedNode = stripParenExpression(node);
|
|
65175
64585
|
if (isNodeOfType(unwrappedNode, "Literal")) return unwrappedNode.value !== null && unwrappedNode.value !== true && unwrappedNode.value !== false && unwrappedNode.value !== "";
|
|
65176
64586
|
if (isNodeOfType(unwrappedNode, "TemplateLiteral")) return unwrappedNode.expressions.length > 0 || unwrappedNode.quasis[0]?.value.cooked !== "";
|
|
65177
|
-
if (isNodeOfType(unwrappedNode, "CallExpression")) return isProvenReactCreateElementCall(unwrappedNode, scopes);
|
|
65178
64587
|
return isNodeOfType(unwrappedNode, "JSXElement") || isNodeOfType(unwrappedNode, "JSXFragment");
|
|
65179
64588
|
};
|
|
65180
|
-
const findRenderedValueInAndBranch = (node
|
|
64589
|
+
const findRenderedValueInAndBranch = (node) => {
|
|
65181
64590
|
const unwrappedNode = stripParenExpression(node);
|
|
65182
|
-
if (
|
|
64591
|
+
if (isRenderedValue(unwrappedNode)) return unwrappedNode;
|
|
65183
64592
|
if (!isNodeOfType(unwrappedNode, "LogicalExpression") || unwrappedNode.operator !== "&&") return null;
|
|
65184
|
-
return findRenderedValueInAndBranch(unwrappedNode.right
|
|
64593
|
+
return findRenderedValueInAndBranch(unwrappedNode.right);
|
|
65185
64594
|
};
|
|
65186
64595
|
const findEnclosingJsxAttribute = (node) => {
|
|
65187
64596
|
let currentNode = node.parent;
|
|
@@ -65214,11 +64623,6 @@ const getReturnedValues = (statement) => {
|
|
|
65214
64623
|
if (!statement) return [];
|
|
65215
64624
|
if (isNodeOfType(statement, "ReturnStatement")) return statement.argument ? [statement.argument] : [];
|
|
65216
64625
|
if (isNodeOfType(statement, "IfStatement")) return [...getReturnedValues(statement.consequent), ...getReturnedValues(statement.alternate)];
|
|
65217
|
-
if (isNodeOfType(statement, "TryStatement")) return [
|
|
65218
|
-
...getReturnedValues(statement.block),
|
|
65219
|
-
...getReturnedValues(statement.handler?.body),
|
|
65220
|
-
...getReturnedValues(statement.finalizer)
|
|
65221
|
-
];
|
|
65222
64626
|
if (!isNodeOfType(statement, "BlockStatement")) return [];
|
|
65223
64627
|
const returnedValues = [];
|
|
65224
64628
|
for (const childStatement of statement.body) {
|
|
@@ -65227,127 +64631,6 @@ const getReturnedValues = (statement) => {
|
|
|
65227
64631
|
}
|
|
65228
64632
|
return returnedValues;
|
|
65229
64633
|
};
|
|
65230
|
-
const isPotentiallyRenderedValueInternal = (node, scopes, visitedFunctionNodes) => {
|
|
65231
|
-
const unwrappedNode = stripParenExpression(node);
|
|
65232
|
-
if (isRenderedValue(unwrappedNode, scopes)) return true;
|
|
65233
|
-
if (isNodeOfType(unwrappedNode, "ConditionalExpression")) return isPotentiallyRenderedValueInternal(unwrappedNode.consequent, scopes, visitedFunctionNodes) && isPotentiallyRenderedValueInternal(unwrappedNode.alternate, scopes, visitedFunctionNodes);
|
|
65234
|
-
if (isNodeOfType(unwrappedNode, "LogicalExpression")) return isPotentiallyRenderedValueInternal(unwrappedNode.right, scopes, visitedFunctionNodes);
|
|
65235
|
-
if (!isNodeOfType(unwrappedNode, "CallExpression")) return false;
|
|
65236
|
-
const calledFunction = resolveExactLocalFunction(unwrappedNode.callee, scopes);
|
|
65237
|
-
if (!isFunctionLike$1(calledFunction) || visitedFunctionNodes.has(calledFunction)) return false;
|
|
65238
|
-
visitedFunctionNodes.add(calledFunction);
|
|
65239
|
-
const returnedValues = isNodeOfType(calledFunction.body, "BlockStatement") ? getReturnedValues(calledFunction.body) : [calledFunction.body];
|
|
65240
|
-
const isPotentiallyRendered = returnedValues.length > 0 && returnedValues.every((returnedValue) => isPotentiallyRenderedValueInternal(returnedValue, scopes, visitedFunctionNodes));
|
|
65241
|
-
visitedFunctionNodes.delete(calledFunction);
|
|
65242
|
-
return isPotentiallyRendered;
|
|
65243
|
-
};
|
|
65244
|
-
const isPotentiallyRenderedValue = (node, scopes) => isPotentiallyRenderedValueInternal(node, scopes, /* @__PURE__ */ new Set());
|
|
65245
|
-
const findUseStateBindingSymbol = (node, componentOrHookNode, scopes) => {
|
|
65246
|
-
let currentNode = node.parent;
|
|
65247
|
-
while (currentNode && currentNode !== componentOrHookNode) {
|
|
65248
|
-
if (isNodeOfType(currentNode, "CallExpression") && isReactApiCall(currentNode, "useState", scopes, {
|
|
65249
|
-
allowGlobalReactNamespace: true,
|
|
65250
|
-
resolveNamedAliases: true
|
|
65251
|
-
}) && isNodeOfType(currentNode.parent, "VariableDeclarator") && isNodeOfType(currentNode.parent.id, "ArrayPattern")) {
|
|
65252
|
-
const stateBinding = currentNode.parent.id.elements?.[0];
|
|
65253
|
-
return isNodeOfType(stateBinding, "Identifier") ? scopes.symbolFor(stateBinding) : null;
|
|
65254
|
-
}
|
|
65255
|
-
if (isFunctionLike$1(currentNode)) return null;
|
|
65256
|
-
currentNode = currentNode.parent;
|
|
65257
|
-
}
|
|
65258
|
-
return null;
|
|
65259
|
-
};
|
|
65260
|
-
const doesReferenceControlStructuralRenderedValue = (referenceIdentifier) => {
|
|
65261
|
-
let currentNode = referenceIdentifier;
|
|
65262
|
-
let parentNode = currentNode.parent;
|
|
65263
|
-
while (parentNode) {
|
|
65264
|
-
if (isNodeOfType(parentNode, "ConditionalExpression") && parentNode.test === currentNode && (isStructuralRenderedValue(parentNode.consequent) || isStructuralRenderedValue(parentNode.alternate))) return true;
|
|
65265
|
-
if (isNodeOfType(parentNode, "LogicalExpression") && parentNode.left === currentNode && isStructuralRenderedValue(parentNode.right)) return true;
|
|
65266
|
-
if (isNodeOfType(parentNode, "JSXExpressionContainer") || isFunctionLike$1(parentNode)) return false;
|
|
65267
|
-
currentNode = parentNode;
|
|
65268
|
-
parentNode = currentNode.parent;
|
|
65269
|
-
}
|
|
65270
|
-
return false;
|
|
65271
|
-
};
|
|
65272
|
-
const isRenderedHydrationConsumer = (node, producerHookNode, scopes) => {
|
|
65273
|
-
const renderingComponent = findRenderPhaseComponentOrHook(node, scopes);
|
|
65274
|
-
return Boolean(renderingComponent && renderingComponent !== producerHookNode && isInRenderedOutput(node, renderingComponent, scopes) && !isGatedByFalsyInitialState(node, scopes) && !isAfterClientOnlyEarlyReturn(node, renderingComponent, scopes) && (!hasSuppressHydrationWarningAttribute(findEnclosingJsxOpeningElement(node)) || doesReferenceControlStructuralRenderedValue(node)));
|
|
65275
|
-
};
|
|
65276
|
-
const doesConsumerExpressionReachRenderedOutput = (node, producerHookNode, scopes, visitedSymbolIds) => {
|
|
65277
|
-
if (isRenderedHydrationConsumer(node, producerHookNode, scopes)) return true;
|
|
65278
|
-
const parentNode = node.parent;
|
|
65279
|
-
if (!isNodeOfType(parentNode, "VariableDeclarator") || parentNode.init !== node || !isNodeOfType(parentNode.id, "Identifier")) return false;
|
|
65280
|
-
const aliasSymbol = scopes.symbolFor(parentNode.id);
|
|
65281
|
-
if (!aliasSymbol || visitedSymbolIds.has(aliasSymbol.id)) return false;
|
|
65282
|
-
visitedSymbolIds.add(aliasSymbol.id);
|
|
65283
|
-
const doesReachRenderedOutput = aliasSymbol.references.some((reference) => doesConsumerExpressionReachRenderedOutput(reference.identifier, producerHookNode, scopes, visitedSymbolIds));
|
|
65284
|
-
visitedSymbolIds.delete(aliasSymbol.id);
|
|
65285
|
-
return doesReachRenderedOutput;
|
|
65286
|
-
};
|
|
65287
|
-
const doesConsumerBindingReachRenderedOutput = (bindingIdentifier, producerHookNode, scopes) => {
|
|
65288
|
-
if (!isNodeOfType(bindingIdentifier, "Identifier")) return false;
|
|
65289
|
-
const consumerSymbol = scopes.symbolFor(bindingIdentifier);
|
|
65290
|
-
if (!consumerSymbol) return false;
|
|
65291
|
-
return consumerSymbol.references.some((reference) => doesConsumerExpressionReachRenderedOutput(reference.identifier, producerHookNode, scopes, new Set([consumerSymbol.id])));
|
|
65292
|
-
};
|
|
65293
|
-
const getReturnedStatePaths = (returnedValue, stateSymbol, scopes) => {
|
|
65294
|
-
const unwrappedValue = stripParenExpression(returnedValue);
|
|
65295
|
-
if (isNodeOfType(unwrappedValue, "ObjectExpression")) return unwrappedValue.properties.flatMap((property) => {
|
|
65296
|
-
if (!isNodeOfType(property, "Property") || property.kind !== "init" || !doesNodeReadSymbol(property.value, stateSymbol)) return [];
|
|
65297
|
-
const propertyName = getResolvedStaticPropertyName(property, scopes);
|
|
65298
|
-
return propertyName === null ? [] : [{
|
|
65299
|
-
kind: "property",
|
|
65300
|
-
key: propertyName
|
|
65301
|
-
}];
|
|
65302
|
-
});
|
|
65303
|
-
if (isNodeOfType(unwrappedValue, "ArrayExpression")) return (unwrappedValue.elements ?? []).flatMap((element, index) => element && isAstNode(element) && doesNodeReadSymbol(element, stateSymbol) ? [{
|
|
65304
|
-
kind: "index",
|
|
65305
|
-
key: String(index)
|
|
65306
|
-
}] : []);
|
|
65307
|
-
return doesNodeReadSymbol(unwrappedValue, stateSymbol) ? [{
|
|
65308
|
-
kind: "direct",
|
|
65309
|
-
key: null
|
|
65310
|
-
}] : [];
|
|
65311
|
-
};
|
|
65312
|
-
const doesCallResultPathReachRenderedOutput = (callExpression, returnedStatePath, producerHookNode, scopes) => {
|
|
65313
|
-
const callParent = callExpression.parent;
|
|
65314
|
-
if (returnedStatePath.kind === "direct") return doesConsumerExpressionReachRenderedOutput(callExpression, producerHookNode, scopes, /* @__PURE__ */ new Set());
|
|
65315
|
-
if (isNodeOfType(callParent, "MemberExpression") && callParent.object === callExpression && getResolvedStaticPropertyName(callParent, scopes, {
|
|
65316
|
-
allowConstNumericLiteral: true,
|
|
65317
|
-
stringifyNonStringLiterals: true
|
|
65318
|
-
}) === returnedStatePath.key) return doesConsumerExpressionReachRenderedOutput(callParent, producerHookNode, scopes, /* @__PURE__ */ new Set());
|
|
65319
|
-
if (!isNodeOfType(callParent, "VariableDeclarator") || callParent.init !== callExpression) return false;
|
|
65320
|
-
if (returnedStatePath.kind === "property" && isNodeOfType(callParent.id, "ObjectPattern")) return callParent.id.properties.some((property) => isNodeOfType(property, "Property") && getResolvedStaticPropertyName(property, scopes) === returnedStatePath.key && doesConsumerBindingReachRenderedOutput(property.value, producerHookNode, scopes));
|
|
65321
|
-
if (returnedStatePath.kind === "index" && isNodeOfType(callParent.id, "ArrayPattern")) {
|
|
65322
|
-
const element = callParent.id.elements?.[Number(returnedStatePath.key)];
|
|
65323
|
-
return Boolean(element && doesConsumerBindingReachRenderedOutput(element, producerHookNode, scopes));
|
|
65324
|
-
}
|
|
65325
|
-
if (!isNodeOfType(callParent.id, "Identifier")) return false;
|
|
65326
|
-
const resultSymbol = scopes.symbolFor(callParent.id);
|
|
65327
|
-
if (!resultSymbol) return false;
|
|
65328
|
-
return resultSymbol.references.some((reference) => {
|
|
65329
|
-
const memberExpression = reference.identifier.parent;
|
|
65330
|
-
return Boolean(isNodeOfType(memberExpression, "MemberExpression") && memberExpression.object === reference.identifier && getResolvedStaticPropertyName(memberExpression, scopes, {
|
|
65331
|
-
allowConstNumericLiteral: true,
|
|
65332
|
-
stringifyNonStringLiterals: true
|
|
65333
|
-
}) === returnedStatePath.key && doesConsumerExpressionReachRenderedOutput(memberExpression, producerHookNode, scopes, new Set([resultSymbol.id])));
|
|
65334
|
-
});
|
|
65335
|
-
};
|
|
65336
|
-
const isReturnedUseStateInitializerRendered = (node, componentOrHookNode, scopes) => {
|
|
65337
|
-
if (!isFunctionLike$1(componentOrHookNode)) return false;
|
|
65338
|
-
const stateSymbol = findUseStateBindingSymbol(node, componentOrHookNode, scopes);
|
|
65339
|
-
if (!stateSymbol) return false;
|
|
65340
|
-
const returnedStatePaths = (isNodeOfType(componentOrHookNode.body, "BlockStatement") ? getReturnedValues(componentOrHookNode.body) : [componentOrHookNode.body]).flatMap((returnedValue) => getReturnedStatePaths(returnedValue, stateSymbol, scopes));
|
|
65341
|
-
if (returnedStatePaths.length === 0) return false;
|
|
65342
|
-
const functionBinding = getDirectFunctionBindingIdentifier(componentOrHookNode);
|
|
65343
|
-
if (!isNodeOfType(functionBinding, "Identifier")) return false;
|
|
65344
|
-
const functionSymbol = scopes.symbolFor(functionBinding);
|
|
65345
|
-
if (!functionSymbol) return false;
|
|
65346
|
-
return functionSymbol.references.some((functionReference) => {
|
|
65347
|
-
const callExpression = functionReference.identifier.parent;
|
|
65348
|
-
return Boolean(isNodeOfType(callExpression, "CallExpression") && callExpression.callee === functionReference.identifier && returnedStatePaths.some((returnedStatePath) => doesCallResultPathReachRenderedOutput(callExpression, returnedStatePath, componentOrHookNode, scopes)));
|
|
65349
|
-
});
|
|
65350
|
-
};
|
|
65351
64634
|
const findFollowingReturnedValues = (ifStatement) => {
|
|
65352
64635
|
const parentNode = ifStatement.parent;
|
|
65353
64636
|
if (!isNodeOfType(parentNode, "BlockStatement")) return [];
|
|
@@ -65360,24 +64643,24 @@ const findFollowingReturnedValues = (ifStatement) => {
|
|
|
65360
64643
|
}
|
|
65361
64644
|
return returnedValues;
|
|
65362
64645
|
};
|
|
65363
|
-
const areConditionExpressionsEquivalent = (leftExpression, rightExpression
|
|
64646
|
+
const areConditionExpressionsEquivalent = (leftExpression, rightExpression) => {
|
|
65364
64647
|
const left = stripParenExpression(leftExpression);
|
|
65365
64648
|
const right = stripParenExpression(rightExpression);
|
|
65366
|
-
if (areExpressionsStructurallyEqual(left, right)) return
|
|
64649
|
+
if (areExpressionsStructurallyEqual(left, right)) return true;
|
|
65367
64650
|
if (left.type !== right.type) return false;
|
|
65368
|
-
if (isNodeOfType(left, "UnaryExpression") && isNodeOfType(right, "UnaryExpression")) return left.operator === right.operator && areConditionExpressionsEquivalent(left.argument, right.argument
|
|
65369
|
-
if (isNodeOfType(left, "LogicalExpression") && isNodeOfType(right, "LogicalExpression")) return left.operator === right.operator && areConditionExpressionsEquivalent(left.left, right.left
|
|
65370
|
-
if (isNodeOfType(left, "BinaryExpression") && isNodeOfType(right, "BinaryExpression")) return left.operator === right.operator && areConditionExpressionsEquivalent(left.left, right.left
|
|
64651
|
+
if (isNodeOfType(left, "UnaryExpression") && isNodeOfType(right, "UnaryExpression")) return left.operator === right.operator && areConditionExpressionsEquivalent(left.argument, right.argument);
|
|
64652
|
+
if (isNodeOfType(left, "LogicalExpression") && isNodeOfType(right, "LogicalExpression")) return left.operator === right.operator && areConditionExpressionsEquivalent(left.left, right.left) && areConditionExpressionsEquivalent(left.right, right.right);
|
|
64653
|
+
if (isNodeOfType(left, "BinaryExpression") && isNodeOfType(right, "BinaryExpression")) return left.operator === right.operator && areConditionExpressionsEquivalent(left.left, right.left) && areConditionExpressionsEquivalent(left.right, right.right);
|
|
65371
64654
|
return false;
|
|
65372
64655
|
};
|
|
65373
|
-
const areReturnTreesEquivalent = (leftStatement, rightStatement
|
|
64656
|
+
const areReturnTreesEquivalent = (leftStatement, rightStatement) => {
|
|
65374
64657
|
if (!leftStatement || !rightStatement) return leftStatement === rightStatement;
|
|
65375
|
-
if (isNodeOfType(leftStatement, "ReturnStatement") && isNodeOfType(rightStatement, "ReturnStatement")) return areRenderedBranchesEquivalent(leftStatement.argument, rightStatement.argument
|
|
65376
|
-
if (isNodeOfType(leftStatement, "IfStatement") && isNodeOfType(rightStatement, "IfStatement")) return areConditionExpressionsEquivalent(leftStatement.test, rightStatement.test
|
|
64658
|
+
if (isNodeOfType(leftStatement, "ReturnStatement") && isNodeOfType(rightStatement, "ReturnStatement")) return areRenderedBranchesEquivalent(leftStatement.argument, rightStatement.argument);
|
|
64659
|
+
if (isNodeOfType(leftStatement, "IfStatement") && isNodeOfType(rightStatement, "IfStatement")) return areConditionExpressionsEquivalent(leftStatement.test, rightStatement.test) && areReturnTreesEquivalent(leftStatement.consequent, rightStatement.consequent) && areReturnTreesEquivalent(leftStatement.alternate, rightStatement.alternate);
|
|
65377
64660
|
if (!isNodeOfType(leftStatement, "BlockStatement") || !isNodeOfType(rightStatement, "BlockStatement")) return false;
|
|
65378
64661
|
const leftReturningStatements = leftStatement.body.filter((statement) => getReturnedValues(statement).length > 0);
|
|
65379
64662
|
const rightReturningStatements = rightStatement.body.filter((statement) => getReturnedValues(statement).length > 0);
|
|
65380
|
-
return leftReturningStatements.length === rightReturningStatements.length && leftReturningStatements.every((statement, index) => areReturnTreesEquivalent(statement, rightReturningStatements[index]
|
|
64663
|
+
return leftReturningStatements.length === rightReturningStatements.length && leftReturningStatements.every((statement, index) => areReturnTreesEquivalent(statement, rightReturningStatements[index]));
|
|
65381
64664
|
};
|
|
65382
64665
|
const isStructuralRenderedValue = (node) => {
|
|
65383
64666
|
if (!node) return false;
|
|
@@ -65401,22 +64684,19 @@ const noHydrationBranchOnBrowserGlobal = defineRule({
|
|
|
65401
64684
|
if (isTestlikeFilename(context.filename)) return {};
|
|
65402
64685
|
if (classifyReactNativeFileTarget(context) === "react-native") return {};
|
|
65403
64686
|
let fileHasUseClientDirective = false;
|
|
65404
|
-
let fileHasExplicitReactRuntimeReference = false;
|
|
65405
64687
|
let fileIsEmailTemplate = false;
|
|
65406
64688
|
const reportedNodes = /* @__PURE__ */ new Set();
|
|
65407
|
-
const reportHydrationBranch = (conditionNode, leftBranch, rightBranch, requiresRenderedContext
|
|
64689
|
+
const reportHydrationBranch = (conditionNode, leftBranch, rightBranch, requiresRenderedContext) => {
|
|
65408
64690
|
const conditionMatch = matchHydrationCondition(conditionNode, context);
|
|
65409
64691
|
if (!conditionMatch) return;
|
|
65410
64692
|
const { predicateMatch, predicateNode } = conditionMatch;
|
|
65411
64693
|
if (reportedNodes.has(predicateNode)) return;
|
|
65412
|
-
if (rightBranch && areRenderedBranchesEquivalent(leftBranch, rightBranch
|
|
65413
|
-
const
|
|
65414
|
-
const componentOrHookNode = findRenderPhaseComponentOrHook(conditionNode, context.scopes) ?? (enclosingFunction ? findComponentRenderingLocalFunctionResult(enclosingFunction, context.scopes) : null);
|
|
64694
|
+
if (rightBranch && areRenderedBranchesEquivalent(leftBranch, rightBranch)) return;
|
|
64695
|
+
const componentOrHookNode = findRenderPhaseComponentOrHook(conditionNode, context.scopes);
|
|
65415
64696
|
if (!componentOrHookNode) return;
|
|
65416
|
-
|
|
65417
|
-
if (!
|
|
65418
|
-
if (
|
|
65419
|
-
if (!hasProvenRenderedConsumer && !(requiresRenderedContext ? isPotentiallyRenderedValue(leftBranch, context.scopes) : isRenderedValue(leftBranch, context.scopes)) && (!rightBranch || !(requiresRenderedContext ? isPotentiallyRenderedValue(rightBranch, context.scopes) : isRenderedValue(rightBranch, context.scopes)))) {
|
|
64697
|
+
if (!hasClientRenderEvidence(componentOrHookNode, fileHasUseClientDirective)) return;
|
|
64698
|
+
if (requiresRenderedContext && !isInRenderedOutput(conditionNode, componentOrHookNode, context.scopes)) return;
|
|
64699
|
+
if (!isRenderedValue(leftBranch) && (!rightBranch || !isRenderedValue(rightBranch))) {
|
|
65420
64700
|
const attribute = findEnclosingJsxAttribute(conditionNode);
|
|
65421
64701
|
if (!attribute || isEventHandlerAttribute(attribute)) return;
|
|
65422
64702
|
}
|
|
@@ -65435,31 +64715,28 @@ const noHydrationBranchOnBrowserGlobal = defineRule({
|
|
|
65435
64715
|
return {
|
|
65436
64716
|
Program(node) {
|
|
65437
64717
|
fileHasUseClientDirective = hasDirective(node, "use client");
|
|
65438
|
-
fileHasExplicitReactRuntimeReference = containsExplicitReactRuntimeReference(node, context.scopes);
|
|
65439
64718
|
fileIsEmailTemplate = hasEmailTemplateImport(node);
|
|
65440
64719
|
},
|
|
65441
64720
|
ConditionalExpression(node) {
|
|
65442
64721
|
reportHydrationBranch(node.test, node.consequent, node.alternate, true);
|
|
65443
|
-
const componentOrHookNode = findRenderPhaseComponentOrHook(node, context.scopes);
|
|
65444
|
-
if (componentOrHookNode && isReturnedUseStateInitializerRendered(node, componentOrHookNode, context.scopes)) reportHydrationBranch(node.test, node.consequent, node.alternate, false, true);
|
|
65445
64722
|
},
|
|
65446
64723
|
LogicalExpression(node) {
|
|
65447
64724
|
if (node.operator !== "&&" && node.operator !== "||") return;
|
|
65448
|
-
const renderedValue = node.operator === "&&" ? findRenderedValueInAndBranch(node.right
|
|
64725
|
+
const renderedValue = node.operator === "&&" ? findRenderedValueInAndBranch(node.right) : isRenderedValue(node.right) ? node.right : null;
|
|
65449
64726
|
if (!renderedValue) return;
|
|
65450
64727
|
reportHydrationBranch(node, renderedValue, null, true);
|
|
65451
64728
|
},
|
|
65452
64729
|
IfStatement(node) {
|
|
65453
|
-
if (node.alternate && areReturnTreesEquivalent(node.consequent, node.alternate
|
|
64730
|
+
if (node.alternate && areReturnTreesEquivalent(node.consequent, node.alternate)) return;
|
|
65454
64731
|
const consequentValues = getReturnedValues(node.consequent);
|
|
65455
64732
|
const alternateValues = node.alternate ? getReturnedValues(node.alternate) : findFollowingReturnedValues(node);
|
|
65456
64733
|
if (consequentValues.length === 0 || alternateValues.length === 0) return;
|
|
65457
|
-
const
|
|
65458
|
-
const componentOrHookNode = findRenderPhaseComponentOrHook(node.test, context.scopes) ?? (enclosingFunction ? findComponentRenderingLocalFunctionResult(enclosingFunction, context.scopes) : null);
|
|
64734
|
+
const componentOrHookNode = findRenderPhaseComponentOrHook(node.test, context.scopes);
|
|
65459
64735
|
if (!componentOrHookNode) return;
|
|
65460
|
-
|
|
64736
|
+
const enclosingFunction = findEnclosingFunction$1(node);
|
|
64737
|
+
if (enclosingFunction !== componentOrHookNode && (!enclosingFunction || !isInRenderedOutput(enclosingFunction, componentOrHookNode, context.scopes))) return;
|
|
65461
64738
|
for (const consequentValue of consequentValues) for (const alternateValue of alternateValues) {
|
|
65462
|
-
if (!isRenderedValue(consequentValue
|
|
64739
|
+
if (!isRenderedValue(consequentValue) && !isRenderedValue(alternateValue)) continue;
|
|
65463
64740
|
reportHydrationBranch(node.test, consequentValue, alternateValue, false);
|
|
65464
64741
|
}
|
|
65465
64742
|
}
|
|
@@ -67193,124 +66470,6 @@ const isInsideSnapshotHelper = (node) => {
|
|
|
67193
66470
|
}
|
|
67194
66471
|
return false;
|
|
67195
66472
|
};
|
|
67196
|
-
const findEnclosingNextjsPageDataFunction = (node) => {
|
|
67197
|
-
let outermostFunction = null;
|
|
67198
|
-
let cursor = node.parent;
|
|
67199
|
-
while (cursor) {
|
|
67200
|
-
if (isFunctionLike$1(cursor)) outermostFunction = cursor;
|
|
67201
|
-
if (isNodeOfType(cursor, "Program")) {
|
|
67202
|
-
if (!outermostFunction) return null;
|
|
67203
|
-
for (const exportName of NEXTJS_PAGE_DATA_EXPORT_NAMES) {
|
|
67204
|
-
const exportedValue = findExportedValue(cursor, exportName);
|
|
67205
|
-
if (exportedValue && isAstDescendant(outermostFunction, exportedValue)) return outermostFunction;
|
|
67206
|
-
}
|
|
67207
|
-
return null;
|
|
67208
|
-
}
|
|
67209
|
-
cursor = cursor.parent ?? null;
|
|
67210
|
-
}
|
|
67211
|
-
return null;
|
|
67212
|
-
};
|
|
67213
|
-
const findConditionalReturnExpressionRoot = (node) => {
|
|
67214
|
-
let expressionRoot = findTransparentExpressionRoot(node);
|
|
67215
|
-
while (expressionRoot.parent && isNodeOfType(expressionRoot.parent, "ConditionalExpression") && (expressionRoot.parent.consequent === expressionRoot || expressionRoot.parent.alternate === expressionRoot)) expressionRoot = findTransparentExpressionRoot(expressionRoot.parent);
|
|
67216
|
-
return expressionRoot;
|
|
67217
|
-
};
|
|
67218
|
-
const isReturnedPageDataResultBinding = (returnExpression, pageDataFunction, context) => {
|
|
67219
|
-
const declarator = returnExpression.parent;
|
|
67220
|
-
if (!isNodeOfType(declarator, "VariableDeclarator") || declarator.init !== returnExpression || !isNodeOfType(declarator.id, "Identifier") || findEnclosingFunction$1(declarator) !== pageDataFunction) return false;
|
|
67221
|
-
const bindingSymbol = context.scopes.symbolFor(declarator.id);
|
|
67222
|
-
if (!bindingSymbol || bindingSymbol.references.length !== 1) return false;
|
|
67223
|
-
const referenceRoot = findTransparentExpressionRoot(bindingSymbol.references[0].identifier);
|
|
67224
|
-
const returnStatement = referenceRoot.parent;
|
|
67225
|
-
return isNodeOfType(returnStatement, "ReturnStatement") && returnStatement.argument === referenceRoot && findEnclosingFunction$1(returnStatement) === pageDataFunction;
|
|
67226
|
-
};
|
|
67227
|
-
const isSameShorthandPropertyValue = (node, property) => property.shorthand && (node === property.key || node === property.value);
|
|
67228
|
-
const isValueForwardedThroughLiteralStructure = (node, structure) => {
|
|
67229
|
-
const strippedNode = stripParenExpression(node);
|
|
67230
|
-
const strippedStructure = stripParenExpression(structure);
|
|
67231
|
-
if (strippedNode === strippedStructure) return true;
|
|
67232
|
-
if (isNodeOfType(strippedStructure, "ConditionalExpression")) return isValueForwardedThroughLiteralStructure(strippedNode, strippedStructure.consequent) || isValueForwardedThroughLiteralStructure(strippedNode, strippedStructure.alternate);
|
|
67233
|
-
if (isNodeOfType(strippedStructure, "ArrayExpression")) return strippedStructure.elements.some((element) => element && !isNodeOfType(element, "SpreadElement") && isValueForwardedThroughLiteralStructure(strippedNode, element));
|
|
67234
|
-
if (!isNodeOfType(strippedStructure, "ObjectExpression")) return false;
|
|
67235
|
-
return strippedStructure.properties.some((property) => {
|
|
67236
|
-
if (isNodeOfType(property, "SpreadElement")) return isValueForwardedThroughLiteralStructure(strippedNode, property.argument);
|
|
67237
|
-
if (!isNodeOfType(property, "Property")) return false;
|
|
67238
|
-
if (isValueForwardedThroughLiteralStructure(strippedNode, property.value)) return true;
|
|
67239
|
-
return isSameShorthandPropertyValue(strippedNode, property);
|
|
67240
|
-
});
|
|
67241
|
-
};
|
|
67242
|
-
const isValueForwardedToPropertyValue = (node, property) => {
|
|
67243
|
-
const directValue = findConditionalReturnExpressionRoot(node);
|
|
67244
|
-
if (isValueForwardedThroughLiteralStructure(directValue, property.value)) return true;
|
|
67245
|
-
return isSameShorthandPropertyValue(directValue, property);
|
|
67246
|
-
};
|
|
67247
|
-
const isInsideReturnedNextjsProps = (node, pageDataFunction, context) => {
|
|
67248
|
-
let cursor = node.parent;
|
|
67249
|
-
while (cursor && cursor !== pageDataFunction) {
|
|
67250
|
-
if (isNodeOfType(cursor, "Property") && getStaticPropertyKeyName(cursor, { allowComputedString: true }) === "props" && isValueForwardedToPropertyValue(node, cursor)) {
|
|
67251
|
-
const propertyContainer = cursor.parent;
|
|
67252
|
-
if (!propertyContainer) return false;
|
|
67253
|
-
const returnExpression = findConditionalReturnExpressionRoot(propertyContainer);
|
|
67254
|
-
const returnStatement = returnExpression.parent;
|
|
67255
|
-
if (isNodeOfType(returnStatement, "ReturnStatement") && findEnclosingFunction$1(returnStatement) === pageDataFunction) return true;
|
|
67256
|
-
if (isNodeOfType(pageDataFunction, "ArrowFunctionExpression") && !isNodeOfType(pageDataFunction.body, "BlockStatement") && stripParenExpression(pageDataFunction.body) === stripParenExpression(returnExpression)) return true;
|
|
67257
|
-
if (isReturnedPageDataResultBinding(returnExpression, pageDataFunction, context)) return true;
|
|
67258
|
-
}
|
|
67259
|
-
cursor = cursor.parent ?? null;
|
|
67260
|
-
}
|
|
67261
|
-
return false;
|
|
67262
|
-
};
|
|
67263
|
-
const isExpressionReturnedByFunction = (node, functionNode) => {
|
|
67264
|
-
const returnExpression = findConditionalReturnExpressionRoot(node);
|
|
67265
|
-
if (isNodeOfType(functionNode, "ArrowFunctionExpression") && !isNodeOfType(functionNode.body, "BlockStatement")) return stripParenExpression(functionNode.body) === stripParenExpression(returnExpression);
|
|
67266
|
-
const returnStatement = returnExpression.parent;
|
|
67267
|
-
return isNodeOfType(returnStatement, "ReturnStatement") && returnStatement.argument === returnExpression && findEnclosingFunction$1(returnStatement) === functionNode;
|
|
67268
|
-
};
|
|
67269
|
-
const isValueForwardedToBindingInitializer = (node, bindingInitializer) => {
|
|
67270
|
-
if (isValueForwardedThroughLiteralStructure(findConditionalReturnExpressionRoot(node), bindingInitializer)) return true;
|
|
67271
|
-
const initializer = stripParenExpression(bindingInitializer);
|
|
67272
|
-
if (!isNodeOfType(initializer, "CallExpression")) return false;
|
|
67273
|
-
const callee = stripParenExpression(initializer.callee);
|
|
67274
|
-
return isFunctionLike$1(callee) && isExpressionReturnedByFunction(node, callee);
|
|
67275
|
-
};
|
|
67276
|
-
const findPageDataResultBinding = (node) => {
|
|
67277
|
-
let cursor = node.parent;
|
|
67278
|
-
while (cursor) {
|
|
67279
|
-
if (isNodeOfType(cursor, "VariableDeclarator")) {
|
|
67280
|
-
if (cursor.init && isNodeOfType(cursor.id, "Identifier") && isValueForwardedToBindingInitializer(node, cursor.init)) return cursor.id;
|
|
67281
|
-
return null;
|
|
67282
|
-
}
|
|
67283
|
-
cursor = cursor.parent ?? null;
|
|
67284
|
-
}
|
|
67285
|
-
return null;
|
|
67286
|
-
};
|
|
67287
|
-
const isUsedToSerializeNextjsPageProps = (node, context) => {
|
|
67288
|
-
if (!isInProjectDirectory(context, "pages") || isInProjectDirectory(context, "pages/api")) return false;
|
|
67289
|
-
const pageDataFunction = findEnclosingNextjsPageDataFunction(node);
|
|
67290
|
-
if (!pageDataFunction) return false;
|
|
67291
|
-
if (isInsideReturnedNextjsProps(node, pageDataFunction, context)) return true;
|
|
67292
|
-
const bindingIdentifier = findPageDataResultBinding(node);
|
|
67293
|
-
const bindingSymbol = bindingIdentifier ? context.scopes.symbolFor(bindingIdentifier) : null;
|
|
67294
|
-
if (!bindingSymbol) return false;
|
|
67295
|
-
const aliasSymbols = collectConstAliasSymbols(bindingSymbol, context.scopes);
|
|
67296
|
-
const aliasSymbolIds = new Set(aliasSymbols.map((aliasSymbol) => aliasSymbol.id));
|
|
67297
|
-
let hasPagePropsReference = false;
|
|
67298
|
-
for (const aliasSymbol of aliasSymbols) for (const reference of aliasSymbol.references) {
|
|
67299
|
-
if (findEnclosingFunction$1(reference.identifier) !== pageDataFunction) return false;
|
|
67300
|
-
if (isInsideReturnedNextjsProps(reference.identifier, pageDataFunction, context)) {
|
|
67301
|
-
hasPagePropsReference = true;
|
|
67302
|
-
continue;
|
|
67303
|
-
}
|
|
67304
|
-
const referenceRoot = findTransparentExpressionRoot(reference.identifier);
|
|
67305
|
-
const declarator = referenceRoot.parent;
|
|
67306
|
-
if (isNodeOfType(declarator, "VariableDeclarator") && declarator.init === referenceRoot && isNodeOfType(declarator.id, "Identifier")) {
|
|
67307
|
-
const aliasSymbolForReference = context.scopes.symbolFor(declarator.id);
|
|
67308
|
-
if (aliasSymbolForReference && aliasSymbolIds.has(aliasSymbolForReference.id)) continue;
|
|
67309
|
-
}
|
|
67310
|
-
return false;
|
|
67311
|
-
}
|
|
67312
|
-
return hasPagePropsReference;
|
|
67313
|
-
};
|
|
67314
66473
|
const noJsonParseStringifyClone = defineRule({
|
|
67315
66474
|
id: "no-json-parse-stringify-clone",
|
|
67316
66475
|
title: "JSON parse/stringify deep clone",
|
|
@@ -67328,7 +66487,6 @@ const noJsonParseStringifyClone = defineRule({
|
|
|
67328
66487
|
if (isInsideSnapshotHelper(node)) return;
|
|
67329
66488
|
if (isAssignedToNormalizationBinding(node)) return;
|
|
67330
66489
|
if (isCatchParameterRoundTrip(firstArgument)) return;
|
|
67331
|
-
if (isUsedToSerializeNextjsPageProps(node, context)) return;
|
|
67332
66490
|
context.report({
|
|
67333
66491
|
node,
|
|
67334
66492
|
message: MESSAGE$35
|
|
@@ -68744,77 +67902,6 @@ const isCancellationGuardTest = (test) => {
|
|
|
68744
67902
|
});
|
|
68745
67903
|
return matches;
|
|
68746
67904
|
};
|
|
68747
|
-
const getReactRefCurrent = (expression, context) => {
|
|
68748
|
-
const stripped = stripParenExpression(expression);
|
|
68749
|
-
if (!isNodeOfType(stripped, "MemberExpression") || getStaticPropertyName(stripped) !== "current") return null;
|
|
68750
|
-
const receiver = stripParenExpression(stripped.object);
|
|
68751
|
-
if (!isNodeOfType(receiver, "Identifier")) return null;
|
|
68752
|
-
const binding = findVariableInitializer(receiver, receiver.name);
|
|
68753
|
-
const initializer = binding?.initializer ? stripParenExpression(binding.initializer) : null;
|
|
68754
|
-
return initializer && isNodeOfType(initializer, "CallExpression") && isReactApiCall(initializer, USE_REF_HOOK_NAMES$1, context.scopes, {
|
|
68755
|
-
allowGlobalReactNamespace: true,
|
|
68756
|
-
allowUnboundBareCalls: true
|
|
68757
|
-
}) ? stripped : null;
|
|
68758
|
-
};
|
|
68759
|
-
const getStableOwnershipToken = (expression, context) => {
|
|
68760
|
-
const stripped = stripParenExpression(expression);
|
|
68761
|
-
if (!isNodeOfType(stripped, "Identifier")) return null;
|
|
68762
|
-
const symbol = context.scopes.symbolFor(stripped);
|
|
68763
|
-
const initializer = symbol?.initializer ? stripParenExpression(symbol.initializer) : null;
|
|
68764
|
-
const isStableAsyncIdentity = Boolean(initializer && isNodeOfType(initializer, "ObjectExpression")) || Boolean(initializer && getReactRefCurrent(initializer, context)) || Boolean(initializer && isNodeOfType(initializer, "UpdateExpression") && initializer.operator === "++" && getReactRefCurrent(initializer.argument, context));
|
|
68765
|
-
return symbol && symbol.kind === "const" && symbol.references.every((reference) => reference.flag === "read") && isStableAsyncIdentity ? stripped : null;
|
|
68766
|
-
};
|
|
68767
|
-
const getAsyncOwnershipComparison = (test, context) => {
|
|
68768
|
-
const stripped = stripParenExpression(test);
|
|
68769
|
-
if (!isNodeOfType(stripped, "BinaryExpression")) return null;
|
|
68770
|
-
const leftRef = getReactRefCurrent(stripped.left, context);
|
|
68771
|
-
const rightRef = getReactRefCurrent(stripped.right, context);
|
|
68772
|
-
const leftToken = getStableOwnershipToken(stripped.left, context);
|
|
68773
|
-
const rightToken = getStableOwnershipToken(stripped.right, context);
|
|
68774
|
-
if (stripped.operator === "===" || stripped.operator === "==") {
|
|
68775
|
-
if (leftRef && rightToken) return {
|
|
68776
|
-
refCurrent: leftRef,
|
|
68777
|
-
token: rightToken,
|
|
68778
|
-
mode: "owns",
|
|
68779
|
-
isOrdered: false
|
|
68780
|
-
};
|
|
68781
|
-
if (rightRef && leftToken) return {
|
|
68782
|
-
refCurrent: rightRef,
|
|
68783
|
-
token: leftToken,
|
|
68784
|
-
mode: "owns",
|
|
68785
|
-
isOrdered: false
|
|
68786
|
-
};
|
|
68787
|
-
return null;
|
|
68788
|
-
}
|
|
68789
|
-
if (stripped.operator === "!==" || stripped.operator === "!=") {
|
|
68790
|
-
if (leftRef && rightToken) return {
|
|
68791
|
-
refCurrent: leftRef,
|
|
68792
|
-
token: rightToken,
|
|
68793
|
-
mode: "lost",
|
|
68794
|
-
isOrdered: false
|
|
68795
|
-
};
|
|
68796
|
-
if (rightRef && leftToken) return {
|
|
68797
|
-
refCurrent: rightRef,
|
|
68798
|
-
token: leftToken,
|
|
68799
|
-
mode: "lost",
|
|
68800
|
-
isOrdered: false
|
|
68801
|
-
};
|
|
68802
|
-
return null;
|
|
68803
|
-
}
|
|
68804
|
-
if (stripped.operator === "<=" && leftRef && rightToken) return {
|
|
68805
|
-
refCurrent: leftRef,
|
|
68806
|
-
token: rightToken,
|
|
68807
|
-
mode: "owns",
|
|
68808
|
-
isOrdered: true
|
|
68809
|
-
};
|
|
68810
|
-
if (stripped.operator === ">=" && rightRef && leftToken) return {
|
|
68811
|
-
refCurrent: rightRef,
|
|
68812
|
-
token: leftToken,
|
|
68813
|
-
mode: "owns",
|
|
68814
|
-
isOrdered: true
|
|
68815
|
-
};
|
|
68816
|
-
return null;
|
|
68817
|
-
};
|
|
68818
67905
|
const dedupeCatchPathStates = (states) => {
|
|
68819
67906
|
const statesByKey = /* @__PURE__ */ new Map();
|
|
68820
67907
|
for (const state of states) statesByKey.set(`${Number(state.isCleared)}:${Number(state.isCancellationPath)}`, state);
|
|
@@ -69147,221 +68234,7 @@ const isInsideTryFinalizer = (node, tryStatement) => {
|
|
|
69147
68234
|
}
|
|
69148
68235
|
return false;
|
|
69149
68236
|
};
|
|
69150
|
-
const
|
|
69151
|
-
let entry = node;
|
|
69152
|
-
let cursor = node.parent;
|
|
69153
|
-
while (cursor && cursor !== functionNode) {
|
|
69154
|
-
if (isNodeOfType(cursor, "BlockStatement")) return {
|
|
69155
|
-
block: cursor,
|
|
69156
|
-
entry
|
|
69157
|
-
};
|
|
69158
|
-
entry = cursor;
|
|
69159
|
-
cursor = cursor.parent ?? null;
|
|
69160
|
-
}
|
|
69161
|
-
return null;
|
|
69162
|
-
};
|
|
69163
|
-
const claimPrecedesTruthySet = (claimNode, truthySet, firstRiskyAwait, functionNode, context) => {
|
|
69164
|
-
const claimStart = getNodeStart$1(claimNode);
|
|
69165
|
-
if (claimStart === null || claimStart >= firstRiskyAwait.start || truthySet.start >= firstRiskyAwait.start) return false;
|
|
69166
|
-
const claimEntry = getDirectBlockEntry(claimNode, functionNode);
|
|
69167
|
-
const truthyEntry = getDirectBlockEntry(truthySet.node, functionNode);
|
|
69168
|
-
if (!claimEntry || !truthyEntry || claimEntry.block !== truthyEntry.block) return false;
|
|
69169
|
-
let claimCursor = claimNode.parent;
|
|
69170
|
-
while (claimCursor && claimCursor !== claimEntry.block) {
|
|
69171
|
-
if (isNodeOfType(claimCursor, "IfStatement") || isNodeOfType(claimCursor, "SwitchCase") || isNodeOfType(claimCursor, "ConditionalExpression") || isNodeOfType(claimCursor, "LogicalExpression") || isNodeOfType(claimCursor, "ForStatement") || isNodeOfType(claimCursor, "ForInStatement") || isNodeOfType(claimCursor, "ForOfStatement") || isNodeOfType(claimCursor, "WhileStatement") || isNodeOfType(claimCursor, "DoWhileStatement")) return false;
|
|
69172
|
-
claimCursor = claimCursor.parent ?? null;
|
|
69173
|
-
}
|
|
69174
|
-
const claimIndex = claimEntry.block.body.findIndex((statement) => statement === claimEntry.entry);
|
|
69175
|
-
const truthyIndex = claimEntry.block.body.findIndex((statement) => statement === truthyEntry.entry);
|
|
69176
|
-
if (claimIndex === -1 || truthyIndex === -1 || claimIndex >= truthyIndex) return false;
|
|
69177
|
-
return claimEntry.block.body.slice(claimIndex + 1, truthyIndex).every((statement) => !subtreeHasAbruptSynchronousOperation(statement, functionNode, context));
|
|
69178
|
-
};
|
|
69179
|
-
const getOwningFunction = (functionNode) => {
|
|
69180
|
-
let ownerFunction = functionNode;
|
|
69181
|
-
let cursor = functionNode.parent;
|
|
69182
|
-
while (cursor) {
|
|
69183
|
-
if (isFunctionLike$1(cursor)) ownerFunction = cursor;
|
|
69184
|
-
cursor = cursor.parent ?? null;
|
|
69185
|
-
}
|
|
69186
|
-
return ownerFunction;
|
|
69187
|
-
};
|
|
69188
|
-
const isEffectInvalidationPairedWithReset = (writeNode, truthySets, context) => {
|
|
69189
|
-
const truthyCall = truthySets[0]?.node;
|
|
69190
|
-
if (!truthyCall || !isNodeOfType(truthyCall, "CallExpression")) return false;
|
|
69191
|
-
const setter = getSetterBooleanValue(truthyCall, context);
|
|
69192
|
-
if (!setter) return false;
|
|
69193
|
-
let effectCallback = writeNode.parent;
|
|
69194
|
-
while (effectCallback && !isFunctionLike$1(effectCallback)) effectCallback = effectCallback.parent ?? null;
|
|
69195
|
-
if (!effectCallback || !isEffectCallback(effectCallback, context)) return false;
|
|
69196
|
-
if (!isUnconditionallyExecutedWithinFunction(writeNode, effectCallback, context)) return false;
|
|
69197
|
-
const writeEntry = getDirectBlockEntry(writeNode, effectCallback);
|
|
69198
|
-
if (!writeEntry) return false;
|
|
69199
|
-
let isPaired = false;
|
|
69200
|
-
walkOwnFunctionScope(effectCallback, (candidate) => {
|
|
69201
|
-
if (isPaired || !isNodeOfType(candidate, "CallExpression")) return;
|
|
69202
|
-
const candidateSetter = getSetterBooleanValue(candidate, context);
|
|
69203
|
-
if (candidateSetter?.setterKey !== setter.setterKey || candidateSetter.value || !isUnconditionallyExecutedWithinFunction(candidate, effectCallback, context)) return;
|
|
69204
|
-
const resetEntry = getDirectBlockEntry(candidate, effectCallback);
|
|
69205
|
-
if (!resetEntry || resetEntry.block !== writeEntry.block) return;
|
|
69206
|
-
const writeIndex = writeEntry.block.body.findIndex((statement) => statement === writeEntry.entry);
|
|
69207
|
-
const resetIndex = resetEntry.block.body.findIndex((statement) => statement === resetEntry.entry);
|
|
69208
|
-
if (writeIndex === -1 || resetIndex === -1) return;
|
|
69209
|
-
if (resetIndex <= writeIndex) {
|
|
69210
|
-
isPaired = true;
|
|
69211
|
-
return false;
|
|
69212
|
-
}
|
|
69213
|
-
isPaired = writeEntry.block.body.slice(writeIndex + 1, resetIndex).every((statement) => !subtreeHasAbruptSynchronousOperation(statement, effectCallback, context));
|
|
69214
|
-
return isPaired ? false : void 0;
|
|
69215
|
-
});
|
|
69216
|
-
return isPaired;
|
|
69217
|
-
};
|
|
69218
|
-
const isUnconditionalReturnBranch = (statement) => {
|
|
69219
|
-
if (isNodeOfType(statement, "ReturnStatement")) return true;
|
|
69220
|
-
return Boolean(isNodeOfType(statement, "BlockStatement") && statement.body.length === 1 && isNodeOfType(statement.body[0], "ReturnStatement"));
|
|
69221
|
-
};
|
|
69222
|
-
const findSingleFlightSnapshotClaim = (tokenInitializer, functionNode, truthySets, firstRiskyAwait, resetNode, context) => {
|
|
69223
|
-
const snapshotEntry = getDirectBlockEntry(tokenInitializer, functionNode);
|
|
69224
|
-
const resetEntry = getDirectBlockEntry(resetNode, functionNode);
|
|
69225
|
-
if (!snapshotEntry || !resetEntry) return null;
|
|
69226
|
-
const claimCandidates = [];
|
|
69227
|
-
const releaseCandidates = [];
|
|
69228
|
-
walkOwnFunctionScope(functionNode, (candidate) => {
|
|
69229
|
-
if (!isNodeOfType(candidate, "AssignmentExpression") || candidate.operator !== "=" || !getReactRefCurrent(candidate.left, context)) return;
|
|
69230
|
-
const assignedValue = stripParenExpression(candidate.right);
|
|
69231
|
-
if (!isNodeOfType(assignedValue, "Literal") || typeof assignedValue.value !== "boolean") return;
|
|
69232
|
-
const candidateKey = serializeReferenceKey({
|
|
69233
|
-
node: candidate.left,
|
|
69234
|
-
scopes: context.scopes
|
|
69235
|
-
});
|
|
69236
|
-
if (!candidateKey) return;
|
|
69237
|
-
if (!assignedValue.value) {
|
|
69238
|
-
if (getDirectBlockEntry(candidate, functionNode)?.block === resetEntry.block) releaseCandidates.push(candidate);
|
|
69239
|
-
return;
|
|
69240
|
-
}
|
|
69241
|
-
if (!truthySets.some((truthySet) => claimPrecedesTruthySet(candidate, truthySet, firstRiskyAwait, functionNode, context))) return;
|
|
69242
|
-
const candidateEntry = getDirectBlockEntry(candidate, functionNode);
|
|
69243
|
-
if (!candidateEntry || candidateEntry.block !== snapshotEntry.block) return;
|
|
69244
|
-
const candidateIndex = candidateEntry.block.body.findIndex((statement) => statement === candidateEntry.entry);
|
|
69245
|
-
const snapshotIndex = candidateEntry.block.body.findIndex((statement) => statement === snapshotEntry.entry);
|
|
69246
|
-
if (candidateIndex === -1 || snapshotIndex === -1 || candidateIndex >= snapshotIndex) return;
|
|
69247
|
-
const guardIndex = candidateEntry.block.body.findLastIndex((statement, statementIndex) => {
|
|
69248
|
-
if (statementIndex >= candidateIndex || !isNodeOfType(statement, "IfStatement") || statement.alternate !== null || !isUnconditionalReturnBranch(statement.consequent)) return false;
|
|
69249
|
-
return serializeReferenceKey({
|
|
69250
|
-
node: stripParenExpression(statement.test),
|
|
69251
|
-
scopes: context.scopes
|
|
69252
|
-
}) === candidateKey;
|
|
69253
|
-
});
|
|
69254
|
-
if (guardIndex === -1 || !candidateEntry.block.body.slice(guardIndex + 1, candidateIndex).every((statement) => !subtreeHasAbruptSynchronousOperation(statement, functionNode, context))) return;
|
|
69255
|
-
claimCandidates.push(candidate);
|
|
69256
|
-
});
|
|
69257
|
-
const claim = claimCandidates.find((claimCandidate) => {
|
|
69258
|
-
const candidateKey = serializeReferenceKey({
|
|
69259
|
-
node: claimCandidate.left,
|
|
69260
|
-
scopes: context.scopes
|
|
69261
|
-
});
|
|
69262
|
-
return releaseCandidates.some((releaseCandidate) => serializeReferenceKey({
|
|
69263
|
-
node: releaseCandidate.left,
|
|
69264
|
-
scopes: context.scopes
|
|
69265
|
-
}) === candidateKey);
|
|
69266
|
-
});
|
|
69267
|
-
if (!claim) return null;
|
|
69268
|
-
const claimKey = serializeReferenceKey({
|
|
69269
|
-
node: claim.left,
|
|
69270
|
-
scopes: context.scopes
|
|
69271
|
-
});
|
|
69272
|
-
const release = releaseCandidates.find((releaseCandidate) => serializeReferenceKey({
|
|
69273
|
-
node: releaseCandidate.left,
|
|
69274
|
-
scopes: context.scopes
|
|
69275
|
-
}) === claimKey);
|
|
69276
|
-
if (!claimKey || !release) return null;
|
|
69277
|
-
const releaseEntry = getDirectBlockEntry(release, functionNode);
|
|
69278
|
-
if (!releaseEntry || releaseEntry.block !== resetEntry.block) return null;
|
|
69279
|
-
const releaseIndex = resetEntry.block.body.findIndex((statement) => statement === releaseEntry.entry);
|
|
69280
|
-
const resetIndex = resetEntry.block.body.findIndex((statement) => statement === resetEntry.entry);
|
|
69281
|
-
if (releaseIndex === -1 || resetIndex === -1 || !resetEntry.block.body.slice(Math.min(releaseIndex, resetIndex) + 1, Math.max(releaseIndex, resetIndex)).every((statement) => !subtreeHasAbruptSynchronousOperation(statement, functionNode, context))) return null;
|
|
69282
|
-
let didFindUnsafeWrite = false;
|
|
69283
|
-
walkAst(getOwningFunction(functionNode), (candidate) => {
|
|
69284
|
-
if (didFindUnsafeWrite || candidate === claim || candidate === release) return;
|
|
69285
|
-
const writeTarget = isNodeOfType(candidate, "AssignmentExpression") ? candidate.left : isNodeOfType(candidate, "UpdateExpression") || isNodeOfType(candidate, "UnaryExpression") && candidate.operator === "delete" ? candidate.argument : null;
|
|
69286
|
-
if (writeTarget && serializeReferenceKey({
|
|
69287
|
-
node: writeTarget,
|
|
69288
|
-
scopes: context.scopes
|
|
69289
|
-
}) === claimKey && !isEffectInvalidationPairedWithReset(candidate, truthySets, context)) didFindUnsafeWrite = true;
|
|
69290
|
-
});
|
|
69291
|
-
return didFindUnsafeWrite ? null : claim;
|
|
69292
|
-
};
|
|
69293
|
-
const findOwnershipClaim = (comparison, functionNode, truthySets, firstRiskyAwait, resetNode, context) => {
|
|
69294
|
-
const refKey = serializeReferenceKey({
|
|
69295
|
-
node: comparison.refCurrent,
|
|
69296
|
-
scopes: context.scopes
|
|
69297
|
-
});
|
|
69298
|
-
const tokenKey = serializeReferenceKey({
|
|
69299
|
-
node: comparison.token,
|
|
69300
|
-
scopes: context.scopes
|
|
69301
|
-
});
|
|
69302
|
-
if (!refKey || !tokenKey) return null;
|
|
69303
|
-
const candidates = [];
|
|
69304
|
-
const tokenSymbol = context.scopes.symbolFor(comparison.token);
|
|
69305
|
-
const tokenInitializer = tokenSymbol?.initializer ? stripParenExpression(tokenSymbol.initializer) : null;
|
|
69306
|
-
if (comparison.isOrdered && !isNodeOfType(tokenInitializer, "UpdateExpression")) return null;
|
|
69307
|
-
if (tokenInitializer && isNodeOfType(tokenInitializer, "UpdateExpression") && tokenInitializer.operator === "++" && serializeReferenceKey({
|
|
69308
|
-
node: tokenInitializer.argument,
|
|
69309
|
-
scopes: context.scopes
|
|
69310
|
-
}) === refKey) candidates.push(tokenInitializer);
|
|
69311
|
-
if (tokenInitializer && getReactRefCurrent(tokenInitializer, context) && serializeReferenceKey({
|
|
69312
|
-
node: tokenInitializer,
|
|
69313
|
-
scopes: context.scopes
|
|
69314
|
-
}) === refKey) {
|
|
69315
|
-
const singleFlightClaim = findSingleFlightSnapshotClaim(tokenInitializer, functionNode, truthySets, firstRiskyAwait, resetNode, context);
|
|
69316
|
-
if (singleFlightClaim) candidates.push(singleFlightClaim);
|
|
69317
|
-
}
|
|
69318
|
-
if (tokenInitializer && isNodeOfType(tokenInitializer, "UpdateExpression")) {
|
|
69319
|
-
const generationKey = serializeReferenceKey({
|
|
69320
|
-
node: tokenInitializer.argument,
|
|
69321
|
-
scopes: context.scopes
|
|
69322
|
-
});
|
|
69323
|
-
if (generationKey && generationKey === refKey) {
|
|
69324
|
-
const ownerFunction = getOwningFunction(functionNode);
|
|
69325
|
-
let didFindOtherGenerationWrite = false;
|
|
69326
|
-
walkAst(ownerFunction, (candidate) => {
|
|
69327
|
-
if (didFindOtherGenerationWrite || candidate === tokenInitializer) return;
|
|
69328
|
-
const writeTarget = isNodeOfType(candidate, "AssignmentExpression") ? candidate.left : isNodeOfType(candidate, "UpdateExpression") || isNodeOfType(candidate, "UnaryExpression") && candidate.operator === "delete" ? candidate.argument : null;
|
|
69329
|
-
if (writeTarget && serializeReferenceKey({
|
|
69330
|
-
node: writeTarget,
|
|
69331
|
-
scopes: context.scopes
|
|
69332
|
-
}) === generationKey && !isEffectInvalidationPairedWithReset(candidate, truthySets, context)) didFindOtherGenerationWrite = true;
|
|
69333
|
-
});
|
|
69334
|
-
if (didFindOtherGenerationWrite) return null;
|
|
69335
|
-
}
|
|
69336
|
-
}
|
|
69337
|
-
walkOwnFunctionScope(functionNode, (candidate) => {
|
|
69338
|
-
if (!isNodeOfType(candidate, "AssignmentExpression") || candidate.operator !== "=") return;
|
|
69339
|
-
if (serializeReferenceKey({
|
|
69340
|
-
node: candidate.left,
|
|
69341
|
-
scopes: context.scopes
|
|
69342
|
-
}) === refKey && serializeReferenceKey({
|
|
69343
|
-
node: candidate.right,
|
|
69344
|
-
scopes: context.scopes
|
|
69345
|
-
}) === tokenKey) candidates.push(candidate);
|
|
69346
|
-
});
|
|
69347
|
-
const claim = candidates.find((candidate) => truthySets.some((truthySet) => claimPrecedesTruthySet(candidate, truthySet, firstRiskyAwait, functionNode, context)));
|
|
69348
|
-
if (!claim) return null;
|
|
69349
|
-
let didFindOtherWrite = false;
|
|
69350
|
-
walkAst(getOwningFunction(functionNode), (candidate) => {
|
|
69351
|
-
if (didFindOtherWrite || candidate === claim) return;
|
|
69352
|
-
const writeTarget = isNodeOfType(candidate, "AssignmentExpression") ? candidate.left : isNodeOfType(candidate, "UpdateExpression") || isNodeOfType(candidate, "UnaryExpression") && candidate.operator === "delete" ? candidate.argument : null;
|
|
69353
|
-
if (writeTarget && serializeReferenceKey({
|
|
69354
|
-
node: writeTarget,
|
|
69355
|
-
scopes: context.scopes
|
|
69356
|
-
}) === refKey && !isEffectInvalidationPairedWithReset(candidate, truthySets, context)) didFindOtherWrite = true;
|
|
69357
|
-
});
|
|
69358
|
-
return didFindOtherWrite ? null : claim;
|
|
69359
|
-
};
|
|
69360
|
-
const isClaimedOwnershipComparison = (test, expectedMode, functionNode, truthySets, firstRiskyAwait, resetNode, context) => {
|
|
69361
|
-
const comparison = getAsyncOwnershipComparison(test, context);
|
|
69362
|
-
return Boolean(comparison && comparison.mode === expectedMode && findOwnershipClaim(comparison, functionNode, truthySets, firstRiskyAwait, resetNode, context));
|
|
69363
|
-
};
|
|
69364
|
-
const hasLifecycleGuardWriteOutsideCleanup = (effectCallback, guardKey, acceptedAssignments, context) => {
|
|
68237
|
+
const hasLifecycleGuardWriteOutsideCleanup = (effectCallback, guardKey, acceptedCleanupAssignments, context) => {
|
|
69365
68238
|
let didFindOtherWrite = false;
|
|
69366
68239
|
walkAst(effectCallback, (candidate) => {
|
|
69367
68240
|
if (didFindOtherWrite) return false;
|
|
@@ -69369,7 +68242,7 @@ const hasLifecycleGuardWriteOutsideCleanup = (effectCallback, guardKey, accepted
|
|
|
69369
68242
|
if (serializeReferenceKey({
|
|
69370
68243
|
node: candidate.left,
|
|
69371
68244
|
scopes: context.scopes
|
|
69372
|
-
}) === guardKey && !
|
|
68245
|
+
}) === guardKey && !acceptedCleanupAssignments.has(candidate)) {
|
|
69373
68246
|
didFindOtherWrite = true;
|
|
69374
68247
|
return false;
|
|
69375
68248
|
}
|
|
@@ -69385,103 +68258,48 @@ const hasLifecycleGuardWriteOutsideCleanup = (effectCallback, guardKey, accepted
|
|
|
69385
68258
|
});
|
|
69386
68259
|
return didFindOtherWrite;
|
|
69387
68260
|
};
|
|
69388
|
-
const
|
|
69389
|
-
const acceptedAssignments = /* @__PURE__ */ new Set();
|
|
69390
|
-
for (const cleanupFunction of collectReturnedCleanupFunctions(effectCallback, context.scopes)) walkOwnFunctionScope(cleanupFunction, (cleanupNode) => {
|
|
69391
|
-
const assignedValue = isNodeOfType(cleanupNode, "AssignmentExpression") ? stripParenExpression(cleanupNode.right) : null;
|
|
69392
|
-
if (!isNodeOfType(cleanupNode, "AssignmentExpression") || cleanupNode.operator !== "=" || !isNodeOfType(assignedValue, "Literal") || assignedValue.value !== false || serializeReferenceKey({
|
|
69393
|
-
node: cleanupNode.left,
|
|
69394
|
-
scopes: context.scopes
|
|
69395
|
-
}) !== guardKey || !isUnconditionallyExecutedWithinFunction(cleanupNode, cleanupFunction, context)) return;
|
|
69396
|
-
acceptedAssignments.add(cleanupNode);
|
|
69397
|
-
});
|
|
69398
|
-
if (acceptedAssignments.size === 0) return null;
|
|
69399
|
-
walkOwnFunctionScope(effectCallback, (effectNode) => {
|
|
69400
|
-
const assignedValue = isNodeOfType(effectNode, "AssignmentExpression") ? stripParenExpression(effectNode.right) : null;
|
|
69401
|
-
if (isNodeOfType(effectNode, "AssignmentExpression") && effectNode.operator === "=" && isNodeOfType(assignedValue, "Literal") && assignedValue.value === true && serializeReferenceKey({
|
|
69402
|
-
node: effectNode.left,
|
|
69403
|
-
scopes: context.scopes
|
|
69404
|
-
}) === guardKey && isUnconditionallyExecutedWithinFunction(effectNode, effectCallback, context)) acceptedAssignments.add(effectNode);
|
|
69405
|
-
});
|
|
69406
|
-
return acceptedAssignments;
|
|
69407
|
-
};
|
|
69408
|
-
const isEffectCallback = (node, context) => {
|
|
69409
|
-
const callbackRoot = findTransparentExpressionRoot(node);
|
|
69410
|
-
const callbackCall = callbackRoot.parent;
|
|
69411
|
-
return Boolean(callbackCall && isNodeOfType(callbackCall, "CallExpression") && callbackCall.arguments[0] === callbackRoot && isReactApiCall(callbackCall, EFFECT_HOOK_NAMES$6, context.scopes, {
|
|
69412
|
-
allowGlobalReactNamespace: true,
|
|
69413
|
-
allowUnboundBareCalls: true
|
|
69414
|
-
}));
|
|
69415
|
-
};
|
|
69416
|
-
const isCleanupBackedLifecycleGuard = (guardExpression, functionNode, context) => {
|
|
69417
|
-
const guardKey = serializeReferenceKey({
|
|
69418
|
-
node: guardExpression,
|
|
69419
|
-
scopes: context.scopes
|
|
69420
|
-
});
|
|
69421
|
-
if (!guardKey || !isInitiallyActiveLifecycleGuard(guardExpression, context)) return false;
|
|
69422
|
-
let ownerFunction = functionNode.parent;
|
|
69423
|
-
while (ownerFunction && !isFunctionLike$1(ownerFunction)) ownerFunction = ownerFunction.parent ?? null;
|
|
69424
|
-
if (!ownerFunction) return false;
|
|
69425
|
-
const effectCallbacks = [];
|
|
69426
|
-
if (isEffectCallback(ownerFunction, context)) effectCallbacks.push(ownerFunction);
|
|
69427
|
-
walkOwnFunctionScope(ownerFunction, (candidate) => {
|
|
69428
|
-
if (!isNodeOfType(candidate, "CallExpression")) return;
|
|
69429
|
-
if (!isReactApiCall(candidate, EFFECT_HOOK_NAMES$6, context.scopes, {
|
|
69430
|
-
allowGlobalReactNamespace: true,
|
|
69431
|
-
allowUnboundBareCalls: true
|
|
69432
|
-
})) return;
|
|
69433
|
-
const effectCallback = candidate.arguments[0];
|
|
69434
|
-
if (effectCallback && isFunctionLike$1(effectCallback)) effectCallbacks.push(effectCallback);
|
|
69435
|
-
});
|
|
69436
|
-
const acceptedAssignments = /* @__PURE__ */ new Set();
|
|
69437
|
-
for (const effectCallback of effectCallbacks) {
|
|
69438
|
-
const effectAssignments = collectCleanupBackedLifecycleAssignments(effectCallback, guardKey, context);
|
|
69439
|
-
if (!effectAssignments) continue;
|
|
69440
|
-
for (const assignment of effectAssignments) acceptedAssignments.add(assignment);
|
|
69441
|
-
}
|
|
69442
|
-
return Boolean(acceptedAssignments.size > 0 && !hasLifecycleGuardWriteOutsideCleanup(ownerFunction, guardKey, acceptedAssignments, context));
|
|
69443
|
-
};
|
|
69444
|
-
const collectLogicalOperands = (expression, operator) => {
|
|
69445
|
-
const stripped = stripParenExpression(expression);
|
|
69446
|
-
if (isNodeOfType(stripped, "LogicalExpression") && stripped.operator === operator) return [...collectLogicalOperands(stripped.left, operator), ...collectLogicalOperands(stripped.right, operator)];
|
|
69447
|
-
return [stripped];
|
|
69448
|
-
};
|
|
69449
|
-
const collectFinalizerGuardExpressions = (resetNode, protectingTry) => {
|
|
69450
|
-
const positive = [];
|
|
69451
|
-
const negative = [];
|
|
68261
|
+
const isResetGuardedByCleanupBackedLifecycle = (resetNode, functionNode, context) => {
|
|
69452
68262
|
let child = resetNode;
|
|
69453
68263
|
let cursor = resetNode.parent;
|
|
69454
|
-
|
|
69455
|
-
|
|
69456
|
-
|
|
69457
|
-
|
|
69458
|
-
|
|
69459
|
-
|
|
69460
|
-
|
|
69461
|
-
|
|
69462
|
-
|
|
69463
|
-
|
|
69464
|
-
|
|
69465
|
-
negative.push(...collectLogicalOperands(statement.test, "||"));
|
|
69466
|
-
}
|
|
69467
|
-
} else if (isNodeOfType(cursor, "SwitchCase") || isNodeOfType(cursor, "ConditionalExpression") || isNodeOfType(cursor, "ForStatement") || isNodeOfType(cursor, "ForInStatement") || isNodeOfType(cursor, "ForOfStatement") || isNodeOfType(cursor, "WhileStatement") || isNodeOfType(cursor, "DoWhileStatement")) return null;
|
|
68264
|
+
let guardKey = null;
|
|
68265
|
+
let guardExpression = null;
|
|
68266
|
+
while (cursor && cursor !== functionNode) {
|
|
68267
|
+
if (isNodeOfType(cursor, "IfStatement") && cursor.consequent === child && cursor.alternate === null) {
|
|
68268
|
+
guardExpression = cursor.test;
|
|
68269
|
+
guardKey = serializeReferenceKey({
|
|
68270
|
+
node: cursor.test,
|
|
68271
|
+
scopes: context.scopes
|
|
68272
|
+
});
|
|
68273
|
+
break;
|
|
68274
|
+
}
|
|
69468
68275
|
child = cursor;
|
|
69469
68276
|
cursor = cursor.parent ?? null;
|
|
69470
68277
|
}
|
|
69471
|
-
|
|
69472
|
-
|
|
69473
|
-
|
|
69474
|
-
|
|
69475
|
-
|
|
69476
|
-
const
|
|
69477
|
-
|
|
69478
|
-
|
|
69479
|
-
|
|
69480
|
-
|
|
69481
|
-
|
|
69482
|
-
const
|
|
69483
|
-
|
|
69484
|
-
|
|
68278
|
+
if (!guardKey || !guardExpression || !isInitiallyActiveLifecycleGuard(guardExpression, context)) return false;
|
|
68279
|
+
cursor = functionNode.parent;
|
|
68280
|
+
while (cursor) {
|
|
68281
|
+
if (isFunctionLike$1(cursor)) {
|
|
68282
|
+
const callbackRoot = findTransparentExpressionRoot(cursor);
|
|
68283
|
+
const callbackCall = callbackRoot.parent;
|
|
68284
|
+
if (Boolean(callbackCall && isNodeOfType(callbackCall, "CallExpression") && callbackCall.arguments[0] === callbackRoot && isReactApiCall(callbackCall, EFFECT_HOOK_NAMES$6, context.scopes, {
|
|
68285
|
+
allowGlobalReactNamespace: true,
|
|
68286
|
+
allowUnboundBareCalls: true
|
|
68287
|
+
}))) {
|
|
68288
|
+
const acceptedCleanupAssignments = /* @__PURE__ */ new Set();
|
|
68289
|
+
for (const cleanupFunction of collectReturnedCleanupFunctions(cursor, context.scopes)) walkOwnFunctionScope(cleanupFunction, (cleanupNode) => {
|
|
68290
|
+
const assignedValue = isNodeOfType(cleanupNode, "AssignmentExpression") ? stripParenExpression(cleanupNode.right) : null;
|
|
68291
|
+
if (!isNodeOfType(cleanupNode, "AssignmentExpression") || cleanupNode.operator !== "=" || !isNodeOfType(assignedValue, "Literal") || assignedValue.value !== false || serializeReferenceKey({
|
|
68292
|
+
node: cleanupNode.left,
|
|
68293
|
+
scopes: context.scopes
|
|
68294
|
+
}) !== guardKey || !isUnconditionallyExecutedWithinFunction(cleanupNode, cleanupFunction, context)) return;
|
|
68295
|
+
acceptedCleanupAssignments.add(cleanupNode);
|
|
68296
|
+
});
|
|
68297
|
+
if (acceptedCleanupAssignments.size > 0 && !hasLifecycleGuardWriteOutsideCleanup(cursor, guardKey, acceptedCleanupAssignments, context)) return true;
|
|
68298
|
+
}
|
|
68299
|
+
}
|
|
68300
|
+
cursor = cursor.parent ?? null;
|
|
68301
|
+
}
|
|
68302
|
+
return false;
|
|
69485
68303
|
};
|
|
69486
68304
|
const isAwaitInsideProtectedTry = (awaitNode, tryStatement) => {
|
|
69487
68305
|
let child = awaitNode;
|
|
@@ -69587,13 +68405,7 @@ const analyzeFunction = (functionNode, context) => {
|
|
|
69587
68405
|
const exceptionallyProtectedAwaits = collectExceptionallyProtectedAwaits(awaitSites, calls);
|
|
69588
68406
|
const riskyAwaitsWithTruthySet = awaitSites.filter((awaitSite) => rejectingAwaitNodes.has(awaitSite.node) && !exceptionallyProtectedAwaits.has(awaitSite.node) && truthySets.some((truthySet) => truthySet.start < awaitSite.start && !areOnExclusiveBranches(truthySet.node, awaitSite.node, functionNode)));
|
|
69589
68407
|
if (riskyAwaitsWithTruthySet.length === 0) continue;
|
|
69590
|
-
const conditionalExceptionalResets = calls.filter((call) =>
|
|
69591
|
-
if (call.value || call.context === "plain" || call.isUnconditional || call.protectingTry === null) return false;
|
|
69592
|
-
const protectingTry = call.protectingTry;
|
|
69593
|
-
if (!isInsideTryFinalizer(call.node, protectingTry)) return true;
|
|
69594
|
-
const firstRiskyAwait = riskyAwaitsWithTruthySet.find((awaitSite) => isAwaitInsideProtectedTry(awaitSite.node, protectingTry));
|
|
69595
|
-
return !(firstRiskyAwait && isFinalizerResetProvablyGuarded(call.node, protectingTry, functionNode, truthySets, firstRiskyAwait, context));
|
|
69596
|
-
});
|
|
68408
|
+
const conditionalExceptionalResets = calls.filter((call) => !call.value && call.context !== "plain" && !call.isUnconditional && call.protectingTry !== null && !(isInsideTryFinalizer(call.node, call.protectingTry) && isResetGuardedByCleanupBackedLifecycle(call.node, functionNode, context)));
|
|
69597
68409
|
for (const reset of conditionalExceptionalResets) {
|
|
69598
68410
|
const catchHandler = reset.protectingTry?.handler;
|
|
69599
68411
|
if (catchHandler && !catchHandlerCanBypassReset(catchHandler, functionNode, setterKey, context, false)) continue;
|
|
@@ -75465,29 +74277,6 @@ const doesPredicateTruthRequireMatch = (matchCall, predicateFunction) => {
|
|
|
75465
74277
|
}
|
|
75466
74278
|
return !isNegated && predicateFunction.body === child;
|
|
75467
74279
|
};
|
|
75468
|
-
const doesPredicateReturnNormalizedMatch = (matchCall, predicateFunction) => {
|
|
75469
|
-
if (!isFunctionLike$1(predicateFunction) || !isNodeOfType(predicateFunction.body, "BlockStatement") || predicateFunction.body.body.length !== 2 || !isNodeOfType(predicateFunction.body.body[0], "VariableDeclaration")) return false;
|
|
75470
|
-
const returnStatement = predicateFunction.body.body[1];
|
|
75471
|
-
if (!isNodeOfType(returnStatement, "ReturnStatement") || !returnStatement.argument) return false;
|
|
75472
|
-
let negationCount = 0;
|
|
75473
|
-
let expression = matchCall;
|
|
75474
|
-
let parent = expression.parent ?? null;
|
|
75475
|
-
while (parent && parent !== returnStatement) {
|
|
75476
|
-
if (isNodeOfType(parent, "UnaryExpression") && parent.operator === "!") {
|
|
75477
|
-
negationCount += 1;
|
|
75478
|
-
expression = parent;
|
|
75479
|
-
parent = parent.parent ?? null;
|
|
75480
|
-
continue;
|
|
75481
|
-
}
|
|
75482
|
-
if (TRANSPARENT_EXPRESSION_WRAPPER_TYPES.has(parent.type) || isNodeOfType(parent, "ChainExpression")) {
|
|
75483
|
-
expression = parent;
|
|
75484
|
-
parent = parent.parent ?? null;
|
|
75485
|
-
continue;
|
|
75486
|
-
}
|
|
75487
|
-
return false;
|
|
75488
|
-
}
|
|
75489
|
-
return parent === returnStatement && returnStatement.argument === expression && negationCount % 2 === 0;
|
|
75490
|
-
};
|
|
75491
74280
|
const isStringTypeofGuardForPath = (test, expectedPath) => {
|
|
75492
74281
|
const target = stripParenExpression(test);
|
|
75493
74282
|
if (!isNodeOfType(target, "BinaryExpression") || target.operator !== "===") return false;
|
|
@@ -75528,26 +74317,6 @@ const pathUsesOptionalAccess = (node) => {
|
|
|
75528
74317
|
current = current.object;
|
|
75529
74318
|
}
|
|
75530
74319
|
};
|
|
75531
|
-
const getNormalizedClassNameRoot = (expression) => {
|
|
75532
|
-
const conditional = stripParenExpression(expression);
|
|
75533
|
-
if (!isNodeOfType(conditional, "ConditionalExpression")) return null;
|
|
75534
|
-
const consequent = stripParenExpression(conditional.consequent);
|
|
75535
|
-
const rootIdentifier = getRootIdentifier(consequent);
|
|
75536
|
-
if (!rootIdentifier || receiverPathKey(consequent) !== `${rootIdentifier.name}.className`) return null;
|
|
75537
|
-
const test = stripParenExpression(conditional.test);
|
|
75538
|
-
if (!isNodeOfType(test, "BinaryExpression") || test.operator !== "===") return null;
|
|
75539
|
-
const testOperands = [test.left, test.right].map((operand) => stripParenExpression(operand));
|
|
75540
|
-
const typeofOperand = testOperands.find((operand) => isNodeOfType(operand, "UnaryExpression"));
|
|
75541
|
-
const stringOperand = testOperands.find((operand) => isNodeOfType(operand, "Literal"));
|
|
75542
|
-
if (!typeofOperand || !isNodeOfType(typeofOperand, "UnaryExpression") || typeofOperand.operator !== "typeof" || receiverPathKey(typeofOperand.argument) !== `${rootIdentifier.name}.className` || !stringOperand || !isNodeOfType(stringOperand, "Literal") || stringOperand.value !== "string") return null;
|
|
75543
|
-
const alternate = stripParenExpression(conditional.alternate);
|
|
75544
|
-
if (!isNodeOfType(alternate, "LogicalExpression") || alternate.operator !== "??") return null;
|
|
75545
|
-
const fallback = stripParenExpression(alternate.right);
|
|
75546
|
-
const attributeCall = stripParenExpression(alternate.left);
|
|
75547
|
-
if (!isNodeOfType(fallback, "Literal") || fallback.value !== "" || !isNodeOfType(attributeCall, "CallExpression") || !isNodeOfType(attributeCall.callee, "MemberExpression") || getStaticPropertyName(attributeCall.callee) !== "getAttribute" || receiverPathKey(attributeCall.callee.object) !== rootIdentifier.name) return null;
|
|
75548
|
-
const attributeName = attributeCall.arguments[0] ? stripParenExpression(attributeCall.arguments[0]) : null;
|
|
75549
|
-
return attributeName && isNodeOfType(attributeName, "Literal") && attributeName.value === "class" ? rootIdentifier : null;
|
|
75550
|
-
};
|
|
75551
74320
|
const isMatchProvenByFindUpUntilPredicate = (assertion, matchReceiver, assertedPattern, context) => {
|
|
75552
74321
|
const resultIdentifier = getRootIdentifier(matchReceiver);
|
|
75553
74322
|
const resultPath = receiverPathKey(matchReceiver);
|
|
@@ -75556,17 +74325,11 @@ const isMatchProvenByFindUpUntilPredicate = (assertion, matchReceiver, assertedP
|
|
|
75556
74325
|
if (!isDirectFinderMatchReturn(assertion) && !isOptionalResultPath) return false;
|
|
75557
74326
|
const resultSymbol = context.scopes.symbolFor(resultIdentifier);
|
|
75558
74327
|
const initializer = resultSymbol?.initializer ? stripParenExpression(resultSymbol.initializer) : null;
|
|
75559
|
-
if (resultSymbol?.kind !== "const" || !initializer) return false;
|
|
75560
|
-
const finderCall = isNodeOfType(initializer, "CallExpression") ? initializer : isNodeOfType(initializer, "ConditionalExpression") ? (() => {
|
|
75561
|
-
const alternate = stripParenExpression(initializer.alternate);
|
|
75562
|
-
const consequent = stripParenExpression(initializer.consequent);
|
|
75563
|
-
return (isNodeOfType(alternate, "Literal") && alternate.value === null || isNodeOfType(alternate, "Identifier") && alternate.name === "undefined" && context.scopes.isGlobalReference(alternate)) && isNodeOfType(consequent, "CallExpression") ? consequent : null;
|
|
75564
|
-
})() : null;
|
|
75565
|
-
if (!finderCall || !isNodeOfType(finderCall, "CallExpression")) return false;
|
|
74328
|
+
if (resultSymbol?.kind !== "const" || !initializer || !isNodeOfType(initializer, "CallExpression")) return false;
|
|
75566
74329
|
if (!isOptionalResultPath && !isImmediatelyGuardedFinderResult(assertion, resultSymbol, resultPath, context)) return false;
|
|
75567
|
-
const finderCallee = stripParenExpression(
|
|
74330
|
+
const finderCallee = stripParenExpression(initializer.callee);
|
|
75568
74331
|
if (!isNodeOfType(finderCallee, "Identifier") || !(context.scopes.symbolFor(finderCallee)?.kind === "import" && getImportedNameFromModule(assertion, finderCallee.name, CLOUDSCAPE_DOM_MODULE) === "findUpUntil" || finderCallee.name === "findUpUntil" && context.scopes.isGlobalReference(finderCallee))) return false;
|
|
75569
|
-
const predicateArgument =
|
|
74332
|
+
const predicateArgument = initializer.arguments[1];
|
|
75570
74333
|
if (!predicateArgument) return false;
|
|
75571
74334
|
const predicateFunction = resolveExactLocalFunction(predicateArgument, context.scopes);
|
|
75572
74335
|
if (!predicateFunction || !isFunctionLike$1(predicateFunction)) return false;
|
|
@@ -75590,43 +74353,6 @@ const isMatchProvenByFindUpUntilPredicate = (assertion, matchReceiver, assertedP
|
|
|
75590
74353
|
});
|
|
75591
74354
|
return didProveMatch;
|
|
75592
74355
|
};
|
|
75593
|
-
const isMatchProvenByNormalizedFindUpUntilPredicate = (assertion, matchReceiver, assertedPattern, context) => {
|
|
75594
|
-
const normalizedReceiver = stripParenExpression(matchReceiver);
|
|
75595
|
-
if (!isNodeOfType(normalizedReceiver, "Identifier")) return false;
|
|
75596
|
-
const normalizedReceiverSymbol = context.scopes.symbolFor(normalizedReceiver);
|
|
75597
|
-
const normalizedReceiverInitializer = normalizedReceiverSymbol?.initializer ? stripParenExpression(normalizedReceiverSymbol.initializer) : null;
|
|
75598
|
-
const resultIdentifier = normalizedReceiverInitializer ? getNormalizedClassNameRoot(normalizedReceiverInitializer) : null;
|
|
75599
|
-
if (normalizedReceiverSymbol?.kind !== "const" || normalizedReceiverSymbol.references.some((reference) => reference.flag !== "read") || !resultIdentifier) return false;
|
|
75600
|
-
const resultSymbol = context.scopes.symbolFor(resultIdentifier);
|
|
75601
|
-
const finderCall = resultSymbol?.initializer ? stripParenExpression(resultSymbol.initializer) : null;
|
|
75602
|
-
if (resultSymbol?.kind !== "const" || resultSymbol.references.some((reference) => reference.flag !== "read") || !finderCall || !isNodeOfType(finderCall, "CallExpression")) return false;
|
|
75603
|
-
const finderCallee = stripParenExpression(finderCall.callee);
|
|
75604
|
-
if (!isNodeOfType(finderCallee, "Identifier") || context.scopes.symbolFor(finderCallee)?.kind !== "import" || getImportedNameFromModule(assertion, finderCallee.name, CLOUDSCAPE_DOM_MODULE) !== "findUpUntil") return false;
|
|
75605
|
-
if (!isPresenceProvenBeforeNode(assertion, (test) => {
|
|
75606
|
-
const expression = stripParenExpression(test);
|
|
75607
|
-
return isNodeOfType(expression, "Identifier") && context.scopes.symbolFor(expression)?.id === resultSymbol.id;
|
|
75608
|
-
})) return false;
|
|
75609
|
-
const predicateArgument = finderCall.arguments[1];
|
|
75610
|
-
const predicateFunction = predicateArgument ? resolveExactLocalFunction(predicateArgument, context.scopes) : null;
|
|
75611
|
-
if (!predicateFunction || !isFunctionLike$1(predicateFunction) || predicateFunction.async || predicateFunction.generator) return false;
|
|
75612
|
-
const predicateParameter = predicateFunction.params[0];
|
|
75613
|
-
if (!isNodeOfType(predicateParameter, "Identifier")) return false;
|
|
75614
|
-
let didProveNormalizedMatch = false;
|
|
75615
|
-
walkAst(predicateFunction.body, (child) => {
|
|
75616
|
-
if (didProveNormalizedMatch || isFunctionLike$1(child)) return false;
|
|
75617
|
-
if (!isNodeOfType(child, "CallExpression") || !isNodeOfType(child.callee, "MemberExpression") || getStaticPropertyName(child.callee) !== "match" || !child.arguments[0] || !areRegexPatternsEquivalent(child.arguments[0], assertedPattern, context) || !doesPredicateTruthRequireMatch(child, predicateFunction) && !doesPredicateReturnNormalizedMatch(child, predicateFunction)) return;
|
|
75618
|
-
const predicateReceiver = stripParenExpression(child.callee.object);
|
|
75619
|
-
if (!isNodeOfType(predicateReceiver, "Identifier")) return;
|
|
75620
|
-
const predicateReceiverSymbol = context.scopes.symbolFor(predicateReceiver);
|
|
75621
|
-
const predicateReceiverInitializer = predicateReceiverSymbol?.initializer ? stripParenExpression(predicateReceiverSymbol.initializer) : null;
|
|
75622
|
-
const predicateRoot = predicateReceiverInitializer ? getNormalizedClassNameRoot(predicateReceiverInitializer) : null;
|
|
75623
|
-
if (predicateReceiverSymbol?.kind === "const" && predicateReceiverSymbol.references.every((reference) => reference.flag === "read") && predicateRoot?.name === predicateParameter.name) {
|
|
75624
|
-
didProveNormalizedMatch = true;
|
|
75625
|
-
return false;
|
|
75626
|
-
}
|
|
75627
|
-
});
|
|
75628
|
-
return didProveNormalizedMatch;
|
|
75629
|
-
};
|
|
75630
74356
|
const scopeProvesFindMatch = (assertion, findReceiver, findPredicate, context) => {
|
|
75631
74357
|
if (!isStablePredicate(findPredicate, context)) return false;
|
|
75632
74358
|
return isPresenceProvenBeforeNode(assertion, (test) => testPositivelyContainsCall(test, (call) => {
|
|
@@ -75727,123 +74453,6 @@ const isEnsureThenFind = (assertion, findReceiver, findPredicate) => {
|
|
|
75727
74453
|
}
|
|
75728
74454
|
return false;
|
|
75729
74455
|
};
|
|
75730
|
-
const getReceiverRootIdentifier = (node) => {
|
|
75731
|
-
let target = stripParenExpression(node);
|
|
75732
|
-
while (isNodeOfType(target, "MemberExpression")) target = stripParenExpression(target.object);
|
|
75733
|
-
return isNodeOfType(target, "Identifier") ? target : null;
|
|
75734
|
-
};
|
|
75735
|
-
const getReceiverStatePath = (node) => {
|
|
75736
|
-
const target = stripParenExpression(node);
|
|
75737
|
-
if (isNodeOfType(target, "Identifier")) return target.name;
|
|
75738
|
-
if (!isNodeOfType(target, "MemberExpression")) return null;
|
|
75739
|
-
const objectPath = getReceiverStatePath(target.object);
|
|
75740
|
-
if (!objectPath) return null;
|
|
75741
|
-
return `${objectPath}.${getStaticPropertyName(target) ?? "*"}`;
|
|
75742
|
-
};
|
|
75743
|
-
const doesReceiverStateChangeBeforeAssertion = (ownerFunction, receiver, startOffset, assertion, context) => {
|
|
75744
|
-
const receiverRoot = getReceiverRootIdentifier(receiver);
|
|
75745
|
-
const receiverSymbol = receiverRoot ? context.scopes.symbolFor(receiverRoot) : null;
|
|
75746
|
-
const receiverPath = getReceiverStatePath(receiver);
|
|
75747
|
-
if (!receiverRoot || !receiverSymbol || !receiverPath) return true;
|
|
75748
|
-
const receiverAliasPaths = new Map([[receiverSymbol.id, receiverRoot.name]]);
|
|
75749
|
-
let didAddAlias = true;
|
|
75750
|
-
while (didAddAlias) {
|
|
75751
|
-
didAddAlias = false;
|
|
75752
|
-
walkAst(ownerFunction, (child) => {
|
|
75753
|
-
if (child !== ownerFunction && isFunctionLike$1(child)) return false;
|
|
75754
|
-
if (!isNodeOfType(child, "VariableDeclarator") || !isNodeOfType(child.id, "Identifier") || !child.init) return;
|
|
75755
|
-
const initializer = stripParenExpression(child.init);
|
|
75756
|
-
if (!isNodeOfType(initializer, "Identifier") && !isNodeOfType(initializer, "MemberExpression")) return;
|
|
75757
|
-
const initializerRoot = getReceiverRootIdentifier(initializer);
|
|
75758
|
-
const initializerSymbol = initializerRoot ? context.scopes.symbolFor(initializerRoot) : null;
|
|
75759
|
-
const initializerBasePath = initializerSymbol ? receiverAliasPaths.get(initializerSymbol.id) : null;
|
|
75760
|
-
const initializerPath = getReceiverStatePath(initializer);
|
|
75761
|
-
if (!initializerRoot || !initializerBasePath || !initializerPath) return;
|
|
75762
|
-
const aliasSymbol = context.scopes.symbolFor(child.id);
|
|
75763
|
-
if (aliasSymbol && !receiverAliasPaths.has(aliasSymbol.id)) {
|
|
75764
|
-
const initializerSuffix = initializerPath.slice(initializerRoot.name.length);
|
|
75765
|
-
receiverAliasPaths.set(aliasSymbol.id, `${initializerBasePath}${initializerSuffix}`);
|
|
75766
|
-
didAddAlias = true;
|
|
75767
|
-
}
|
|
75768
|
-
});
|
|
75769
|
-
}
|
|
75770
|
-
let didChangeReceiverState = false;
|
|
75771
|
-
walkAst(ownerFunction, (child) => {
|
|
75772
|
-
if (didChangeReceiverState) return false;
|
|
75773
|
-
if (child !== ownerFunction && isFunctionLike$1(child)) return false;
|
|
75774
|
-
if (child.range[0] <= startOffset || child.range[0] >= assertion.range[0]) return;
|
|
75775
|
-
if (isNodeOfType(child, "CallExpression")) {
|
|
75776
|
-
didChangeReceiverState = true;
|
|
75777
|
-
return false;
|
|
75778
|
-
}
|
|
75779
|
-
const mutationTarget = isNodeOfType(child, "AssignmentExpression") || isNodeOfType(child, "UpdateExpression") || isNodeOfType(child, "UnaryExpression") && child.operator === "delete" ? stripParenExpression(isNodeOfType(child, "AssignmentExpression") ? child.left : child.argument) : null;
|
|
75780
|
-
const mutationRoot = mutationTarget ? getReceiverRootIdentifier(mutationTarget) : null;
|
|
75781
|
-
const mutationSymbol = mutationRoot ? context.scopes.symbolFor(mutationRoot) : null;
|
|
75782
|
-
const mutationBasePath = mutationSymbol ? receiverAliasPaths.get(mutationSymbol.id) : null;
|
|
75783
|
-
const mutationPath = mutationTarget ? getReceiverStatePath(mutationTarget) : null;
|
|
75784
|
-
if (mutationRoot && mutationBasePath && mutationPath) {
|
|
75785
|
-
const canonicalMutationPath = `${mutationBasePath}${mutationPath.slice(mutationRoot.name.length)}`;
|
|
75786
|
-
if (canonicalMutationPath !== receiverPath && !canonicalMutationPath.startsWith(`${receiverPath}.`) && !receiverPath.startsWith(`${canonicalMutationPath}.`)) return;
|
|
75787
|
-
didChangeReceiverState = true;
|
|
75788
|
-
return false;
|
|
75789
|
-
}
|
|
75790
|
-
});
|
|
75791
|
-
return didChangeReceiverState;
|
|
75792
|
-
};
|
|
75793
|
-
const isFindProvenByGuardedMaximum = (assertion, findReceiver, findPredicate, context) => {
|
|
75794
|
-
const findLookup = findEqualityLookupParts(findPredicate);
|
|
75795
|
-
const maximumIdentifier = findLookup ? stripParenExpression(findLookup.comparedValue) : null;
|
|
75796
|
-
if (!findLookup || !maximumIdentifier || !isNodeOfType(maximumIdentifier, "Identifier")) return false;
|
|
75797
|
-
const maximumSymbol = context.scopes.symbolFor(maximumIdentifier);
|
|
75798
|
-
const maximumInitializer = maximumSymbol?.initializer ? stripParenExpression(maximumSymbol.initializer) : null;
|
|
75799
|
-
if (maximumSymbol?.kind !== "const" || maximumSymbol.references.some((reference) => reference.flag !== "read") || !maximumInitializer || !isNodeOfType(maximumInitializer, "CallExpression") || !isNodeOfType(maximumInitializer.callee, "MemberExpression") || getStaticPropertyName(maximumInitializer.callee) !== "reduce") return false;
|
|
75800
|
-
const filterCall = stripParenExpression(maximumInitializer.callee.object);
|
|
75801
|
-
if (!isNodeOfType(filterCall, "CallExpression") || !isNodeOfType(filterCall.callee, "MemberExpression") || getStaticPropertyName(filterCall.callee) !== "filter" || !areNodesLooselyEqual(filterCall.callee.object, findReceiver)) return false;
|
|
75802
|
-
const filterPredicate = filterCall.arguments[0] ? stripParenExpression(filterCall.arguments[0]) : null;
|
|
75803
|
-
if (!filterPredicate || !isStablePredicate(filterPredicate, context)) return false;
|
|
75804
|
-
const reducerArgument = maximumInitializer.arguments[0] ? stripParenExpression(maximumInitializer.arguments[0]) : null;
|
|
75805
|
-
const reducerFunction = reducerArgument ? resolveExactLocalFunction(reducerArgument, context.scopes) : null;
|
|
75806
|
-
const initialValue = maximumInitializer.arguments[1] ? stripParenExpression(maximumInitializer.arguments[1]) : null;
|
|
75807
|
-
if (!reducerFunction || !isFunctionLike$1(reducerFunction) || reducerFunction.async || reducerFunction.generator || !initialValue || !isNodeOfType(initialValue, "Literal") || typeof initialValue.value !== "number") return false;
|
|
75808
|
-
const accumulatorParameter = reducerFunction.params[0];
|
|
75809
|
-
const itemParameter = reducerFunction.params[1];
|
|
75810
|
-
const reducerBody = singleExpressionPredicateBody(reducerFunction);
|
|
75811
|
-
if (!isNodeOfType(accumulatorParameter, "Identifier") || !isNodeOfType(itemParameter, "Identifier") || !reducerBody || !isNodeOfType(reducerBody, "CallExpression") || !isNodeOfType(reducerBody.callee, "MemberExpression") || getStaticPropertyName(reducerBody.callee) !== "max") return false;
|
|
75812
|
-
const mathReceiver = stripParenExpression(reducerBody.callee.object);
|
|
75813
|
-
if (!isNodeOfType(mathReceiver, "Identifier") || mathReceiver.name !== "Math" || !context.scopes.isGlobalReference(mathReceiver) || reducerBody.arguments.length !== 2) return false;
|
|
75814
|
-
const accumulatorArgument = reducerBody.arguments.find((argument) => {
|
|
75815
|
-
const expression = stripParenExpression(argument);
|
|
75816
|
-
return isNodeOfType(expression, "Identifier") && expression.name === accumulatorParameter.name;
|
|
75817
|
-
});
|
|
75818
|
-
const itemMemberArgument = reducerBody.arguments.find((argument) => {
|
|
75819
|
-
const expression = stripParenExpression(argument);
|
|
75820
|
-
const rootIdentifier = getRootIdentifier(expression);
|
|
75821
|
-
return isNodeOfType(expression, "MemberExpression") && rootIdentifier?.name === itemParameter.name && receiverPathKey(expression)?.slice(itemParameter.name.length + 1) === findLookup.propertyName;
|
|
75822
|
-
});
|
|
75823
|
-
if (!accumulatorArgument || !itemMemberArgument) return false;
|
|
75824
|
-
if (!receiverPathKey(findReceiver)) return false;
|
|
75825
|
-
let ownerFunction = assertion.parent ?? null;
|
|
75826
|
-
while (ownerFunction && !isFunctionLike$1(ownerFunction)) ownerFunction = ownerFunction.parent ?? null;
|
|
75827
|
-
if (!ownerFunction || !isFunctionLike$1(ownerFunction)) return false;
|
|
75828
|
-
const maximumEnd = maximumInitializer.range[1];
|
|
75829
|
-
if (doesReceiverStateChangeBeforeAssertion(ownerFunction.body, findReceiver, maximumEnd, assertion, context)) return false;
|
|
75830
|
-
return isPresenceProvenBeforeNode(assertion, (test) => {
|
|
75831
|
-
const comparison = stripParenExpression(test);
|
|
75832
|
-
if (!isNodeOfType(comparison, "BinaryExpression")) return false;
|
|
75833
|
-
return [[
|
|
75834
|
-
comparison.left,
|
|
75835
|
-
comparison.right,
|
|
75836
|
-
comparison.operator
|
|
75837
|
-
], [
|
|
75838
|
-
comparison.right,
|
|
75839
|
-
comparison.left,
|
|
75840
|
-
comparison.operator === "<" ? ">" : comparison.operator === ">" ? "<" : comparison.operator
|
|
75841
|
-
]].some(([candidateMaximum, candidateInitial, operator]) => {
|
|
75842
|
-
const candidateMaximumIdentifier = stripParenExpression(candidateMaximum);
|
|
75843
|
-
return operator === ">" && isNodeOfType(candidateMaximumIdentifier, "Identifier") && context.scopes.symbolFor(candidateMaximumIdentifier)?.id === maximumSymbol.id && areNodesLooselyEqual(stripParenExpression(candidateInitial), initialValue);
|
|
75844
|
-
});
|
|
75845
|
-
});
|
|
75846
|
-
};
|
|
75847
74456
|
const isDefinitelyNonNullishMapValue = (value) => {
|
|
75848
74457
|
if (!value) return false;
|
|
75849
74458
|
const expression = stripParenExpression(value);
|
|
@@ -75867,15 +74476,15 @@ const unwrapFalseBooleanGuard = (test) => {
|
|
|
75867
74476
|
};
|
|
75868
74477
|
const isEnsureThenMapGet = (assertion, receiver, lookupKey, context) => {
|
|
75869
74478
|
const stableLookupKey = stripParenExpression(lookupKey);
|
|
75870
|
-
|
|
75871
|
-
const lookupKeySymbol = isNodeOfType(stableLookupKey, "Identifier") ? context.scopes.symbolFor(stableLookupKey) : lookupKeyRoot ? context.scopes.symbolFor(lookupKeyRoot) : null;
|
|
75872
|
-
if (!isNodeOfType(stableLookupKey, "Identifier") && !isNodeOfType(stableLookupKey, "Literal") && (!isNodeOfType(stableLookupKey, "MemberExpression") || !lookupKeyRoot || lookupKeySymbol?.kind !== "const")) return false;
|
|
74479
|
+
if (!isNodeOfType(stableLookupKey, "Identifier") && !isNodeOfType(stableLookupKey, "Literal")) return false;
|
|
75873
74480
|
const receiverSymbol = context.scopes.symbolFor(receiver);
|
|
75874
74481
|
if (!receiverSymbol) return false;
|
|
75875
74482
|
const receiverMatches = (candidate) => {
|
|
75876
74483
|
const target = stripParenExpression(candidate);
|
|
75877
74484
|
return isNodeOfType(target, "Identifier") && context.scopes.symbolFor(target)?.id === receiverSymbol.id;
|
|
75878
74485
|
};
|
|
74486
|
+
const lookupKeyExpression = stripParenExpression(lookupKey);
|
|
74487
|
+
const lookupKeySymbol = isNodeOfType(lookupKeyExpression, "Identifier") ? context.scopes.symbolFor(lookupKeyExpression) : null;
|
|
75879
74488
|
let child = assertion;
|
|
75880
74489
|
let ancestor = assertion.parent ?? null;
|
|
75881
74490
|
while (ancestor && !isFunctionLike$1(ancestor)) {
|
|
@@ -75895,7 +74504,7 @@ const isEnsureThenMapGet = (assertion, receiver, lookupKey, context) => {
|
|
|
75895
74504
|
const populationCall = populationCalls[0];
|
|
75896
74505
|
if (!populationCall) continue;
|
|
75897
74506
|
const populationCallStart = populationCall.range[0];
|
|
75898
|
-
if (Boolean(lookupKeySymbol?.references.some((reference) => reference.flag !== "read" && reference.identifier.range[0] > populationCallStart && reference.identifier.range[0] < assertion.range[0]))
|
|
74507
|
+
if (Boolean(lookupKeySymbol?.references.some((reference) => reference.flag !== "read" && reference.identifier.range[0] > populationCallStart && reference.identifier.range[0] < assertion.range[0]))) continue;
|
|
75899
74508
|
if (receiverSymbol.references.some((reference) => reference.flag !== "read" && reference.identifier.range[0] > populationCallStart && reference.identifier.range[0] < assertion.range[0])) continue;
|
|
75900
74509
|
if (!indexedRelevantCalls(ancestor).some((laterCall) => {
|
|
75901
74510
|
if (laterCall.range[0] <= populationCallStart || laterCall.range[0] >= assertion.range[0] || !isNodeOfType(laterCall.callee, "MemberExpression") || !receiverMatches(laterCall.callee.object)) return false;
|
|
@@ -76005,7 +74614,6 @@ const noNonNullAssertionOnMaybeUndefinedResult = defineRule({
|
|
|
76005
74614
|
const findReceiver = callee.object;
|
|
76006
74615
|
if (predicate && isExhaustiveLiteralTupleMapping(findReceiver, predicate, context)) return;
|
|
76007
74616
|
if (predicate && scopeProvesFindMatch(node, findReceiver, predicate, context)) return;
|
|
76008
|
-
if (predicate && isFindProvenByGuardedMaximum(node, findReceiver, predicate, context)) return;
|
|
76009
74617
|
if (predicate && isEnsureThenFind(node, findReceiver, predicate)) return;
|
|
76010
74618
|
}
|
|
76011
74619
|
if (methodName === "match") {
|
|
@@ -76015,7 +74623,6 @@ const noNonNullAssertionOnMaybeUndefinedResult = defineRule({
|
|
|
76015
74623
|
const regexKey = pattern ? regexComparableKey(pattern, context) : null;
|
|
76016
74624
|
if (pattern && isGuardedAnchoredCharacterMatch(node, matchReceiver, pattern)) return;
|
|
76017
74625
|
if (pattern && regexKey && isMatchProvenByFindUpUntilPredicate(node, matchReceiver, pattern, context)) return;
|
|
76018
|
-
if (pattern && regexKey && isMatchProvenByNormalizedFindUpUntilPredicate(node, matchReceiver, pattern, context)) return;
|
|
76019
74626
|
if (regexKey && scopeProvesMatchTested(node, regexKey, matchReceiver, context)) return;
|
|
76020
74627
|
}
|
|
76021
74628
|
if (methodName === "get") {
|
|
@@ -79954,23 +78561,16 @@ const MAX_INITIATOR_RESOLUTION_DEPTH = 3;
|
|
|
79954
78561
|
const STATE_DISPATCHER_HOOK_NAMES = new Set(["useState", "useReducer"]);
|
|
79955
78562
|
const REF_HOOK_NAMES = new Set(["useRef"]);
|
|
79956
78563
|
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).";
|
|
79957
|
-
const
|
|
78564
|
+
const isKnownNonThenableHandlerReturn = (expression, context, visitedBindingIdentifiers = /* @__PURE__ */ new Set()) => {
|
|
79958
78565
|
const strippedExpression = stripParenExpression(expression);
|
|
79959
78566
|
if (isDefinitelyNonThenableValue(strippedExpression)) return true;
|
|
79960
|
-
if (isNodeOfType(strippedExpression, "CallExpression") && isNodeOfType(strippedExpression.callee, "MemberExpression")) {
|
|
79961
|
-
const receiver = stripParenExpression(strippedExpression.callee.object);
|
|
79962
|
-
if (isNodeOfType(receiver, "Identifier") && receiver.name === "Promise" && context.scopes.isGlobalReference(receiver) && getStaticPropertyName(strippedExpression.callee) === "resolve") {
|
|
79963
|
-
const resolvedValue = strippedExpression.arguments[0];
|
|
79964
|
-
return !resolvedValue || !isNodeOfType(resolvedValue, "SpreadElement") && isKnownNonRejectingHandlerReturn(resolvedValue, context, visitedBindingIdentifiers);
|
|
79965
|
-
}
|
|
79966
|
-
}
|
|
79967
78567
|
if (!isNodeOfType(strippedExpression, "Identifier")) return false;
|
|
79968
78568
|
if (strippedExpression.name === "undefined" && context.scopes.isGlobalReference(strippedExpression)) return true;
|
|
79969
78569
|
const symbol = context.scopes.symbolFor(strippedExpression);
|
|
79970
78570
|
if (!symbol || visitedBindingIdentifiers.has(symbol.bindingIdentifier)) return false;
|
|
79971
78571
|
visitedBindingIdentifiers.add(symbol.bindingIdentifier);
|
|
79972
78572
|
const initializer = getDirectUnreassignedInitializer(symbol);
|
|
79973
|
-
return Boolean(initializer &&
|
|
78573
|
+
return Boolean(initializer && isKnownNonThenableHandlerReturn(initializer, context, visitedBindingIdentifiers));
|
|
79974
78574
|
};
|
|
79975
78575
|
const isKnownNonRejectingHandler = (argument, context) => {
|
|
79976
78576
|
if (!argument) return false;
|
|
@@ -79985,7 +78585,7 @@ const isKnownNonRejectingHandler = (argument, context) => {
|
|
|
79985
78585
|
canReject = true;
|
|
79986
78586
|
return false;
|
|
79987
78587
|
}
|
|
79988
|
-
if (isNodeOfType(child, "ReturnStatement") && child.argument && !
|
|
78588
|
+
if (isNodeOfType(child, "ReturnStatement") && child.argument && !isKnownNonThenableHandlerReturn(child.argument, context)) {
|
|
79989
78589
|
if (!isNodeOfType(stripParenExpression(child.argument), "CallExpression")) {
|
|
79990
78590
|
canReject = true;
|
|
79991
78591
|
return false;
|
|
@@ -80034,28 +78634,6 @@ const handlerHasPotentiallyThrowingMemberRead = (argument, context) => {
|
|
|
80034
78634
|
});
|
|
80035
78635
|
return hasPotentiallyThrowingMemberRead;
|
|
80036
78636
|
};
|
|
80037
|
-
const hasRejectionHandler = (chain, argument, context, allowTerminalCatchBlock) => {
|
|
80038
|
-
if (!argument) return false;
|
|
80039
|
-
if (!handlerHasPotentiallyThrowingMemberRead(argument, context) && (chainCarriesRejectionHandler(chain, context.scopes) || isKnownNonRejectingHandler(argument, context))) return true;
|
|
80040
|
-
if (!allowTerminalCatchBlock) return false;
|
|
80041
|
-
const candidate = stripParenExpression(argument);
|
|
80042
|
-
const handler = isNodeOfType(candidate, "Identifier") ? resolveExactLocalFunction(candidate, context.scopes) : candidate;
|
|
80043
|
-
if (!handler || !isFunctionLike$1(handler)) return isNodeOfType(candidate, "MemberExpression") || isNodeOfType(candidate, "Identifier") && candidate.name !== "undefined";
|
|
80044
|
-
if (!isNodeOfType(handler.body, "BlockStatement")) return false;
|
|
80045
|
-
let doesExplicitlyReject = false;
|
|
80046
|
-
walkOwnFunctionScope(handler, (child) => {
|
|
80047
|
-
if (doesExplicitlyReject) return false;
|
|
80048
|
-
if (isNodeOfType(child, "ThrowStatement") || isNodeOfType(child, "AwaitExpression")) {
|
|
80049
|
-
doesExplicitlyReject = true;
|
|
80050
|
-
return false;
|
|
80051
|
-
}
|
|
80052
|
-
if (isNodeOfType(child, "ReturnStatement") && child.argument && !isKnownNonRejectingHandlerReturn(child.argument, context)) {
|
|
80053
|
-
doesExplicitlyReject = true;
|
|
80054
|
-
return false;
|
|
80055
|
-
}
|
|
80056
|
-
});
|
|
80057
|
-
return !doesExplicitlyReject;
|
|
80058
|
-
};
|
|
80059
78637
|
const walkPromiseChain = (chainExpression, context) => {
|
|
80060
78638
|
let cursor = stripParenExpression(chainExpression);
|
|
80061
78639
|
let hasCatch = false;
|
|
@@ -80067,9 +78645,10 @@ const walkPromiseChain = (chainExpression, context) => {
|
|
|
80067
78645
|
while (isNodeOfType(cursor, "CallExpression") && isNodeOfType(cursor.callee, "MemberExpression") && PROMISE_METHOD_NAMES.has(getStaticPropertyName(cursor.callee) ?? "")) {
|
|
80068
78646
|
const methodName = getStaticPropertyName(cursor.callee);
|
|
80069
78647
|
const rejectionHandlerArgument = methodName === "catch" ? cursor.arguments[0] : cursor.arguments[1];
|
|
80070
|
-
|
|
78648
|
+
const hasAbsorbingRejectionHandler = !handlerHasPotentiallyThrowingMemberRead(rejectionHandlerArgument, context) && (chainCarriesRejectionHandler(cursor, context.scopes) || isKnownNonRejectingHandler(rejectionHandlerArgument, context));
|
|
78649
|
+
if (!didReachTerminalThen && methodName === "catch" && hasAbsorbingRejectionHandler) hasCatch = true;
|
|
80071
78650
|
if (methodName === "then") {
|
|
80072
|
-
if (!didReachTerminalThen &&
|
|
78651
|
+
if (!didReachTerminalThen && hasAbsorbingRejectionHandler) hasRejectionHandlerArgument = true;
|
|
80073
78652
|
didReachTerminalThen = true;
|
|
80074
78653
|
sawThen = true;
|
|
80075
78654
|
const callbackArgument = cursor.arguments[0];
|
|
@@ -82396,45 +80975,6 @@ const noRefCallbackCleanupBeforeReact19 = defineRule({
|
|
|
82396
80975
|
} })
|
|
82397
80976
|
});
|
|
82398
80977
|
//#endregion
|
|
82399
|
-
//#region src/plugin/utils/contains-non-deterministic-source.ts
|
|
82400
|
-
const NON_DETERMINISTIC_MEMBER_CALLS = new Set([
|
|
82401
|
-
"Math.random",
|
|
82402
|
-
"Date.now",
|
|
82403
|
-
"performance.now",
|
|
82404
|
-
"crypto.randomUUID",
|
|
82405
|
-
"crypto.getRandomValues"
|
|
82406
|
-
]);
|
|
82407
|
-
const NON_DETERMINISTIC_ID_GENERATOR_NAMES = new Set([
|
|
82408
|
-
"nanoid",
|
|
82409
|
-
"uuid",
|
|
82410
|
-
"cuid",
|
|
82411
|
-
"ulid",
|
|
82412
|
-
"createId"
|
|
82413
|
-
]);
|
|
82414
|
-
const isZeroArgDateConstruction = (node) => isNodeOfType(node, "NewExpression") && isNodeOfType(node.callee, "Identifier") && node.callee.name === "Date" && (node.arguments?.length ?? 0) === 0;
|
|
82415
|
-
const containsNonDeterministicSource = (root) => {
|
|
82416
|
-
let found = false;
|
|
82417
|
-
walkAst(root, (child) => {
|
|
82418
|
-
if (found) return false;
|
|
82419
|
-
if (isFunctionLike$1(child)) return false;
|
|
82420
|
-
if (isZeroArgDateConstruction(child)) {
|
|
82421
|
-
found = true;
|
|
82422
|
-
return false;
|
|
82423
|
-
}
|
|
82424
|
-
if (!isNodeOfType(child, "CallExpression")) return;
|
|
82425
|
-
const callee = child.callee;
|
|
82426
|
-
if (isNodeOfType(callee, "Identifier") && NON_DETERMINISTIC_ID_GENERATOR_NAMES.has(callee.name)) {
|
|
82427
|
-
found = true;
|
|
82428
|
-
return false;
|
|
82429
|
-
}
|
|
82430
|
-
if (isNodeOfType(callee, "MemberExpression") && isNodeOfType(callee.object, "Identifier") && isNodeOfType(callee.property, "Identifier") && NON_DETERMINISTIC_MEMBER_CALLS.has(`${callee.object.name}.${callee.property.name}`)) {
|
|
82431
|
-
found = true;
|
|
82432
|
-
return false;
|
|
82433
|
-
}
|
|
82434
|
-
});
|
|
82435
|
-
return found;
|
|
82436
|
-
};
|
|
82437
|
-
//#endregion
|
|
82438
80978
|
//#region src/plugin/rules/state-and-effects/no-ref-current-in-render.ts
|
|
82439
80979
|
const REPEATED_ANCESTOR_TYPES = new Set([
|
|
82440
80980
|
"DoWhileStatement",
|
|
@@ -82465,75 +81005,45 @@ const resolveImmutableInitializationValue = (node, scopes, visitedSymbolIds = /*
|
|
|
82465
81005
|
};
|
|
82466
81006
|
const isProvablyTruthyInitializationValue = (node, scopes) => {
|
|
82467
81007
|
const expression = resolveImmutableInitializationValue(node, scopes);
|
|
82468
|
-
|
|
82469
|
-
if (isNodeOfType(expression, "CallExpression")) {
|
|
82470
|
-
const callee = stripParenExpression(expression.callee);
|
|
82471
|
-
return isNodeOfType(callee, "Identifier") && callee.name.startsWith("create");
|
|
82472
|
-
}
|
|
82473
|
-
return isNodeOfType(expression, "NewExpression") || isNodeOfType(expression, "ObjectExpression") || isNodeOfType(expression, "ArrayExpression") || isNodeOfType(expression, "ArrowFunctionExpression") || isNodeOfType(expression, "FunctionExpression") || isNodeOfType(expression, "ClassExpression");
|
|
81008
|
+
return Boolean(expression && (isNodeOfType(expression, "NewExpression") || isNodeOfType(expression, "ObjectExpression") || isNodeOfType(expression, "ArrayExpression") || isNodeOfType(expression, "ArrowFunctionExpression") || isNodeOfType(expression, "FunctionExpression") || isNodeOfType(expression, "ClassExpression")));
|
|
82474
81009
|
};
|
|
82475
|
-
const
|
|
81010
|
+
const getInitializationConstructorName = (node, scopes) => {
|
|
82476
81011
|
const expression = resolveImmutableInitializationValue(node, scopes);
|
|
82477
81012
|
if (!expression) return null;
|
|
82478
|
-
if (isNodeOfType(expression, "NewExpression")
|
|
81013
|
+
if (isNodeOfType(expression, "NewExpression")) {
|
|
82479
81014
|
const callee = stripParenExpression(expression.callee);
|
|
82480
|
-
|
|
82481
|
-
return callee.name.startsWith("create") && callee.name.length > 6 ? callee.name.slice(6) : callee.name;
|
|
81015
|
+
return isNodeOfType(callee, "Identifier") ? callee.name : null;
|
|
82482
81016
|
}
|
|
82483
81017
|
return null;
|
|
82484
81018
|
};
|
|
82485
|
-
const isMatchingReturnType = (typeNode, initializationValue, scopes) => {
|
|
82486
|
-
if (!isNodeOfType(typeNode, "TSTypeReference")) return false;
|
|
82487
|
-
const typeName = typeNode.typeName;
|
|
82488
|
-
if (!isNodeOfType(typeName, "Identifier") || typeName.name !== "ReturnType") return false;
|
|
82489
|
-
const [returnTypeArgument] = typeNode.typeArguments?.params ?? [];
|
|
82490
|
-
if (!returnTypeArgument || !isNodeOfType(returnTypeArgument, "TSTypeQuery")) return false;
|
|
82491
|
-
const queriedName = returnTypeArgument.exprName;
|
|
82492
|
-
const expression = stripParenExpression(initializationValue);
|
|
82493
|
-
if (!isNodeOfType(queriedName, "Identifier") || !isNodeOfType(expression, "CallExpression")) return false;
|
|
82494
|
-
const callee = stripParenExpression(expression.callee);
|
|
82495
|
-
if (!isNodeOfType(callee, "Identifier")) return false;
|
|
82496
|
-
const queriedSymbol = scopes.symbolFor(queriedName);
|
|
82497
|
-
const calleeSymbol = scopes.symbolFor(callee);
|
|
82498
|
-
return queriedSymbol && calleeSymbol ? queriedSymbol.id === calleeSymbol.id : queriedName.name === callee.name;
|
|
82499
|
-
};
|
|
82500
81019
|
const isClosedTruthyTypeDomain = (typeNode, initializationValue, scopes) => {
|
|
82501
81020
|
const initializationExpression = stripParenExpression(initializationValue);
|
|
82502
81021
|
if (isNodeOfType(typeNode, "TSTypeLiteral")) return isNodeOfType(initializationExpression, "ObjectExpression");
|
|
82503
81022
|
if (isNodeOfType(typeNode, "TSArrayType") || isNodeOfType(typeNode, "TSTupleType")) return isNodeOfType(initializationExpression, "ArrayExpression");
|
|
82504
81023
|
if (isNodeOfType(typeNode, "TSFunctionType") || isNodeOfType(typeNode, "TSConstructorType")) return isNodeOfType(initializationExpression, "ArrowFunctionExpression") || isNodeOfType(initializationExpression, "FunctionExpression") || isNodeOfType(initializationExpression, "ClassExpression");
|
|
82505
81024
|
if (isNodeOfType(typeNode, "TSObjectKeyword")) return true;
|
|
82506
|
-
if (isNodeOfType(typeNode, "TSIndexedAccessType")) return isNodeOfType(initializationExpression, "ObjectExpression");
|
|
82507
81025
|
if (!isNodeOfType(typeNode, "TSTypeReference")) return false;
|
|
82508
81026
|
const typeName = typeNode.typeName;
|
|
82509
|
-
|
|
82510
|
-
return isNodeOfType(typeName, "Identifier") && typeName.name === getInitializationValueName(initializationExpression, scopes);
|
|
81027
|
+
return isNodeOfType(typeName, "Identifier") && typeName.name === getInitializationConstructorName(initializationExpression, scopes);
|
|
82511
81028
|
};
|
|
82512
81029
|
const refHasClosedFalsySentinelDomain = (refSymbol, initializationValue, scopes) => {
|
|
82513
81030
|
const initializer = refSymbol.initializer ? stripParenExpression(refSymbol.initializer) : null;
|
|
82514
81031
|
if (!initializer || !isNodeOfType(initializer, "CallExpression")) return false;
|
|
82515
81032
|
const [initialValue] = initializer.arguments ?? [];
|
|
82516
|
-
if (initialValue
|
|
81033
|
+
if (!initialValue || isNodeOfType(initialValue, "SpreadElement") || !isEmptySentinel(initialValue, scopes)) return false;
|
|
82517
81034
|
const [declaredType] = initializer.typeArguments?.params ?? [];
|
|
82518
|
-
if (!declaredType) return false;
|
|
82519
|
-
|
|
81035
|
+
if (!declaredType || !isNodeOfType(declaredType, "TSUnionType")) return false;
|
|
81036
|
+
let hasEmptySentinel = false;
|
|
82520
81037
|
let hasTruthyDomain = false;
|
|
82521
|
-
for (const memberType of
|
|
82522
|
-
if (isNodeOfType(memberType, "TSNullKeyword") || isNodeOfType(memberType, "TSUndefinedKeyword"))
|
|
81038
|
+
for (const memberType of declaredType.types ?? []) {
|
|
81039
|
+
if (isNodeOfType(memberType, "TSNullKeyword") || isNodeOfType(memberType, "TSUndefinedKeyword")) {
|
|
81040
|
+
hasEmptySentinel = true;
|
|
81041
|
+
continue;
|
|
81042
|
+
}
|
|
82523
81043
|
if (!isClosedTruthyTypeDomain(memberType, initializationValue, scopes)) return false;
|
|
82524
81044
|
hasTruthyDomain = true;
|
|
82525
81045
|
}
|
|
82526
|
-
return hasTruthyDomain;
|
|
82527
|
-
};
|
|
82528
|
-
const refHasEmptySentinelInitializer = (refSymbol, scopes) => {
|
|
82529
|
-
const initializer = refSymbol.initializer ? stripParenExpression(refSymbol.initializer) : null;
|
|
82530
|
-
if (!initializer || !isNodeOfType(initializer, "CallExpression")) return false;
|
|
82531
|
-
const [initialValue] = initializer.arguments ?? [];
|
|
82532
|
-
return Boolean(!initialValue || !isNodeOfType(initialValue, "SpreadElement") && isEmptySentinel(initialValue, scopes));
|
|
82533
|
-
};
|
|
82534
|
-
const refHasDeclaredType = (refSymbol) => {
|
|
82535
|
-
const initializer = refSymbol.initializer ? stripParenExpression(refSymbol.initializer) : null;
|
|
82536
|
-
return Boolean(initializer && isNodeOfType(initializer, "CallExpression") && (initializer.typeArguments?.params.length ?? 0) > 0);
|
|
81046
|
+
return hasEmptySentinel && hasTruthyDomain;
|
|
82537
81047
|
};
|
|
82538
81048
|
const isSafeRefIdentifierUse = (identifier) => {
|
|
82539
81049
|
const expressionRoot = findTransparentExpressionRoot(identifier);
|
|
@@ -82565,40 +81075,25 @@ const expressionContainsRefCurrent = (expression, refSymbol, scopes) => {
|
|
|
82565
81075
|
});
|
|
82566
81076
|
return didFindRefCurrent;
|
|
82567
81077
|
};
|
|
82568
|
-
const
|
|
82569
|
-
|
|
82570
|
-
|
|
82571
|
-
|
|
82572
|
-
|
|
82573
|
-
|
|
82574
|
-
|
|
82575
|
-
if (!isInputIndependent) return false;
|
|
82576
|
-
if (resolveReactRefSymbol(child, scopes)) return false;
|
|
82577
|
-
if (!isNodeOfType(child, "Identifier")) return;
|
|
82578
|
-
const symbol = scopes.symbolFor(child);
|
|
82579
|
-
if (!symbol) return;
|
|
82580
|
-
if (symbol.kind === "import") return false;
|
|
82581
|
-
if (symbol.kind === "let" || symbol.kind === "var" || symbol.kind === "using") {
|
|
82582
|
-
isInputIndependent = false;
|
|
82583
|
-
return false;
|
|
81078
|
+
const hasNoCompetingRefCurrentWrite = (branchRoot, assignmentExpression, refSymbol, scopes) => {
|
|
81079
|
+
let writeCount = 0;
|
|
81080
|
+
walkAst(branchRoot, (child) => {
|
|
81081
|
+
if (writeCount > 1) return false;
|
|
81082
|
+
if (isNodeOfType(child, "AssignmentExpression")) {
|
|
81083
|
+
if (expressionContainsRefCurrent(child.left, refSymbol, scopes)) writeCount++;
|
|
81084
|
+
return;
|
|
82584
81085
|
}
|
|
82585
|
-
if (
|
|
82586
|
-
|
|
82587
|
-
|
|
82588
|
-
return false;
|
|
81086
|
+
if (isNodeOfType(child, "UpdateExpression") || isNodeOfType(child, "UnaryExpression") && child.operator === "delete") {
|
|
81087
|
+
if (expressionContainsRefCurrent(child.argument, refSymbol, scopes)) writeCount++;
|
|
81088
|
+
return;
|
|
82589
81089
|
}
|
|
82590
|
-
if (
|
|
82591
|
-
|
|
82592
|
-
return false;
|
|
81090
|
+
if (isNodeOfType(child, "ForInStatement") || isNodeOfType(child, "ForOfStatement")) {
|
|
81091
|
+
if (expressionContainsRefCurrent(child.left, refSymbol, scopes)) writeCount++;
|
|
82593
81092
|
}
|
|
82594
|
-
if (visitedSymbolIds.has(symbol.id)) return false;
|
|
82595
|
-
visitedSymbolIds.add(symbol.id);
|
|
82596
|
-
if (!isInitializationInputIndependent(symbol.initializer, renderOwner, scopes, visitedSymbolIds)) isInputIndependent = false;
|
|
82597
|
-
return false;
|
|
82598
81093
|
});
|
|
82599
|
-
return
|
|
81094
|
+
return writeCount === 1 && expressionContainsRefCurrent(assignmentExpression.left, refSymbol, scopes);
|
|
82600
81095
|
};
|
|
82601
|
-
const
|
|
81096
|
+
const isEmptySentinel = (node, scopes) => isNodeOfType(node, "Literal") && node.value === null || isNodeOfType(node, "Identifier") && node.name === "undefined" && scopes.isGlobalReference(node);
|
|
82602
81097
|
const hasRepeatedExecutionAncestor = (node, stop) => {
|
|
82603
81098
|
let ancestor = node.parent;
|
|
82604
81099
|
while (ancestor && ancestor !== stop) {
|
|
@@ -82628,27 +81123,6 @@ const canExecuteTogether = (firstConstraints, secondConstraints) => {
|
|
|
82628
81123
|
}
|
|
82629
81124
|
return true;
|
|
82630
81125
|
};
|
|
82631
|
-
const hasNoCoExecutableCompetingWrite = (assignmentExpression, renderOwner, refSymbol, scopes) => {
|
|
82632
|
-
const assignmentConstraints = getBranchConstraints(assignmentExpression, renderOwner);
|
|
82633
|
-
const synchronouslyInvokedFunctions = collectSynchronouslyEffectInvokedFunctions(renderOwner, scopes);
|
|
82634
|
-
let hasCompetingWrite = false;
|
|
82635
|
-
walkAst(renderOwner, (child) => {
|
|
82636
|
-
if (hasCompetingWrite) return false;
|
|
82637
|
-
let writtenExpression = null;
|
|
82638
|
-
if (isNodeOfType(child, "AssignmentExpression")) {
|
|
82639
|
-
if (child === assignmentExpression) return;
|
|
82640
|
-
writtenExpression = child.left;
|
|
82641
|
-
} else if (isNodeOfType(child, "UpdateExpression") || isNodeOfType(child, "UnaryExpression") && child.operator === "delete") writtenExpression = child.argument;
|
|
82642
|
-
else if (isNodeOfType(child, "ForInStatement") || isNodeOfType(child, "ForOfStatement")) writtenExpression = child.left;
|
|
82643
|
-
const deferredExecutionBoundary = findDeferredExecutionBoundary(child);
|
|
82644
|
-
const deferredWriteValue = isNodeOfType(child, "AssignmentExpression") && child.operator === "=" ? resolveImmutableInitializationValue(child.right, scopes) : null;
|
|
82645
|
-
const isDeferredTruthyWrite = deferredExecutionBoundary !== null && deferredExecutionBoundary !== renderOwner && !synchronouslyInvokedFunctions.has(deferredExecutionBoundary) && !executesDuringRender(deferredExecutionBoundary, scopes) && deferredWriteValue !== null && !isNodeOfType(deferredWriteValue, "CallExpression") && isProvablyTruthyInitializationValue(deferredWriteValue, scopes);
|
|
82646
|
-
if (!writtenExpression || isDeferredTruthyWrite || !expressionContainsRefCurrent(writtenExpression, refSymbol, scopes) || !canExecuteTogether(assignmentConstraints, getBranchConstraints(child, renderOwner))) return;
|
|
82647
|
-
hasCompetingWrite = true;
|
|
82648
|
-
return false;
|
|
82649
|
-
});
|
|
82650
|
-
return !hasCompetingWrite;
|
|
82651
|
-
};
|
|
82652
81126
|
const hasNoPriorCoExecutableWrite = (assignmentExpression, branchRoot, refSymbol, scopes) => {
|
|
82653
81127
|
const assignmentConstraints = getBranchConstraints(assignmentExpression, branchRoot);
|
|
82654
81128
|
const assignmentStart = getRangeStart(assignmentExpression);
|
|
@@ -82664,17 +81138,16 @@ const hasNoPriorCoExecutableWrite = (assignmentExpression, branchRoot, refSymbol
|
|
|
82664
81138
|
});
|
|
82665
81139
|
return !hasCoExecutableWrite;
|
|
82666
81140
|
};
|
|
82667
|
-
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);
|
|
82668
81141
|
const isDocumentedLazyInitialization = (assignmentExpression, refSymbol, scopes) => {
|
|
81142
|
+
if (assignmentExpression.operator === "??=" || assignmentExpression.operator === "||=") return true;
|
|
81143
|
+
if (assignmentExpression.operator !== "=") return false;
|
|
82669
81144
|
const renderOwner = findRenderPhaseComponentOrHook(assignmentExpression, scopes);
|
|
82670
81145
|
if (!renderOwner) return false;
|
|
82671
|
-
if (assignmentExpression.operator === "??=" || assignmentExpression.operator === "||=") return isPredictableGuardedInitialization(assignmentExpression, renderOwner, renderOwner, refSymbol, scopes, assignmentExpression.operator === "||=");
|
|
82672
|
-
if (assignmentExpression.operator !== "=") return false;
|
|
82673
81146
|
let descendant = assignmentExpression;
|
|
82674
81147
|
let ancestor = descendant.parent;
|
|
82675
81148
|
while (ancestor) {
|
|
82676
81149
|
const test = isNodeOfType(ancestor, "IfStatement") ? stripParenExpression(ancestor.test) : null;
|
|
82677
|
-
if (isNodeOfType(ancestor, "IfStatement") && test && isNodeOfType(test, "UnaryExpression") && test.operator === "!" && isSameRefCurrentAlias(test.argument, refSymbol, scopes) && ancestor.consequent === descendant &&
|
|
81150
|
+
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;
|
|
82678
81151
|
if (isNodeOfType(ancestor, "IfStatement") && isNodeOfType(test, "BinaryExpression") && [
|
|
82679
81152
|
"===",
|
|
82680
81153
|
"==",
|
|
@@ -82684,7 +81157,7 @@ const isDocumentedLazyInitialization = (assignmentExpression, refSymbol, scopes)
|
|
|
82684
81157
|
const { left, right } = test;
|
|
82685
81158
|
const comparesEmptySentinel = isSameRefCurrentAlias(left, refSymbol, scopes) && isEmptySentinel(right, scopes) || isSameRefCurrentAlias(right, refSymbol, scopes) && isEmptySentinel(left, scopes);
|
|
82686
81159
|
const guardedBranch = test.operator === "===" || test.operator === "==" ? ancestor.consequent : ancestor.alternate;
|
|
82687
|
-
if (comparesEmptySentinel && guardedBranch === descendant && guardedBranch &&
|
|
81160
|
+
if (comparesEmptySentinel && guardedBranch === descendant && guardedBranch && !hasRepeatedExecutionAncestor(assignmentExpression, guardedBranch) && hasNoPriorCoExecutableWrite(assignmentExpression, guardedBranch, refSymbol, scopes)) return true;
|
|
82688
81161
|
}
|
|
82689
81162
|
descendant = ancestor;
|
|
82690
81163
|
ancestor = descendant.parent;
|
|
@@ -110491,6 +108964,9 @@ const rerenderFunctionalSetstate = defineRule({
|
|
|
110491
108964
|
} })
|
|
110492
108965
|
});
|
|
110493
108966
|
//#endregion
|
|
108967
|
+
//#region src/plugin/utils/is-trivial-built-in-construction.ts
|
|
108968
|
+
const isTrivialBuiltInConstruction = (expression) => isNodeOfType(expression, "NewExpression") && isNodeOfType(expression.callee, "Identifier") && TRIVIAL_CONSTRUCTOR_NAMES.has(expression.callee.name) && (expression.arguments ?? []).length === 0;
|
|
108969
|
+
//#endregion
|
|
110494
108970
|
//#region src/plugin/rules/state-and-effects/rerender-lazy-ref-init.ts
|
|
110495
108971
|
const rerenderLazyRefInit = defineRule({
|
|
110496
108972
|
id: "rerender-lazy-ref-init",
|
|
@@ -110509,6 +108985,7 @@ const rerenderLazyRefInit = defineRule({
|
|
|
110509
108985
|
const memberPropertyName = isNodeOfType(callee, "MemberExpression") && (isNodeOfType(callee.property, "Identifier") || isNodeOfType(callee.property, "PrivateIdentifier")) ? callee.property.name : null;
|
|
110510
108986
|
const calleeName = isNodeOfType(callee, "Identifier") ? callee.name : memberPropertyName ?? "fn";
|
|
110511
108987
|
if (TRIVIAL_INITIALIZER_NAMES.has(calleeName)) return;
|
|
108988
|
+
if (isTrivialBuiltInConstruction(initializer)) return;
|
|
110512
108989
|
if (isPlainCall && isReactHookName(calleeName)) return;
|
|
110513
108990
|
const callShape = isNewCall ? `new ${calleeName}()` : `${calleeName}()`;
|
|
110514
108991
|
context.report({
|